From 682db96b7cb636d1b483dcc752d2a55e9b28d246 Mon Sep 17 00:00:00 2001 From: Joshua Sangmeister Date: Thu, 16 Jan 2020 17:22:12 +0100 Subject: [PATCH] added vote per user table and progress for polls added update for options after stopping a poll --- .../motions/motion-poll-repository.service.ts | 7 +++ .../app/core/ui-services/voting.service.ts | 3 +- .../site/assignments/assignments.module.ts | 3 +- .../assignment-poll-detail.component.html | 55 +++++++++++-------- .../assignment-poll-detail.component.ts | 51 +++++++++-------- .../site/motions/models/view-motion-poll.ts | 2 + .../motion-poll-detail.component.html | 39 ++++++++----- .../motion-poll-detail.component.ts | 10 ++-- .../modules/motion-poll/motion-poll.module.ts | 3 +- .../components/base-poll-detail.component.ts | 49 ++++++++++++++++- .../poll-progress.component.html | 1 + .../poll-progress.component.scss | 0 .../poll-progress.component.spec.ts | 26 +++++++++ .../poll-progress/poll-progress.component.ts | 44 +++++++++++++++ client/src/app/site/polls/polls.module.ts | 4 +- .../services/poll-list-observable.service.ts | 9 ++- openslides/poll/views.py | 6 +- openslides/utils/auth.py | 11 +--- tests/integration/agenda/test_viewset.py | 1 - tests/integration/assignments/test_polls.py | 1 + tests/integration/mediafiles/test_viewset.py | 4 ++ 21 files changed, 244 insertions(+), 85 deletions(-) create mode 100644 client/src/app/site/polls/components/poll-progress/poll-progress.component.html create mode 100644 client/src/app/site/polls/components/poll-progress/poll-progress.component.scss create mode 100644 client/src/app/site/polls/components/poll-progress/poll-progress.component.spec.ts create mode 100644 client/src/app/site/polls/components/poll-progress/poll-progress.component.ts diff --git a/client/src/app/core/repositories/motions/motion-poll-repository.service.ts b/client/src/app/core/repositories/motions/motion-poll-repository.service.ts index a35f2c1c3..bb35c03d2 100644 --- a/client/src/app/core/repositories/motions/motion-poll-repository.service.ts +++ b/client/src/app/core/repositories/motions/motion-poll-repository.service.ts @@ -9,6 +9,7 @@ import { ViewModelStoreService } from 'app/core/core-services/view-model-store.s import { RelationDefinition } from 'app/core/definitions/relations'; import { VotingService } from 'app/core/ui-services/voting.service'; import { MotionPoll } from 'app/shared/models/motions/motion-poll'; +import { ViewMotion } from 'app/site/motions/models/view-motion'; import { ViewMotionOption } from 'app/site/motions/models/view-motion-option'; import { MotionPollTitleInformation, ViewMotionPoll } from 'app/site/motions/models/view-motion-poll'; import { BasePollRepositoryService } from 'app/site/polls/services/base-poll-repository.service'; @@ -35,6 +36,12 @@ const MotionPollRelations: RelationDefinition[] = [ ownIdKey: 'options_id', ownKey: 'options', foreignViewModel: ViewMotionOption + }, + { + type: 'M2O', + ownIdKey: 'motion_id', + ownKey: 'motion', + foreignViewModel: ViewMotion } ]; diff --git a/client/src/app/core/ui-services/voting.service.ts b/client/src/app/core/ui-services/voting.service.ts index 772af1597..f50a67a71 100644 --- a/client/src/app/core/ui-services/voting.service.ts +++ b/client/src/app/core/ui-services/voting.service.ts @@ -35,7 +35,8 @@ export class VotingService { * checks whether the operator can vote on the given poll */ public canVote(poll: ViewBasePoll): boolean { - return !this.getVotePermissionError(poll); + const error = this.getVotePermissionError(poll); + return !error; } /** diff --git a/client/src/app/site/assignments/assignments.module.ts b/client/src/app/site/assignments/assignments.module.ts index 49236c070..ac6067455 100644 --- a/client/src/app/site/assignments/assignments.module.ts +++ b/client/src/app/site/assignments/assignments.module.ts @@ -7,10 +7,11 @@ import { AssignmentPollDetailComponent } from './components/assignment-poll-deta import { AssignmentPollVoteComponent } from './components/assignment-poll-vote/assignment-poll-vote.component'; import { AssignmentPollComponent } from './components/assignment-poll/assignment-poll.component'; import { AssignmentsRoutingModule } from './assignments-routing.module'; +import { PollsModule } from '../polls/polls.module'; import { SharedModule } from '../../shared/shared.module'; @NgModule({ - imports: [CommonModule, AssignmentsRoutingModule, SharedModule], + imports: [CommonModule, AssignmentsRoutingModule, SharedModule, PollsModule], declarations: [ AssignmentDetailComponent, AssignmentListComponent, diff --git a/client/src/app/site/assignments/components/assignment-poll-detail/assignment-poll-detail.component.html b/client/src/app/site/assignments/components/assignment-poll-detail/assignment-poll-detail.component.html index 64ea46abf..33f00ac45 100644 --- a/client/src/app/site/assignments/components/assignment-poll-detail/assignment-poll-detail.component.html +++ b/client/src/app/site/assignments/components/assignment-poll-detail/assignment-poll-detail.component.html @@ -38,30 +38,13 @@
{{ 'Majority method' | translate }}: {{ poll.majorityMethodVerbose | translate }}
{{ '100% base' | translate }}: {{ poll.percentBaseVerbose | translate }}
+
+ +

Result

-
- -
- - -
{{ option.user.full_name }}
-
{{ 'Unknown user' | translate }}
-
- - -
{{ obj.value.user.full_name }}
-
{{ 'Unknown user' | translate }}
- -
{{ obj.value.votes[option.user_id] }}
-
-
-
@@ -88,9 +71,10 @@ - - + + + + + + + + + {{ "User" | translate }} + +
{{ row.user.getFullName() }}
+
{{ "Unknown user" | translate }}
+
+
+ + +
{{ option.user.getFullName() }}
+
{{ "Unknown user" | translate }}
+
+ + {{ row.votes[option.user_id] }} + +
+ + + +
+
@@ -106,7 +115,7 @@ diff --git a/client/src/app/site/assignments/components/assignment-poll-detail/assignment-poll-detail.component.ts b/client/src/app/site/assignments/components/assignment-poll-detail/assignment-poll-detail.component.ts index 384e47093..e2607799a 100644 --- a/client/src/app/site/assignments/components/assignment-poll-detail/assignment-poll-detail.component.ts +++ b/client/src/app/site/assignments/components/assignment-poll-detail/assignment-poll-detail.component.ts @@ -12,10 +12,8 @@ import { PromptService } from 'app/core/ui-services/prompt.service'; import { ChartType } from 'app/shared/components/charts/charts.component'; import { AssignmentPollMethods } from 'app/shared/models/assignments/assignment-poll'; import { BasePollDetailComponent } from 'app/site/polls/components/base-poll-detail.component'; -import { ViewUser } from 'app/site/users/models/view-user'; import { AssignmentPollDialogService } from '../../services/assignment-poll-dialog.service'; import { ViewAssignmentPoll } from '../../models/view-assignment-poll'; -import { ViewAssignmentVote } from '../../models/view-assignment-vote'; @Component({ selector: 'os-assignment-poll-detail', @@ -27,20 +25,20 @@ export class AssignmentPollDetailComponent extends BasePollDetailComponentthis.poll).pollmethod === AssignmentPollMethods.YNA) { + if (this.poll.pollmethod === AssignmentPollMethods.YNA) { columns.splice(3, 0, 'abstain'); } return columns; } + public columnDefinitionPerName: string[]; + public constructor( title: Title, translate: TranslateService, @@ -55,27 +53,32 @@ export class AssignmentPollDetailComponent extends BasePollDetailComponent 'votes-' + option.user_id)); - setTimeout(() => { - for (const option of this.poll.options) { - for (const vote of option.votes) { - if (!votes[vote.user_id]) { - votes[vote.user_id] = { - user: vote.user, - votes: {} - }; - } - votes[vote.user_id].votes[option.user_id] = - this.poll.pollmethod === AssignmentPollMethods.Votes ? vote.weight : vote.valueVerbose; + const votes = {}; + let i = -1; + for (const option of this.poll.options) { + for (const vote of option.votes) { + // if poll was pseudoanonymized, use a negative index to not interfere with + // possible named votes (although this should never happen) + const userId = vote.user_id || i--; + if (!votes[userId]) { + votes[userId] = { + user: vote.user, + votes: {} + }; } + votes[userId].votes[option.user_id] = + this.poll.pollmethod === AssignmentPollMethods.Votes ? vote.weight : vote.valueVerbose; } - console.log(votes, this.poll, this.poll.options); - this.votesByUser = votes; - this.candidatesLabels = this.poll.initChartLabels(); - this.isReady = true; - }); + } + + this.setVotesData(Object.values(votes)); + + this.candidatesLabels = this.poll.initChartLabels(); + + this.isReady = true; } protected hasPerms(): boolean { diff --git a/client/src/app/site/motions/models/view-motion-poll.ts b/client/src/app/site/motions/models/view-motion-poll.ts index 6085dce58..97bfd5a5a 100644 --- a/client/src/app/site/motions/models/view-motion-poll.ts +++ b/client/src/app/site/motions/models/view-motion-poll.ts @@ -4,6 +4,7 @@ import { PollColor } from 'app/shared/models/poll/base-poll'; import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable'; import { ViewMotionOption } from 'app/site/motions/models/view-motion-option'; import { ViewBasePoll } from 'app/site/polls/models/view-base-poll'; +import { ViewMotion } from './view-motion'; export interface MotionPollTitleInformation { title: string; @@ -72,5 +73,6 @@ export class ViewMotionPoll extends ViewBasePoll implements MotionPo } export interface ViewMotionPoll extends MotionPoll { + motion: ViewMotion; options: ViewMotionOption[]; } diff --git a/client/src/app/site/motions/modules/motion-poll/motion-poll-detail/motion-poll-detail.component.html b/client/src/app/site/motions/modules/motion-poll/motion-poll-detail/motion-poll-detail.component.html index 7a14db653..de621c05b 100644 --- a/client/src/app/site/motions/modules/motion-poll/motion-poll-detail/motion-poll-detail.component.html +++ b/client/src/app/site/motions/modules/motion-poll/motion-poll-detail/motion-poll-detail.component.html @@ -1,6 +1,6 @@
-

{{ 'Motion' | translate }} {{ motion.id }}

+

{{ 'Motion' | translate }} {{ poll.motion.id }}

@@ -76,6 +85,10 @@
{{ 'Majority method' | translate }}: {{ poll.majorityMethodVerbose | translate }}
{{ '100% base' | translate }}: {{ poll.percentBaseVerbose | translate }}
+ +
+ +
@@ -87,7 +100,7 @@ Edit diff --git a/client/src/app/site/motions/modules/motion-poll/motion-poll-detail/motion-poll-detail.component.ts b/client/src/app/site/motions/modules/motion-poll/motion-poll-detail/motion-poll-detail.component.ts index 84fec4a21..03773c9a2 100644 --- a/client/src/app/site/motions/modules/motion-poll/motion-poll-detail/motion-poll-detail.component.ts +++ b/client/src/app/site/motions/modules/motion-poll/motion-poll-detail/motion-poll-detail.component.ts @@ -7,7 +7,6 @@ import { TranslateService } from '@ngx-translate/core'; import { OperatorService } from 'app/core/core-services/operator.service'; import { MotionPollRepositoryService } from 'app/core/repositories/motions/motion-poll-repository.service'; -import { MotionRepositoryService } from 'app/core/repositories/motions/motion-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'; @@ -45,14 +44,13 @@ export class MotionPollDetailComponent extends BasePollDetailComponentthis.poll).motion_id); + protected onPollWithOptionsLoaded(): void { + this.setVotesData(this.poll.options[0].votes); } public openDialog(): void { @@ -61,7 +59,7 @@ export class MotionPollDetailComponent extends BasePollDetailComponentthis.poll).motion_id]); + this.router.navigate(['motions', this.poll.motion_id]); } protected hasPerms(): boolean { diff --git a/client/src/app/site/motions/modules/motion-poll/motion-poll.module.ts b/client/src/app/site/motions/modules/motion-poll/motion-poll.module.ts index acb7ca28a..170b4b8d3 100644 --- a/client/src/app/site/motions/modules/motion-poll/motion-poll.module.ts +++ b/client/src/app/site/motions/modules/motion-poll/motion-poll.module.ts @@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { SharedModule } from 'app/shared/shared.module'; +import { PollsModule } from 'app/site/polls/polls.module'; import { MotionPollDetailComponent } from './motion-poll-detail/motion-poll-detail.component'; import { MotionPollListComponent } from './motion-poll-list/motion-poll-list.component'; import { MotionPollRoutingModule } from './motion-poll-routing.module'; @@ -9,7 +10,7 @@ import { MotionPollVoteComponent } from './motion-poll-vote/motion-poll-vote.com import { MotionPollComponent } from './motion-poll/motion-poll.component'; @NgModule({ - imports: [CommonModule, SharedModule, MotionPollRoutingModule], + imports: [CommonModule, SharedModule, MotionPollRoutingModule, PollsModule], exports: [MotionPollComponent], declarations: [MotionPollComponent, MotionPollDetailComponent, MotionPollListComponent, MotionPollVoteComponent] }) diff --git a/client/src/app/site/polls/components/base-poll-detail.component.ts b/client/src/app/site/polls/components/base-poll-detail.component.ts index e71c2d794..4e3b88136 100644 --- a/client/src/app/site/polls/components/base-poll-detail.component.ts +++ b/client/src/app/site/polls/components/base-poll-detail.component.ts @@ -1,5 +1,5 @@ import { OnInit } from '@angular/core'; -import { MatSnackBar } from '@angular/material'; +import { MatSnackBar, MatTableDataSource } from '@angular/material'; import { Title } from '@angular/platform-browser'; import { ActivatedRoute } from '@angular/router'; @@ -15,9 +15,14 @@ import { ChartData, ChartType } from 'app/shared/components/charts/charts.compon import { PollState, PollType } from 'app/shared/models/poll/base-poll'; 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 { ViewBasePoll } from '../models/view-base-poll'; +export interface BaseVoteData { + user?: ViewUser; +} + export abstract class BasePollDetailComponent extends BaseViewComponent implements OnInit { /** * All the groups of users. @@ -55,6 +60,9 @@ export abstract class BasePollDetailComponent extends Ba */ public chartDataSubject: BehaviorSubject = new BehaviorSubject(null); + // The datasource for the votes-per-user table + public votesDataSource: MatTableDataSource = new MatTableDataSource(); + /** * Constructor * @@ -81,6 +89,7 @@ export abstract class BasePollDetailComponent extends Ba protected pollDialog: BasePollDialogService ) { super(title, translate, matSnackbar); + this.votesDataSource.filterPredicate = this.dataSourceFilterPredicate; } /** @@ -100,7 +109,7 @@ export abstract class BasePollDetailComponent extends Ba const text = 'Do you really want to delete the selected poll?'; if (await this.promptDialog.open(title, text)) { - this.repo.delete(this.poll).then(() => this.onDeleted()); + this.repo.delete(this.poll).then(() => this.onDeleted(), this.raiseError); } } @@ -109,7 +118,7 @@ export abstract class BasePollDetailComponent extends Ba const text = 'Do you really want to pseudoanonymize the selected poll?'; if (await this.promptDialog.open(title, text)) { - await this.repo.pseudoanonymize(this.poll); + this.repo.pseudoanonymize(this.poll).then(() => this.onPollLoaded(), this.raiseError); // votes have changed, but not the poll, so the components have to be informed about the update } } @@ -129,10 +138,35 @@ export abstract class BasePollDetailComponent extends Ba */ protected onPollLoaded(): void {} + protected onPollWithOptionsLoaded(): void {} + protected onStateChanged(): void {} protected abstract hasPerms(): boolean; + // custom filter for the data source: only search in usernames + protected dataSourceFilterPredicate(data: BaseVoteData, filter: string): boolean { + return ( + data.user && + data.user + .getFullName() + .trim() + .toLowerCase() + .indexOf(filter.trim().toLowerCase()) !== -1 + ); + } + + /** + * sets the votes data only if the poll wasn't pseudoanonymized + */ + protected setVotesData(data: BaseVoteData[]): void { + if (data.every(voteDate => !voteDate.user)) { + this.votesDataSource.data = null; + } else { + this.votesDataSource.data = data; + } + } + /** * This checks, if the poll has votes. */ @@ -155,6 +189,15 @@ export abstract class BasePollDetailComponent extends Ba this.updateBreadcrumbs(); this.checkData(); this.onPollLoaded(); + + // wait for options to be loaded + (function waitForOptions(): void { + if (!this.poll.options || !this.poll.options.length) { + setTimeout(waitForOptions.bind(this), 1); + } else { + this.onPollWithOptionsLoaded(); + } + }.call(this)); } }) ); diff --git a/client/src/app/site/polls/components/poll-progress/poll-progress.component.html b/client/src/app/site/polls/components/poll-progress/poll-progress.component.html new file mode 100644 index 000000000..e76187923 --- /dev/null +++ b/client/src/app/site/polls/components/poll-progress/poll-progress.component.html @@ -0,0 +1 @@ +{{ this.poll.voted_id.length }} von {{ this.max }} haben abgestimmt. \ No newline at end of file diff --git a/client/src/app/site/polls/components/poll-progress/poll-progress.component.scss b/client/src/app/site/polls/components/poll-progress/poll-progress.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/client/src/app/site/polls/components/poll-progress/poll-progress.component.spec.ts b/client/src/app/site/polls/components/poll-progress/poll-progress.component.spec.ts new file mode 100644 index 000000000..34d8353d4 --- /dev/null +++ b/client/src/app/site/polls/components/poll-progress/poll-progress.component.spec.ts @@ -0,0 +1,26 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { E2EImportsModule } from 'e2e-imports.module'; + +import { PollProgressComponent } from './poll-progress.component'; + +describe('PollProgressComponent', () => { + let component: PollProgressComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [E2EImportsModule] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PollProgressComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/site/polls/components/poll-progress/poll-progress.component.ts b/client/src/app/site/polls/components/poll-progress/poll-progress.component.ts new file mode 100644 index 000000000..7ef288aa0 --- /dev/null +++ b/client/src/app/site/polls/components/poll-progress/poll-progress.component.ts @@ -0,0 +1,44 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { MatSnackBar } from '@angular/material'; +import { Title } from '@angular/platform-browser'; + +import { TranslateService } from '@ngx-translate/core'; +import { map } from 'rxjs/operators'; + +import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service'; +import { BaseViewComponent } from 'app/site/base/base-view'; +import { ViewBasePoll } from 'app/site/polls/models/view-base-poll'; + +@Component({ + selector: 'os-poll-progress', + templateUrl: './poll-progress.component.html', + styleUrls: ['./poll-progress.component.scss'] +}) +export class PollProgressComponent extends BaseViewComponent implements OnInit { + @Input() + public poll: ViewBasePoll; + + public max: number; + + public constructor( + title: Title, + protected translate: TranslateService, + snackbar: MatSnackBar, + private userRepo: UserRepositoryService + ) { + super(title, translate, snackbar); + } + + /** + * OnInit. + * Sets the observable for groups. + */ + public ngOnInit(): void { + this.userRepo + .getViewModelListObservable() + .pipe(map(users => users.filter(user => this.poll.groups_id.intersect(user.groups_id).length))) + .subscribe(users => { + this.max = users.length; + }); + } +} diff --git a/client/src/app/site/polls/polls.module.ts b/client/src/app/site/polls/polls.module.ts index ddfc01c45..5cb94a456 100644 --- a/client/src/app/site/polls/polls.module.ts +++ b/client/src/app/site/polls/polls.module.ts @@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { PollListComponent } from './components/poll-list/poll-list.component'; +import { PollProgressComponent } from './components/poll-progress/poll-progress.component'; import { PollsRoutingModule } from './polls-routing.module'; import { SharedModule } from '../../shared/shared.module'; @@ -11,6 +12,7 @@ import { SharedModule } from '../../shared/shared.module'; */ @NgModule({ imports: [CommonModule, PollsRoutingModule, SharedModule], - declarations: [PollListComponent] + exports: [PollProgressComponent], + declarations: [PollListComponent, PollProgressComponent] }) export class PollsModule {} diff --git a/client/src/app/site/polls/services/poll-list-observable.service.ts b/client/src/app/site/polls/services/poll-list-observable.service.ts index 94170ab48..184fc6d2e 100644 --- a/client/src/app/site/polls/services/poll-list-observable.service.ts +++ b/client/src/app/site/polls/services/poll-list-observable.service.ts @@ -2,10 +2,12 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; +import { CollectionStringMapperService } from 'app/core/core-services/collection-string-mapper.service'; import { HasViewModelListObservable } from 'app/core/definitions/has-view-model-list-observable'; import { AssignmentPollRepositoryService } from 'app/core/repositories/assignments/assignment-poll-repository.service'; import { MotionPollRepositoryService } from 'app/core/repositories/motions/motion-poll-repository.service'; 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'; @@ -21,7 +23,8 @@ export class PollListObservableService implements HasViewModelListObservable { return this.viewPollListSubject.asObservable(); } + + public getObservableFromViewModel(poll: ViewBasePoll): Observable { + return this.mapper.getRepository(poll.collectionString).getViewModelObservable(poll.id); + } } diff --git a/openslides/poll/views.py b/openslides/poll/views.py index 0f215cacb..3cd3534ec 100644 --- a/openslides/poll/views.py +++ b/openslides/poll/views.py @@ -94,7 +94,6 @@ class BasePollViewSet(ModelViewSet): return super().update(request, *args, **kwargs) def handle_request_with_votes(self, request, poll): - print(poll, poll.type, BasePoll.TYPE_ANALOG) if poll.type != BasePoll.TYPE_ANALOG: raise ValidationError( {"detail": "You cannot enter votes for a non-analog poll."} @@ -142,6 +141,7 @@ class BasePollViewSet(ModelViewSet): poll.state = BasePoll.STATE_FINISHED poll.save() inform_changed_data(poll.get_votes()) + inform_changed_data(poll.get_options()) return Response() @detail_route(methods=["POST"]) @@ -233,7 +233,9 @@ class BasePollViewSet(ModelViewSet): if poll.state != BasePoll.STATE_STARTED: raise ValidationError("You can only vote on a started poll.") if not request.user.is_present or not in_some_groups( - request.user.id, poll.groups.all(), exact=True + request.user.id, + list(poll.groups.values_list("pk", flat=True)), + exact=True, ): self.permission_denied(request) diff --git a/openslides/utils/auth.py b/openslides/utils/auth.py index 36403a983..5b27a350b 100644 --- a/openslides/utils/auth.py +++ b/openslides/utils/auth.py @@ -7,7 +7,6 @@ from django.contrib.auth import get_user_model from django.contrib.auth.models import AnonymousUser from django.core.exceptions import ImproperlyConfigured from django.db.models import Model -from django.db.models.query import QuerySet from .cache import element_cache @@ -112,9 +111,8 @@ async def async_has_perm(user_id: int, perm: str) -> bool: return has_perm -def in_some_groups( - user_id: int, groups: Union[List[int], QuerySet], exact: bool = False -) -> bool: +# async code doesn't work well with QuerySets, so we have to give a list of ints for groups +def in_some_groups(user_id: int, groups: List[int], exact: bool = False) -> bool: """ Checks that user is in at least one given group. Groups can be given as a list of ids or a QuerySet. @@ -134,7 +132,7 @@ def in_some_groups( async def async_in_some_groups( - user_id: int, groups: Union[List[int], QuerySet], exact: bool = False + user_id: int, groups: List[int], exact: bool = False ) -> bool: """ Checks that user is in at least one given group. Groups can be given as a list @@ -143,9 +141,6 @@ async def async_in_some_groups( user_id 0 means anonymous user. """ - if isinstance(groups, QuerySet): - groups = [group.pk for group in groups] - if not user_id and not await async_anonymous_is_enabled(): in_some_groups = False elif not user_id: diff --git a/tests/integration/agenda/test_viewset.py b/tests/integration/agenda/test_viewset.py index 8f56f032e..18ec5dc99 100644 --- a/tests/integration/agenda/test_viewset.py +++ b/tests/integration/agenda/test_viewset.py @@ -382,7 +382,6 @@ class ManageSpeaker(TestCase): self.assertEqual(response.status_code, 403) def test_remove_someone_else(self): - print(self.user) speaker = Speaker.objects.add(self.user, self.list_of_speakers) response = self.client.delete( reverse("listofspeakers-manage-speaker", args=[self.list_of_speakers.pk]), diff --git a/tests/integration/assignments/test_polls.py b/tests/integration/assignments/test_polls.py index 193fd8461..6d208b3a1 100644 --- a/tests/integration/assignments/test_polls.py +++ b/tests/integration/assignments/test_polls.py @@ -708,6 +708,7 @@ class VoteAssignmentPollBaseTestClass(TestCase): self.admin.save() self.poll.groups.add(GROUP_ADMIN_PK) self.poll.create_options() + inform_changed_data(self.poll) def create_poll(self): # has to be implemented by subclasses diff --git a/tests/integration/mediafiles/test_viewset.py b/tests/integration/mediafiles/test_viewset.py index 40d674ae4..c42b256f1 100644 --- a/tests/integration/mediafiles/test_viewset.py +++ b/tests/integration/mediafiles/test_viewset.py @@ -70,6 +70,7 @@ class TestCreation(TestCase): "is_directory": True, "mediafile": self.file, }, + format="multipart", ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertFalse(Mediafile.objects.exists()) @@ -79,6 +80,7 @@ class TestCreation(TestCase): response = self.client.post( reverse("mediafile-list"), {"title": "test_title_vai8oDogohheideedie4", "mediafile": file}, + format="multipart", ) self.assertEqual(response.status_code, status.HTTP_201_CREATED) mediafile = Mediafile.objects.get() @@ -90,6 +92,7 @@ class TestCreation(TestCase): response = self.client.post( reverse("mediafile-list"), {"title": "test_title_Zeicheipeequie3ohfid", "mediafile": file1}, + format="multipart", ) self.assertEqual(response.status_code, status.HTTP_201_CREATED) mediafile = Mediafile.objects.get() @@ -98,6 +101,7 @@ class TestCreation(TestCase): response = self.client.post( reverse("mediafile-list"), {"title": "test_title_aiChaetohs0quicee9eb", "mediafile": file2}, + format="multipart", ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(Mediafile.objects.count(), 1)