import {Injectable} from '@angular/core'; import {PollConfig} from '../config/PollConfig'; import {HttpClient} 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 {mockPoll3} from '../config/mocks/mock-poll3'; import {mockSuccessVote} from '../config/mocks/mock-success-vote'; import {PollUtilities} from '../config/PollUtilities'; const LocalstoragePreferences = { themeName: 'light-watermelon', themeClass: 'theme-light-watermelon', lang: 'fr', myPolls: [], }; /** * le service transverse à chaque page qui permet de syncroniser la configuration de sondage souhaitée */ @Injectable({ providedIn: 'root' }) export class ConfigService extends PollConfig { preferences: any = LocalstoragePreferences; // user specific preferences, stored in localstorage, used for theme. loading = false; baseHref: any = environment.baseApiHref; constructor(private http: HttpClient, private messageService: MessageService, private router: Router, private utils: PollUtilities, private confirmationService: ConfirmationService, ) { super(); this.fillValuesOnDevEnv(); this.findLocalStoragePreferences(); } set(key, val) { this[key] = val; } // fill in mock values if we are not in production environment fillValuesOnDevEnv() { if (!environment.production) { console.info(' ######### framadate ######### we are not in production env, filling with mock values'); this.currentPoll = mockPoll3; this.myPolls = mockMyPolls; } } findLocalStoragePreferences() { const storage = window.localStorage; console.log('this.preferences', this.preferences); console.log('storage', storage); if (storage) { const preferences = storage.getItem('FramadateConfig'); if (preferences) { const parsed = JSON.parse(preferences); console.log('parsed', parsed); this.preferences = parsed; } } else { console.error('pas de localstorage'); this.preferences = LocalstoragePreferences; } this.saveLocalStoragePreferences(); } setPreference(key, value) { if (this.preferences) { this.preferences[key] = value; if (key === 'themeName' && this.themeChoices.includes(value)) { this.themeSelected = this.themeChoices.indexOf(value); this.preferences.themeClass = this.themeClass = `theme-${value}`; } this.saveLocalStoragePreferences(); } } saveLocalStoragePreferences() { const storage = window.localStorage; if (storage) { const preferences = storage.setItem('FramadateConfig', JSON.stringify(this.preferences)); } else { console.error('pas de localstorage'); } } /** * 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, pollType: 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; } checkIfSlugIsUniqueInDatabase(slug: string = '') { this.customUrlIsUnique = null; if (!slug) { slug = this.utils.makeSlug(this); } this.loading = true; // TODO this.todo('check slug is unique'); this.http.get(`${this.baseHref}/check-slug-is-uniq/${slug}`, this.utils.makeHeaders({slug: this.customUrl}), ) .subscribe((res: any) => { this.customUrlIsUnique = res.poll.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.utils.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.utils.makeHeaders()); } /** * GET * api/v1/poll/{id} * @param id */ getPollById(id: string, password?: string) { return this.http .get(`${this.baseHref}/poll/${id}`, this.utils.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.utils.makeHeaders({ownerEmail}) ) .subscribe( (res: any) => { // this.myPolls = res.poll; }, (e) => { this.handleError(e); } ); } /** * launch creation call to the api */ createPoll() { this.loading = true; this.createPollFromConfig(this.getPollConfig()); } updateCurrentPollFromResponse(res: any) { console.log('update res', res); this.currentPoll = res; this.pollId = res.poll.id; this.owner_modifier_token = res.owner_modifier_token; this.urlPublic = this.baseHref + '#/vote/poll/id/' + res.poll.id; this.urlSlugPublic = this.baseHref + '#/vote/poll/slug/' + res.poll.id; if (res.poll.customUrl) { this.urlSlugPublic = this.baseHref + '#/vote/poll/id/' + res.poll.customUrl; } if (res.vote_stack) { this.loadVoteStack(res.vote_stack); } this.adminKey = res.admin_key; this.urlAdmin = this.baseHref + '#/admin/' + res.admin_key; } resetCurrentChoicesAnswers() { this.currentPoll.choices.map(choice => { choice.answer = null; }); } /** * update current answers with a previous vote * @param voteStack */ loadVoteStack(voteStack: any) { // load the pseudo and email this.myName = voteStack.pseudo; this.myEmail = voteStack.email; this.voteStackId = voteStack.id; this.myVoteStack = voteStack; const keys = Object.keys(voteStack.votes); console.log('voteStack', voteStack); this.resetCurrentChoicesAnswers(); keys.forEach((id: any) => { const voteItem = voteStack.votes[id]; /** * the display of the poll uses the choices data, so we update the choices answers of the current poll to reflect the vote stack we have taken */ if (voteItem.choice_id && voteItem.value) { const foundChoiceToModify = this.currentPoll.choices.find(choicesItem => { return voteItem.choice_id == choicesItem.id; }); console.log('foundChoiceToModify', foundChoiceToModify); if (foundChoiceToModify) { foundChoiceToModify.answer = voteItem.value; } } }); } /** * POST * /api/v1/poll/{id}/poll * @param config */ createPollFromConfig(config: any) { this.loading = true; console.log('config', config); return this.http.post(`${this.baseHref}/poll`, config, this.utils.makeHeaders()) .subscribe((res: any) => { // redirect to the page to administrate the new poll this.messageService.add({severity: 'success', summary: 'Sondage Créé',}); this.updateCurrentPollFromResponse(res); this.loading = false; if (!this.myPolls) { this.myPolls = []; } this.myPolls.push(res); 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) { choiceList = choiceList.filter(c => c.answer ? c : null); // remove choices where we did not answer const converted = choiceList.map(elem => { if (elem.answer) { 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), }; } this.myVoteStack = voteStack; if (!environment.production) { this.handleVoteAdded(mockSuccessVote); return; } this.http.post( `${this.baseHref}/poll/${this.pollId}/vote`, voteStack, this.utils.makeHeaders()) .subscribe((res: any) => { this.handleVoteAdded(res); }, (e) => { this.handleError(e); } ); } handleVoteAdded(res) { if (this.isAdmin) { this.displayConfirmVoteModalAdmin = true; } // save modifier token this.myVoteStack.modifier_token = res.modifier_token; this.myVoteStack.id = res.vote_stack.id; this.updateCurrentPollFromResponse(res); } /** * UPDATE * /api/v1/poll/{id}/vote * @param voteStack */ updateVote(voteStack?: any) { if (!this.myVoteStack) { return; } else { voteStack = this.myVoteStack; } this.http.patch( `${this.baseHref}/vote-stack/${voteStack.id}/token/${this.owner_modifier_token}`, voteStack, this.utils.makeHeaders()) .subscribe((res: any) => { this.messageService.add({severity: 'success', summary: 'Vote mis à jour'}); this.updateCurrentPollFromResponse(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.utils.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.utils.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.utils.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; } const 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.utils.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 * TODO */ updatePoll(voteStack: any) { this.http.put( `${this.baseHref}/poll/${this.pollId}`, voteStack, this.utils.makeHeaders() ) .subscribe((res: any) => { this.messageService.add({ severity: 'success', summary: 'Sondage mis à jour', }); this.updateCurrentPollFromResponse(res); }, (e) => { this.handleError(e); } ); } /** * export all the poll data available to the public as a CSV single file */ exportCSV() { let rows = []; const now = new Date(); const headers = [ ['export de sondage Framadate ', this.customUrl], ['le', now.toISOString()], [this.currentPoll.pollId, this.currentPoll.title, this.customUrl, this.creationDate], ['pseudo']]; const listOfChoices = ['choices : ']; this.currentPoll.choices.map(choice => { listOfChoices.push(choice.text); }); listOfChoices.push('pseudo'); this.currentPoll.stacks.map(voteStack => { const voteStackInArray = [voteStack.pseudo]; const keysVotes = Object.keys(voteStack.votes); keysVotes.map(id => { voteStackInArray.push(voteStack.votes[id].value ? voteStack.votes[id].value : ''); }); rows.push( voteStackInArray ); }); const headersComments = [ ['comments'], ['pseudo', 'text', 'creation_date'], ]; const comments = []; this.currentPoll.comments.map(item => { comments.push( [item.pseudo, item.text, item.date.date, '\n'] ); }); headers.push(listOfChoices); rows = [headers, listOfChoices, rows, headersComments, comments]; const convertedCsv = rows.map(elem => { console.log('elem', elem); return elem.map(item => { console.log('item', item); if (typeof item === typeof Array) { return item.join('\n'); } return item; }).join('\n'); }).join('\n'); console.log('rows', rows); console.log('convertedCsv', convertedCsv); const csvContent = 'data:text/csv;charset=utf-8,' + convertedCsv; console.log('csvContent', csvContent); const encodedUri = encodeURI(csvContent); const link = document.createElement('a'); link.setAttribute('href', encodedUri); const exportFileName = (this.urlPublic ? this.urlPublic : this.utils.makeSlug(this)) + '_export_' + new Date() + '.csv'; link.setAttribute('download', exportFileName); document.body.appendChild(link); // Required for FF link.click(); // This will download the data file named "my_data.csv". } exportJson() { this.download('export_poll_' + this.pollSlug + '.json', JSON.stringify( { export_date: new Date(), creation_date: this.creationDate, title: this.title, description: this.description, pollType: this.pollType, urlPublic: this.urlPublic, currentPoll: this.currentPoll, votes: this.voteChoices }) ); } download(filename, text) { var element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); element.setAttribute('download', filename); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); } 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', }); } execStuff() { const mockResponse = { message: 'you created a vote stack from an existing owner : tktest@tktest.com', poll: { id: 3, title: 'dessin animé préféré', customUrl: null, description: 'choisissez votre animé préféré', creationDate: { date: '2020-01-22 14:28:19.000000', timezone_type: 3, timezone: 'Europe/Paris' }, expiracyDate: { date: '2020-01-22 14:28:19.000000', timezone_type: 3, timezone: 'Europe/Paris' }, owner: { __initializer__: null, __cloner__: null, __isInitialized__: true, pseudo: 'tk_TEST', email: 'tktest@tktest.com' }, kind: 'text', allowedAnswers: [ 'yes' ], modificationPolicy: 'self', mailOnComment: null, mailOnVote: null, hideResults: null, showResultEvenIfPasswords: null, votes: {}, stacksOfVotes: {}, choices: {}, comments: {}, defaultExpiracyDaysFromNow: 60 }, vote_stack: { id: 43, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-04-02 17:55:45.201475', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { id: 93, value: 'yes', choice_id: 5, text: 'Vic le viking', stack_id: 43 }, 6: { id: 94, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 43 }, 7: { id: 95, value: 'yes', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 43 }, 8: { id: 96, value: 'yes', choice_id: 8, text: 'Les mondes engloutis', stack_id: 43 }, 9: { id: 97, value: 'yes', choice_id: 9, text: 'Foot 2 rue', stack_id: 43 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, stacks: [ { id: 3, modifier_token: 'sfdH00Fy17bt5c3Y5zYk5GDsX7Cl67cgec14Qd06V87g74JFOr2UOC2ZL8E919eBmI72W8f5keYDeWfrV7SQW35fw0Vg452k25w9BrS62MtOs89JjLQ', pseudo: 'voting_people_TEST', creation_date: { date: '2020-01-22 14:28:19.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { choice_id: 5 }, 6: { id: 5, value: 'maybe', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 3 }, 7: { id: 4, value: 'yes', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 3 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 4, modifier_token: 'sfdH00Fy17bt5c3Y5zYk5GDsX7Cl67cgec14Qd06V87g74JFOr2UOC2ZL8E919eBmI72W8f5keYDeWfrV7SQW35fw0Vg452k25w9BrS62MtOs89JjLQ', pseudo: 'voting_people_TEST', creation_date: { date: '2020-01-22 14:28:19.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { choice_id: 5 }, 6: { id: 6, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 4 }, 7: { id: 8, value: 'no', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 4 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 5, modifier_token: 'sfdH00Fy17bt5c3Y5zYk5GDsX7Cl67cgec14Qd06V87g74JFOr2UOC2ZL8E919eBmI72W8f5keYDeWfrV7SQW35fw0Vg452k25w9BrS62MtOs89JjLQ', pseudo: 'voting_people_TEST', creation_date: { date: '2020-01-22 16:00:50.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { id: 9, value: 'no', choice_id: 5, text: 'Vic le viking', stack_id: 5 }, 6: { id: 10, value: 'maybe', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 5 }, 7: { id: 11, value: 'yes', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 5 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 6, modifier_token: 'W1275k1tOh7CA9e9F0VbD58teW3Z451848Sh14imcr90QY1d3tK415mHw9Ib8II8S91F2n8dhk135-20d9cT2mX3UfZ92aeuQdwcj32e17E0bc50fp3d', pseudo: '', creation_date: { date: '2020-01-22 16:01:10.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { id: 12, value: 'yes', choice_id: 5, text: 'Vic le viking', stack_id: 6 }, 6: { id: 13, value: 'maybe', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 6 }, 7: { id: 14, value: 'no', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 6 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 7, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-01-23 16:19:29.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { choice_id: 5 }, 6: { id: 15, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 7 }, 7: { choice_id: 7 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { id: 16, value: 'yes', choice_id: 10, text: 'Le chat, la vache, et l\'océan', stack_id: 7 }, 11: { choice_id: 11 } } }, { id: 12, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-01-24 11:34:54.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { id: 21, value: 'yes', choice_id: 5, text: 'Vic le viking', stack_id: 12 }, 6: { choice_id: 6 }, 7: { choice_id: 7 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { choice_id: 10 }, 11: { id: 22, value: 'yes', choice_id: 11, text: 'Digimon', stack_id: 12 } } }, { id: 13, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-01-24 12:00:47.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { choice_id: 5 }, 6: { id: 23, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 13 }, 7: { id: 24, value: 'yes', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 13 }, 8: { choice_id: 8 }, 9: { id: 25, value: 'yes', choice_id: 9, text: 'Foot 2 rue', stack_id: 13 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 14, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-01-24 12:01:47.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { id: 26, value: 'yes', choice_id: 5, text: 'Vic le viking', stack_id: 14 }, 6: { choice_id: 6 }, 7: { choice_id: 7 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 15, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-01-24 12:07:15.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { choice_id: 5 }, 6: { id: 27, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 15 }, 7: { choice_id: 7 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 16, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-01-24 12:08:58.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { choice_id: 5 }, 6: { id: 28, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 16 }, 7: { choice_id: 7 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 17, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-01-24 12:09:15.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { choice_id: 5 }, 6: { choice_id: 6 }, 7: { id: 29, value: 'yes', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 17 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 18, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-01-24 12:15:45.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { choice_id: 5 }, 6: { choice_id: 6 }, 7: { id: 30, value: 'yes', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 18 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 19, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-01-24 12:16:50.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { id: 31, value: 'yes', choice_id: 5, text: 'Vic le viking', stack_id: 19 }, 6: { id: 32, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 19 }, 7: { id: 33, value: 'yes', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 19 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 25, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-01-29 17:55:42.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { choice_id: 5 }, 6: { id: 44, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 25 }, 7: { choice_id: 7 }, 8: { choice_id: 8 }, 9: { id: 45, value: 'yes', choice_id: 9, text: 'Foot 2 rue', stack_id: 25 }, 10: { id: 46, value: 'yes', choice_id: 10, text: 'Le chat, la vache, et l\'océan', stack_id: 25 }, 11: { choice_id: 11 } } }, { id: 26, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-01-30 10:20:06.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { id: 47, value: 'yes', choice_id: 5, text: 'Vic le viking', stack_id: 26 }, 6: { id: 48, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 26 }, 7: { id: 49, value: 'yes', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 26 }, 8: { id: 50, value: 'yes', choice_id: 8, text: 'Les mondes engloutis', stack_id: 26 }, 9: { choice_id: 9 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 28, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-01-30 17:23:48.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { id: 53, value: 'yes', choice_id: 5, text: 'Vic le viking', stack_id: 28 }, 6: { id: 54, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 28 }, 7: { id: 55, value: 'yes', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 28 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { id: 56, value: 'yes', choice_id: 10, text: 'Le chat, la vache, et l\'océan', stack_id: 28 }, 11: { choice_id: 11 } } }, { id: 35, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-01-31 09:42:28.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { choice_id: 5 }, 6: { id: 69, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 35 }, 7: { id: 70, value: 'yes', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 35 }, 8: { choice_id: 8 }, 9: { choice_id: 9 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 37, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-02-05 10:38:47.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { choice_id: 5 }, 6: { choice_id: 6 }, 7: { choice_id: 7 }, 8: { id: 74, value: 'yes', choice_id: 8, text: 'Les mondes engloutis', stack_id: 37 }, 9: { id: 75, value: 'yes', choice_id: 9, text: 'Foot 2 rue', stack_id: 37 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 40, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-02-22 17:53:57.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { id: 82, value: 'no', choice_id: 5, text: 'Vic le viking', stack_id: 40 }, 6: { id: 83, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 40 }, 7: { choice_id: 7 }, 8: { id: 84, value: 'yes', choice_id: 8, text: 'Les mondes engloutis', stack_id: 40 }, 9: { id: 85, value: 'yes', choice_id: 9, text: 'Foot 2 rue', stack_id: 40 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } }, { id: 41, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-04-01 12:24:37.000000', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { id: 86, value: 'yes', choice_id: 5, text: 'Vic le viking', stack_id: 41 }, 6: { id: 87, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 41 }, 7: { id: 88, value: 'yes', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 41 }, 8: { choice_id: 8 }, 9: { id: 89, value: 'yes', choice_id: 9, text: 'Foot 2 rue', stack_id: 41 }, 10: { id: 90, value: 'yes', choice_id: 10, text: 'Le chat, la vache, et l\'océan', stack_id: 41 }, 11: { choice_id: 11 } } }, { id: 43, modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', pseudo: 'tk_TEST', creation_date: { date: '2020-04-02 17:55:45.201475', timezone_type: 3, timezone: 'Europe/Paris' }, votes: { 5: { id: 93, value: 'yes', choice_id: 5, text: 'Vic le viking', stack_id: 43 }, 6: { id: 94, value: 'yes', choice_id: 6, text: 'Boumbo petite automobile', stack_id: 43 }, 7: { id: 95, value: 'yes', choice_id: 7, text: 'Les mystérieuses cités d\'or', stack_id: 43 }, 8: { id: 96, value: 'yes', choice_id: 8, text: 'Les mondes engloutis', stack_id: 43 }, 9: { id: 97, value: 'yes', choice_id: 9, text: 'Foot 2 rue', stack_id: 43 }, 10: { choice_id: 10 }, 11: { choice_id: 11 } } } ], comments: [ { id: 4, text: 'wouah trop bien framadate HOUHOUUUU!', pseudo: 'tk_TEST', date: { date: '2020-01-22 16:00:22.000000', timezone_type: 3, timezone: 'Europe/Paris' } }, { id: 6, text: 'wouah trop bien framadate! zerf zrg ergetetht', pseudo: 'tk_TEST', date: { date: '2020-01-22 16:09:32.000000', timezone_type: 3, timezone: 'Europe/Paris' } }, { id: 7, text: 'comment numléro 4\n', pseudo: 'tk_TEST', date: { date: '2020-01-22 16:09:51.000000', timezone_type: 3, timezone: 'Europe/Paris' } }, { id: 8, text: 'wouah trop bien framadate!', pseudo: 'tk_TEST', date: { date: '2020-01-22 16:15:24.000000', timezone_type: 3, timezone: 'Europe/Paris' } }, { id: 9, text: 'wouah trop bien framadate zef ret r e re!', pseudo: 'tk_TEST', date: { date: '2020-01-23 14:11:21.000000', timezone_type: 3, timezone: 'Europe/Paris' } }, { id: 13, text: 'OUAIIII', pseudo: 'tk_TEST', date: { date: '2020-01-23 16:35:52.000000', timezone_type: 3, timezone: 'Europe/Paris' } }, { id: 14, text: 'MAAAAHAHAHAHHAA', pseudo: 'tk_TEST', date: { date: '2020-01-23 16:36:04.000000', timezone_type: 3, timezone: 'Europe/Paris' } }, { id: 16, text: 'Meeeeeh', pseudo: 'tk_TEST', date: { date: '2020-01-23 18:37:49.000000', timezone_type: 3, timezone: 'Europe/Paris' } }, { id: 18, text: 'wouah trop bien framadate!', pseudo: 'tk_TEST', date: { date: '2020-01-24 11:34:58.000000', timezone_type: 3, timezone: 'Europe/Paris' } }, { id: 19, text: 'Ndjdjkddkld', pseudo: 'tk_TEST', date: { date: '2020-01-24 11:35:08.000000', timezone_type: 3, timezone: 'Europe/Paris' } }, { id: 20, text: 'wouah trop bien framadate!', pseudo: 'tk_TEST', date: { date: '2020-01-24 12:16:24.000000', timezone_type: 3, timezone: 'Europe/Paris' } }, { id: 21, text: 'encore un commentaire ', pseudo: 'tk_TEST', date: { date: '2020-01-24 12:16:38.000000', timezone_type: 3, timezone: 'Europe/Paris' } } ], choices: [ { id: 5, date: { date: '2020-01-22 14:28:19.000000', timezone_type: 3, timezone: 'Europe/Paris' }, text: 'Vic le viking', url: null }, { id: 6, date: { date: '2020-01-22 14:28:19.000000', timezone_type: 3, timezone: 'Europe/Paris' }, text: 'Boumbo petite automobile', url: null }, { id: 7, date: { date: '2020-01-22 14:28:19.000000', timezone_type: 3, timezone: 'Europe/Paris' }, text: 'Les mystérieuses cités d\'or', url: null }, { id: 8, date: { date: '2020-01-22 14:28:19.000000', timezone_type: 3, timezone: 'Europe/Paris' }, text: 'Les mondes engloutis', url: null }, { id: 9, date: { date: '2020-01-22 14:28:19.000000', timezone_type: 3, timezone: 'Europe/Paris' }, text: 'Foot 2 rue', url: null }, { id: 10, date: { date: '2020-01-22 14:28:19.000000', timezone_type: 3, timezone: 'Europe/Paris' }, text: 'Le chat, la vache, et l\'océan', url: null }, { id: 11, date: { date: '2020-01-22 14:28:19.000000', timezone_type: 3, timezone: 'Europe/Paris' }, text: 'Digimon', url: null } ], choices_count: { counts: { 5: { choice_id: 5, choice_text: 'Vic le viking', id: 9, score: 8, yes: { count: 8, people: [ '', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST' ] }, maybe: { count: 0, people: [] }, no: { count: 2, people: [ 'voting_people_TEST', 'tk_TEST' ] } }, 6: { choice_id: 6, choice_text: 'Boumbo petite automobile', id: 5, score: 14.5, yes: { count: 13, people: [ 'voting_people_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST' ] }, maybe: { count: 3, people: [ 'voting_people_TEST', 'voting_people_TEST', '' ] }, no: { count: 0, people: [] } }, 7: { choice_id: 7, choice_text: 'Les mystérieuses cités d\'or', id: 4, score: 12, yes: { count: 12, people: [ 'voting_people_TEST', 'voting_people_TEST', 'voting_people_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST' ] }, maybe: { count: 0, people: [] }, no: { count: 2, people: [ 'voting_people_TEST', '' ] } }, 8: { choice_id: 8, choice_text: 'Les mondes engloutis', id: 50, score: 4, yes: { count: 4, people: [ 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST' ] }, maybe: { count: 0, people: [] }, no: { count: 0, people: [] } }, 9: { choice_id: 9, choice_text: 'Foot 2 rue', id: 25, score: 6, yes: { count: 6, people: [ 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST' ] }, maybe: { count: 0, people: [] }, no: { count: 0, people: [] } }, 10: { choice_id: 10, choice_text: 'Le chat, la vache, et l\'océan', id: 16, score: 4, yes: { count: 4, people: [ 'tk_TEST', 'tk_TEST', 'tk_TEST', 'tk_TEST' ] }, maybe: { count: 0, people: [] }, no: { count: 0, people: [] } }, 11: { choice_id: 11, choice_text: 'Digimon', id: 22, score: 1, yes: { count: 1, people: [ 'tk_TEST' ] }, maybe: { count: 0, people: [] }, no: { count: 0, people: [] } } }, maxScore: 14.5 }, vote_count: 21, owner: { __initializer__: null, __cloner__: null, __isInitialized__: true, pseudo: 'tk_TEST', email: 'tktest@tktest.com' }, owner_modifier_token: 'b88Qnb1A515Sfedee8b74d726A32444m87cn9Zc0f9t6Ued516f76235V93tBKcJVJearh061S8I0o5l24wbIaMe2v4wg76dhEBBi9m-28Qa601b664L', admin_key: 'A8jZ9oc1jsFGZJ024c457f0Wj1bYca5m6537cm9nCg7catZdc18ke5Kqd449eL290oHCqdu3SNmkC7yIHj96n6dnU7ca7qdaf2VSRMI48eXd61O9a3U', json_you_sent: { pseudo: 'mon pseudo', email: 'tktest@tktest.com', votes: [ { choice_id: 5, value: 'yes' }, { choice_id: 6, value: 'yes' }, { choice_id: 7, value: 'yes' }, { choice_id: 8, value: 'yes' }, { choice_id: 9, value: 'yes' } ] } }; this.updateCurrentPollFromResponse(mockResponse); } }