import { Injectable } from '@angular/core'; import axios, { AxiosInstance, AxiosResponse } from 'axios'; import { environment } from 'src/environments/environment'; import { Answer } from '../enums/answer.enum'; import { Poll } from '../models/poll.model'; import { HttpClient } from '@angular/common/http'; import { Observable, Subscription } from 'rxjs'; import { ToastService } from './toast.service'; import { LoaderService } from './loader.service'; import { Stack } from '../models/stack.model'; const apiVersion = environment.api.versionToUse; const currentApiRoutes = environment.api.version[apiVersion]; const apiBaseHref = environment.api.version[apiVersion].baseHref; const apiEndpoints = environment.api.endpoints; @Injectable({ providedIn: 'root', }) export class ApiService { private axiosInstance: AxiosInstance; private readonly pollsEndpoint = apiEndpoints.polls.name; private readonly answersEndpoint = apiEndpoints.polls.answers.name; private readonly commentsEndpoint = apiEndpoints.polls.comments.name; private readonly slugsEndpoint = apiEndpoints.polls.slugs.name; private readonly usersEndpoint = apiEndpoints.users.name; private readonly usersPollsEndpoint = apiEndpoints.users.polls.name; private readonly usersPollsSendEmailEndpoint = apiEndpoints.users.polls.sendEmail.name; private baseHref: string; private static loaderService: LoaderService; constructor(private http: HttpClient, private toastService: ToastService, private loaderService: LoaderService) { this.baseHref = apiBaseHref; this.axiosInstance = axios.create({ baseURL: apiBaseHref }); this.axiosInstance.defaults.timeout = 2500; this.axiosInstance.defaults.headers.post['Content-Type'] = 'application/json'; this.axiosInstance.defaults.headers.post['Accept'] = 'application/json'; this.axiosInstance.defaults.headers.post['Charset'] = 'UTF-8'; // this.axiosInstance.defaults.headers.post['Accept-Charset'] = 'UTF-8'; this.axiosInstance.defaults.headers.post['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'; this.axiosInstance.defaults.headers.post['Referrer-Policy'] = 'origin-when-cross-origin'; this.axiosInstance.defaults.headers.post['Access-Control-Allow-Origin'] = '*'; this.axiosInstance.defaults.headers.post['Allow-Origin'] = '*'; this.axiosInstance.defaults.headers.post['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept'; console.log('this.axiosInstance.defaults.headers', this.axiosInstance.defaults.headers); } ////////////////////// // CREATE OR UPDATE // ////////////////////// ///////////////////// /** * prepare headers like the charset and json type for any call to the backend * @param bodyContent? */ static makeHeaders(bodyContent?: any) { const headerDict = { Charset: 'UTF-8', // 'Content-Type': 'application/json', // Accept: 'application/json', 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json', mode: 'no-cors', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Accept,Accept-Language,Content-Language,Content-Type', // 'Access-Control-Allow-Origin': '*', }; return { headers: headerDict, body: bodyContent, }; } public async createPoll(poll: Poll): Promise { // this.loaderService.setStatus(true); console.log('createPoll config', poll); return this.axiosInstance.post( `${this.baseHref}${currentApiRoutes['api_new_poll']}`, poll, ApiService.makeHeaders() ); } /** * send a new vote stack * @param vote_stack */ public sendNewVoteStackOfPoll(vote_stack: Stack): Promise { // api_new_vote_stack POST ANY ANY /api/v1/poll/{id}/answer console.log('vote_stack', vote_stack); console.log('this.baseHref', this.baseHref); const headers = ApiService.makeHeaders(vote_stack); console.log('headers', headers); const url = `${this.baseHref}/vote-stack/`; const axiosconf = { url, method: 'POST', body: vote_stack, headers, }; return this.axiosInstance.post(url, vote_stack); } ////////// // READ // public async createParticipation( pollId: string, choiceLabel: string, pseudo: string, response: Answer ): Promise { try { return await this.axiosInstance.post(`${this.pollsEndpoint}/${pollId}${this.answersEndpoint}`, { choiceLabel, pseudo, response, }); } catch (error) { ApiService.handleError(error); } } public async createComment(slug: string, comment: string): Promise { try { return await this.axiosInstance.post(`${this.pollsEndpoint}/${slug}${this.commentsEndpoint}`, comment); } catch (error) { ApiService.handleError(error); } } ////////// public async getAllAvailablePolls(): Promise { // TODO: used for facilities in DEV, should be removed in production try { const response: AxiosResponse = await this.axiosInstance.get(`${this.pollsEndpoint}`); return response?.data; } catch (error) { ApiService.handleError(error); } } public async getPollByCustomUrl(slug: string): Promise { try { console.log('fetch API : asking for poll with custom_url=' + slug); const response: AxiosResponse = await this.axiosInstance.get(`${this.pollsEndpoint}/${slug}`); return response && response.data && !Array.isArray(response.data) ? response.data : undefined; } catch (error) { if (error.response?.status === 404) { return undefined; } else { ApiService.handleError(error); } } } public async getPollByCustomUrlWithHash(slug: string, hash: string): Promise { try { const response: AxiosResponse = await this.axiosInstance.get( `${this.pollsEndpoint}/${slug}/pass/${hash}` ); console.log('fetch API : asking for poll with custom_url=' + slug, { response }); return response && response.data && !Array.isArray(response.data) ? response.data : undefined; } catch (error) { if (error.response?.status === 404) { return undefined; } else { ApiService.handleError(error); } } } public async getSlug(slug: string): Promise { try { // TODO: scenario should be : if we can get this custom_url, it exists. if not, it doesn't. It's just a GET. const response: AxiosResponse = await this.axiosInstance.get( `${this.pollsEndpoint}${this.slugsEndpoint}/${slug}` ); if (response?.status !== 404) { return false; } } catch (error) { if (error.response?.status === 404) { return true; } else { ApiService.handleError(error); } } } //////////// // UPDATE // public async sendUpdateVoteStack(vote_stack: Stack) { try { return await this.axiosInstance.patch( `${this.baseHref}/vote-stack/${vote_stack.id}/token/${vote_stack.owner.modifier_token}`, vote_stack ); } catch (error) { ApiService.handleError(error); } } public findMyPollsByEmail(email: string): Promise { return this.axiosInstance.get(`${this.baseHref}/poll/owner/${email}`); } public async updateAnswer(slug: string, choiceLabel: string, pseudo: string, answer: Answer): Promise { try { return await this.axiosInstance.patch(`${this.baseHref}/${slug}${this.answersEndpoint}`, { choiceLabel, pseudo, answer, }); } catch (error) { ApiService.handleError(error); } } //////////// // DELETE // //////////// //////////// public async deletePoll(slug: string): Promise { try { const response: AxiosResponse = await this.axiosInstance.delete(`${this.pollsEndpoint}/${slug}`); return response?.status === 204; } catch (error) { ApiService.handleError(error); } } public async deletePollAnswers(slug: string): Promise { try { const response: AxiosResponse = await this.axiosInstance.delete( `${this.pollsEndpoint}/${slug}${this.answersEndpoint}` ); return response?.status === 204; } catch (error) { ApiService.handleError(error); } } public async deletePollComments(slug: string): Promise { try { const response: AxiosResponse = await this.axiosInstance.delete( `${this.pollsEndpoint}/${slug}${this.commentsEndpoint}` ); return response?.status === 204; } catch (error) { ApiService.handleError(error); } } ///////////////////// // PRIVATE METHODS // ///////////////////// private static handleError(error): void { // this.loaderService.setStatus(true); if (error.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx console.error('Error response data', error.response.data); console.error('Error response status', error.response.status); console.error('Error response headers', error.response.headers); } else if (error.request) { // The request was made but no response was received // `error.request` is an instance of XMLHttpRequest in the browser and an instance of // http.ClientRequest in node.js console.log('ErrorRequest', error.request); } else { // Something happened in setting up the request that triggered an Error console.log('Error', error.message); } console.log(error.config); // this.loaderService.setStatus(false); } public ousideHandleError(error) { // this.loaderService.setStatus(true); if (error.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx console.error('Error response data', error.response.data); console.error('Error response status', error.response.status); console.error('Error response headers', error.response.headers); } else if (error.request) { // The request was made but no response was received // `error.request` is an instance of XMLHttpRequest in the browser and an instance of // http.ClientRequest in node.js console.log('ErrorRequest', error.request); } else { // Something happened in setting up the request that triggered an Error console.log('Error', error.message); } console.log(error.config); // this.loaderService.setStatus(false); } }