Merge pull request #5305 from tsiegleauq/weight-votes
Implement vote weight in client
This commit is contained in:
commit
0aef3f79ce
@ -7,7 +7,7 @@ export abstract class BaseDecimalModel<T = any> extends BaseModel<T> {
|
|||||||
if (input && typeof input === 'object') {
|
if (input && typeof input === 'object') {
|
||||||
this.getDecimalFields().forEach(field => {
|
this.getDecimalFields().forEach(field => {
|
||||||
if (input[field] !== undefined) {
|
if (input[field] !== undefined) {
|
||||||
input[field] = parseInt(input[field], 10);
|
input[field] = parseFloat(input[field]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,10 @@ export class User extends BaseDecimalModel<User> {
|
|||||||
public auth_type?: UserAuthType;
|
public auth_type?: UserAuthType;
|
||||||
public vote_weight: number;
|
public vote_weight: number;
|
||||||
|
|
||||||
|
public get isVoteWeightOne(): boolean {
|
||||||
|
return this.vote_weight === 1;
|
||||||
|
}
|
||||||
|
|
||||||
public constructor(input?: Partial<User>) {
|
public constructor(input?: Partial<User>) {
|
||||||
super(User.COLLECTIONSTRING, input);
|
super(User.COLLECTIONSTRING, input);
|
||||||
}
|
}
|
||||||
|
@ -11,14 +11,13 @@ export class ParsePollNumberPipe implements PipeTransform {
|
|||||||
public constructor(private translate: TranslateService) {}
|
public constructor(private translate: TranslateService) {}
|
||||||
|
|
||||||
public transform(value: number): number | string {
|
public transform(value: number): number | string {
|
||||||
const input = Math.trunc(value);
|
switch (value) {
|
||||||
switch (input) {
|
|
||||||
case VOTE_MAJORITY:
|
case VOTE_MAJORITY:
|
||||||
return this.translate.instant('majority');
|
return this.translate.instant('majority');
|
||||||
case VOTE_UNDOCUMENTED:
|
case VOTE_UNDOCUMENTED:
|
||||||
return this.translate.instant('undocumented');
|
return this.translate.instant('undocumented');
|
||||||
default:
|
default:
|
||||||
return input;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,9 +70,14 @@
|
|||||||
<div *pblNgridCellDef="'user'; row as vote">
|
<div *pblNgridCellDef="'user'; row as vote">
|
||||||
<div *ngIf="vote.user">
|
<div *ngIf="vote.user">
|
||||||
{{ vote.user.getShortName() }}
|
{{ vote.user.getShortName() }}
|
||||||
<div class="user-subtitle" *ngIf="vote.user.getLevelAndNumber()">
|
<div class="user-subtitle">
|
||||||
|
<div *ngIf="vote.user.getLevelAndNumber()">
|
||||||
{{ vote.user.getLevelAndNumber() }}
|
{{ vote.user.getLevelAndNumber() }}
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="isVoteWeightActive">
|
||||||
|
{{ 'Vote weight' | translate }}: {{ vote.user.vote_weight }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="!vote.user">
|
<div *ngIf="!vote.user">
|
||||||
{{ 'Anonymous' | translate }}
|
{{ 'Anonymous' | translate }}
|
||||||
|
@ -10,6 +10,7 @@ import { OperatorService } from 'app/core/core-services/operator.service';
|
|||||||
import { AssignmentPollRepositoryService } from 'app/core/repositories/assignments/assignment-poll-repository.service';
|
import { AssignmentPollRepositoryService } from 'app/core/repositories/assignments/assignment-poll-repository.service';
|
||||||
import { AssignmentVoteRepositoryService } from 'app/core/repositories/assignments/assignment-vote-repository.service';
|
import { AssignmentVoteRepositoryService } from 'app/core/repositories/assignments/assignment-vote-repository.service';
|
||||||
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
|
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
|
||||||
|
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||||
import { VoteValue } from 'app/shared/models/poll/base-vote';
|
import { VoteValue } from 'app/shared/models/poll/base-vote';
|
||||||
import { BasePollDetailComponent } from 'app/site/polls/components/base-poll-detail.component';
|
import { BasePollDetailComponent } from 'app/site/polls/components/base-poll-detail.component';
|
||||||
@ -32,6 +33,8 @@ export class AssignmentPollDetailComponent extends BasePollDetailComponent<ViewA
|
|||||||
|
|
||||||
public candidatesLabels: string[] = [];
|
public candidatesLabels: string[] = [];
|
||||||
|
|
||||||
|
public isVoteWeightActive: boolean;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
title: Title,
|
title: Title,
|
||||||
translate: TranslateService,
|
translate: TranslateService,
|
||||||
@ -41,12 +44,16 @@ export class AssignmentPollDetailComponent extends BasePollDetailComponent<ViewA
|
|||||||
groupRepo: GroupRepositoryService,
|
groupRepo: GroupRepositoryService,
|
||||||
prompt: PromptService,
|
prompt: PromptService,
|
||||||
pollDialog: AssignmentPollDialogService,
|
pollDialog: AssignmentPollDialogService,
|
||||||
|
configService: ConfigService,
|
||||||
protected pollService: AssignmentPollService,
|
protected pollService: AssignmentPollService,
|
||||||
votesRepo: AssignmentVoteRepositoryService,
|
votesRepo: AssignmentVoteRepositoryService,
|
||||||
private operator: OperatorService,
|
private operator: OperatorService,
|
||||||
private router: Router
|
private router: Router
|
||||||
) {
|
) {
|
||||||
super(title, translate, matSnackbar, repo, route, groupRepo, prompt, pollDialog, pollService, votesRepo);
|
super(title, translate, matSnackbar, repo, route, groupRepo, prompt, pollDialog, pollService, votesRepo);
|
||||||
|
configService
|
||||||
|
.get<boolean>('users_activate_vote_weight')
|
||||||
|
.subscribe(active => (this.isVoteWeightActive = active));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createVotesData(): void {
|
protected createVotesData(): void {
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
[filterProps]="filterProps"
|
[filterProps]="filterProps"
|
||||||
[allowProjector]="false"
|
[allowProjector]="false"
|
||||||
[fullScreen]="true"
|
[fullScreen]="true"
|
||||||
[vScrollFixed]="60"
|
[vScrollFixed]="-1"
|
||||||
listStorageKey="motion-poll-vote"
|
listStorageKey="motion-poll-vote"
|
||||||
[cssClasses]="{ 'single-votes-table': true }"
|
[cssClasses]="{ 'single-votes-table': true }"
|
||||||
>
|
>
|
||||||
@ -56,7 +56,18 @@
|
|||||||
|
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<div *pblNgridCellDef="'user'; row as vote">
|
<div *pblNgridCellDef="'user'; row as vote">
|
||||||
<div *ngIf="vote.user">{{ vote.user.getFullName() }}</div>
|
<div *ngIf="vote.user">
|
||||||
|
{{ vote.user.getShortName() }}
|
||||||
|
<div class="user-subtitle">
|
||||||
|
<div *ngIf="vote.user.getLevelAndNumber()">
|
||||||
|
{{ vote.user.getLevelAndNumber() }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="isVoteWeightActive">
|
||||||
|
{{ 'Vote weight' | translate }}: {{ vote.user.vote_weight }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div *ngIf="!vote.user">{{ 'Anonymous' | translate }}</div>
|
<div *ngIf="!vote.user">{{ 'Anonymous' | translate }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div *pblNgridCellDef="'vote'; row as vote" class="vote-cell">
|
<div *pblNgridCellDef="'vote'; row as vote" class="vote-cell">
|
||||||
|
@ -10,6 +10,7 @@ import { OperatorService } from 'app/core/core-services/operator.service';
|
|||||||
import { MotionPollRepositoryService } from 'app/core/repositories/motions/motion-poll-repository.service';
|
import { MotionPollRepositoryService } from 'app/core/repositories/motions/motion-poll-repository.service';
|
||||||
import { MotionVoteRepositoryService } from 'app/core/repositories/motions/motion-vote-repository.service';
|
import { MotionVoteRepositoryService } from 'app/core/repositories/motions/motion-vote-repository.service';
|
||||||
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
|
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
|
||||||
|
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||||
import { ViewMotion } from 'app/site/motions/models/view-motion';
|
import { ViewMotion } from 'app/site/motions/models/view-motion';
|
||||||
import { ViewMotionPoll } from 'app/site/motions/models/view-motion-poll';
|
import { ViewMotionPoll } from 'app/site/motions/models/view-motion-poll';
|
||||||
@ -41,6 +42,8 @@ export class MotionPollDetailComponent extends BasePollDetailComponent<ViewMotio
|
|||||||
|
|
||||||
public filterProps = ['user.getFullName', 'valueVerbose'];
|
public filterProps = ['user.getFullName', 'valueVerbose'];
|
||||||
|
|
||||||
|
public isVoteWeightActive: boolean;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
title: Title,
|
title: Title,
|
||||||
translate: TranslateService,
|
translate: TranslateService,
|
||||||
@ -52,10 +55,14 @@ export class MotionPollDetailComponent extends BasePollDetailComponent<ViewMotio
|
|||||||
pollDialog: MotionPollDialogService,
|
pollDialog: MotionPollDialogService,
|
||||||
pollService: MotionPollService,
|
pollService: MotionPollService,
|
||||||
votesRepo: MotionVoteRepositoryService,
|
votesRepo: MotionVoteRepositoryService,
|
||||||
|
configService: ConfigService,
|
||||||
private operator: OperatorService,
|
private operator: OperatorService,
|
||||||
private router: Router
|
private router: Router
|
||||||
) {
|
) {
|
||||||
super(title, translate, matSnackbar, repo, route, groupRepo, prompt, pollDialog, pollService, votesRepo);
|
super(title, translate, matSnackbar, repo, route, groupRepo, prompt, pollDialog, pollService, votesRepo);
|
||||||
|
configService
|
||||||
|
.get<boolean>('users_activate_vote_weight')
|
||||||
|
.subscribe(active => (this.isVoteWeightActive = active));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createVotesData(): void {
|
protected createVotesData(): void {
|
||||||
|
@ -381,10 +381,15 @@ export class MotionPdfService {
|
|||||||
column1.push(`${votingOption}:`);
|
column1.push(`${votingOption}:`);
|
||||||
if (value.showPercent) {
|
if (value.showPercent) {
|
||||||
const resultInPercent = this.motionPollService.getVoteValueInPercent(value.amount, poll);
|
const resultInPercent = this.motionPollService.getVoteValueInPercent(value.amount, poll);
|
||||||
|
// hard check for "null" since 0 is a valid number in this case
|
||||||
|
if (resultInPercent !== null) {
|
||||||
column2.push(`(${resultInPercent})`);
|
column2.push(`(${resultInPercent})`);
|
||||||
} else {
|
} else {
|
||||||
column2.push('');
|
column2.push('');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
column2.push('');
|
||||||
|
}
|
||||||
column3.push(resultValue);
|
column3.push(resultValue);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,13 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<!-- Strucuture Level -->
|
<!-- Strucuture Level -->
|
||||||
<mat-form-field class="form70 distance">
|
<mat-form-field
|
||||||
|
class="distance"
|
||||||
|
[ngClass]="{
|
||||||
|
form37: showVoteWeight,
|
||||||
|
form70: !showVoteWeight
|
||||||
|
}"
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
matInput
|
matInput
|
||||||
@ -119,8 +125,15 @@
|
|||||||
formControlName="structure_level"
|
formControlName="structure_level"
|
||||||
/>
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<!-- Participant Number -->
|
<!-- Participant Number -->
|
||||||
<mat-form-field class="form25 force-min-with">
|
<mat-form-field
|
||||||
|
[ngClass]="{
|
||||||
|
distance: showVoteWeight,
|
||||||
|
form37: showVoteWeight,
|
||||||
|
form25: !showVoteWeight
|
||||||
|
}"
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
matInput
|
matInput
|
||||||
@ -128,6 +141,17 @@
|
|||||||
formControlName="number"
|
formControlName="number"
|
||||||
/>
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
|
<!-- Vote weight -->
|
||||||
|
<mat-form-field class="form16 force-min-with" *ngIf="showVoteWeight">
|
||||||
|
<!-- TODO Input type should be number with limited decimal spaces -->
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
matInput
|
||||||
|
placeholder="{{ 'Vote weight' | translate }}"
|
||||||
|
formControlName="vote_weight"
|
||||||
|
/>
|
||||||
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@ -275,6 +299,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="isAllowed('manage')">
|
<div *ngIf="isAllowed('manage')">
|
||||||
|
<!-- Vote weight -->
|
||||||
|
<div *ngIf="user.vote_weight && showVoteWeight">
|
||||||
|
<h4>{{ 'Vote weight' | translate }}</h4>
|
||||||
|
<span>{{ user.vote_weight }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Initial Password -->
|
<!-- Initial Password -->
|
||||||
<div *ngIf="user.default_password">
|
<div *ngIf="user.default_password">
|
||||||
<h4>{{ 'Initial password' | translate }}</h4>
|
<h4>{{ 'Initial password' | translate }}</h4>
|
||||||
|
@ -11,10 +11,12 @@ import { ConstantsService } from 'app/core/core-services/constants.service';
|
|||||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||||
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
|
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
|
||||||
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
|
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
|
||||||
|
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||||
import { genders } from 'app/shared/models/users/user';
|
import { genders } from 'app/shared/models/users/user';
|
||||||
import { OneOfValidator } from 'app/shared/validators/one-of-validator';
|
import { OneOfValidator } from 'app/shared/validators/one-of-validator';
|
||||||
import { BaseViewComponent } from 'app/site/base/base-view';
|
import { BaseViewComponent } from 'app/site/base/base-view';
|
||||||
|
import { PollService } from 'app/site/polls/services/poll.service';
|
||||||
import { UserPdfExportService } from '../../services/user-pdf-export.service';
|
import { UserPdfExportService } from '../../services/user-pdf-export.service';
|
||||||
import { ViewGroup } from '../../models/view-group';
|
import { ViewGroup } from '../../models/view-group';
|
||||||
import { ViewUser } from '../../models/view-user';
|
import { ViewUser } from '../../models/view-user';
|
||||||
@ -76,6 +78,12 @@ export class UserDetailComponent extends BaseViewComponent implements OnInit {
|
|||||||
|
|
||||||
private userBackends: UserBackends | null = null;
|
private userBackends: UserBackends | null = null;
|
||||||
|
|
||||||
|
private isVoteWeightActive: boolean;
|
||||||
|
|
||||||
|
public get showVoteWeight(): boolean {
|
||||||
|
return this.pollService.isElectronicVotingEnabled && this.isVoteWeightActive;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for user
|
* Constructor for user
|
||||||
*
|
*
|
||||||
@ -103,12 +111,17 @@ export class UserDetailComponent extends BaseViewComponent implements OnInit {
|
|||||||
private promptService: PromptService,
|
private promptService: PromptService,
|
||||||
private pdfService: UserPdfExportService,
|
private pdfService: UserPdfExportService,
|
||||||
private groupRepo: GroupRepositoryService,
|
private groupRepo: GroupRepositoryService,
|
||||||
private constantsService: ConstantsService
|
private constantsService: ConstantsService,
|
||||||
|
private pollService: PollService,
|
||||||
|
configService: ConfigService
|
||||||
) {
|
) {
|
||||||
super(title, translate, matSnackBar);
|
super(title, translate, matSnackBar);
|
||||||
this.createForm();
|
this.createForm();
|
||||||
|
|
||||||
this.constantsService.get<UserBackends>('UserBackends').subscribe(backends => (this.userBackends = backends));
|
this.constantsService.get<UserBackends>('UserBackends').subscribe(backends => (this.userBackends = backends));
|
||||||
|
configService
|
||||||
|
.get<boolean>('users_activate_vote_weight')
|
||||||
|
.subscribe(active => (this.isVoteWeightActive = active));
|
||||||
|
|
||||||
this.groupRepo.getViewModelListObservableWithoutDefaultGroup().subscribe(this.groups);
|
this.groupRepo.getViewModelListObservableWithoutDefaultGroup().subscribe(this.groups);
|
||||||
}
|
}
|
||||||
@ -157,6 +170,7 @@ export class UserDetailComponent extends BaseViewComponent implements OnInit {
|
|||||||
gender: [''],
|
gender: [''],
|
||||||
structure_level: [''],
|
structure_level: [''],
|
||||||
number: [''],
|
number: [''],
|
||||||
|
vote_weight: [],
|
||||||
about_me: [''],
|
about_me: [''],
|
||||||
groups_id: [''],
|
groups_id: [''],
|
||||||
is_present: [true],
|
is_present: [true],
|
||||||
|
@ -51,20 +51,9 @@
|
|||||||
</span>
|
</span>
|
||||||
<br />
|
<br />
|
||||||
<div class="code red-warning-text">
|
<div class="code red-warning-text">
|
||||||
<span>{{ 'Title' | translate }}</span
|
<span *ngFor="let entry of headerRow; let last = last">
|
||||||
>, <span>{{ 'Given name' | translate }}</span
|
{{ entry | translate }}<span *ngIf="!last">, </span>
|
||||||
>, <span>{{ 'Surname' | translate }}</span
|
</span>
|
||||||
>, <span>{{ 'Structure level' | translate }}</span
|
|
||||||
>, <span>{{ 'Participant number' | translate }}</span
|
|
||||||
>, <span>{{ 'Groups' | translate }}</span
|
|
||||||
>, <span>{{ 'Comment' | translate }}</span
|
|
||||||
>, <span>{{ 'Is active' | translate }}</span
|
|
||||||
>, <span>{{ 'Is present' | translate }}</span
|
|
||||||
>, <span>{{ 'Is committee' | translate }}</span
|
|
||||||
>, <span>{{ 'Initial password' | translate }}</span
|
|
||||||
>, <span>{{ 'Email' | translate }}</span
|
|
||||||
>, <span>{{ 'Username' | translate }}</span
|
|
||||||
>, <span>{{ 'Gender' | translate }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
@ -282,35 +271,46 @@
|
|||||||
<mat-checkbox disabled [checked]="entry.newEntry.is_active"> </mat-checkbox>
|
<mat-checkbox disabled [checked]="entry.newEntry.is_active"> </mat-checkbox>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="is_present">
|
<ng-container matColumnDef="is_present">
|
||||||
<mat-header-cell *matHeaderCellDef>{{ 'Is present' | translate }}</mat-header-cell>
|
<mat-header-cell *matHeaderCellDef>{{ 'Is present' | translate }}</mat-header-cell>
|
||||||
<mat-cell *matCellDef="let entry">
|
<mat-cell *matCellDef="let entry">
|
||||||
<mat-checkbox disabled [checked]="entry.newEntry.is_present"> </mat-checkbox>
|
<mat-checkbox disabled [checked]="entry.newEntry.is_present"> </mat-checkbox>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="is_committee">
|
<ng-container matColumnDef="is_committee">
|
||||||
<mat-header-cell *matHeaderCellDef>{{ 'Is committee' | translate }}</mat-header-cell>
|
<mat-header-cell *matHeaderCellDef>{{ 'Is committee' | translate }}</mat-header-cell>
|
||||||
<mat-cell *matCellDef="let entry">
|
<mat-cell *matCellDef="let entry">
|
||||||
<mat-checkbox disabled [checked]="entry.newEntry.is_committee"> </mat-checkbox>
|
<mat-checkbox disabled [checked]="entry.newEntry.is_committee"> </mat-checkbox>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="default_password">
|
<ng-container matColumnDef="default_password">
|
||||||
<mat-header-cell *matHeaderCellDef>{{ 'Initial password' | translate }}</mat-header-cell>
|
<mat-header-cell *matHeaderCellDef>{{ 'Initial password' | translate }}</mat-header-cell>
|
||||||
<mat-cell *matCellDef="let entry"> {{ entry.newEntry.default_password }} </mat-cell>
|
<mat-cell *matCellDef="let entry"> {{ entry.newEntry.default_password }} </mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="email">
|
<ng-container matColumnDef="email">
|
||||||
<mat-header-cell *matHeaderCellDef>{{ 'Email' | translate }}</mat-header-cell>
|
<mat-header-cell *matHeaderCellDef>{{ 'Email' | translate }}</mat-header-cell>
|
||||||
<mat-cell *matCellDef="let entry"> {{ entry.newEntry.email }} </mat-cell>
|
<mat-cell *matCellDef="let entry"> {{ entry.newEntry.email }} </mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="username">
|
<ng-container matColumnDef="username">
|
||||||
<mat-header-cell *matHeaderCellDef>{{ 'Username' | translate }}</mat-header-cell>
|
<mat-header-cell *matHeaderCellDef>{{ 'Username' | translate }}</mat-header-cell>
|
||||||
<mat-cell *matCellDef="let entry"> {{ entry.newEntry.username }} </mat-cell>
|
<mat-cell *matCellDef="let entry"> {{ entry.newEntry.username }} </mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="gender">
|
<ng-container matColumnDef="gender">
|
||||||
<mat-header-cell *matHeaderCellDef>{{ 'Gender' | translate }}</mat-header-cell>
|
<mat-header-cell *matHeaderCellDef>{{ 'Gender' | translate }}</mat-header-cell>
|
||||||
<mat-cell *matCellDef="let entry"> {{ entry.newEntry.gender }} </mat-cell>
|
<mat-cell *matCellDef="let entry"> {{ entry.newEntry.gender }} </mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="vote_weight">
|
||||||
|
<mat-header-cell *matHeaderCellDef>{{ 'Vote weight' | translate }}</mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let entry"> {{ entry.newEntry.vote_weight }} </mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<mat-header-row *matHeaderRowDef="getColumnDefinition()"></mat-header-row>
|
<mat-header-row *matHeaderRowDef="getColumnDefinition()"></mat-header-row>
|
||||||
<mat-row [ngClass]="getStateClass(row)" *matRowDef="let row; columns: getColumnDefinition()"> </mat-row>
|
<mat-row [ngClass]="getStateClass(row)" *matRowDef="let row; columns: getColumnDefinition()"> </mat-row>
|
||||||
</table>
|
</table>
|
||||||
|
@ -21,6 +21,24 @@ import { UserImportService } from '../../services/user-import.service';
|
|||||||
export class UserImportListComponent extends BaseImportListComponentDirective<User> {
|
export class UserImportListComponent extends BaseImportListComponentDirective<User> {
|
||||||
public textAreaForm: FormGroup;
|
public textAreaForm: FormGroup;
|
||||||
|
|
||||||
|
public headerRow = [
|
||||||
|
'Title',
|
||||||
|
'Given name',
|
||||||
|
'Surname',
|
||||||
|
'Structure level',
|
||||||
|
'Participant number',
|
||||||
|
'Groups',
|
||||||
|
'Comment',
|
||||||
|
'Is active',
|
||||||
|
'Is present',
|
||||||
|
'Is a committee',
|
||||||
|
'Initial password',
|
||||||
|
'Email',
|
||||||
|
'Username',
|
||||||
|
'Gender',
|
||||||
|
'Vote weight'
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for list view bases
|
* Constructor for list view bases
|
||||||
*
|
*
|
||||||
@ -47,22 +65,6 @@ export class UserImportListComponent extends BaseImportListComponentDirective<Us
|
|||||||
* Triggers an example csv download
|
* Triggers an example csv download
|
||||||
*/
|
*/
|
||||||
public downloadCsvExample(): void {
|
public downloadCsvExample(): void {
|
||||||
const headerRow = [
|
|
||||||
'Title',
|
|
||||||
'Given name',
|
|
||||||
'Surname',
|
|
||||||
'Structure level',
|
|
||||||
'Participant number',
|
|
||||||
'Groups',
|
|
||||||
'Comment',
|
|
||||||
'Is active',
|
|
||||||
'Is present',
|
|
||||||
'Is a committee',
|
|
||||||
'Initial password',
|
|
||||||
'Email',
|
|
||||||
'Username',
|
|
||||||
'Gender'
|
|
||||||
];
|
|
||||||
const rows = [
|
const rows = [
|
||||||
[
|
[
|
||||||
'Dr.',
|
'Dr.',
|
||||||
@ -78,7 +80,8 @@ export class UserImportListComponent extends BaseImportListComponentDirective<Us
|
|||||||
'initialPassword',
|
'initialPassword',
|
||||||
null,
|
null,
|
||||||
'mmustermann',
|
'mmustermann',
|
||||||
'm'
|
'm',
|
||||||
|
1.0
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
null,
|
null,
|
||||||
@ -94,12 +97,13 @@ export class UserImportListComponent extends BaseImportListComponentDirective<Us
|
|||||||
null,
|
null,
|
||||||
'john.doe@email.com',
|
'john.doe@email.com',
|
||||||
'jdoe',
|
'jdoe',
|
||||||
'diverse'
|
'diverse',
|
||||||
|
2.0
|
||||||
],
|
],
|
||||||
[null, 'Julia', 'Bloggs', 'London', null, null, null, null, null, null, null, null, 'jbloggs', 'f'],
|
[null, 'Julia', 'Bloggs', 'London', null, null, null, null, null, null, null, null, 'jbloggs', 'f', 1.5],
|
||||||
[null, null, 'Executive Board', null, null, null, null, null, null, 1, null, null, 'executive', null]
|
[null, null, 'Executive Board', null, null, null, null, null, null, 1, null, null, 'executive', null, 2.5]
|
||||||
];
|
];
|
||||||
this.exporter.dummyCSVExport(headerRow, rows, `${this.translate.instant('participants-example')}.csv`);
|
this.exporter.dummyCSVExport(this.headerRow, rows, `${this.translate.instant('participants-example')}.csv`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,18 +30,26 @@
|
|||||||
(dataSourceChange)="onDataSourceChange($event)"
|
(dataSourceChange)="onDataSourceChange($event)"
|
||||||
>
|
>
|
||||||
<!-- Name column -->
|
<!-- Name column -->
|
||||||
<div *pblNgridCellDef="'short_name'; value as name; row as user; rowContext as rowContext" class="cell-slot fill">
|
<div *pblNgridCellDef="'short_name'; row as user; rowContext as rowContext" class="cell-slot fill">
|
||||||
<a class="detail-link" [routerLink]="user.id" *ngIf="!isMultiSelect"></a>
|
<a class="detail-link" [routerLink]="user.id" *ngIf="!isMultiSelect"></a>
|
||||||
<div class="nameCell">
|
<div class="nameCell">
|
||||||
<span>{{ name }}</span>
|
<div>
|
||||||
|
<div>{{ user.short_name }}</div>
|
||||||
|
<div class="user-subtitle" *ngIf="showVoteWeight">
|
||||||
|
{{ 'Vote weight' | translate }}: {{ user.vote_weight }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="icon-group">
|
<div class="icon-group">
|
||||||
<mat-icon matTooltip="{{ 'Is committee' | translate }}" *ngIf="user.is_committee">account_balance</mat-icon>
|
<mat-icon matTooltip="{{ 'Is committee' | translate }}" *ngIf="user.is_committee">
|
||||||
|
account_balance
|
||||||
|
</mat-icon>
|
||||||
<mat-icon
|
<mat-icon
|
||||||
matTooltip="{{ 'Inactive' | translate }}"
|
matTooltip="{{ 'Inactive' | translate }}"
|
||||||
*ngIf="!user.is_active && this.operator.hasPerms('users.see_extra')"
|
*ngIf="!user.is_active && this.operator.hasPerms('users.see_extra')"
|
||||||
>block</mat-icon
|
|
||||||
>
|
>
|
||||||
|
block
|
||||||
|
</mat-icon>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -29,5 +29,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.icon-group {
|
.icon-group {
|
||||||
|
margin-left: 1em;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import { PromptService } from 'app/core/ui-services/prompt.service';
|
|||||||
import { genders } from 'app/shared/models/users/user';
|
import { genders } from 'app/shared/models/users/user';
|
||||||
import { infoDialogSettings } from 'app/shared/utils/dialog-settings';
|
import { infoDialogSettings } from 'app/shared/utils/dialog-settings';
|
||||||
import { BaseListViewComponent } from 'app/site/base/base-list-view';
|
import { BaseListViewComponent } from 'app/site/base/base-list-view';
|
||||||
|
import { PollService } from 'app/site/polls/services/poll.service';
|
||||||
import { UserFilterListService } from '../../services/user-filter-list.service';
|
import { UserFilterListService } from '../../services/user-filter-list.service';
|
||||||
import { UserPdfExportService } from '../../services/user-pdf-export.service';
|
import { UserPdfExportService } from '../../services/user-pdf-export.service';
|
||||||
import { UserSortListService } from '../../services/user-sort-list.service';
|
import { UserSortListService } from '../../services/user-sort-list.service';
|
||||||
@ -98,6 +99,8 @@ export class UserListComponent extends BaseListViewComponent<ViewUser> implement
|
|||||||
return this._presenceViewConfigured && this.operator.hasPerms('users.can_manage');
|
return this._presenceViewConfigured && this.operator.hasPerms('users.can_manage');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isVoteWeightActive: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to check for main button permissions
|
* Helper to check for main button permissions
|
||||||
*
|
*
|
||||||
@ -107,6 +110,10 @@ export class UserListComponent extends BaseListViewComponent<ViewUser> implement
|
|||||||
return this.operator.hasPerms('users.can_manage');
|
return this.operator.hasPerms('users.can_manage');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get showVoteWeight(): boolean {
|
||||||
|
return this.pollService.isElectronicVotingEnabled && this.isVoteWeightActive;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the columns to show
|
* Define the columns to show
|
||||||
*/
|
*/
|
||||||
@ -173,13 +180,15 @@ export class UserListComponent extends BaseListViewComponent<ViewUser> implement
|
|||||||
public sortService: UserSortListService,
|
public sortService: UserSortListService,
|
||||||
config: ConfigService,
|
config: ConfigService,
|
||||||
private userPdf: UserPdfExportService,
|
private userPdf: UserPdfExportService,
|
||||||
private dialog: MatDialog
|
private dialog: MatDialog,
|
||||||
|
private pollService: PollService
|
||||||
) {
|
) {
|
||||||
super(titleService, translate, matSnackBar, storage);
|
super(titleService, translate, matSnackBar, storage);
|
||||||
|
|
||||||
// enable multiSelect for this listView
|
// enable multiSelect for this listView
|
||||||
this.canMultiSelect = true;
|
this.canMultiSelect = true;
|
||||||
config.get<boolean>('users_enable_presence_view').subscribe(state => (this._presenceViewConfigured = state));
|
config.get<boolean>('users_enable_presence_view').subscribe(state => (this._presenceViewConfigured = state));
|
||||||
|
config.get<boolean>('users_activate_vote_weight').subscribe(active => (this.isVoteWeightActive = active));
|
||||||
config.get<boolean>(this.selfPresentConfStr).subscribe(allowed => (this.allowSelfSetPresent = allowed));
|
config.get<boolean>(this.selfPresentConfStr).subscribe(allowed => (this.allowSelfSetPresent = allowed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +85,14 @@ export class UserFilterListService extends BaseFilterListService<ViewUser> {
|
|||||||
{ condition: true, label: this.translate.instant('Got an email') },
|
{ condition: true, label: this.translate.instant('Got an email') },
|
||||||
{ condition: false, label: this.translate.instant("Didn't get an email") }
|
{ condition: false, label: this.translate.instant("Didn't get an email") }
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: 'isVoteWeightOne',
|
||||||
|
label: this.translate.instant('Vote Weight'),
|
||||||
|
options: [
|
||||||
|
{ condition: false, label: this.translate.instant('Has changed vote weight') },
|
||||||
|
{ condition: true, label: this.translate.instant('Has unchanged vote weight') }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
return staticFilterOptions.concat(this.userGroupFilterOptions);
|
return staticFilterOptions.concat(this.userGroupFilterOptions);
|
||||||
|
@ -33,7 +33,8 @@ export class UserImportService extends BaseImportService<User> {
|
|||||||
'default_password',
|
'default_password',
|
||||||
'email',
|
'email',
|
||||||
'username',
|
'username',
|
||||||
'gender'
|
'gender',
|
||||||
|
'vote_weight'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,6 +118,13 @@ export class UserImportService extends BaseImportService<User> {
|
|||||||
case 'number':
|
case 'number':
|
||||||
newViewUser.number = line[idx];
|
newViewUser.number = line[idx];
|
||||||
break;
|
break;
|
||||||
|
case 'vote_weight':
|
||||||
|
if (!line[idx]) {
|
||||||
|
newViewUser[this.expectedHeader[idx]] = 1;
|
||||||
|
} else {
|
||||||
|
newViewUser[this.expectedHeader[idx]] = line[idx];
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
newViewUser[this.expectedHeader[idx]] = line[idx];
|
newViewUser[this.expectedHeader[idx]] = line[idx];
|
||||||
break;
|
break;
|
||||||
|
@ -31,6 +31,7 @@ export class UserSortListService extends BaseSortListService<ViewUser> {
|
|||||||
{ property: 'is_committee', label: 'Is committee' },
|
{ property: 'is_committee', label: 'Is committee' },
|
||||||
{ property: 'number', label: 'Participant number' },
|
{ property: 'number', label: 'Participant number' },
|
||||||
{ property: 'structure_level', label: 'Structure level' },
|
{ property: 'structure_level', label: 'Structure level' },
|
||||||
|
{ property: 'vote_weight', label: 'Vote weight' },
|
||||||
{ property: 'comment' }
|
{ property: 'comment' }
|
||||||
// TODO email send?
|
// TODO email send?
|
||||||
];
|
];
|
||||||
|
@ -3,6 +3,7 @@ from decimal import Decimal
|
|||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
|
from openslides.core.config import config
|
||||||
from openslides.poll.views import BaseOptionViewSet, BasePollViewSet, BaseVoteViewSet
|
from openslides.poll.views import BaseOptionViewSet, BasePollViewSet, BaseVoteViewSet
|
||||||
from openslides.utils.auth import has_perm
|
from openslides.utils.auth import has_perm
|
||||||
from openslides.utils.autoupdate import inform_changed_data
|
from openslides.utils.autoupdate import inform_changed_data
|
||||||
@ -489,14 +490,20 @@ class AssignmentPollViewSet(BasePollViewSet):
|
|||||||
# skip creating votes with empty weights
|
# skip creating votes with empty weights
|
||||||
if amount == 0:
|
if amount == 0:
|
||||||
continue
|
continue
|
||||||
|
weight = Decimal(amount)
|
||||||
|
if config["users_activate_vote_weight"]:
|
||||||
|
weight *= user.vote_weight
|
||||||
vote = AssignmentVote.objects.create(
|
vote = AssignmentVote.objects.create(
|
||||||
option=option, user=user, weight=Decimal(amount), value="Y"
|
option=option, user=user, weight=weight, value="Y"
|
||||||
)
|
)
|
||||||
inform_changed_data(vote, no_delete_on_restriction=True)
|
inform_changed_data(vote, no_delete_on_restriction=True)
|
||||||
else: # global_no or global_abstain
|
else: # global_no or global_abstain
|
||||||
option = options[0]
|
option = options[0]
|
||||||
|
weight = (
|
||||||
|
user.vote_weight if config["users_activate_vote_weight"] else Decimal(1)
|
||||||
|
)
|
||||||
vote = AssignmentVote.objects.create(
|
vote = AssignmentVote.objects.create(
|
||||||
option=option, user=user, weight=Decimal(1), value=data
|
option=option, user=user, weight=weight, value=data
|
||||||
)
|
)
|
||||||
inform_changed_data(vote, no_delete_on_restriction=True)
|
inform_changed_data(vote, no_delete_on_restriction=True)
|
||||||
inform_changed_data(option)
|
inform_changed_data(option)
|
||||||
@ -512,13 +519,15 @@ class AssignmentPollViewSet(BasePollViewSet):
|
|||||||
vote_user is the one put into the vote
|
vote_user is the one put into the vote
|
||||||
"""
|
"""
|
||||||
options = poll.get_options()
|
options = poll.get_options()
|
||||||
|
weight = (
|
||||||
|
check_user.vote_weight
|
||||||
|
if config["users_activate_vote_weight"]
|
||||||
|
else Decimal(1)
|
||||||
|
)
|
||||||
for option_id, result in data.items():
|
for option_id, result in data.items():
|
||||||
option = options.get(pk=option_id)
|
option = options.get(pk=option_id)
|
||||||
vote = AssignmentVote.objects.create(
|
vote = AssignmentVote.objects.create(
|
||||||
option=option,
|
option=option, user=vote_user, value=result, weight=weight,
|
||||||
user=vote_user,
|
|
||||||
value=result,
|
|
||||||
weight=check_user.vote_weight,
|
|
||||||
)
|
)
|
||||||
inform_changed_data(vote, no_delete_on_restriction=True)
|
inform_changed_data(vote, no_delete_on_restriction=True)
|
||||||
inform_changed_data(option, no_delete_on_restriction=True)
|
inform_changed_data(option, no_delete_on_restriction=True)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from decimal import Decimal
|
||||||
from typing import List, Set
|
from typing import List, Set
|
||||||
|
|
||||||
import jsonschema
|
import jsonschema
|
||||||
@ -1227,16 +1228,20 @@ class MotionPollViewSet(BasePollViewSet):
|
|||||||
VotedModel.objects.create(motionpoll=poll, user=user)
|
VotedModel.objects.create(motionpoll=poll, user=user)
|
||||||
|
|
||||||
def handle_named_vote(self, data, poll, user):
|
def handle_named_vote(self, data, poll, user):
|
||||||
self.handle_named_and_pseudoanonymous_vote(data, user.vote_weight, user, poll)
|
self.handle_named_and_pseudoanonymous_vote(data, user, user, poll)
|
||||||
|
|
||||||
def handle_pseudoanonymous_vote(self, data, poll, user):
|
def handle_pseudoanonymous_vote(self, data, poll, user):
|
||||||
self.handle_named_and_pseudoanonymous_vote(data, user.vote_weight, None, poll)
|
self.handle_named_and_pseudoanonymous_vote(data, user, None, poll)
|
||||||
|
|
||||||
def handle_named_and_pseudoanonymous_vote(self, data, weight, user, poll):
|
def handle_named_and_pseudoanonymous_vote(self, data, weight_user, vote_user, poll):
|
||||||
option = poll.options.get()
|
option = poll.options.get()
|
||||||
vote = MotionVote.objects.create(user=user, option=option)
|
vote = MotionVote.objects.create(user=vote_user, option=option)
|
||||||
vote.value = data
|
vote.value = data
|
||||||
vote.weight = weight
|
vote.weight = (
|
||||||
|
weight_user.vote_weight
|
||||||
|
if config["users_activate_vote_weight"]
|
||||||
|
else Decimal(1)
|
||||||
|
)
|
||||||
vote.save(no_delete_on_restriction=True)
|
vote.save(no_delete_on_restriction=True)
|
||||||
inform_changed_data(option)
|
inform_changed_data(option)
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ from django.conf import settings
|
|||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
from ..core.config import config
|
||||||
from ..utils.autoupdate import inform_changed_data, inform_deleted_data
|
from ..utils.autoupdate import inform_changed_data, inform_deleted_data
|
||||||
from ..utils.models import SET_NULL_AND_AUTOUPDATE
|
from ..utils.models import SET_NULL_AND_AUTOUPDATE
|
||||||
|
|
||||||
@ -184,7 +185,7 @@ class BasePoll(models.Model):
|
|||||||
if self.type == self.TYPE_ANALOG:
|
if self.type == self.TYPE_ANALOG:
|
||||||
return self.db_votesvalid
|
return self.db_votesvalid
|
||||||
else:
|
else:
|
||||||
return Decimal(self.amount_users_voted())
|
return Decimal(self.amount_users_voted_with_individual_weight())
|
||||||
|
|
||||||
def set_votesvalid(self, value):
|
def set_votesvalid(self, value):
|
||||||
if self.type != self.TYPE_ANALOG:
|
if self.type != self.TYPE_ANALOG:
|
||||||
@ -210,7 +211,7 @@ class BasePoll(models.Model):
|
|||||||
if self.type == self.TYPE_ANALOG:
|
if self.type == self.TYPE_ANALOG:
|
||||||
return self.db_votescast
|
return self.db_votescast
|
||||||
else:
|
else:
|
||||||
return Decimal(self.amount_users_voted())
|
return Decimal(self.amount_users_voted_with_individual_weight())
|
||||||
|
|
||||||
def set_votescast(self, value):
|
def set_votescast(self, value):
|
||||||
if self.type != self.TYPE_ANALOG:
|
if self.type != self.TYPE_ANALOG:
|
||||||
@ -219,7 +220,10 @@ class BasePoll(models.Model):
|
|||||||
|
|
||||||
votescast = property(get_votescast, set_votescast)
|
votescast = property(get_votescast, set_votescast)
|
||||||
|
|
||||||
def amount_users_voted(self):
|
def amount_users_voted_with_individual_weight(self):
|
||||||
|
if config["users_activate_vote_weight"]:
|
||||||
|
return sum(user.vote_weight for user in self.voted.all())
|
||||||
|
else:
|
||||||
return len(self.voted.all())
|
return len(self.voted.all())
|
||||||
|
|
||||||
def create_options(self):
|
def create_options(self):
|
||||||
|
@ -44,6 +44,15 @@ def get_config_variables():
|
|||||||
group="Participants",
|
group="Participants",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
yield ConfigVariable(
|
||||||
|
name="users_activate_vote_weight",
|
||||||
|
default_value=False,
|
||||||
|
input_type="boolean",
|
||||||
|
label="Activate vote weight",
|
||||||
|
weight=513,
|
||||||
|
group="Participants",
|
||||||
|
)
|
||||||
|
|
||||||
# PDF
|
# PDF
|
||||||
|
|
||||||
yield ConfigVariable(
|
yield ConfigVariable(
|
||||||
|
@ -15,6 +15,7 @@ from openslides.assignments.models import (
|
|||||||
AssignmentPoll,
|
AssignmentPoll,
|
||||||
AssignmentVote,
|
AssignmentVote,
|
||||||
)
|
)
|
||||||
|
from openslides.core.config import config
|
||||||
from openslides.poll.models import BasePoll
|
from openslides.poll.models import BasePoll
|
||||||
from openslides.utils.auth import get_group_model
|
from openslides.utils.auth import get_group_model
|
||||||
from openslides.utils.autoupdate import inform_changed_data
|
from openslides.utils.autoupdate import inform_changed_data
|
||||||
@ -982,6 +983,7 @@ class VoteAssignmentPollNamedYNA(VoteAssignmentPollBaseTestClass):
|
|||||||
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
||||||
self.assertEqual(poll.votescast, Decimal("1"))
|
self.assertEqual(poll.votescast, Decimal("1"))
|
||||||
self.assertEqual(poll.state, AssignmentPoll.STATE_STARTED)
|
self.assertEqual(poll.state, AssignmentPoll.STATE_STARTED)
|
||||||
|
self.assertEqual(poll.amount_users_voted_with_individual_weight(), Decimal("1"))
|
||||||
option1 = poll.options.get(pk=1)
|
option1 = poll.options.get(pk=1)
|
||||||
option2 = poll.options.get(pk=2)
|
option2 = poll.options.get(pk=2)
|
||||||
option3 = poll.options.get(pk=3)
|
option3 = poll.options.get(pk=3)
|
||||||
@ -995,6 +997,43 @@ class VoteAssignmentPollNamedYNA(VoteAssignmentPollBaseTestClass):
|
|||||||
self.assertEqual(option3.no, Decimal("0"))
|
self.assertEqual(option3.no, Decimal("0"))
|
||||||
self.assertEqual(option3.abstain, Decimal("1"))
|
self.assertEqual(option3.abstain, Decimal("1"))
|
||||||
|
|
||||||
|
def test_vote_with_voteweight(self):
|
||||||
|
config["users_activate_vote_weight"] = True
|
||||||
|
self.admin.vote_weight = weight = Decimal("4.2")
|
||||||
|
self.admin.save()
|
||||||
|
self.add_candidate()
|
||||||
|
self.add_candidate()
|
||||||
|
self.start_poll()
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("assignmentpoll-vote", args=[self.poll.pk]),
|
||||||
|
{"1": "Y", "2": "N", "3": "A"},
|
||||||
|
)
|
||||||
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
||||||
|
self.assertEqual(AssignmentVote.objects.count(), 3)
|
||||||
|
poll = AssignmentPoll.objects.get()
|
||||||
|
self.assertEqual(poll.votesvalid, weight)
|
||||||
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
||||||
|
self.assertEqual(poll.votescast, weight)
|
||||||
|
self.assertEqual(poll.state, AssignmentPoll.STATE_STARTED)
|
||||||
|
self.assertEqual(poll.amount_users_voted_with_individual_weight(), weight)
|
||||||
|
option1 = poll.options.get(pk=1)
|
||||||
|
option2 = poll.options.get(pk=2)
|
||||||
|
option3 = poll.options.get(pk=3)
|
||||||
|
self.assertEqual(option1.yes, weight)
|
||||||
|
self.assertEqual(option1.no, Decimal("0"))
|
||||||
|
self.assertEqual(option1.abstain, Decimal("0"))
|
||||||
|
self.assertEqual(option2.yes, Decimal("0"))
|
||||||
|
self.assertEqual(option2.no, weight)
|
||||||
|
self.assertEqual(option2.abstain, Decimal("0"))
|
||||||
|
self.assertEqual(option3.yes, Decimal("0"))
|
||||||
|
self.assertEqual(option3.no, Decimal("0"))
|
||||||
|
self.assertEqual(option3.abstain, weight)
|
||||||
|
|
||||||
|
def test_vote_without_voteweight(self):
|
||||||
|
self.admin.vote_weight = Decimal("4.2")
|
||||||
|
self.admin.save()
|
||||||
|
self.test_vote()
|
||||||
|
|
||||||
def test_change_vote(self):
|
def test_change_vote(self):
|
||||||
self.start_poll()
|
self.start_poll()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
@ -2233,7 +2272,7 @@ class PseudoanonymizeAssignmentPoll(TestCase):
|
|||||||
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
||||||
poll = AssignmentPoll.objects.get()
|
poll = AssignmentPoll.objects.get()
|
||||||
self.assertEqual(poll.get_votes().count(), 2)
|
self.assertEqual(poll.get_votes().count(), 2)
|
||||||
self.assertEqual(poll.amount_users_voted(), 2)
|
self.assertEqual(poll.amount_users_voted_with_individual_weight(), 2)
|
||||||
self.assertEqual(poll.votesvalid, Decimal("2"))
|
self.assertEqual(poll.votesvalid, Decimal("2"))
|
||||||
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
||||||
self.assertEqual(poll.votescast, Decimal("2"))
|
self.assertEqual(poll.votescast, Decimal("2"))
|
||||||
|
@ -763,6 +763,36 @@ class VoteMotionPollNamed(TestCase):
|
|||||||
self.assertEqual(option.abstain, Decimal("0"))
|
self.assertEqual(option.abstain, Decimal("0"))
|
||||||
vote = option.votes.get()
|
vote = option.votes.get()
|
||||||
self.assertEqual(vote.user, self.admin)
|
self.assertEqual(vote.user, self.admin)
|
||||||
|
self.assertEqual(vote.weight, Decimal("1"))
|
||||||
|
|
||||||
|
def test_vote_with_voteweight(self):
|
||||||
|
config["users_activate_vote_weight"] = True
|
||||||
|
self.start_poll()
|
||||||
|
self.make_admin_delegate()
|
||||||
|
self.make_admin_present()
|
||||||
|
self.admin.vote_weight = weight = Decimal("3.5")
|
||||||
|
self.admin.save()
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("motionpoll-vote", args=[self.poll.pk]), "A"
|
||||||
|
)
|
||||||
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
||||||
|
poll = MotionPoll.objects.get()
|
||||||
|
self.assertEqual(poll.votesvalid, weight)
|
||||||
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
||||||
|
self.assertEqual(poll.votescast, weight)
|
||||||
|
self.assertEqual(poll.get_votes().count(), 1)
|
||||||
|
self.assertEqual(poll.amount_users_voted_with_individual_weight(), weight)
|
||||||
|
option = poll.options.get()
|
||||||
|
self.assertEqual(option.yes, Decimal("0"))
|
||||||
|
self.assertEqual(option.no, Decimal("0"))
|
||||||
|
self.assertEqual(option.abstain, weight)
|
||||||
|
vote = option.votes.get()
|
||||||
|
self.assertEqual(vote.weight, weight)
|
||||||
|
|
||||||
|
def test_vote_without_voteweight(self):
|
||||||
|
self.admin.vote_weight = Decimal("3.5")
|
||||||
|
self.admin.save()
|
||||||
|
self.test_vote()
|
||||||
|
|
||||||
def test_change_vote(self):
|
def test_change_vote(self):
|
||||||
self.start_poll()
|
self.start_poll()
|
||||||
@ -1155,7 +1185,7 @@ class VoteMotionPollPseudoanonymous(TestCase):
|
|||||||
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
||||||
self.assertEqual(poll.votescast, Decimal("1"))
|
self.assertEqual(poll.votescast, Decimal("1"))
|
||||||
self.assertEqual(poll.get_votes().count(), 1)
|
self.assertEqual(poll.get_votes().count(), 1)
|
||||||
self.assertEqual(poll.amount_users_voted(), 1)
|
self.assertEqual(poll.amount_users_voted_with_individual_weight(), 1)
|
||||||
option = poll.options.get()
|
option = poll.options.get()
|
||||||
self.assertEqual(option.yes, Decimal("0"))
|
self.assertEqual(option.yes, Decimal("0"))
|
||||||
self.assertEqual(option.no, Decimal("1"))
|
self.assertEqual(option.no, Decimal("1"))
|
||||||
@ -1378,7 +1408,7 @@ class PseudoanonymizeMotionPoll(TestCase):
|
|||||||
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
||||||
poll = MotionPoll.objects.get()
|
poll = MotionPoll.objects.get()
|
||||||
self.assertEqual(poll.get_votes().count(), 2)
|
self.assertEqual(poll.get_votes().count(), 2)
|
||||||
self.assertEqual(poll.amount_users_voted(), 2)
|
self.assertEqual(poll.amount_users_voted_with_individual_weight(), 2)
|
||||||
self.assertEqual(poll.votesvalid, Decimal("2"))
|
self.assertEqual(poll.votesvalid, Decimal("2"))
|
||||||
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
||||||
self.assertEqual(poll.votescast, Decimal("2"))
|
self.assertEqual(poll.votescast, Decimal("2"))
|
||||||
@ -1446,7 +1476,7 @@ class ResetMotionPoll(TestCase):
|
|||||||
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
||||||
poll = MotionPoll.objects.get()
|
poll = MotionPoll.objects.get()
|
||||||
self.assertEqual(poll.get_votes().count(), 0)
|
self.assertEqual(poll.get_votes().count(), 0)
|
||||||
self.assertEqual(poll.amount_users_voted(), 0)
|
self.assertEqual(poll.amount_users_voted_with_individual_weight(), 0)
|
||||||
self.assertEqual(poll.votesvalid, None)
|
self.assertEqual(poll.votesvalid, None)
|
||||||
self.assertEqual(poll.votesinvalid, None)
|
self.assertEqual(poll.votesinvalid, None)
|
||||||
self.assertEqual(poll.votescast, None)
|
self.assertEqual(poll.votescast, None)
|
||||||
|
Loading…
Reference in New Issue
Block a user