funky-framadate-front/src/app/services/config.service.ts

551 lines
17 KiB
TypeScript

import {Injectable} from '@angular/core';
import {PollConfig} from '../config/PollConfig';
import {HttpClient, HttpHeaders} from "@angular/common/http";
import {environment} from "../../environments/environment";
import {ConfirmationService, MessageService} from 'primeng/api';
import {Router} from "@angular/router";
import {mockMyPolls} from "../config/mocks/mockmypolls";
import {defaultAnswers, defaultDates, timeOfDay} from "../config/defaultConfigs";
import {mockPoll1} from "../config/mocks/mock1";
/**
* le service transverse à chaque page qui permet de syncroniser la configuration de sondage souhaitée
*/
@Injectable({
providedIn: 'root'
})
export class ConfigService extends PollConfig {
loading: boolean = false;
baseHref: any = environment.baseApiHref;
constructor(private http: HttpClient,
private messageService: MessageService,
private router: Router,
private confirmationService: ConfirmationService,
) {
super();
// fill in mock values if we are not in production environment
if (!environment.production) {
console.info(' ######### framadate ######### we are not in production env, filling with mock values');
this.currentPoll = mockPoll1;
this.myPolls = mockMyPolls;
this.dateList = defaultDates;
this.timeList = timeOfDay;
this.answers = defaultAnswers;
}
}
set(key, val) {
this[key] = val;
}
clear() {
this.messageService.clear();
}
// utils functions
/**
* generate unique id to have a default url for future poll
*/
makeUuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
/**
* make a uniq slug for the current poll creation
* @param str
*/
makeSlug(str?: string) {
if (!str) {
str = this.creationDate.getFullYear() + '_' + (this.creationDate.getMonth() + 1) + '_' + this.creationDate.getDate() + '_' + this.myName + '_' + this.title;
}
str = str.replace(/^\s+|\s+$/g, ''); // trim
str = str.toLowerCase();
// remove accents, swap ñ for n, etc
var from = "àáäâèéëêìíïîòóöôùúüûñç·/_,:;";
var to = "aaaaeeeeiiiioooouuuunc------";
for (var i = 0, l = from.length; i < l; i++) {
str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
}
str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
.replace(/\s+/g, '-') // collapse whitespace and replace by -
.replace(/-+/g, '-'); // collapse dashes
return str;
}
/**
* add some days to a date, to compute intervals
* @param days
* @param date
*/
addDaysToDate(days: number, date: Date) {
date = new Date(date.valueOf());
date.setDate(date.getDate() + days);
return date;
};
/** ==================================
*
* poll public calls to get non authenticated info
*
* ==================================/
/**
* convert current poll config to a payload to send to the backend API
*/
getPollConfig() {
const jsonConfig = {
owner: {
email: this.myEmail,
pseudo: this.myName,
},
title: this.title,
description: this.description,
type: this.pollType,
visibility: this.visibility,
voteChoices: this.voteChoices,
allowSeveralHours: this.allowSeveralHours,
expirationDate: this.expirationDate,
passwordAccess: this.passwordAccess,
password: this.password,
customUrl: this.customUrl,
canModifyAnswers: this.canModifyAnswers,
whoModifiesAnswers: this.whoModifiesAnswers,
dateList: this.dateList,
timeList: this.timeList,
answers: this.answers,
expiracyDateDefaultInDays: this.expiracyDateDefaultInDays,
deletionDateAfterLastModification: this.deletionDateAfterLastModification,
};
return jsonConfig
}
/**
* prepare headers like the charset and json type for any call to the backend
* @param bodyContent
*/
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-Origin': '*'
};
const requestOptions = {
headers: new HttpHeaders(headerDict),
body: bodyContent
};
return requestOptions;
}
checkIfSlugIsUniqueInDatabase(slug: string = '') {
this.customUrlIsUnique = null;
if (!slug) {
slug = this.makeSlug();
}
this.loading = true;
// TODO
this.todo('check slug is unique');
this.http.get(`${this.baseHref}/check-slug-is-uniq/${slug}`,
this.makeHeaders({slug: this.customUrl}),
)
.subscribe((res: any) => {
this.customUrlIsUnique = res.data.isUnique;
this.loading = false;
},
(e) => this.handleError(e))
;
}
/**
* search in localstorage, fallback asking the backend to send an email to the owner if it exists
* @param email
*/
findPollsByEmail(email: string) {
this.findLocalStorageData();
// If no key is found in the localstorage, ask the backend to send an email to the user
this.myEmail = email;
this.todo('send email for real : TODO');
this.loading = true;
this.http.get(`${this.baseHref}/send-polls-to-user/${this.myEmail}`,
this.makeHeaders(),
)
.subscribe(res => {
// message: 'Trouvé! Allez voir votre boite email',
this.myPolls = res;
this.loading = false;
this.messageService.add({
severity: 'success',
summary: 'Succès',
detail: `Vos infos de sondages vous ont été transmises. Allez voir votre boite email ${this.myEmail}`
});
}, (e) => {
this.handleError(e)
}
)
}
/**
* display error message depending on the response of the backend
* @param err
*/
handleError(err: any) {
console.error('err', err);
this.loading = false;
this.messageService.add({severity: 'warning', summary: "Erreur lors de l'appel ", detail: err.message});
}
findLocalStorageData() {
// TODO check if the person has a key to retrieve her polls
console.log('localStorage', localStorage);
if (localStorage) {
console.log('localStorage', localStorage)
}
}
/**
* get one poll by its slug name
* @param url
*/
getPollByURL(url: string) {
this.todo();
return this.http.get(`${this.baseHref}/poll/slug/${url}`, this.makeHeaders())
}
/**
* GET
* api/v1/poll/{id}
* @param id
*/
getPollById(id: string, password?: string) {
return this.http
.get(`${this.baseHref}/poll/${id}`,
this.makeHeaders({body: password}))
}
fetchPollFromRoute(event) {
console.log('time to fetch poll', event)
}
/**
* GET
* api/v1/my-polls
* @param ownerEmail
*/
getMyPolls(ownerEmail: string) {
this.http
.get(`${this.baseHref}/my-polls`,
this.makeHeaders({ownerEmail: ownerEmail})
)
.subscribe(
(res: any) => {
this.myPolls = res.data;
}, (e) => {
this.handleError(e)
}
);
}
/**
* launch creation call to the api
*/
createPoll() {
this.loading = true;
this.createPollFromConfig(this.getPollConfig())
}
/**
* POST
* /api/v1/poll/{id}/poll
* @param config
*/
createPollFromConfig(config: any) {
this.loading = true;
return this.http.post(`${this.baseHref}/poll`,
config,
this.makeHeaders())
.subscribe((res: any) => {
// redirect to the page to administrate the new poll
this.messageService.add({severity: 'success', summary: 'Sondage Créé',});
this.currentPoll = res;
this.pollId = res.pollId;
this.loading = false;
if (!this.myPolls) {
this.myPolls = [];
}
this.myPolls.push(config);
this.router.navigate(['step/end']);
// TODO save new poll to localstorage
// reset all fields in current config
this.resetConfig();
}, (e) => {
this.handleError(e)
}
);
}
/**
* conversion to send to back
* @param choiceList
*/
convertChoicesAnsweredToSend(choiceList) {
const converted = choiceList.map(elem => {
return {
choice_id: elem.id,
value: elem.answer
}
});
console.log('converted', converted);
return converted;
}
/**
* POST
* /api/v1/poll/{id}/vote
* @param voteStack
*/
addVote(voteStack?: any) {
if (!voteStack) {
voteStack = {
pseudo: this.myName,
email: this.myEmail,
votes: this.convertChoicesAnsweredToSend(this.currentPoll.choices),
}
}
console.log('voteStack', voteStack)
this.http.post(
`${this.baseHref}/poll/${this.currentPoll.id}/vote`,
voteStack,
this.makeHeaders())
.subscribe((res: any) => {
this.messageService.add({severity: 'success', summary: 'Vote ajouté'});
this.currentPoll = res;
}, (e) => {
this.handleError(e)
}
);
}
/**
* UPDATE
* /api/v1/poll/{id}/vote
* @param voteStack
*/
updateVote(voteStack: any) {
this.http.put(
`${this.baseHref}/vote-stack/${voteStack.id}`,
voteStack,
this.makeHeaders())
.subscribe((res: any) => {
this.messageService.add({severity: 'success', summary: 'Vote mis à jour'});
this.currentPoll = res;
}, (e) => {
this.handleError(e)
}
);
}
/**
* POST
* /api/v1/poll/{id}/comment
* @param comment
*/
addComment(comment?: any) {
if (!comment && this.myComment) {
comment = {
name: this.myName,
pseudo: this.myName,
email: this.myEmail,
date: new Date(),
text: this.myComment,
}
}
console.log('comment', comment)
this.http.post(
`${this.baseHref}/poll/${this.pollId}/comment`,
comment,
this.makeHeaders())
.subscribe((res: any) => {
this.messageService.add({
severity: 'success',
summary: 'Commentaire Créé',
detail: comment.text
});
// empty comment after success
this.myComment = '';
comment.date = {
date: comment.date
};
this.currentPoll.comments.push(comment);
}, (e) => {
this.handleError(e);
}
);
}
/**
* administrator calls
*/
deleteComments() {
// prompt for confirmation
this.confirmationService.confirm({
message: 'Are you sure that you want to completely delete the comments of this poll (' + this.title + ') permanentely?',
accept: () => {
this.http.delete(
`${this.baseHref}/poll/${this.pollId}/comments`,
this.makeHeaders())
.subscribe((res: any) => {
this.messageService.add({
severity: 'success',
summary: 'Commentaires bien supprimés',
detail: 'Commentaires du sondage "' + this.title + '" supprimé'
});
}, (e) => {
this.handleError(e)
}
);
}
});
}
deleteVotes() {
// prompt for confirmation
this.confirmationService.confirm({
message: 'Are you sure that you want to completely delete the votes of this poll (' + this.title + ') permanentely?',
accept: () => {
this.http.delete(
`${this.baseHref}/poll/${this.pollId}/votes`,
this.makeHeaders())
.subscribe((res: any) => {
this.messageService.add({
severity: 'success',
summary: 'Votes bien supprimés',
detail: 'Votes du sondage "' + this.title + '" supprimé'
});
}, (e) => {
this.handleError(e)
}
);
}
});
}
deletePoll() {
if (!this.pollId) {
this.messageService.add({
summary: 'this poll is not administrable, it has no ID',
severity: 'warning'
});
return;
}
let self = this;
// prompt for confirmation
this.confirmationService.confirm({
message: 'Are you sure that you want to completely delete this poll (' + self.title + ') and all is data permanentely?',
accept: () => {
this.http.delete(
`${this.baseHref}/poll/${this.pollId}`,
this.makeHeaders())
.subscribe((res: any) => {
this.messageService.add({
severity: 'success',
summary: 'Sondage bien supprimé',
detail: 'sondage "' + this.title + '" supprimé'
});
this.router.navigate(['home']);
}, (e) => {
this.handleError(e)
}
);
}
});
}
/**
* UPDATE
* /api/v1/poll/{id}/vote
* @param voteStack
*/
updatePoll(voteStack: any) {
this.http.put(
`${this.baseHref}/poll/${this.pollId}`,
voteStack,
this.makeHeaders()
)
.subscribe((res: any) => {
this.messageService.add({
severity: 'success',
summary: 'Sondage mis à jour',
});
this.currentPoll = res;
}, (e) => {
this.handleError(e)
}
);
}
/**
* export all the poll data available to the public as a CSV single file
*/
exportCSV() {
// TODO
const rows = [
["name1", "city1", "some other info"],
["name2", "city2", "more info"]
];
let csvContent = "data:text/csv;charset=utf-8,"
+ rows.map(e => e.join(",")).join("\n");
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", this.makeSlug() + "_export_" + new Date() + ".csv");
document.body.appendChild(link); // Required for FF
this.todo();
link.click(); // This will download the data file named "my_data.csv".
}
print() {
alert('TODO');
}
todo(message = '') {
this.messageService.add({
severity: 'info' + message,
detail: "cette fonctionnalité n'est pas encore disponible. Venez en discuter sur framateam.org / Ux et design libre / Framasoft",
summary: "Work in progress",
});
}
}