Show "Deleted user" if a poll user cannot be found

Fixes an error that would freeze OpenSlides
If a user was deleted but registered as a poll option,
The Assignment Detail View would freeze
This commit is contained in:
Sean 2020-11-27 16:50:38 +01:00
parent 96f96f09ee
commit 5e1b5b5658
10 changed files with 36 additions and 16 deletions

View File

@ -14,7 +14,7 @@
<div *ngFor="let option of options" class="votes-grid">
<div>
<span *ngIf="option.user">{{ option.user.getFullName() }}</span>
<span *ngIf="!option.user">{{ 'Unknown user' | translate }}</span>
<i *ngIf="!option.user">{{ unknownUserLabel | translate }}</i>
</div>
<div>

View File

@ -19,7 +19,7 @@ import { BasePollDialogComponent } from 'app/site/polls/components/base-poll-dia
import { PollFormComponent } from 'app/site/polls/components/poll-form/poll-form.component';
import { PollPropertyVerbose } from 'app/site/polls/models/view-base-poll';
import { ViewUser } from 'app/site/users/models/view-user';
import { AssignmentPollService } from '../../services/assignment-poll.service';
import { AssignmentPollService, UnknownUserLabel } from '../../services/assignment-poll.service';
type OptionsObject = { user_id: number; user: ViewUser }[];
@ -34,6 +34,7 @@ type OptionsObject = { user_id: number; user: ViewUser }[];
export class AssignmentPollDialogComponent
extends BasePollDialogComponent<ViewAssignmentPoll, AssignmentPollService>
implements OnInit {
public unknownUserLabel = UnknownUserLabel;
/**
* The summary values that will have fields in the dialog
*/

View File

@ -51,7 +51,7 @@
{{ option.user.getLevelAndNumber() }}
</div>
</span>
<span *ngIf="!option.user">{{ 'Unknown user' | translate }}</span>
<i *ngIf="!option.user">{{ unknownUserLabel | translate }}</i>
</div>
<div *ngFor="let action of voteActions">

View File

@ -43,7 +43,8 @@
.vote-candidate-name {
grid-area: name;
display: flex;
span {
span,
i {
margin-top: auto;
margin-bottom: auto;
}

View File

@ -18,6 +18,7 @@ import { ViewAssignmentOption } from 'app/site/assignments/models/view-assignmen
import { ViewAssignmentPoll } from 'app/site/assignments/models/view-assignment-poll';
import { BasePollVoteComponentDirective, VoteOption } from 'app/site/polls/components/base-poll-vote.component';
import { ViewUser } from 'app/site/users/models/view-user';
import { UnknownUserLabel } from '../../services/assignment-poll.service';
const voteOptions = {
Yes: {
@ -47,6 +48,7 @@ const voteOptions = {
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AssignmentPollVoteComponent extends BasePollVoteComponentDirective<ViewAssignmentPoll> implements OnInit {
public unknownUserLabel = UnknownUserLabel;
public AssignmentPollMethod = AssignmentPollMethod;
public PollType = PollType;
public voteActions: VoteOption[] = [];

View File

@ -72,15 +72,18 @@ export class AssignmentPollComponent
this.descriptionForm = this.formBuilder.group({
description: this.poll ? this.poll.description : ''
});
console.log('the poll: ', this.poll);
}
/**
* Print the PDF of this poll with the corresponding options and numbers
*/
public printBallot(): void {
this.pdfService.printBallots(this.poll);
try {
this.pdfService.printBallots(this.poll);
} catch (e) {
console.error(e);
this.raiseError(e);
}
}
public openVotingWarning(): void {

View File

@ -141,9 +141,14 @@ export class AssignmentPollPdfService extends PollPdfService {
return a.weight - b.weight;
});
const resultObject = candidates.map(cand => {
return poll.pollmethod === AssignmentPollMethod.Y
? this.createBallotOption(cand.user.full_name)
: this.createYNBallotEntry(cand.user.full_name, poll.pollmethod);
const candidateName = cand.user?.full_name;
if (candidateName) {
return poll.pollmethod === AssignmentPollMethod.Y
? this.createBallotOption(candidateName)
: this.createYNBallotEntry(candidateName, poll.pollmethod);
} else {
throw new Error(this.translate.instant('This ballot contains deleted users.'));
}
});
if (poll.pollmethod === AssignmentPollMethod.Y) {

View File

@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { TranslateService } from '@ngx-translate/core';
import { ConstantsService } from 'app/core/core-services/constants.service';
@ -23,6 +24,7 @@ import {
VotingResult
} from 'app/site/polls/services/poll.service';
export const UnknownUserLabel = _('Deleted user');
@Injectable({
providedIn: 'root'
})
@ -159,11 +161,13 @@ export class AssignmentPollService extends PollService {
};
// Since pollData does not have any subtitle option
if (candidate instanceof ViewAssignmentOption) {
if (candidate instanceof ViewAssignmentOption && candidate.user) {
pollTableEntry.votingOption = candidate.user.short_name;
pollTableEntry.votingOptionSubtitle = candidate.user.getLevelAndNumber();
} else {
} else if (candidate.user) {
pollTableEntry.votingOption = (candidate as PollDataOption).user.short_name;
} else {
pollTableEntry.votingOption = UnknownUserLabel;
}
return pollTableEntry;
@ -248,8 +252,8 @@ export class AssignmentPollService extends PollService {
}
return resultLabel;
});
return `${option.user.short_name} · ${votingResults.join(' · ')}`;
const optionName = option.user?.short_name ?? UnknownUserLabel;
return `${optionName} · ${votingResults.join(' · ')}`;
});
}
}

View File

@ -10,12 +10,12 @@
<ng-container *ngIf="data.data.assignment_related_users && data.data.assignment_related_users.length">
<ol *ngIf="data.data.number_poll_candidates">
<li *ngFor="let candidate of data.data.assignment_related_users">
{{ candidate.user }}
{{ getUserName(candidate) }}
</li>
</ol>
<ul *ngIf="!data.data.number_poll_candidates">
<li *ngFor="let candidate of data.data.assignment_related_users">
{{ candidate.user }}
{{ getUserName(candidate) }}
</li>
</ul>
</ng-container>

View File

@ -26,4 +26,8 @@ export class AssignmentSlideComponent extends BaseSlideComponentDirective<Assign
public constructor() {
super();
}
public getUserName(relatedUser: { user: string }): string {
return relatedUser.user;
}
}