add fetch of config with admin key

This commit is contained in:
Tykayn 2021-11-12 15:59:44 +01:00 committed by tykayn
parent 96ef61c541
commit b9aea18d34
20 changed files with 180 additions and 33 deletions

View File

@ -3,7 +3,7 @@ import { RouterModule } from '@angular/router';
import { routes } from './routes-framadate';
@NgModule({
imports: [RouterModule.forRoot(routes, { useHash: true })],
imports: [RouterModule.forRoot(routes, { useHash: true, enableTracing: true })],
exports: [RouterModule],
})
export class AppRoutingModule {}

View File

@ -123,4 +123,10 @@
</div>
</div>
</div>
<a
class="has-text-black"
href="http://localhost:4200/#/administration/key/8Ubcg2YI99f69xz946cn4O64bQAebi11012P70trL5372qJ9JOem1Ks2fz7XD0b09p-8Ubcg2YI99f69xz946cn4O64bQAeb"
>
<i class="fa fa-hand-paper-o"></i> test admin link to edit poll
</a>
</header>

View File

@ -136,7 +136,9 @@ export class ApiService {
}
}
//////////
/**
* get all polls published by the API
*/
public async getAllAvailablePolls(): Promise<Poll[]> {
// TODO: used for facilities in DEV, should be removed in production
try {
@ -147,10 +149,32 @@ export class ApiService {
}
}
public async getPollByCustomUrl(slug: string): Promise<Poll | undefined> {
/**
* get one poll by its admin key
* @param admin_key
*/
public async getPollByAdminKey(admin_key: string): Promise<any | undefined> {
try {
console.log('fetch API : asking for poll with custom_url=' + slug);
const response: AxiosResponse<Poll> = await this.axiosInstance.get<Poll>(`${this.pollsEndpoint}/${slug}`);
console.log('fetch API : asking for poll with admin_key=' + admin_key);
const response: AxiosResponse<Poll> = await this.axiosInstance.get<any>(
`${this.pollsEndpoint}/admin/${admin_key}`
);
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 getPollByCustomUrl(custom_url: string): Promise<Poll | undefined> {
try {
console.log('fetch API : asking for poll with custom_url=' + custom_url);
const response: AxiosResponse<Poll> = await this.axiosInstance.get<Poll>(
`${this.pollsEndpoint}/${custom_url}`
);
return response && response.data && !Array.isArray(response.data) ? response.data : undefined;
} catch (error) {
@ -162,12 +186,12 @@ export class ApiService {
}
}
public async getPollByCustomUrlWithHash(slug: string, hash: string): Promise<Poll | undefined> {
public async getPollByCustomUrlWithHash(custom_url: string, hash: string): Promise<Poll | undefined> {
try {
const response: AxiosResponse<Poll> = await this.axiosInstance.get<Poll>(
`${this.pollsEndpoint}/${slug}/pass/${hash}`
`${this.pollsEndpoint}/${custom_url}/pass/${hash}`
);
console.log('fetch API : asking for poll with custom_url=' + slug, { response });
console.log('fetch API : asking for poll with custom_url=' + custom_url, { response });
return response && response.data && !Array.isArray(response.data) ? response.data : undefined;
} catch (error) {
@ -181,11 +205,11 @@ export class ApiService {
}
}
public async getSlug(slug: string): Promise<boolean> {
public async getSlug(custom_url: string): Promise<boolean> {
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}`
`${this.pollsEndpoint}${this.slugsEndpoint}/${custom_url}`
);
if (response?.status !== 404) {
return false;
@ -201,7 +225,7 @@ export class ApiService {
////////////
// UPDATE //
////////////
public async sendUpdateVoteStack(vote_stack: Stack) {
try {
return await this.axiosInstance.patch(

View File

@ -65,6 +65,7 @@ export class PollService implements Resolve<Poll> {
) {
this.createFormGroup();
// fill in the next 3 days of the calendar date picker
this.calendar = [
this.DateUtilitiesService.addDaysToDate(1, new Date()),
this.DateUtilitiesService.addDaysToDate(2, new Date()),
@ -80,7 +81,7 @@ export class PollService implements Resolve<Poll> {
}
/**
* add example values to the form
* add example values to the form for demo env
*/
setDemoValues(): void {
this.addChoice('orange');
@ -125,8 +126,6 @@ export class PollService implements Resolve<Poll> {
whoModifiesAnswers: ['', [Validators.required]],
whoCanChangeAnswers: ['', [Validators.required]],
isAboutDate: [true, [Validators.required]],
// startDateInterval: ['', [Validators.required]],
// endDateInterval: ['', [Validators.required]],
expiresDaysDelay: [60, []],
maxCountOfAnswers: [300, []],
isZeroKnoledge: [false, [Validators.required]],
@ -148,6 +147,9 @@ export class PollService implements Resolve<Poll> {
return form;
}
/**
* set default configs to the form
*/
public patchFormDefaultValues() {
this.form.patchValue({
title: 'mon titre de sondage',
@ -169,6 +171,9 @@ export class PollService implements Resolve<Poll> {
this.setDefaultDatesForInterval();
}
/**
* get a new slug from form title and creation date
*/
public updateSlug(): void {
console.log('this.form.value', this.form.value);
this.form.patchValue({ custom_url: this.makeSlug(this.form) });
@ -176,6 +181,7 @@ export class PollService implements Resolve<Poll> {
/**
* auto fetch a poll when route is looking for one in the administration pattern
* DO NOT USE - needs refacto
* @param route
* @param state
*/
@ -259,7 +265,7 @@ export class PollService implements Resolve<Poll> {
* update poll and parse its fields
* @param poll
*/
public updateCurrentPoll(poll: Poll): void {
public updateCurrentPoll(poll: Poll): Poll {
console.log('this.storageService.vote_stack.id', this.storageService.vote_stack.id);
if (!this.storageService.vote_stack.id || this.storageService.vote_stack.poll_custom_url !== poll.custom_url) {
@ -272,8 +278,9 @@ export class PollService implements Resolve<Poll> {
// this.storageService.setChoicesForVoteStack(poll.choices);
}
this.toastService.display('sondage bien mis à jour', 'success');
this._poll.next(poll);
this.toastService.display(`sondage ${poll.title} bien mis à jour`, 'success');
return poll;
}
/**
@ -577,7 +584,9 @@ export class PollService implements Resolve<Poll> {
public getAdministrationUrlFromForm(): string {
// admin_key is filled after creation
return `${environment.frontDomain}#/admin/${this.admin_key}/consultation`;
// example http://localhost:4200/#/administration/8Ubcg2YI99f69xz946cn4O64bQAeb
return `${environment.frontDomain}#/administration/${this.admin_key}`;
}
public getParticipationUrl(): string {
@ -648,6 +657,13 @@ export class PollService implements Resolve<Poll> {
return array_dates;
}
patchFormWithPoll(poll: Poll) {
this.form.patchValue({
...poll,
isAboutDate: poll.kind == 'date',
});
}
/**
* @description convert to API version 1 data transition object
*/

View File

@ -7,12 +7,15 @@ import { StepThreeComponent } from './form/steps/step-three/step-three.component
import { StepFourComponent } from './form/steps/step-four/step-four.component';
import { StepFiveComponent } from './form/steps/step-five/step-five.component';
import { StepOneComponent } from './form/steps/step-one/step-one.component';
import { SuccessComponent } from './success/success.component';
import { AdminConsultationComponent } from './consultation/consultation.component';
const routes: Routes = [
{
path: '',
component: AdministrationComponent,
},
{ path: 'key/:admin_key', component: AdminConsultationComponent },
{
path: 'step',
children: [
@ -23,6 +26,10 @@ const routes: Routes = [
{ path: '5', component: StepFiveComponent },
],
},
{
path: 'success',
component: SuccessComponent,
},
];
@NgModule({

View File

@ -20,7 +20,7 @@ export class AdministrationComponent implements OnInit, OnDestroy {
ngOnInit(): void {
this.routeSubscription = this.route.data.subscribe((data: { poll: Poll }) => {
console.log('data', data);
console.log('routeSubscription data', data);
if (data.poll) {
this.poll = data.poll;
}

View File

@ -27,6 +27,7 @@ import { IntervalComponent } from './form/date/interval/interval.component';
import { DayListComponent } from './form/date/list/day/day-list.component';
import { PickerComponent } from './form/date/picker/picker.component';
import { TimeListComponent } from './form/date/list/time/time-list.component';
import { AdminConsultationComponent } from './consultation/consultation.component';
@NgModule({
declarations: [
@ -50,6 +51,7 @@ import { TimeListComponent } from './form/date/list/time/time-list.component';
DayListComponent,
PickerComponent,
TimeListComponent,
AdminConsultationComponent,
],
imports: [
AdministrationRoutingModule,

View File

@ -0,0 +1,16 @@
<div class="admin-consultation min-height padded">
<h2 class="title is-2">Consulter le sondage</h2>
<button class="btn is-primary" [routerLink]="'/administration'">
<i class="fa fa-pencil"></i>
modifier
</button>
<div>
<h2>{{ form.value.title }}</h2>
<div *ngIf="poll">
<h2>{{ poll.title }}</h2>
Créé le {{ poll.created_at | date }} par {{ poll.owner.pseudo }}, {{ poll.owner.email }}
</div>
</div>
</div>

View File

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ConsultationComponent } from './consultation.component';
describe('ConsultationComponent', () => {
let component: ConsultationComponent;
let fixture: ComponentFixture<ConsultationComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ConsultationComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ConsultationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,54 @@
import { Component, OnInit } from '@angular/core';
import { PollService } from '../../../core/services/poll.service';
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { ApiService } from '../../../core/services/api.service';
import { FormGroup } from '@angular/forms';
import { Poll } from '../../../core/models/poll.model';
@Component({
selector: 'app-admin-consultation',
templateUrl: './consultation.component.html',
styleUrls: ['./consultation.component.scss'],
})
export class AdminConsultationComponent implements OnInit {
private admin_key: string;
public form: FormGroup;
public poll: any;
constructor(
private pollService: PollService,
private apiService: ApiService,
private _Activatedroute: ActivatedRoute,
private router: Router
) {
this.poll = this.pollService._poll.getValue();
this.form = this.pollService.form;
}
ngOnInit(): void {
this._Activatedroute.paramMap.subscribe((params: ParamMap) => {
this.admin_key = params.get('admin_key');
if (!this.admin_key) {
this.router.navigate('page-not-found');
}
this.apiService.getPollByAdminKey(this.admin_key).then(
(res) => {
this.pollService.updateCurrentPoll(res.poll);
this.patchFormLoadedWithPoll();
this.form = this.pollService.form;
this.poll = this.pollService._poll.getValue();
console.log('formulaire patché', this.pollService.form, this.pollService.poll);
},
(err) => {
if (!this.admin_key) {
this.router.navigate('page-not-found');
}
}
);
});
}
patchFormLoadedWithPoll() {
this.pollService.patchFormWithPoll(this.pollService._poll.getValue());
}
}

View File

@ -1,7 +1,7 @@
<div class="step">
<div class="min-height">
<form action="#" [formGroup]="pollService.form">
<app-stepper [step_current]="pollService.step_current" [step_max]="5"></app-stepper>
<app-stepper [step_current]="4" [step_max]="pollService.step_max"></app-stepper>
<div class="creator-infos">
<label class="" for="creatorEmail">

View File

@ -2,6 +2,7 @@ import { Component, Input, OnInit } from '@angular/core';
import { PollService } from '../../../../../core/services/poll.service';
import { ApiService } from '../../../../../core/services/api.service';
import { environment } from '../../../../../../environments/environment';
import { Router } from '@angular/router';
@Component({
selector: 'app-step-four',
@ -15,12 +16,14 @@ export class StepFourComponent implements OnInit {
step_max: any;
@Input()
form: any;
constructor(public pollService: PollService, private apiService: ApiService) {}
constructor(private router: Router, public pollService: PollService, private apiService: ApiService) {}
ngOnInit(): void {}
createPoll() {
let apiData = this.pollService.newPollFromForm();
this.apiService.createPoll(apiData);
this.apiService.createPoll(apiData).then((resp) => {
this.router.navigate(['administration/success']);
});
}
}

View File

@ -44,7 +44,7 @@
<p class="note">
Note : Le sondage sera supprimé {{ pollService.form.value.default_expiracy_days_from_now }} jours
après la date de sa dernière modification.
<span class="expiracy-detail" *ngIf="poll.expiracy_date">
<span class="expiracy-detail" *ngIf="pollService.form.value.expiracy_date">
Le {{ pollService.form.value.expiracy_date | date: 'short' }}
</span>
</p>

View File

@ -19,5 +19,5 @@ a {
padding: 2em;
}
.has-background-success {
background: $logo_color_2;
background: $logo_color_2 !important;
}

View File

@ -7,6 +7,7 @@ import { PasswordPromptComponent } from './password/password-prompt/password-pro
const routes: Routes = [
{ path: 'secure/:pass_hash', component: ConsultationComponent },
{ path: 'prompt', component: PasswordPromptComponent },
{ path: 'simple', component: WipTodoComponent },
{ path: 'table', component: WipTodoComponent },

View File

@ -8,7 +8,7 @@
</div>
<div class="message is-warning" *ngIf="poll && poll.admin_key">
<div class="message-body">
vous êtes admin de ce sondage
vous êtes admin de ce sondage et pouvez le modifier
</div>
</div>

View File

@ -20,13 +20,6 @@ export const routes: Routes = [
data: { animation: 'AdminPage' },
loadChildren: () =>
import('./features/administration/administration.module').then((m) => m.AdministrationModule),
// resolve: { poll: PollService },
},
{
path: 'admin/:admin_key',
loadChildren: () =>
import('./features/administration/administration.module').then((m) => m.AdministrationModule),
// resolve: { poll: PollService },
},
{
path: 'poll/:custom_url/consultation',

View File

@ -73,7 +73,7 @@
"continue": "Voyons ce que ça donne"
},
"resume": {
"title": "Et c'est tout pour nous !",
"title": "Félicitations !",
"admins": "Côté administrateur-ice-eux",
"users": "Côté sondés",
"links_mail": "Recevoir les liens par e-mail"

View File

@ -16,7 +16,8 @@ export const environment = {
autofill_participation: true,
// autofill: false,
showDemoWarning: false,
autoSendNewPoll: true,
// autoSendNewPoll: true,
autoSendNewPoll: false,
interval_days_default: 7,
expiresDaysDelay: 60,
maxCountOfAnswers: 150,