funky-framadate-front/src/app/core/services/api.service.ts

284 lines
9.2 KiB
TypeScript

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, HttpHeaders } from '@angular/common/http';
import { Subscription } from 'rxjs';
import { ToastService } from './toast.service';
import { LoaderService } from './loader.service';
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 useDevLocalServer = true;
private devLocalServerBaseHref = 'http://localhost:8000/';
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 static loader: LoaderService;
constructor(private http: HttpClient, private loader: LoaderService, private toastService: ToastService) {
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['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS';
this.axiosInstance.defaults.headers.post['Access-Control-Allow-Origin'] = '*';
this.axiosInstance.defaults.headers.post['Charset'] = 'UTF-8';
}
//////////////////////
// CREATE OR UPDATE //
//////////////////////
public async createPoll(poll: Poll): Promise<Subscription> {
// this.loader.setStatus(true);
console.log('config', poll);
// const baseHref = this.useDevLocalServer ? 'http://localhost:8000' : apiBaseHref;
// return this.http
// .post(`${baseHref}${currentApiRoutes['api_new_poll']}`, poll, ApiService.makeHeaders())
// .subscribe(
// (res: Observable<any>) => {
// // redirect to the page to administrate the new poll
// this.toastService.display('Sondage Créé');
//
// console.log('res', res);
// // this.updateCurrentPollFromResponse(res);
//
// this.loader.setStatus(false);
// },
// (e) => {
// ApiService.handleError(e);
// }
// );
try {
console.log('currentApiRoutes', currentApiRoutes);
return await this.axiosInstance.post(`${apiBaseHref}${currentApiRoutes['api_new_poll']}`, poll);
} catch (error) {
ApiService.handleError(error);
}
}
public async createParticipation(
pollId: string,
choiceLabel: string,
pseudo: string,
response: Answer
): Promise<string> {
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<string> {
try {
return await this.axiosInstance.post(`${this.pollsEndpoint}/${slug}${this.commentsEndpoint}`, comment);
} catch (error) {
ApiService.handleError(error);
}
}
//////////
// READ //
//////////
public async getAllAvailablePolls(): Promise<Poll[]> {
// TODO: used for facilities in DEV, should be removed in production
try {
const response: AxiosResponse<Poll[]> = await this.axiosInstance.get<Poll[]>(`${this.pollsEndpoint}`);
return response?.data;
} catch (error) {
ApiService.handleError(error);
}
}
public async getPollBySlug(slug: string): Promise<Poll | undefined> {
// TODO: identifier should be decided according to backend : Id || Slug ?
try {
// TODO: this interceptor should be avoided if backends returns the good object
const adapterInterceptor: number = this.axiosInstance.interceptors.response.use(
(response: AxiosResponse): AxiosResponse => {
if (response.data['poll']) {
// response from cipherbliss backend, actually used by oldstuffModule
response.data = response.data['poll'];
} else if (response.data[0] && response.data[0]['slug'] && response.data[0]['question']) {
// response from local json-server
response.data = Poll.adaptFromLocalJsonServer(response.data[0]);
}
return response;
}
);
const response: AxiosResponse<Poll> = await this.axiosInstance.get<Poll>(`${this.pollsEndpoint}/${slug}`);
console.log('fetch API : asking for poll with slug=' + slug, { response });
axios.interceptors.request.eject(adapterInterceptor);
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<boolean> {
try {
// TODO: scenario should be : if we can get this slug, 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);
}
}
}
public async sendEmailToUserOfItsPollsList(email: string): Promise<void> {
// If user is not authenticated: the list of polls is send to user's email by the backend.
try {
await this.axiosInstance.get<Poll[]>(
`${this.usersEndpoint}/${email}${this.usersPollsEndpoint}${this.usersPollsSendEmailEndpoint}`
);
} catch (error) {
ApiService.handleError(error);
}
}
public async getPollsUrlsByUserEmail(email: string): Promise<Poll[]> {
// If user is authenticated : retrieve polls & display directly in frontend.
// TODO: Backend should handle this case. Actually the endpoint doesn't exist in backend.
// Here, only the list of slugs is usefull. Maybe just handle the list of slugs.
try {
const response: AxiosResponse<Poll[]> = await this.axiosInstance.get<Poll[]>(
`${this.usersEndpoint}/${email}${this.usersPollsEndpoint}`
);
return response?.data;
} catch (error) {
ApiService.handleError(error);
}
}
////////////
// UPDATE //
////////////
public async updateAnswer(slug: string, choiceLabel: string, pseudo: string, answer: Answer): Promise<string> {
try {
return await this.axiosInstance.patch(`${this.pollsEndpoint}/${slug}${this.answersEndpoint}`, {
choiceLabel,
pseudo,
answer,
});
} catch (error) {
ApiService.handleError(error);
}
}
////////////
// DELETE //
////////////
public async deletePoll(slug: string): Promise<boolean> {
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<boolean> {
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<boolean> {
try {
const response: AxiosResponse = await this.axiosInstance.delete(
`${this.pollsEndpoint}/${slug}${this.commentsEndpoint}`
);
return response?.status === 204;
} catch (error) {
ApiService.handleError(error);
}
}
/////////////////////
// PRIVATE METHODS //
/////////////////////
/**
* 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-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Accept,Accept-Language,Content-Language,Content-Type',
'Access-Control-Allow-Origin': '*',
};
const requestOptions = {
headers: new HttpHeaders(headerDict),
body: bodyContent,
};
return requestOptions;
}
private static handleError(error): void {
// this.loader.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.log(error.response.data);
console.log(error.response.status);
console.log(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(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
}
}