table update on pseudoanonymize, view base classes for votes and

options, renaming for assignment percent bases
This commit is contained in:
Joshua Sangmeister 2020-02-25 10:44:39 +01:00 committed by FinnStutzenstein
parent 82c8ade0ba
commit 72678770bb
38 changed files with 298 additions and 202 deletions

View File

@ -2,24 +2,36 @@ import { CalculablePollKey } from 'app/site/polls/services/poll.service';
import { AssignmentOption } from './assignment-option';
import { BasePoll } from '../poll/base-poll';
export enum AssignmentPollMethods {
export enum AssignmentPollMethod {
YN = 'YN',
YNA = 'YNA',
Votes = 'votes'
}
export enum AssignmentPollPercentBase {
YN = 'YN',
YNA = 'YNA',
Votes = 'votes',
Valid = 'valid',
Cast = 'cast',
Disabled = 'disabled'
}
/**
* Content of the 'polls' property of assignments
* @ignore
* Class representing a poll for an assignment.
*/
export class AssignmentPoll extends BasePoll<AssignmentPoll, AssignmentOption> {
export class AssignmentPoll extends BasePoll<
AssignmentPoll,
AssignmentOption,
AssignmentPollMethod,
AssignmentPollPercentBase
> {
public static COLLECTIONSTRING = 'assignments/assignment-poll';
public static defaultGroupsConfig = 'assignment_poll_default_groups';
public static defaultPollMethodConfig = 'assignment_poll_method';
public id: number;
public assignment_id: number;
public pollmethod: AssignmentPollMethods;
public votes_amount: number;
public allow_multiple_votes_per_candidate: boolean;
public global_no: boolean;
@ -27,11 +39,11 @@ export class AssignmentPoll extends BasePoll<AssignmentPoll, AssignmentOption> {
public description: string;
public get pollmethodFields(): CalculablePollKey[] {
if (this.pollmethod === AssignmentPollMethods.YN) {
if (this.pollmethod === AssignmentPollMethod.YN) {
return ['yes', 'no'];
} else if (this.pollmethod === AssignmentPollMethods.YNA) {
} else if (this.pollmethod === AssignmentPollMethod.YNA) {
return ['yes', 'no', 'abstain'];
} else if (this.pollmethod === AssignmentPollMethods.Votes) {
} else if (this.pollmethod === AssignmentPollMethod.Votes) {
return ['yes'];
}
}

View File

@ -1,8 +1,8 @@
import { CalculablePollKey } from 'app/site/polls/services/poll.service';
import { BasePoll } from '../poll/base-poll';
import { BasePoll, PercentBase } from '../poll/base-poll';
import { MotionOption } from './motion-option';
export enum MotionPollMethods {
export enum MotionPollMethod {
YN = 'YN',
YNA = 'YNA'
}
@ -10,19 +10,18 @@ export enum MotionPollMethods {
/**
* Class representing a poll for a motion.
*/
export class MotionPoll extends BasePoll<MotionPoll, MotionOption> {
export class MotionPoll extends BasePoll<MotionPoll, MotionOption, MotionPollMethod, PercentBase> {
public static COLLECTIONSTRING = 'motions/motion-poll';
public static defaultGroupsConfig = 'motion_poll_default_groups';
public id: number;
public motion_id: number;
public pollmethod: MotionPollMethods;
public get pollmethodFields(): CalculablePollKey[] {
const ynField: CalculablePollKey[] = ['yes', 'no'];
if (this.pollmethod === MotionPollMethods.YN) {
if (this.pollmethod === MotionPollMethod.YN) {
return ynField;
} else if (this.pollmethod === MotionPollMethods.YNA) {
} else if (this.pollmethod === MotionPollMethod.YNA) {
return ynField.concat(['abstain']);
}
}

View File

@ -23,6 +23,13 @@ export enum PollType {
Pseudoanonymous = 'pseudoanonymous'
}
export enum MajorityMethod {
Simple = 'simple',
TwoThirds = 'two_thirds',
ThreeQuarters = 'three_quarters',
Disabled = 'disabled'
}
export enum PercentBase {
YN = 'YN',
YNA = 'YNA',
@ -31,14 +38,12 @@ export enum PercentBase {
Disabled = 'disabled'
}
export enum MajorityMethod {
Simple = 'simple',
TwoThirds = 'two_thirds',
ThreeQuarters = 'three_quarters',
Disabled = 'disabled'
}
export abstract class BasePoll<T = any, O extends BaseOption<any> = any> extends BaseDecimalModel<T> {
export abstract class BasePoll<
T = any,
O extends BaseOption<any> = any,
PM extends string = string,
PB extends string = string
> extends BaseDecimalModel<T> {
public state: PollState;
public type: PollType;
public title: string;
@ -47,7 +52,9 @@ export abstract class BasePoll<T = any, O extends BaseOption<any> = any> extends
public votescast: number;
public groups_id: number[];
public majority_method: MajorityMethod;
public onehundred_percent_base: PercentBase;
public pollmethod: PM;
public onehundred_percent_base: PB;
public get isCreated(): boolean {
return this.state === PollState.Created;

View File

@ -16,7 +16,7 @@ export const GeneralValueVerbose = {
votesabstain: 'Votes abstain'
};
export abstract class BaseVote<T> extends BaseDecimalModel<T> {
export abstract class BaseVote<T = any> extends BaseDecimalModel<T> {
public weight: number;
public value: VoteValue;
public option_id: number;

View File

@ -103,7 +103,7 @@
<b *ngIf="!vote.user">{{ 'Anonymous' | translate }}</b>
</div>
<!-- Y/N/(A) -->
<ng-container *ngIf="poll.pollmethod !== AssignmentPollMethods.Votes">
<ng-container *ngIf="poll.pollmethod !== AssignmentPollMethod.Votes">
<ng-container *ngFor="let option of poll.options">
<div
*pblNgridCellDef="'votes-' + option.user_id; row as vote"
@ -116,7 +116,7 @@
</ng-container>
</ng-container>
<!-- Votes method -->
<ng-container *ngIf="poll.pollmethod === AssignmentPollMethods.Votes">
<ng-container *ngIf="poll.pollmethod === AssignmentPollMethod.Votes">
<div *pblNgridCellDef="'votes'; row as vote">
<div *ngFor="let candidate of vote.votes">{{ candidate }}</div>
</div>

View File

@ -8,11 +8,12 @@ import { PblColumnDefinition } from '@pebula/ngrid';
import { OperatorService } from 'app/core/core-services/operator.service';
import { AssignmentPollRepositoryService } from 'app/core/repositories/assignments/assignment-poll-repository.service';
import { AssignmentVoteRepositoryService } from 'app/core/repositories/assignments/assignment-vote-repository.service';
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
import { PromptService } from 'app/core/ui-services/prompt.service';
import { ViewportService } from 'app/core/ui-services/viewport.service';
import { ChartType } from 'app/shared/components/charts/charts.component';
import { AssignmentPollMethods } from 'app/shared/models/assignments/assignment-poll';
import { AssignmentPollMethod } from 'app/shared/models/assignments/assignment-poll';
import { BasePollDetailComponent } from 'app/site/polls/components/base-poll-detail.component';
import { VotingResult } from 'app/site/polls/models/view-base-poll';
import { PollService } from 'app/site/polls/services/poll.service';
@ -26,7 +27,7 @@ import { ViewAssignmentPoll } from '../../models/view-assignment-poll';
encapsulation: ViewEncapsulation.None
})
export class AssignmentPollDetailComponent extends BasePollDetailComponent<ViewAssignmentPoll> {
public AssignmentPollMethods = AssignmentPollMethods;
public AssignmentPollMethod = AssignmentPollMethod;
public columnDefinitionSingleVotes: PblColumnDefinition[];
@ -41,7 +42,7 @@ export class AssignmentPollDetailComponent extends BasePollDetailComponent<ViewA
}
public get isVotedPoll(): boolean {
return this.poll.pollmethod === AssignmentPollMethods.Votes;
return this.poll.pollmethod === AssignmentPollMethod.Votes;
}
private _chartType: ChartType = 'horizontalBar';
@ -56,17 +57,18 @@ export class AssignmentPollDetailComponent extends BasePollDetailComponent<ViewA
prompt: PromptService,
pollDialog: AssignmentPollDialogService,
pollService: PollService,
votesRepo: AssignmentVoteRepositoryService,
private operator: OperatorService,
private viewport: ViewportService
) {
super(title, translate, matSnackbar, repo, route, groupRepo, prompt, pollDialog, pollService);
super(title, translate, matSnackbar, repo, route, groupRepo, prompt, pollDialog, pollService, votesRepo);
}
public onPollWithOptionsLoaded(): void {
protected createVotesData(): void {
const votes = {};
let i = -1;
this.columnDefinitionSingleVotes = [
const definitions: PblColumnDefinition[] = [
{
prop: 'user',
label: 'Participant',
@ -75,7 +77,7 @@ export class AssignmentPollDetailComponent extends BasePollDetailComponent<ViewA
}
];
if (this.isVotedPoll) {
this.columnDefinitionSingleVotes.push(this.getVoteColumnDefinition('votes', 'Votes'));
definitions.push(this.getVoteColumnDefinition('votes', 'Votes'));
}
/**
@ -90,9 +92,7 @@ export class AssignmentPollDetailComponent extends BasePollDetailComponent<ViewA
*/
for (const option of this.poll.options) {
if (!this.isVotedPoll) {
this.columnDefinitionSingleVotes.push(
this.getVoteColumnDefinition('votes-' + option.user_id, option.user.getFullName())
);
definitions.push(this.getVoteColumnDefinition('votes-' + option.user_id, option.user.getFullName()));
}
for (const vote of option.votes) {
@ -125,6 +125,7 @@ export class AssignmentPollDetailComponent extends BasePollDetailComponent<ViewA
this.setVotesData(Object.values(votes));
this.candidatesLabels = this.pollService.getChartLabels(this.poll);
this.columnDefinitionSingleVotes = definitions;
this.isReady = true;
}
@ -151,11 +152,11 @@ export class AssignmentPollDetailComponent extends BasePollDetailComponent<ViewA
}
public voteFitsMethod(result: VotingResult): boolean {
if (this.poll.pollmethod === AssignmentPollMethods.Votes) {
if (this.poll.pollmethod === AssignmentPollMethod.Votes) {
if (result.vote === 'abstain' || result.vote === 'no') {
return false;
}
} else if (this.poll.pollmethod === AssignmentPollMethods.YN) {
} else if (this.poll.pollmethod === AssignmentPollMethod.YN) {
if (result.vote === 'abstain') {
return false;
}

View File

@ -1,4 +1,4 @@
<os-poll-form [data]="pollData" [pollMethods]="assignmentPollMethods" #pollForm></os-poll-form>
<os-poll-form [data]="pollData" [pollMethods]="AssignmentPollMethodVerbose" [percentBases]="AssignmentPollPercentBaseVerbose" #pollForm></os-poll-form>
<!-- Analog voting -->
<ng-container *ngIf="pollForm.contentForm.get('type').value === 'analog'">

View File

@ -6,9 +6,12 @@ import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { AssignmentPollMethods } from 'app/shared/models/assignments/assignment-poll';
import { AssignmentPollMethod } from 'app/shared/models/assignments/assignment-poll';
import { GeneralValueVerbose, VoteValue, VoteValueVerbose } from 'app/shared/models/poll/base-vote';
import { AssignmentPollMethodsVerbose } from 'app/site/assignments/models/view-assignment-poll';
import {
AssignmentPollMethodVerbose,
AssignmentPollPercentBaseVerbose
} from 'app/site/assignments/models/view-assignment-poll';
import { BasePollDialogComponent } from 'app/site/polls/components/base-poll-dialog.component';
import { PollFormComponent } from 'app/site/polls/components/poll-form/poll-form.component';
import { ViewUser } from 'app/site/users/models/view-user';
@ -50,7 +53,8 @@ export class AssignmentPollDialogComponent extends BasePollDialogComponent<ViewA
public voteValueVerbose = VoteValueVerbose;
public generalValueVerbose = GeneralValueVerbose;
public assignmentPollMethods = AssignmentPollMethodsVerbose;
public AssignmentPollMethodVerbose = AssignmentPollMethodVerbose;
public AssignmentPollPercentBaseVerbose = AssignmentPollPercentBaseVerbose;
public options: OptionsObject;
@ -92,10 +96,10 @@ export class AssignmentPollDialogComponent extends BasePollDialogComponent<ViewA
private setAnalogPollValues(): void {
const pollmethod = this.pollForm.contentForm.get('pollmethod').value;
this.analogPollValues = ['Y'];
if (pollmethod !== AssignmentPollMethods.Votes) {
if (pollmethod !== AssignmentPollMethod.Votes) {
this.analogPollValues.push('N');
}
if (pollmethod === AssignmentPollMethods.YNA) {
if (pollmethod === AssignmentPollMethod.YNA) {
this.analogPollValues.push('A');
}
}
@ -110,10 +114,10 @@ export class AssignmentPollDialogComponent extends BasePollDialogComponent<ViewA
for (const option of data.options) {
const votes: any = {};
votes.Y = option.yes;
if (data.pollmethod !== AssignmentPollMethods.Votes) {
if (data.pollmethod !== AssignmentPollMethod.Votes) {
votes.N = option.no;
}
if (data.pollmethod === AssignmentPollMethods.YNA) {
if (data.pollmethod === AssignmentPollMethod.YNA) {
votes.A = option.abstain;
}
update.options[option.user_id] = votes;

View File

@ -7,7 +7,7 @@
<span *ngIf="poll.user_has_not_voted">You have not give any voting here!</span>
<!-- Leftover votes -->
<h4 *ngIf="poll.pollmethod === pollMethods.Votes && poll.votes_amount > 1 && !currentVotes.global">
<h4 *ngIf="poll.pollmethod === AssignmentPollMethod.Votes && poll.votes_amount > 1 && !currentVotes.global">
{{ 'Votes for this poll' | translate }}: {{ getVotesCount() }}/{{ poll.votes_amount }}
</h4>
@ -16,9 +16,9 @@
<div *ngIf="poll.type !== PollType.Pseudoanonymous || !option.user_has_voted">
<div
[ngClass]="{
'yna-grid': poll.pollmethod === pollMethods.YNA,
'yn-grid': poll.pollmethod === pollMethods.YN,
'single-vote-grid': poll.pollmethod === pollMethods.Votes
'yna-grid': poll.pollmethod === AssignmentPollMethod.YNA,
'yn-grid': poll.pollmethod === AssignmentPollMethod.YN,
'single-vote-grid': poll.pollmethod === AssignmentPollMethod.Votes
}"
>
<div class="vote-candidate-name">
@ -34,7 +34,7 @@
>
<mat-icon> {{ action.icon }}</mat-icon>
</button>
<span *ngIf="poll.pollmethod !== pollMethods.Votes" class="vote-label">
<span *ngIf="poll.pollmethod !== AssignmentPollMethod.Votes" class="vote-label">
{{ action.label | translate }}
</span>
</div>
@ -44,7 +44,7 @@
</div>
<!-- global no/abstain -->
<ng-container *ngIf="poll.pollmethod === pollMethods.Votes && (poll.global_no || poll.global_abstain)">
<ng-container *ngIf="poll.pollmethod === AssignmentPollMethod.Votes && (poll.global_no || poll.global_abstain)">
<mat-divider></mat-divider>
<div class="global-option-grid">
<div *ngIf="poll.global_no">

View File

@ -8,7 +8,7 @@ import { OperatorService } from 'app/core/core-services/operator.service';
import { AssignmentPollRepositoryService } from 'app/core/repositories/assignments/assignment-poll-repository.service';
import { AssignmentVoteRepositoryService } from 'app/core/repositories/assignments/assignment-vote-repository.service';
import { VotingService } from 'app/core/ui-services/voting.service';
import { AssignmentPollMethods } from 'app/shared/models/assignments/assignment-poll';
import { AssignmentPollMethod } from 'app/shared/models/assignments/assignment-poll';
import { PollType } from 'app/shared/models/poll/base-poll';
import { BasePollVoteComponent } from 'app/site/polls/components/base-poll-vote.component';
import { ViewAssignmentPoll } from '../../models/view-assignment-poll';
@ -28,7 +28,7 @@ interface VoteActions {
styleUrls: ['./assignment-poll-vote.component.scss']
})
export class AssignmentPollVoteComponent extends BasePollVoteComponent<ViewAssignmentPoll> implements OnInit {
public pollMethods = AssignmentPollMethods;
public AssignmentPollMethod = AssignmentPollMethod;
public PollType = PollType;
public voteActions: VoteActions[] = [];
@ -70,7 +70,7 @@ export class AssignmentPollVoteComponent extends BasePollVoteComponent<ViewAssig
label: 'Yes'
});
if (this.poll.pollmethod !== AssignmentPollMethods.Votes) {
if (this.poll.pollmethod !== AssignmentPollMethod.Votes) {
this.voteActions.push({
vote: 'N',
css: 'voted-no',
@ -79,7 +79,7 @@ export class AssignmentPollVoteComponent extends BasePollVoteComponent<ViewAssig
});
}
if (this.poll.pollmethod === AssignmentPollMethods.YNA) {
if (this.poll.pollmethod === AssignmentPollMethod.YNA) {
this.voteActions.push({
vote: 'A',
css: 'voted-abstain',
@ -101,7 +101,7 @@ export class AssignmentPollVoteComponent extends BasePollVoteComponent<ViewAssig
for (const option of this.poll.options) {
let curr_vote = filtered.find(vote => vote.option.id === option.id);
if (this.poll.pollmethod === AssignmentPollMethods.Votes && curr_vote) {
if (this.poll.pollmethod === AssignmentPollMethod.Votes && curr_vote) {
if (curr_vote.value !== 'Y') {
this.currentVotes.global = curr_vote.valueVerbose;
curr_vote = null;
@ -120,7 +120,7 @@ export class AssignmentPollVoteComponent extends BasePollVoteComponent<ViewAssig
public saveSingleVote(optionId: number, vote: 'Y' | 'N' | 'A'): void {
let requestData;
if (this.poll.pollmethod === AssignmentPollMethods.Votes) {
if (this.poll.pollmethod === AssignmentPollMethod.Votes) {
const pollOptionIds = this.getPollOptionIds();
requestData = pollOptionIds.reduce((o, n) => {
if ((n === optionId && vote === 'Y') !== (this.currentVotes[n] === 'Yes')) {

View File

@ -45,7 +45,7 @@
</div>
</div>
<div *ngIf="hasVotes">
<div *ngIf="canSeeVotes">
<os-charts
[class]="chartType === 'doughnut' ? 'doughnut-chart' : 'bar-chart'"
[type]="chartType"

View File

@ -10,7 +10,6 @@ import { OperatorService } from 'app/core/core-services/operator.service';
import { AssignmentPollRepositoryService } from 'app/core/repositories/assignments/assignment-poll-repository.service';
import { PromptService } from 'app/core/ui-services/prompt.service';
import { ChartType } from 'app/shared/components/charts/charts.component';
import { PollState } from 'app/shared/models/poll/base-poll';
import { BasePollComponent } from 'app/site/polls/components/base-poll.component';
import { PollService } from 'app/site/polls/services/poll.service';
import { AssignmentPollDialogService } from '../../services/assignment-poll-dialog.service';
@ -61,8 +60,8 @@ export class AssignmentPollComponent extends BasePollComponent<ViewAssignmentPol
return this.operator.hasPerms('assignments.can_see');
}
public get hasVotes(): boolean {
return (this.canManage && this.poll.state === PollState.Finished) || this.poll.state === PollState.Published;
public get canSeeVotes(): boolean {
return (this.canManage && this.poll.isFinished) || this.poll.isPublished;
}
/**

View File

@ -1,21 +1,12 @@
import { AssignmentOption } from 'app/shared/models/assignments/assignment-option';
import { ViewBaseOption } from 'app/site/polls/models/view-base-option';
import { ViewUser } from 'app/site/users/models/view-user';
import { BaseViewModel } from '../../base/base-view-model';
import { ViewAssignmentPoll } from './view-assignment-poll';
import { ViewAssignmentVote } from './view-assignment-vote';
export class ViewAssignmentOption extends BaseViewModel<AssignmentOption> {
public get option(): AssignmentOption {
return this._model;
}
export class ViewAssignmentOption extends ViewBaseOption<AssignmentOption> {
public static COLLECTIONSTRING = AssignmentOption.COLLECTIONSTRING;
protected _collectionString = AssignmentOption.COLLECTIONSTRING;
}
interface TIAssignmentOptionRelations {
votes: ViewAssignmentVote[];
export interface ViewAssignmentOption extends AssignmentOption {
user: ViewUser;
poll: ViewAssignmentPoll;
}
export interface ViewAssignmentOption extends AssignmentOption, TIAssignmentOptionRelations {}

View File

@ -1,10 +1,14 @@
import { BehaviorSubject } from 'rxjs';
import { ChartData } from 'app/shared/components/charts/charts.component';
import { AssignmentPoll } from 'app/shared/models/assignments/assignment-poll';
import {
AssignmentPoll,
AssignmentPollMethod,
AssignmentPollPercentBase
} from 'app/shared/models/assignments/assignment-poll';
import { BaseViewModel } from 'app/site/base/base-view-model';
import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
import { PollTableData, ViewBasePoll, VotingResult } from 'app/site/polls/models/view-base-poll';
import { PollClassType, PollTableData, ViewBasePoll, VotingResult } from 'app/site/polls/models/view-base-poll';
import { ViewAssignment } from './view-assignment';
import { ViewAssignmentOption } from './view-assignment-option';
@ -12,21 +16,35 @@ export interface AssignmentPollTitleInformation {
title: string;
}
export const AssignmentPollMethodsVerbose = {
export const AssignmentPollMethodVerbose = {
votes: 'Yes per candidate',
YN: 'Yes/No per candidate',
YNA: 'Yes/No/Abstain per candidate'
};
export class ViewAssignmentPoll extends ViewBasePoll<AssignmentPoll> implements AssignmentPollTitleInformation {
export const AssignmentPollPercentBaseVerbose = {
YN: 'Yes/No per candidate',
YNA: 'Yes/No/Abstain per candidate',
votes: 'Sum of votes inclusive global ones',
valid: 'All valid ballots',
cast: 'All casted ballots',
disabled: 'Disabled (no percents)'
};
export class ViewAssignmentPoll extends ViewBasePoll<AssignmentPoll, AssignmentPollMethod, AssignmentPollPercentBase>
implements AssignmentPollTitleInformation {
public static COLLECTIONSTRING = AssignmentPoll.COLLECTIONSTRING;
protected _collectionString = AssignmentPoll.COLLECTIONSTRING;
public readonly tableChartData: Map<string, BehaviorSubject<ChartData>> = new Map();
public readonly pollClassType: 'assignment' | 'motion' = 'assignment';
public readonly pollClassType = PollClassType.Assignment;
public get pollmethodVerbose(): string {
return AssignmentPollMethodsVerbose[this.pollmethod];
return AssignmentPollMethodVerbose[this.pollmethod];
}
public get percentBaseVerbose(): string {
return AssignmentPollPercentBaseVerbose[this.onehundred_percent_base];
}
public getContentObject(): BaseViewModel {

View File

@ -1,19 +1,9 @@
import { AssignmentVote } from 'app/shared/models/assignments/assignment-vote';
import { ViewUser } from 'app/site/users/models/view-user';
import { BaseViewModel } from '../../base/base-view-model';
import { ViewAssignmentOption } from './view-assignment-option';
import { ViewBaseVote } from 'app/site/polls/models/view-base-vote';
export class ViewAssignmentVote extends BaseViewModel<AssignmentVote> {
public get vote(): AssignmentVote {
return this._model;
}
export class ViewAssignmentVote extends ViewBaseVote<AssignmentVote> {
public static COLLECTIONSTRING = AssignmentVote.COLLECTIONSTRING;
protected _collectionString = AssignmentVote.COLLECTIONSTRING;
}
interface TIAssignmentVoteRelations {
user: ViewUser;
option: ViewAssignmentOption;
}
export interface ViewAssignmentVote extends AssignmentVote, TIAssignmentVoteRelations {}
export interface ViewAssignmentVote extends AssignmentVote {}

View File

@ -7,7 +7,7 @@ import { PdfDocumentService } from 'app/core/pdf-services/pdf-document.service';
import { AssignmentRepositoryService } from 'app/core/repositories/assignments/assignment-repository.service';
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { AssignmentPollMethods } from 'app/shared/models/assignments/assignment-poll';
import { AssignmentPollMethod } from 'app/shared/models/assignments/assignment-poll';
import { ViewAssignmentPoll } from '../models/view-assignment-poll';
/**
@ -162,7 +162,7 @@ export class AssignmentPollPdfService extends PollPdfService {
return resultObject;
}
private createYNBallotEntry(option: string, method: AssignmentPollMethods): object {
private createYNBallotEntry(option: string, method: AssignmentPollMethod): object {
const choices = method === 'YNA' ? ['Yes', 'No', 'Abstain'] : ['Yes', 'No'];
const columnstack = choices.map(choice => {
return {

View File

@ -5,8 +5,12 @@ import { TranslateService } from '@ngx-translate/core';
import { ConstantsService } from 'app/core/core-services/constants.service';
import { AssignmentPollRepositoryService } from 'app/core/repositories/assignments/assignment-poll-repository.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { AssignmentPoll, AssignmentPollMethods } from 'app/shared/models/assignments/assignment-poll';
import { MajorityMethod, PercentBase } from 'app/shared/models/poll/base-poll';
import {
AssignmentPoll,
AssignmentPollMethod,
AssignmentPollPercentBase
} from 'app/shared/models/assignments/assignment-poll';
import { MajorityMethod } from 'app/shared/models/poll/base-poll';
import { PollData, PollService } from 'app/site/polls/services/poll.service';
@Injectable({
@ -16,7 +20,7 @@ export class AssignmentPollService extends PollService {
/**
* The default percentage base
*/
public defaultPercentBase: PercentBase;
public defaultPercentBase: AssignmentPollPercentBase;
/**
* The default majority method
@ -25,7 +29,7 @@ export class AssignmentPollService extends PollService {
public defaultGroupIds: number[];
public defaultPollMethod: AssignmentPollMethods;
public defaultPollMethod: AssignmentPollMethod;
/**
* Constructor. Subscribes to the configuration values needed
@ -39,14 +43,14 @@ export class AssignmentPollService extends PollService {
) {
super(constants);
config
.get<PercentBase>('motion_poll_default_100_percent_base')
.get<AssignmentPollPercentBase>('assignment_poll_default_100_percent_base')
.subscribe(base => (this.defaultPercentBase = base));
config
.get<MajorityMethod>('motion_poll_default_majority_method')
.get<MajorityMethod>('assignment_poll_default_majority_method')
.subscribe(method => (this.defaultMajorityMethod = method));
config.get<number[]>(AssignmentPoll.defaultGroupsConfig).subscribe(ids => (this.defaultGroupIds = ids));
config
.get<AssignmentPollMethods>(AssignmentPoll.defaultPollMethodConfig)
.get<AssignmentPollMethod>(AssignmentPoll.defaultPollMethodConfig)
.subscribe(method => (this.defaultPollMethod = method));
}
@ -77,19 +81,22 @@ export class AssignmentPollService extends PollService {
}
public getPercentBase(poll: PollData): number {
const base: PercentBase = poll.onehundred_percent_base;
const base: AssignmentPollPercentBase = poll.onehundred_percent_base as AssignmentPollPercentBase;
let totalByBase: number;
switch (base) {
case PercentBase.YN:
case AssignmentPollPercentBase.YN:
totalByBase = this.sumOptionsYN(poll);
break;
case PercentBase.YNA:
case AssignmentPollPercentBase.YNA:
totalByBase = this.sumOptionsYNA(poll);
break;
case PercentBase.Valid:
case AssignmentPollPercentBase.Votes:
totalByBase = this.sumOptionsYNA(poll);
break;
case AssignmentPollPercentBase.Valid:
totalByBase = poll.votesvalid;
break;
case PercentBase.Cast:
case AssignmentPollPercentBase.Cast:
totalByBase = poll.votescast;
break;
default:

View File

@ -1,19 +1,8 @@
import { MotionOption } from 'app/shared/models/motions/motion-option';
import { BaseViewModel } from '../../base/base-view-model';
import { ViewMotionPoll } from './view-motion-poll';
import { ViewMotionVote } from './view-motion-vote';
import { ViewBaseOption } from 'app/site/polls/models/view-base-option';
export class ViewMotionOption extends BaseViewModel<MotionOption> {
public get option(): MotionOption {
return this._model;
}
export class ViewMotionOption extends ViewBaseOption<MotionOption> {
public static COLLECTIONSTRING = MotionOption.COLLECTIONSTRING;
protected _collectionString = MotionOption.COLLECTIONSTRING;
}
interface TIMotionOptionRelations {
votes: ViewMotionVote[];
poll: ViewMotionPoll;
}
export interface ViewMotionOption extends MotionOption, TIMotionOptionRelations {}
export interface ViewMotionOption extends MotionOption {}

View File

@ -1,31 +1,41 @@
import { MotionPoll } from 'app/shared/models/motions/motion-poll';
import { MotionPoll, MotionPollMethod } from 'app/shared/models/motions/motion-poll';
import { PercentBase } from 'app/shared/models/poll/base-poll';
import { BaseViewModel } from 'app/site/base/base-view-model';
import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
import { ViewMotionOption } from 'app/site/motions/models/view-motion-option';
import { PollTableData, ViewBasePoll, VotingResult } from 'app/site/polls/models/view-base-poll';
import { PollClassType, PollTableData, ViewBasePoll, VotingResult } from 'app/site/polls/models/view-base-poll';
import { ViewMotion } from './view-motion';
export interface MotionPollTitleInformation {
title: string;
}
export const MotionPollMethodsVerbose = {
export const MotionPollMethodVerbose = {
YN: 'Yes/No',
YNA: 'Yes/No/Abstain'
};
export class ViewMotionPoll extends ViewBasePoll<MotionPoll> implements MotionPollTitleInformation {
export const MotionPollPercentBaseVerbose = {
YN: 'Yes/No',
YNA: 'Yes/No/Abstain',
valid: 'All valid ballots',
cast: 'All casted ballots',
disabled: 'Disabled (no percents)'
};
export class ViewMotionPoll extends ViewBasePoll<MotionPoll, MotionPollMethod, PercentBase>
implements MotionPollTitleInformation {
public static COLLECTIONSTRING = MotionPoll.COLLECTIONSTRING;
protected _collectionString = MotionPoll.COLLECTIONSTRING;
public readonly pollClassType: 'assignment' | 'motion' = 'motion';
public readonly pollClassType = PollClassType.Motion;
public get result(): ViewMotionOption {
return this.options[0];
}
public get hasVotes(): boolean {
return !!this.result.votes.length;
return this.result && !!this.result.votes.length;
}
public getContentObject(): BaseViewModel {
@ -71,7 +81,11 @@ export class ViewMotionPoll extends ViewBasePoll<MotionPoll> implements MotionPo
}
public get pollmethodVerbose(): string {
return MotionPollMethodsVerbose[this.pollmethod];
return MotionPollMethodVerbose[this.pollmethod];
}
public get percentBaseVerbose(): string {
return MotionPollPercentBaseVerbose[this.onehundred_percent_base];
}
public anySpecialVotes(): boolean {

View File

@ -1,19 +1,9 @@
import { MotionVote } from 'app/shared/models/motions/motion-vote';
import { ViewUser } from 'app/site/users/models/view-user';
import { BaseViewModel } from '../../base/base-view-model';
import { ViewMotionOption } from './view-motion-option';
import { ViewBaseVote } from 'app/site/polls/models/view-base-vote';
export class ViewMotionVote extends BaseViewModel<MotionVote> {
public get vote(): MotionVote {
return this._model;
}
export class ViewMotionVote extends ViewBaseVote<MotionVote> {
public static COLLECTIONSTRING = MotionVote.COLLECTIONSTRING;
protected _collectionString = MotionVote.COLLECTIONSTRING;
}
interface TIMotionVoteRelations {
user?: ViewUser;
option: ViewMotionOption;
}
export interface ViewMotionVote extends MotionVote, TIMotionVoteRelations {}
export interface ViewMotionVote extends MotionVote {}

View File

@ -82,6 +82,7 @@
<div class="named-result-table" *ngIf="poll.type === 'named'">
<h2>{{ 'Single votes' | translate }}</h2>
<os-list-view-table
*ngIf="votesDataObservable"
[listObservable]="votesDataObservable"
[columns]="columnDefinition"
[filterProps]="filterProps"
@ -107,12 +108,10 @@
</div>
<div>{{ vote.valueVerbose | translate }}</div>
</div>
<!-- No Results -->
<div *pblNgridNoDataRef class="pbl-ngrid-no-data">
{{ 'The individual votes were made anonymous.' | translate }}
</div>
</os-list-view-table>
<div *ngIf="!votesDataObservable">
{{ 'The individual votes were anonymized.' | translate }}
</div>
</div>
</div>

View File

@ -8,6 +8,7 @@ import { PblColumnDefinition } from '@pebula/ngrid';
import { OperatorService } from 'app/core/core-services/operator.service';
import { MotionPollRepositoryService } from 'app/core/repositories/motions/motion-poll-repository.service';
import { MotionVoteRepositoryService } from 'app/core/repositories/motions/motion-vote-repository.service';
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
import { PromptService } from 'app/core/ui-services/prompt.service';
import { ChartType } from 'app/shared/components/charts/charts.component';
@ -60,12 +61,13 @@ export class MotionPollDetailComponent extends BasePollDetailComponent<ViewMotio
pollDialog: MotionPollDialogService,
pollService: PollService,
private operator: OperatorService,
private router: Router
private router: Router,
votesRepo: MotionVoteRepositoryService
) {
super(title, translate, matSnackbar, repo, route, groupRepo, prompt, pollDialog, pollService);
super(title, translate, matSnackbar, repo, route, groupRepo, prompt, pollDialog, pollService, votesRepo);
}
protected onPollWithOptionsLoaded(): void {
protected createVotesData(): void {
this.setVotesData(this.poll.options[0].votes);
}

View File

@ -1,4 +1,4 @@
<os-poll-form [data]="pollData" #pollForm></os-poll-form>
<os-poll-form [data]="pollData" [percentBases]="PercentBaseVerbose" #pollForm></os-poll-form>
<ng-container *ngIf="pollForm.contentForm.get('type').value === 'analog'">
<div class="os-form-card-mobile" mat-dialog-content>
<form [formGroup]="dialogVoteForm">

View File

@ -6,9 +6,9 @@ import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { ViewMotionPoll } from 'app/site/motions/models/view-motion-poll';
import { MotionPollMethodsVerbose } from 'app/site/motions/models/view-motion-poll';
import { BasePollDialogComponent } from 'app/site/polls/components/base-poll-dialog.component';
import { PollFormComponent } from 'app/site/polls/components/poll-form/poll-form.component';
import { PercentBaseVerbose } from 'app/site/polls/models/view-base-poll';
@Component({
selector: 'os-motion-poll-dialog',
@ -16,7 +16,7 @@ import { PollFormComponent } from 'app/site/polls/components/poll-form/poll-form
styleUrls: ['./motion-poll-dialog.component.scss']
})
export class MotionPollDialogComponent extends BasePollDialogComponent<ViewMotionPoll> {
public motionPollMethods = { YNA: MotionPollMethodsVerbose.YNA };
public PercentBaseVerbose = PercentBaseVerbose;
@ViewChild('pollForm', { static: false })
protected pollForm: PollFormComponent<ViewMotionPoll>;

View File

@ -8,7 +8,7 @@ import { OperatorService } from 'app/core/core-services/operator.service';
import { MotionPollRepositoryService } from 'app/core/repositories/motions/motion-poll-repository.service';
import { MotionVoteRepositoryService } from 'app/core/repositories/motions/motion-vote-repository.service';
import { VotingService } from 'app/core/ui-services/voting.service';
import { MotionPollMethods } from 'app/shared/models/motions/motion-poll';
import { MotionPollMethod } from 'app/shared/models/motions/motion-poll';
import { ViewMotionPoll } from 'app/site/motions/models/view-motion-poll';
import { ViewMotionVote } from 'app/site/motions/models/view-motion-vote';
import { BasePollVoteComponent } from 'app/site/polls/components/base-poll-vote.component';
@ -34,7 +34,7 @@ export class MotionPollVoteComponent extends BasePollVoteComponent<ViewMotionPol
*/
public currentVote: ViewMotionVote;
public pollMethods = MotionPollMethods;
public MotionPollMethod = MotionPollMethod;
private votes: ViewMotionVote[];

View File

@ -5,7 +5,7 @@ import { TranslateService } from '@ngx-translate/core';
import { ConstantsService } from 'app/core/core-services/constants.service';
import { MotionPollRepositoryService } from 'app/core/repositories/motions/motion-poll-repository.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { MotionPoll, MotionPollMethods } from 'app/shared/models/motions/motion-poll';
import { MotionPoll, MotionPollMethod } from 'app/shared/models/motions/motion-poll';
import { MajorityMethod, PercentBase } from 'app/shared/models/poll/base-poll';
import { PollData, PollService } from 'app/site/polls/services/poll.service';
@ -60,13 +60,13 @@ export class MotionPollService extends PollService {
const length = this.pollRepo.getViewModelList().filter(item => item.motion_id === poll.motion_id).length;
poll.title = !length ? this.translate.instant('Vote') : `${this.translate.instant('Vote')} (${length + 1})`;
poll.pollmethod = MotionPollMethods.YNA;
poll.pollmethod = MotionPollMethod.YNA;
return poll;
}
public getPercentBase(poll: PollData): number {
const base: PercentBase = poll.onehundred_percent_base;
const base: PercentBase = poll.onehundred_percent_base as PercentBase;
let totalByBase: number;
const result = poll.options[0];

View File

@ -6,17 +6,21 @@ import { ActivatedRoute } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { Label } from 'ng2-charts';
import { BehaviorSubject, from, Observable } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { BaseRepository } from 'app/core/repositories/base-repository';
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
import { BasePollDialogService } from 'app/core/ui-services/base-poll-dialog.service';
import { PromptService } from 'app/core/ui-services/prompt.service';
import { ChartData, ChartType } from 'app/shared/components/charts/charts.component';
import { BaseVote } from 'app/shared/models/poll/base-vote';
import { BaseViewComponent } from 'app/site/base/base-view';
import { ViewGroup } from 'app/site/users/models/view-group';
import { ViewUser } from 'app/site/users/models/view-user';
import { BasePollRepositoryService } from '../services/base-poll-repository.service';
import { PollService } from '../services/poll.service';
import { ViewBasePoll } from '../models/view-base-poll';
import { ViewBaseVote } from '../models/view-base-vote';
export interface BaseVoteData {
user?: ViewUser;
@ -74,6 +78,8 @@ export abstract class BasePollDetailComponent<V extends ViewBasePoll> extends Ba
// The observable for the votes-per-user table
public votesDataObservable: Observable<BaseVoteData[]>;
protected optionsLoaded = false;
/**
* Constructor
*
@ -98,9 +104,23 @@ export abstract class BasePollDetailComponent<V extends ViewBasePoll> extends Ba
protected groupRepo: GroupRepositoryService,
protected promptService: PromptService,
protected pollDialog: BasePollDialogService<V>,
protected pollService: PollService
protected pollService: PollService,
protected votesRepo: BaseRepository<ViewBaseVote, BaseVote, object>
) {
super(title, translate, matSnackbar);
votesRepo
.getViewModelListObservable()
.pipe(
filter(() => this.poll && this.canSeeVotes), // filter first for valid poll state to avoid unneccessary iteration of potentially thousands of votes
map(votes => votes.filter(vote => vote.option.poll_id === this.poll.id)),
filter(votes => !!votes.length)
)
.subscribe(() => {
// votes data can only be created when options are ready
if (this.optionsLoaded) {
this.createVotesData();
}
});
}
/**
@ -143,12 +163,18 @@ export abstract class BasePollDetailComponent<V extends ViewBasePoll> extends Ba
*/
protected onPollLoaded(): void {}
protected onPollWithOptionsLoaded(): void {}
protected onPollWithOptionsLoaded(): void {
this.createVotesData();
}
protected onStateChanged(): void {}
protected abstract hasPerms(): boolean;
protected get canSeeVotes(): boolean {
return (this.hasPerms && this.poll.isFinished) || this.poll.isPublished;
}
/**
* sets the votes data only if the poll wasn't pseudoanonymized
*/
@ -160,6 +186,11 @@ export abstract class BasePollDetailComponent<V extends ViewBasePoll> extends Ba
}
}
/**
* Is called when the underlying vote data changes. Is supposed to call setVotesData
*/
protected abstract createVotesData(): void;
/**
* Initializes data for the shown chart.
* Could be overwritten to implement custom chart data.
@ -169,10 +200,10 @@ export abstract class BasePollDetailComponent<V extends ViewBasePoll> extends Ba
}
/**
* This checks, if the poll has votes.
* This checks if the poll has votes.
*/
private checkData(): void {
if (this.poll.state === 3 || this.poll.state === 4) {
if (this.poll.stateHasVotes) {
setTimeout(() => this.initChartData());
}
}
@ -203,6 +234,7 @@ export abstract class BasePollDetailComponent<V extends ViewBasePoll> extends Ba
if (!this.poll.options || !this.poll.options.length) {
setTimeout(() => this.waitForOptions(), 1);
} else {
this.optionsLoaded = true;
this.onPollWithOptionsLoaded();
}
}

View File

@ -65,7 +65,7 @@
formControlName="onehundred_percent_base"
required
>
<ng-container *ngFor="let option of percentBases | keyvalue">
<ng-container *ngFor="let option of percentBases | keyvalue: keepEntryOrder">
<mat-option [value]="option.key">{{ option.value | translate }}</mat-option>
</ng-container>
</mat-select>

View File

@ -44,6 +44,12 @@ export class PollFormComponent<T extends ViewBasePoll> extends BaseViewComponent
@Input()
public pollMethods: { [key: string]: string };
/**
* The different percent bases for this poll.
*/
@Input()
public percentBases: { [key: string]: string };
@Input()
public data: Partial<T>;
@ -52,11 +58,6 @@ export class PollFormComponent<T extends ViewBasePoll> extends BaseViewComponent
*/
public pollTypes = PollTypeVerbose;
/**
* The percent base for the poll.
*/
public percentBases: { [key: string]: string } = PercentBaseVerbose;
/**
* The majority methods for the poll.
*/
@ -233,4 +234,11 @@ export class PollFormComponent<T extends ViewBasePoll> extends BaseViewComponent
global_abstain: [false]
});
}
/**
* compare function used with the KeyValuePipe to display the percent bases in original order
*/
public keepEntryOrder(): number {
return 0;
}
}

View File

@ -0,0 +1,15 @@
import { BaseOption } from 'app/shared/models/poll/base-option';
import { BaseViewModel } from '../../base/base-view-model';
import { ViewBasePoll } from './view-base-poll';
import { ViewBaseVote } from './view-base-vote';
export class ViewBaseOption<M extends BaseOption<M> = any> extends BaseViewModel<M> {
public get option(): M {
return this._model;
}
}
export interface ViewBaseOption<M extends BaseOption<M> = any> extends BaseOption<M> {
votes: ViewBaseVote[];
poll: ViewBasePoll;
}

View File

@ -1,11 +1,10 @@
import { BasePoll, PercentBase, PollType } from 'app/shared/models/poll/base-poll';
import { ViewAssignmentOption } from 'app/site/assignments/models/view-assignment-option';
import { BaseProjectableViewModel } from 'app/site/base/base-projectable-view-model';
import { BaseViewModel } from 'app/site/base/base-view-model';
import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
import { ViewMotionOption } from 'app/site/motions/models/view-motion-option';
import { ViewGroup } from 'app/site/users/models/view-group';
import { ViewUser } from 'app/site/users/models/view-user';
import { ViewBaseOption } from './view-base-option';
export enum PollClassType {
Motion = 'motion',
@ -73,9 +72,6 @@ export const MajorityMethodVerbose = {
disabled: 'Disabled'
};
/**
* TODO: These need to be in order
*/
export const PercentBaseVerbose = {
YN: 'Yes/No',
YNA: 'Yes/No/Abstain',
@ -84,7 +80,11 @@ export const PercentBaseVerbose = {
disabled: 'Disabled'
};
export abstract class ViewBasePoll<M extends BasePoll<M, any> = any> extends BaseProjectableViewModel<M> {
export abstract class ViewBasePoll<
M extends BasePoll<M, any, PM, PB> = any,
PM extends string = string,
PB extends string = string
> extends BaseProjectableViewModel<M> {
private _tableData: PollTableData[] = [];
protected voteTableKeys: VotingResult[] = [
@ -157,15 +157,15 @@ export abstract class ViewBasePoll<M extends BasePoll<M, any> = any> extends Bas
return MajorityMethodVerbose[this.majority_method];
}
public get percentBaseVerbose(): string {
return PercentBaseVerbose[this.onehundred_percent_base];
}
public abstract get pollmethodVerbose(): string;
public abstract get percentBaseVerbose(): string;
public get showAbstainPercent(): boolean {
return this.onehundred_percent_base === PercentBase.YNA;
}
public abstract readonly pollClassType: 'motion' | 'assignment';
public abstract readonly pollClassType: PollClassType;
public canBeVotedFor: () => boolean;
@ -188,8 +188,12 @@ export abstract class ViewBasePoll<M extends BasePoll<M, any> = any> extends Bas
public abstract generateTableData(): PollTableData[];
}
export interface ViewBasePoll<M extends BasePoll<M, any> = any> extends BasePoll<M, any> {
export interface ViewBasePoll<
M extends BasePoll<M, any, PM, PB> = any,
PM extends string = string,
PB extends string = string
> extends BasePoll<M, any, PM, PB> {
voted: ViewUser[];
groups: ViewGroup[];
options: (ViewMotionOption | ViewAssignmentOption)[]; // TODO find a better solution. but works for the moment
options: ViewBaseOption[];
}

View File

@ -0,0 +1,15 @@
import { BaseVote } from 'app/shared/models/poll/base-vote';
import { ViewUser } from 'app/site/users/models/view-user';
import { BaseViewModel } from '../../base/base-view-model';
import { ViewBaseOption } from './view-base-option';
export class ViewBaseVote<M extends BaseVote<M> = any> extends BaseViewModel<M> {
public get vote(): M {
return this._model;
}
}
export interface ViewBaseVote<M extends BaseVote<M> = any> extends BaseVote<M> {
user?: ViewUser;
option: ViewBaseOption;
}

View File

@ -9,7 +9,7 @@ import { MotionPollRepositoryService } from 'app/core/repositories/motions/motio
import { ViewAssignmentPoll } from 'app/site/assignments/models/view-assignment-poll';
import { BaseViewModel } from 'app/site/base/base-view-model';
import { ViewMotionPoll } from 'app/site/motions/models/view-motion-poll';
import { ViewBasePoll } from '../models/view-base-poll';
import { PollClassType, ViewBasePoll } from '../models/view-base-poll';
@Injectable({
providedIn: 'root'
@ -28,13 +28,13 @@ export class PollListObservableService implements HasViewModelListObservable<Vie
) {
motionPollRepo
.getViewModelListObservable()
.subscribe(polls => this.adjustViewModelListObservable(polls, 'motion'));
.subscribe(polls => this.adjustViewModelListObservable(polls, PollClassType.Motion));
assignmentPollRepo
.getViewModelListObservable()
.subscribe(polls => this.adjustViewModelListObservable(polls, 'assignment'));
.subscribe(polls => this.adjustViewModelListObservable(polls, PollClassType.Assignment));
}
private adjustViewModelListObservable(polls: ViewBasePoll[], mode: 'motion' | 'assignment'): void {
private adjustViewModelListObservable(polls: ViewBasePoll[], mode: PollClassType): void {
this[mode + 'Polls'] = polls;
const allPolls = (this.motionPolls as ViewBasePoll[]).concat(this.assignmentPolls);

View File

@ -2,10 +2,10 @@ import { Injectable } from '@angular/core';
import { _ } from 'app/core/translate/translation-marker';
import { ChartData, ChartType } from 'app/shared/components/charts/charts.component';
import { AssignmentPollMethods } from 'app/shared/models/assignments/assignment-poll';
import { MotionPollMethods } from 'app/shared/models/motions/motion-poll';
import { BasePoll, MajorityMethod, PercentBase, PollColor, PollType } from 'app/shared/models/poll/base-poll';
import { AssignmentPollMethodsVerbose } from 'app/site/assignments/models/view-assignment-poll';
import { AssignmentPollMethod } from 'app/shared/models/assignments/assignment-poll';
import { MotionPollMethod } from 'app/shared/models/motions/motion-poll';
import { BasePoll, MajorityMethod, PollColor, PollType } from 'app/shared/models/poll/base-poll';
import { AssignmentPollMethodVerbose } from 'app/site/assignments/models/view-assignment-poll';
import {
MajorityMethodVerbose,
PercentBaseVerbose,
@ -90,8 +90,8 @@ export const PollMajorityMethod: CalculableMajorityMethod[] = [
];
export interface PollData {
pollmethod?: string;
onehundred_percent_base: PercentBase;
pollmethod: string;
onehundred_percent_base: string;
options: {
user?: {
full_name: string;
@ -120,7 +120,7 @@ export abstract class PollService {
/**
* The default percentage base
*/
public abstract defaultPercentBase: PercentBase;
public abstract defaultPercentBase: string;
/**
* The default majority method
@ -170,7 +170,7 @@ export abstract class PollService {
case 'onehundred_percent_base':
return PercentBaseVerbose[value];
case 'pollmethod':
return AssignmentPollMethodsVerbose[value];
return AssignmentPollMethodVerbose[value];
case 'type':
return PollTypeVerbose[value];
}
@ -181,7 +181,7 @@ export abstract class PollService {
}
public generateChartData(poll: PollData): ChartData {
if (poll.pollmethod === AssignmentPollMethods.Votes) {
if (poll.pollmethod === AssignmentPollMethod.Votes) {
return this.generateCircleChartData(poll);
} else {
return this.generateBarChartData(poll);
@ -191,7 +191,7 @@ export abstract class PollService {
public generateBarChartData(poll: PollData): ChartData {
const fields = ['yes', 'no'];
// cast is needed because ViewBasePoll doesn't have the field `pollmethod`, no easy fix :(
if ((<any>poll).pollmethod === MotionPollMethods.YNA) {
if ((<any>poll).pollmethod === MotionPollMethod.YNA) {
fields.push('abstain');
}
const data: ChartData = fields.map(key => ({
@ -213,7 +213,7 @@ export abstract class PollService {
}
public getChartType(poll: PollData): ChartType {
if ((<any>poll).pollmethod === AssignmentPollMethods.Votes) {
if ((<any>poll).pollmethod === AssignmentPollMethod.Votes) {
return 'doughnut';
} else {
return 'horizontalBar';

View File

@ -1,4 +1,4 @@
import { AssignmentPollMethods } from 'app/shared/models/assignments/assignment-poll';
import { AssignmentPollMethod } from 'app/shared/models/assignments/assignment-poll';
import { MajorityMethod, PercentBase, PollState, PollType } from 'app/shared/models/poll/base-poll';
import { AssignmentTitleInformation } from 'app/site/assignments/models/view-assignment';
import { BasePollSlideData } from 'app/slides/polls/base-poll-slide-data';
@ -8,7 +8,7 @@ export interface AssignmentPollSlideData extends BasePollSlideData {
poll: {
title: string;
type: PollType;
pollmethod: AssignmentPollMethods;
pollmethod: AssignmentPollMethod;
votes_amount: number;
description: string;
state: PollState;

View File

@ -1,4 +1,4 @@
import { MotionPollMethods } from 'app/shared/models/motions/motion-poll';
import { MotionPollMethod } from 'app/shared/models/motions/motion-poll';
import { MajorityMethod, PercentBase, PollState, PollType } from 'app/shared/models/poll/base-poll';
import { MotionTitleInformation } from 'app/site/motions/models/view-motion';
import { BasePollSlideData } from 'app/slides/polls/base-poll-slide-data';
@ -8,7 +8,7 @@ export interface MotionPollSlideData extends BasePollSlideData {
poll: {
title: string;
type: PollType;
pollmethod: MotionPollMethods;
pollmethod: MotionPollMethod;
state: PollState;
onehundred_percent_base: PercentBase;
majority_method: MajorityMethod;

View File

@ -96,8 +96,8 @@ class Migration(migrations.Migration):
name="onehundred_percent_base",
field=models.CharField(
choices=[
("YN", "Yes/No per candidate"),
("YNA", "Yes/No/Abstain per candidate"),
("YN", "Yes/No"),
("YNA", "Yes/No/Abstain"),
("valid", "All valid ballots"),
("cast", "All casted ballots"),
("disabled", "Disabled (no percents)"),

View File

@ -155,8 +155,8 @@ class BasePoll(models.Model):
PERCENT_BASE_CAST = "cast"
PERCENT_BASE_DISABLED = "disabled"
PERCENT_BASES: Iterable[Tuple[str, str]] = (
(PERCENT_BASE_YN, "Yes/No per candidate"),
(PERCENT_BASE_YNA, "Yes/No/Abstain per candidate"),
(PERCENT_BASE_YN, "Yes/No"),
(PERCENT_BASE_YNA, "Yes/No/Abstain"),
(PERCENT_BASE_VALID, "All valid ballots"),
(PERCENT_BASE_CAST, "All casted ballots"),
(PERCENT_BASE_DISABLED, "Disabled (no percents)"),