-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
+
+
-
+
diff --git a/client/src/app/site/motions/components/motion-list/motion-list.component.ts b/client/src/app/site/motions/components/motion-list/motion-list.component.ts
index d6a79eae4..b8ca7a486 100644
--- a/client/src/app/site/motions/components/motion-list/motion-list.component.ts
+++ b/client/src/app/site/motions/components/motion-list/motion-list.component.ts
@@ -3,22 +3,23 @@ import { Router, ActivatedRoute } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
-import { ConfigService } from '../../../../core/services/config.service';
-import { MotionCsvExportService } from '../../services/motion-csv-export.service';
-import { ListViewBaseComponent } from '../../../base/list-view-base';
-import { MatSnackBar } from '@angular/material';
-import { ViewMotion } from '../../models/view-motion';
-import { WorkflowState } from '../../../../shared/models/motions/workflow-state';
-import { MotionMultiselectService } from '../../services/motion-multiselect.service';
-import { TagRepositoryService } from 'app/site/tags/services/tag-repository.service';
import { CategoryRepositoryService } from '../../services/category-repository.service';
+import { ConfigService } from '../../../../core/services/config.service';
+import { ListViewBaseComponent } from '../../../base/list-view-base';
+import { LocalPermissionsService } from '../../services/local-permissions.service';
+import { MatSnackBar } from '@angular/material';
import { MotionBlockRepositoryService } from '../../services/motion-block-repository.service';
+import { MotionCsvExportService } from '../../services/motion-csv-export.service';
import { MotionFilterListService } from '../../services/motion-filter-list.service';
+import { MotionMultiselectService } from '../../services/motion-multiselect.service';
import { MotionSortListService } from '../../services/motion-sort-list.service';
+import { TagRepositoryService } from 'app/site/tags/services/tag-repository.service';
+import { ViewCategory } from '../../models/view-category';
+import { ViewMotion } from '../../models/view-motion';
+import { ViewMotionBlock } from '../../models/view-motion-block';
import { ViewTag } from 'app/site/tags/models/view-tag';
import { ViewWorkflow } from '../../models/view-workflow';
-import { ViewCategory } from '../../models/view-category';
-import { ViewMotionBlock } from '../../models/view-motion-block';
+import { WorkflowState } from '../../../../shared/models/motions/workflow-state';
import { WorkflowRepositoryService } from '../../services/workflow-repository.service';
/**
@@ -75,6 +76,7 @@ export class MotionListComponent extends ListViewBaseComponent
imple
* @param userRepo
* @param sortService
* @param filterService
+ * @param perms LocalPermissionService
*/
public constructor(
titleService: Title,
@@ -90,7 +92,8 @@ export class MotionListComponent extends ListViewBaseComponent imple
private motionCsvExport: MotionCsvExportService,
public multiselectService: MotionMultiselectService,
public sortService: MotionSortListService,
- public filterService: MotionFilterListService
+ public filterService: MotionFilterListService,
+ public perms: LocalPermissionsService
) {
super(titleService, translate, matSnackBar);
diff --git a/client/src/app/site/motions/components/motion-poll/motion-poll.component.html b/client/src/app/site/motions/components/motion-poll/motion-poll.component.html
index 2cd150512..6995789cc 100644
--- a/client/src/app/site/motions/components/motion-poll/motion-poll.component.html
+++ b/client/src/app/site/motions/components/motion-poll/motion-poll.component.html
@@ -6,10 +6,13 @@
-
{{ getIcon(key) }}
+
+ {{ getIcon(key) }}
+
- {{ getLabel(key) }}: {{ getNumber(key) }}
+ {{ getLabel(key) }}: {{ getNumber(key) }}
({{ getPercent(key) }}%)
@@ -22,39 +25,53 @@
-
+
-
Quorum not calculable.
-
-
-
- thumb_down
- thumb_up
+
+
Quorum not calculable.
+
+
+
+ thumb_down
+ thumb_up
+
+
+
+ reached.
+ not reached.
+
+ — No quorum calculated
+
-
-
- reached.
- not reached.
-
- — No quorum calculated
-
-
+
-
+
-
diff --git a/client/src/app/site/motions/services/local-permissions.service.ts b/client/src/app/site/motions/services/local-permissions.service.ts
index 36d1e1397..c239ccfcc 100644
--- a/client/src/app/site/motions/services/local-permissions.service.ts
+++ b/client/src/app/site/motions/services/local-permissions.service.ts
@@ -2,49 +2,124 @@ import { Injectable } from '@angular/core';
import { OperatorService } from '../../../core/services/operator.service';
import { ViewMotion } from '../models/view-motion';
import { ConfigService } from '../../../core/services/config.service';
+import { ConstantsService } from 'app/core/services/constants.service';
@Injectable({
providedIn: 'root'
})
export class LocalPermissionsService {
public configMinSupporters: number;
+ private amendmentEnabled: boolean;
+ private amendmentOfAmendment: boolean;
- public constructor(private operator: OperatorService, private configService: ConfigService) {
+ public constructor(
+ private operator: OperatorService,
+ private configService: ConfigService,
+ private constants: ConstantsService
+ ) {
// load config variables
this.configService
.get('motions_min_supporters')
.subscribe(supporters => (this.configMinSupporters = supporters));
+ this.configService.get('motions_amendments_enabled').subscribe(enabled => (this.amendmentEnabled = enabled));
+ this.constants
+ .get('OpenSlidesSettings')
+ .subscribe(settings => (this.amendmentOfAmendment = settings.MOTIONS_ALLOW_AMENDMENTS_OF_AMENDMENTS));
}
/**
- * Should determine if the user (Operator) has the
- * correct permission to perform the given action.
+ * Determine if the user (Operator) has the correct permission to perform the given action.
*
* actions might be:
+ * - create
* - support
* - unsupport
* - createpoll
+ * - update
+ * - update_submitters
+ * - delete
+ * - change_metadata
+ * - reset_state
+ * - change_recommendation
+ * - can_create_amendments
+ * - can_manage_metadata
+ * - manage
*
* @param action the action the user tries to perform
+ * @param motion the motion for which to perform the action
*/
public isAllowed(action: string, motion?: ViewMotion): boolean {
- if (motion) {
- switch (action) {
- case 'support':
- return (
- this.operator.hasPerms('motions.can_support') &&
- this.configMinSupporters > 0 &&
- motion.state.allow_support &&
- motion.submitters.indexOf(this.operator.user) === -1 &&
- motion.supporters.indexOf(this.operator.user) === -1
- );
- case 'unsupport':
- return motion.state.allow_support && motion.supporters.indexOf(this.operator.user) !== -1;
- case 'createpoll':
- return this.operator.hasPerms('motions.can_manage') && motion.state.allow_create_poll;
- default:
+ switch (action) {
+ case 'create':
+ return this.operator.hasPerms('motions.can_create');
+ case 'support':
+ if (!motion) {
return false;
- }
+ }
+ return (
+ this.operator.hasPerms('motions.can_support') &&
+ this.configMinSupporters > 0 &&
+ motion.state.allow_support &&
+ motion.submitters.indexOf(this.operator.user) === -1 &&
+ motion.supporters.indexOf(this.operator.user) === -1
+ );
+ case 'unsupport':
+ if (!motion) {
+ return false;
+ }
+ return motion.state.allow_support && motion.supporters.indexOf(this.operator.user) !== -1;
+ case 'createpoll':
+ if (!motion) {
+ return false;
+ }
+ return (
+ (this.operator.hasPerms('motions.can_manage') ||
+ this.operator.hasPerms('motions.can_manage_metadata')) &&
+ motion.state.allow_create_poll
+ );
+ case 'update':
+ if (!motion) {
+ return false;
+ }
+ return (
+ this.operator.hasPerms('motions.can_manage') &&
+ motion.state.allow_submitter_edit &&
+ motion.submitters.some(submitter => submitter.id === this.operator.user.id)
+ );
+ case 'update_submitters':
+ return this.operator.hasPerms('motions.can_manage');
+ case 'delete':
+ if (!motion) {
+ return false;
+ }
+ return (
+ this.operator.hasPerms('motions.can_manage') &&
+ motion.state.allow_submitter_edit &&
+ motion.submitters.some(submitter => submitter.id === this.operator.user.id)
+ );
+ case 'change_metadata':
+ return (
+ this.operator.hasPerms('motions.can_manage') ||
+ this.operator.hasPerms('motions.can_manage_metadata')
+ );
+ case 'can_create_amendments':
+ if (!motion) {
+ return false;
+ }
+ return (
+ this.operator.hasPerms('motions.can_create_amendments') &&
+ this.amendmentEnabled &&
+ (!motion.parent_id || (motion.parent_id && this.amendmentOfAmendment))
+ );
+ case 'can_manage_metadata':
+ return (
+ this.operator.hasPerms('motions.can_manage') &&
+ this.operator.hasPerms('motions.can_manage_metadata')
+ );
+ case 'manage':
+ return this.operator.hasPerms('motions.can_manage');
+ default:
+ return false;
}
}
}
diff --git a/client/src/app/site/motions/services/motion-repository.service.ts b/client/src/app/site/motions/services/motion-repository.service.ts
index bff4f7d46..5d8343253 100644
--- a/client/src/app/site/motions/services/motion-repository.service.ts
+++ b/client/src/app/site/motions/services/motion-repository.service.ts
@@ -692,4 +692,13 @@ export class MotionRepositoryService extends BaseRepository
await this.httpService.post(restPath);
}
}
+ /**
+ * Check if a motion currently has any amendments
+ *
+ * @param motion A viewMotion
+ * @returns True if there is at eleast one amendment
+ */
+ public hasAmendments(motion: ViewMotion): boolean {
+ return this.getViewModelList().filter(allMotions => allMotions.parent_id === motion.id).length > 0;
+ }
}