251 lines
8.1 KiB
TypeScript
251 lines
8.1 KiB
TypeScript
import { Injectable } from '@angular/core';
|
||
import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router';
|
||
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
|
||
|
||
import { Answer } from '../enums/answer.enum';
|
||
import { Choice } from '../models/choice.model';
|
||
import { Poll } from '../models/poll.model';
|
||
import { Owner } from '../models/owner.model';
|
||
import { ApiService } from './api.service';
|
||
import { ToastService } from './toast.service';
|
||
import { UserService } from './user.service';
|
||
import { UuidService } from './uuid.service';
|
||
import { HttpClient } from '@angular/common/http';
|
||
import { environment } from '../../../environments/environment';
|
||
import { StorageService } from './storage.service';
|
||
import { Title } from '@angular/platform-browser';
|
||
|
||
@Injectable({
|
||
providedIn: 'root',
|
||
})
|
||
export class PollService implements Resolve<Poll> {
|
||
_poll: BehaviorSubject<Poll | undefined> = new BehaviorSubject<Poll | undefined>(undefined);
|
||
public readonly poll: Observable<Poll | undefined> = this._poll.asObservable();
|
||
|
||
constructor(
|
||
private http: HttpClient,
|
||
private router: Router,
|
||
private apiService: ApiService,
|
||
private storageService: StorageService,
|
||
private userService: UserService,
|
||
private uuidService: UuidService,
|
||
private titleService: Title,
|
||
private toastService: ToastService
|
||
) {}
|
||
|
||
/**
|
||
* auto fetch a poll when route is looking for one in the administration pattern
|
||
* @param route
|
||
* @param state
|
||
*/
|
||
public async resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<Poll> {
|
||
const segments: string[] = state.url.split('/');
|
||
const wantedcustom_url: string = segments.includes('poll') ? segments[segments.indexOf('poll') + 1] : '';
|
||
|
||
// FIXME should be handled by routing
|
||
if (!wantedcustom_url && state.url.includes('administration')) {
|
||
// creation of new poll
|
||
const poll = new Poll(this.userService.getCurrentUser(), this.uuidService.getUUID(), '');
|
||
this._poll.next(poll);
|
||
this.router.navigate(['poll/' + poll.custom_url + '/administration']);
|
||
}
|
||
if (
|
||
!this._poll.getValue() ||
|
||
!this._poll.getValue().custom_url ||
|
||
this._poll.getValue().custom_url !== wantedcustom_url
|
||
) {
|
||
await this.loadPollBycustom_url(wantedcustom_url);
|
||
}
|
||
if (this._poll.getValue()) {
|
||
return this._poll.getValue();
|
||
} else {
|
||
this.router.navigate(['page-not-found']);
|
||
return;
|
||
}
|
||
}
|
||
|
||
getAllAvailablePolls() {
|
||
const baseHref = environment.api.version.apiV1.baseHref;
|
||
console.log('getAllAvailablePolls baseHref', baseHref);
|
||
const headers = ApiService.makeHeaders();
|
||
console.log('getAllAvailablePolls headers', headers);
|
||
try {
|
||
this.http.get(`${baseHref}/poll`, headers).subscribe((res: Observable<any>) => {
|
||
console.log('getAllAvailablePolls res', res);
|
||
});
|
||
} catch (e) {
|
||
console.error('getAllAvailablePolls e', e);
|
||
}
|
||
}
|
||
|
||
public async loadPollBycustom_url(custom_url: string): Promise<void> {
|
||
console.log('custom_url', custom_url);
|
||
if (custom_url) {
|
||
const poll: Poll | undefined = await this.apiService.getPollByCustomUrl(custom_url);
|
||
|
||
console.log({ loadPollBycustom_urlResponse: poll });
|
||
if (poll) {
|
||
this.updateCurrentPoll(poll);
|
||
this.titleService.setTitle(`☑️ ${poll.title} - ${environment.appTitle}`);
|
||
} else {
|
||
this.toastService.display(`sondage ${custom_url} non trouvé`);
|
||
}
|
||
}
|
||
}
|
||
|
||
public async loadPollBycustom_urlWithPasswordHash(custom_url: string, hash: string): Promise<void> {
|
||
console.log('custom_url', custom_url);
|
||
if (custom_url) {
|
||
const poll: Poll | undefined = await this.apiService.getPollByCustomUrlWithHash(custom_url, hash);
|
||
console.log({ loadPollBycustom_urlResponse: poll });
|
||
this.updateCurrentPoll(poll);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* update poll and parse its fields
|
||
* @param poll
|
||
*/
|
||
public updateCurrentPoll(poll: Poll): void {
|
||
this.storageService.setChoicesForVoteStack(poll.choices);
|
||
|
||
this.toastService.display('sondage bien mis à jour', 'success');
|
||
|
||
console.log('poll', poll);
|
||
this._poll.next(poll);
|
||
}
|
||
|
||
/**
|
||
* make a uniq custom_url for the current poll creation
|
||
* @param poll
|
||
*/
|
||
makecustom_url(poll: Poll): string {
|
||
console.log('config', poll);
|
||
let str = '';
|
||
const creation_date = new Date(poll.creation_date);
|
||
str =
|
||
creation_date.getFullYear() +
|
||
'_' +
|
||
(creation_date.getMonth() + 1) +
|
||
'_' +
|
||
creation_date.getDate() +
|
||
'_' +
|
||
poll.owner.pseudo +
|
||
'_' +
|
||
poll.title;
|
||
str = str.replace(/^\s+|\s+$/g, ''); // trim
|
||
str = str.toLowerCase();
|
||
|
||
// remove accents, swap ñ for n, etc
|
||
const from = 'àáäâèéëêìíïîòóöôùúüûñç·/_,:;';
|
||
const to = 'aaaaeeeeiiiioooouuuunc------';
|
||
for (let 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 + '-' + this.uuidService.getUUID();
|
||
}
|
||
|
||
public async saveCurrentPoll(): Promise<Subscription> {
|
||
// .then((resp) => {
|
||
// console.log('resp', resp);
|
||
// if (pollUrl) {
|
||
// console.log('pollUrl', pollUrl);
|
||
// this.toastService.display('Le sondage a été enregistré.');
|
||
// // TODO: redirect to view
|
||
// } else {
|
||
// this.toastService.display('Le sondage n’a été correctement enregistré, veuillez ré-essayer.');
|
||
// }
|
||
// })
|
||
// .catch((err) => {
|
||
// console.error('err', err);
|
||
// });
|
||
return await this.apiService.createPoll(this._poll.getValue());
|
||
}
|
||
|
||
public saveParticipation(choice: Choice, user: Owner, response: Answer): void {
|
||
const currentPoll = this._poll.getValue();
|
||
currentPoll.choices.find((c) => c.name === choice.name)?.updateParticipation(user, response);
|
||
this.updateCurrentPoll(currentPoll);
|
||
this.apiService.createParticipation(currentPoll.custom_url, choice.name, user.pseudo, response);
|
||
this.toastService.display('Votre participation au sondage a été enregistrée.');
|
||
}
|
||
|
||
public async deleteAllAnswers(): Promise<void> {
|
||
await this.apiService.deletePollAnswers(this._poll.getValue().custom_url);
|
||
this.toastService.display('Les participations des votants à ce sondage ont été supprimées.');
|
||
}
|
||
|
||
public async addComment(comment: string): Promise<void> {
|
||
await this.apiService.createComment(this._poll.getValue().custom_url, comment);
|
||
this.toastService.display('Votre commentaire a été enregistré.');
|
||
}
|
||
|
||
public async deleteComments(): Promise<void> {
|
||
await this.apiService.deletePollComments(this._poll.getValue().custom_url);
|
||
this.toastService.display('Les commentaires de ce sondage ont été supprimés.');
|
||
}
|
||
|
||
/**
|
||
* @description convert to API version 1 data transition object
|
||
* @param form
|
||
*/
|
||
newPollFromForm(form: any): Poll {
|
||
const newOwner = this.storageService.vote_stack.owner;
|
||
|
||
const newpoll = new Poll(newOwner, form.value.custom_url, form.value.title);
|
||
|
||
const pollKeys = Object.keys(newpoll);
|
||
const formFields = Object.keys(form.value);
|
||
|
||
console.log('pollKeys, formFields', pollKeys, formFields);
|
||
|
||
for (const pk of pollKeys) {
|
||
if (formFields.indexOf(pk) !== -1) {
|
||
newpoll[pk] = form.value[pk];
|
||
} else {
|
||
console.log('manque pollKey', pk);
|
||
}
|
||
}
|
||
newpoll.description = form.value.description;
|
||
newpoll.max_count_of_answers = form.value.allowComments;
|
||
newpoll.maxCountOfAnswers = form.value.maxCountOfAnswers;
|
||
newpoll.password = form.value.password;
|
||
newpoll.kind = form.value.kind;
|
||
newpoll.allow_comments = form.value.allowComments;
|
||
newpoll.dateChoices = this.storageService.dateList;
|
||
newpoll.timeSlices = this.storageService.timeSlices;
|
||
|
||
console.log('newpoll', newpoll);
|
||
return newpoll;
|
||
}
|
||
|
||
public getAdministrationUrl(): string {
|
||
let url = '';
|
||
if (this._poll && this._poll.getValue) {
|
||
const polltemp = this._poll.getValue();
|
||
if (polltemp) {
|
||
url = `${environment.frontDomain}#/poll/admin/${polltemp.admin_key}`;
|
||
}
|
||
}
|
||
return url;
|
||
}
|
||
|
||
public getParticipationUrl(): string {
|
||
let url = '';
|
||
if (this._poll && this._poll.getValue) {
|
||
const polltemp = this._poll.getValue();
|
||
if (polltemp) {
|
||
url = `${environment.frontDomain}#/poll/${polltemp.custom_url}/consultation`;
|
||
}
|
||
}
|
||
// TODO handle pass access
|
||
return url;
|
||
}
|
||
}
|