Merge pull request #4132 from MaximilianKrambach/motionViewPermissions
adding viewPermissions
This commit is contained in:
commit
3582e71bba
@ -1,17 +1,24 @@
|
||||
<h4 translate>
|
||||
<span translate>Submitters</span>
|
||||
<button class="small-button" type="button" mat-icon-button disableRipple *ngIf="!isEditMode" (click)="onEdit()">
|
||||
<button
|
||||
class="small-button"
|
||||
type="button"
|
||||
mat-icon-button
|
||||
disableRipple
|
||||
*ngIf="!isEditMode && perms.isAllowed('change_metadata')"
|
||||
(click)="onEdit()"
|
||||
>
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
</h4>
|
||||
|
||||
<div *ngIf="!isEditMode">
|
||||
<div *ngIf="!isEditMode || !perms.isAllowed('change_metadata')">
|
||||
<mat-chip-list *ngFor="let submitter of motion.submitters" class="user">
|
||||
<mat-chip>{{ submitter.full_name }}</mat-chip>
|
||||
</mat-chip-list>
|
||||
</div>
|
||||
|
||||
<div *ngIf="isEditMode">
|
||||
<div *ngIf="isEditMode && perms.isAllowed('change_metadata')">
|
||||
<os-sorting-list
|
||||
[input]="editSubmitterObservable"
|
||||
[live]="true"
|
||||
|
@ -1,16 +1,17 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { FormGroup, FormControl } from '@angular/forms';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
|
||||
import { ViewMotion } from '../../models/view-motion';
|
||||
import { User } from 'app/shared/models/users/user';
|
||||
import { DataStoreService } from 'app/core/services/data-store.service';
|
||||
import { MotionRepositoryService } from '../../services/motion-repository.service';
|
||||
import { BaseViewComponent } from 'app/site/base/base-view';
|
||||
import { DataStoreService } from 'app/core/services/data-store.service';
|
||||
import { LocalPermissionsService } from '../../services/local-permissions.service';
|
||||
import { MotionRepositoryService } from '../../services/motion-repository.service';
|
||||
import { User } from 'app/shared/models/users/user';
|
||||
import { ViewMotion } from '../../models/view-motion';
|
||||
|
||||
/**
|
||||
* Component for the motion comments view
|
||||
@ -61,13 +62,15 @@ export class ManageSubmittersComponent extends BaseViewComponent {
|
||||
* @param matSnackBar
|
||||
* @param DS
|
||||
* @param repo
|
||||
* @param perms permission checks for the motion
|
||||
*/
|
||||
public constructor(
|
||||
title: Title,
|
||||
translate: TranslateService,
|
||||
matSnackBar: MatSnackBar,
|
||||
private DS: DataStoreService,
|
||||
private repo: MotionRepositoryService
|
||||
private repo: MotionRepositoryService,
|
||||
public perms: LocalPermissionsService
|
||||
) {
|
||||
super(title, translate, matSnackBar);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<os-head-bar
|
||||
[mainButton]="opCanEdit()"
|
||||
[mainButton]="perms.isAllowed('update_motion', motion)"
|
||||
mainButtonIcon="edit"
|
||||
[nav]="false"
|
||||
[editMode]="editMotion"
|
||||
@ -61,13 +61,12 @@
|
||||
<mat-menu #motionExtraMenu="matMenu">
|
||||
<div *ngIf="motion">
|
||||
<!-- PDF -->
|
||||
<button mat-menu-item
|
||||
(click)="onDownloadPdf()">
|
||||
<button mat-menu-item (click)="onDownloadPdf()">
|
||||
<mat-icon>picture_as_pdf</mat-icon>
|
||||
<span translate>PDF</span>
|
||||
</button>
|
||||
<!-- List of speakers -->
|
||||
<button mat-menu-item [routerLink]="getSpeakerLink()">
|
||||
<button mat-menu-item [routerLink]="getSpeakerLink()" *osPerms="'agenda.can_see'">
|
||||
<mat-icon>mic</mat-icon>
|
||||
<span translate>List of speakers</span>
|
||||
</button>
|
||||
@ -80,7 +79,7 @@
|
||||
<button
|
||||
mat-menu-item
|
||||
(click)="createAmendment()"
|
||||
*ngIf="amendmentsEnabled && motion && !motion.isParagraphBasedAmendment()"
|
||||
*ngIf="perms.isAllowed('can_create_amendments', motion)"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
<span translate>New amendment</span>
|
||||
@ -95,13 +94,14 @@
|
||||
<span translate>Show entire motion text</span>
|
||||
</button>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<!-- Delete -->
|
||||
<button mat-menu-item class="red-warning-text" (click)="deleteMotionButton()">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span translate>Delete</span>
|
||||
</button>
|
||||
<div *ngIf="perms.isAllowed('manage')">
|
||||
<mat-divider></mat-divider>
|
||||
<!-- Delete -->
|
||||
<button mat-menu-item class="red-warning-text" (click)="deleteMotionButton()">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span translate>Delete</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-menu>
|
||||
</os-head-bar>
|
||||
@ -110,9 +110,7 @@
|
||||
<!-- Title -->
|
||||
<div class="title on-transition-fade" *ngIf="motion && !editMotion">
|
||||
<div class="title-line">
|
||||
<h1>
|
||||
{{ motion.title }}
|
||||
</h1>
|
||||
<h1>{{ motion.title }}</h1>
|
||||
<button mat-icon-button color="primary" (click)="toggleFavorite()">
|
||||
<mat-icon>{{ motion.star ? 'star' : 'star_border' }}</mat-icon>
|
||||
</button>
|
||||
@ -124,18 +122,13 @@
|
||||
</div>
|
||||
|
||||
<ng-template #mobileView>
|
||||
|
||||
<!-- Meta info -->
|
||||
<div class="hspacing">
|
||||
<ng-container *ngTemplateOutlet="metaInfoTemplate"></ng-container>
|
||||
</div>
|
||||
<div class="hspacing"><ng-container *ngTemplateOutlet="metaInfoTemplate"></ng-container></div>
|
||||
|
||||
<mat-divider class="spacer-top-10 spacer-bottom-20"></mat-divider>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="hspacing">
|
||||
<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
|
||||
</div>
|
||||
<div class="hspacing"><ng-container *ngTemplateOutlet="contentTemplate"></ng-container></div>
|
||||
|
||||
<mat-divider class="spacer-top-10 spacer-bottom-20"></mat-divider>
|
||||
|
||||
@ -145,11 +138,14 @@
|
||||
<!-- Personal note -->
|
||||
<os-personal-note *ngIf="!editMotion" [motion]="motion"></os-personal-note>
|
||||
|
||||
<!-- Motoin log -->
|
||||
<button mat-button *ngIf="canShowLog" (click)="motionLogExpanded =!motionLogExpanded">
|
||||
<ng-container *ngTemplateOutlet="motionLogTemplate"></ng-container>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #motionLogTemplate>
|
||||
<button mat-button *ngIf="canShowLog" (click)="motionLogExpanded = !motionLogExpanded">
|
||||
<span translate>Show motion log</span>
|
||||
</button>
|
||||
<os-motion-log *ngIf="motionLogExpanded" [motion]="motion"></os-motion-log>
|
||||
<os-motion-log *ngIf="canShowLog && motionLogExpanded" [motion]="motion"></os-motion-log>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #desktopView>
|
||||
@ -162,10 +158,7 @@
|
||||
|
||||
<os-motion-comments *ngIf="!editMotion" [motion]="motion"></os-motion-comments>
|
||||
<os-personal-note *ngIf="!editMotion" [motion]="motion"></os-personal-note>
|
||||
<button mat-button *ngIf="canShowLog" (click)="motionLogExpanded =!motionLogExpanded">
|
||||
<span translate>Show motion log</span>
|
||||
</button>
|
||||
<os-motion-log *ngIf="motionLogExpanded" [motion]="motion"></os-motion-log>
|
||||
<ng-container *ngTemplateOutlet="motionLogTemplate"></ng-container>
|
||||
</div>
|
||||
<div class="desktop-right ">
|
||||
<!-- Content -->
|
||||
@ -229,24 +222,23 @@
|
||||
{{ state.name | translate }}
|
||||
</button>
|
||||
<mat-divider></mat-divider>
|
||||
<button mat-menu-item (click)="setState(null)">
|
||||
<button mat-menu-item (click)="setState(null)" *ngIf="perms.isAllowed('change_metadata', motion)">
|
||||
<mat-icon>replay</mat-icon> {{ 'Reset state' | translate }}
|
||||
</button>
|
||||
</mat-menu>
|
||||
<mat-basic-chip
|
||||
*ngIf="motion.state"
|
||||
*ngIf="perms.isAllowed('change_metadata', motion)"
|
||||
[matMenuTriggerFor]="stateMenu"
|
||||
[ngClass]="{
|
||||
green: motion.state.css_class === 'success',
|
||||
red: motion.state.css_class === 'danger',
|
||||
grey: motion.state.css_class === 'default',
|
||||
lightblue: motion.state.css_class === 'primary'
|
||||
}"
|
||||
[ngClass]="getStateCssColor()"
|
||||
>
|
||||
{{ motion.state.name | translate }}
|
||||
</mat-basic-chip>
|
||||
<mat-basic-chip
|
||||
*ngIf="!perms.isAllowed('change_metadata', motion)"
|
||||
[ngClass]="getStateCssColor()"
|
||||
>
|
||||
{{ motion.state.name | translate }}
|
||||
</mat-basic-chip>
|
||||
|
||||
<!--*osPerms="['motions.can_manage', 'motions.can_manage_metadata']; -->
|
||||
</div>
|
||||
|
||||
<!-- Recommendation -->
|
||||
@ -261,17 +253,33 @@
|
||||
{{ recommendation.recommendation_label | translate }}
|
||||
</button>
|
||||
<mat-divider></mat-divider>
|
||||
<button mat-menu-item (click)="setRecommendation(null)">
|
||||
<button mat-menu-item *ngIf="perms.isAllowed('change_metadata', motion)"
|
||||
(click)="setRecommendation(null)">
|
||||
<mat-icon>replay</mat-icon> {{ 'Reset recommendation' | translate }}
|
||||
</button>
|
||||
</mat-menu>
|
||||
<mat-basic-chip [matMenuTriggerFor]="recommendationMenu" class="bluegrey">
|
||||
<mat-basic-chip
|
||||
*ngIf="perms.isAllowed('change_metadata', motion)"
|
||||
[matMenuTriggerFor]="recommendationMenu"
|
||||
class="bluegrey"
|
||||
>
|
||||
{{
|
||||
motion.recommendation
|
||||
? (motion.recommendation.recommendation_label | translate)
|
||||
: ('not set' | translate)
|
||||
}}
|
||||
</mat-basic-chip>
|
||||
<mat-basic-chip
|
||||
*ngIf="!perms.isAllowed('change_metadata', motion)"
|
||||
class="bluegrey"
|
||||
>
|
||||
{{
|
||||
motion.recommendation
|
||||
? (motion.recommendation.recommendation_label | translate)
|
||||
: ('not set' | translate)
|
||||
}}
|
||||
</mat-basic-chip>
|
||||
|
||||
<button mat-button *ngIf="canFollowRecommendation()" (click)="onFollowRecButton()">
|
||||
<span translate>Follow recommendation</span>
|
||||
</button>
|
||||
@ -291,7 +299,10 @@
|
||||
{{ category }}
|
||||
</button>
|
||||
</mat-menu>
|
||||
<mat-basic-chip [matMenuTriggerFor]="categoryMenu" class="grey">
|
||||
<mat-basic-chip *ngIf="perms.isAllowed('change_metadata', motion)" [matMenuTriggerFor]="categoryMenu" class="grey">
|
||||
{{ motion.category ? motion.category : '–' }}
|
||||
</mat-basic-chip>
|
||||
<mat-basic-chip *ngIf="!perms.isAllowed('change_metadata', motion)" class="grey">
|
||||
{{ motion.category ? motion.category : '–' }}
|
||||
</mat-basic-chip>
|
||||
</div>
|
||||
@ -305,7 +316,10 @@
|
||||
{{ block }}
|
||||
</button>
|
||||
</mat-menu>
|
||||
<mat-basic-chip [matMenuTriggerFor]="blockMenu" class="grey">
|
||||
<mat-basic-chip *ngIf="perms.isAllowed('change_metadata', motion)" [matMenuTriggerFor]="blockMenu" class="grey">
|
||||
{{ motion.motion_block ? motion.motion_block : '–' }}
|
||||
</mat-basic-chip>
|
||||
<mat-basic-chip *ngIf="!perms.isAllowed('change_metadata', motion)" class="grey">
|
||||
{{ motion.motion_block ? motion.motion_block : '–' }}
|
||||
</mat-basic-chip>
|
||||
</div>
|
||||
@ -380,7 +394,7 @@
|
||||
|
||||
<!-- Submitter -->
|
||||
<div *ngIf="newMotion" class="content-field">
|
||||
<div *osPerms="['motions.can_manage', 'motions.can_manage_metadata']">
|
||||
<div *ngIf="perms.isAllowed('change_metadata', motion)">
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="contentForm"
|
||||
@ -537,7 +551,7 @@
|
||||
|
||||
<!-- Supporter form -->
|
||||
<div class="content-field" *ngIf="editMotion && minSupporters">
|
||||
<div *osPerms="['motions.can_manage', 'motions.can_manage_metadata']">
|
||||
<div *ngIf="perms.isAllowed('change_metadata', motion)">
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="contentForm"
|
||||
@ -551,7 +565,7 @@
|
||||
|
||||
<!-- Workflow -->
|
||||
<div class="content-field" *ngIf="editMotion && workflowObserver.value.length > 1">
|
||||
<div *osPerms="['motions.can_manage', 'motions.can_manage_metadata']">
|
||||
<div *ngIf="perms.isAllowed('change_metadata', motion)">
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="contentForm"
|
||||
@ -565,7 +579,7 @@
|
||||
|
||||
<!-- Origin form -->
|
||||
<div class="content-field" *ngIf="editMotion">
|
||||
<div *osPerms="['motions.can_manage', 'motions.can_manage_metadata']">
|
||||
<div *ngIf="perms.isAllowed('change_metadata', motion)">
|
||||
<mat-form-field>
|
||||
<input
|
||||
matInput
|
||||
|
@ -1,45 +1,43 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BehaviorSubject, Subscription, ReplaySubject, concat } from 'rxjs';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatDialog, MatExpansionPanel, MatSnackBar, MatCheckboxChange } from '@angular/material';
|
||||
import { take, takeWhile, multicast, skipWhile } from 'rxjs/operators';
|
||||
|
||||
import { Category } from '../../../../shared/models/motions/category';
|
||||
import { ViewportService } from '../../../../core/services/viewport.service';
|
||||
import { MotionRepositoryService } from '../../services/motion-repository.service';
|
||||
import { ChangeRecoMode, LineNumberingMode, ViewMotion } from '../../models/view-motion';
|
||||
import { User } from '../../../../shared/models/users/user';
|
||||
import { DataStoreService } from '../../../../core/services/data-store.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Motion } from '../../../../shared/models/motions/motion';
|
||||
import { BehaviorSubject, Subscription, ReplaySubject, concat } from 'rxjs';
|
||||
|
||||
import { AgendaRepositoryService } from 'app/site/agenda/services/agenda-repository.service';
|
||||
import { BaseViewComponent } from '../../../base/base-view';
|
||||
import { Category } from '../../../../shared/models/motions/category';
|
||||
import { ChangeRecommendationRepositoryService } from '../../services/change-recommendation-repository.service';
|
||||
import { ChangeRecoMode, LineNumberingMode, ViewMotion } from '../../models/view-motion';
|
||||
import { CreateMotion } from '../../models/create-motion';
|
||||
import { ConfigService } from '../../../../core/services/config.service';
|
||||
import { DataStoreService } from '../../../../core/services/data-store.service';
|
||||
import { DiffLinesInParagraph, LineRange } from '../../services/diff.service';
|
||||
import { itemVisibilityChoices, Item } from 'app/shared/models/agenda/item';
|
||||
import { LocalPermissionsService } from '../../services/local-permissions.service';
|
||||
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||
import { Motion } from '../../../../shared/models/motions/motion';
|
||||
import { MotionBlock } from 'app/shared/models/motions/motion-block';
|
||||
import {
|
||||
MotionChangeRecommendationComponent,
|
||||
MotionChangeRecommendationComponentData
|
||||
} from '../motion-change-recommendation/motion-change-recommendation.component';
|
||||
import { ChangeRecommendationRepositoryService } from '../../services/change-recommendation-repository.service';
|
||||
import { ViewChangeReco } from '../../models/view-change-reco';
|
||||
|
||||
import { ViewUnifiedChange } from '../../models/view-unified-change';
|
||||
import { OperatorService } from '../../../../core/services/operator.service';
|
||||
import { BaseViewComponent } from '../../../base/base-view';
|
||||
import { ViewStatuteParagraph } from '../../models/view-statute-paragraph';
|
||||
import { StatuteParagraphRepositoryService } from '../../services/statute-paragraph-repository.service';
|
||||
import { ConfigService } from '../../../../core/services/config.service';
|
||||
import { Workflow } from 'app/shared/models/motions/workflow';
|
||||
import { LocalPermissionsService } from '../../services/local-permissions.service';
|
||||
import { ViewCreateMotion } from '../../models/view-create-motion';
|
||||
import { CreateMotion } from '../../models/create-motion';
|
||||
import { MotionBlock } from 'app/shared/models/motions/motion-block';
|
||||
import { itemVisibilityChoices, Item } from 'app/shared/models/agenda/item';
|
||||
import { PromptService } from 'app/core/services/prompt.service';
|
||||
import { AgendaRepositoryService } from 'app/site/agenda/services/agenda-repository.service';
|
||||
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||
import { MotionPdfExportService } from '../../services/motion-pdf-export.service';
|
||||
import { PersonalNoteService } from '../../services/personal-note.service';
|
||||
import { MotionRepositoryService } from '../../services/motion-repository.service';
|
||||
import { PersonalNoteContent } from 'app/shared/models/users/personal-note';
|
||||
import { PersonalNoteService } from '../../services/personal-note.service';
|
||||
import { PromptService } from 'app/core/services/prompt.service';
|
||||
import { StatuteParagraphRepositoryService } from '../../services/statute-paragraph-repository.service';
|
||||
import { User } from '../../../../shared/models/users/user';
|
||||
import { ViewChangeReco } from '../../models/view-change-reco';
|
||||
import { ViewCreateMotion } from '../../models/view-create-motion';
|
||||
import { ViewportService } from '../../../../core/services/viewport.service';
|
||||
import { ViewUnifiedChange } from '../../models/view-unified-change';
|
||||
import { ViewStatuteParagraph } from '../../models/view-statute-paragraph';
|
||||
import { Workflow } from 'app/shared/models/motions/workflow';
|
||||
|
||||
/**
|
||||
* Component for the motion detail view
|
||||
@ -107,6 +105,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
if (
|
||||
this.motion &&
|
||||
!this.editMotion &&
|
||||
this.perms.isAllowed('manage') &&
|
||||
this.motion.motion.log_messages &&
|
||||
this.motion.motion.log_messages.length
|
||||
) {
|
||||
@ -316,7 +315,6 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
matSnackBar: MatSnackBar,
|
||||
public vp: ViewportService,
|
||||
public perms: LocalPermissionsService,
|
||||
private op: OperatorService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private formBuilder: FormBuilder,
|
||||
@ -984,15 +982,8 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user has the correct requirements to alter the motion
|
||||
* TODO: All views should probably have a "isAllowedTo" routine to simplify this process
|
||||
*
|
||||
* @returns whether or not the OP is allowed to edit the motion
|
||||
* Handler for creating a poll
|
||||
*/
|
||||
public opCanEdit(): boolean {
|
||||
return this.op.hasPerms('motions.can_manage', 'motions.can_manage_metadata');
|
||||
}
|
||||
|
||||
public async createPoll(): Promise<void> {
|
||||
await this.repo.createPoll(this.motion);
|
||||
}
|
||||
@ -1000,7 +991,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
/**
|
||||
* Check if a recommendation can be followed. Checks for permissions and additionally if a recommentadion is present
|
||||
*/
|
||||
public get canFollowRecommendation(): boolean {
|
||||
public canFollowRecommendation(): boolean {
|
||||
if (
|
||||
this.perms.isAllowed('createPoll', this.motion) &&
|
||||
this.motion.recommendation &&
|
||||
@ -1024,4 +1015,24 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
public async toggleFavorite(): Promise<void> {
|
||||
this.personalNoteService.setPersonalNoteStar(this.motion.motion, !this.motion.star);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the state's css class into a color
|
||||
*
|
||||
* @returns a string representing a color
|
||||
*/
|
||||
public getStateCssColor(): string {
|
||||
switch (this.motion.state.css_class) {
|
||||
case 'success':
|
||||
return 'green';
|
||||
case 'danger':
|
||||
return 'red';
|
||||
case 'default':
|
||||
return 'grey';
|
||||
case 'primary':
|
||||
return 'lightblue';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<os-head-bar [mainButton]="true" (mainEvent)="onPlusButton()" [multiSelectMode]="isMultiSelect">
|
||||
<os-head-bar [mainButton]="perms.isAllowed('create')" (mainEvent)="onPlusButton()" [multiSelectMode]="isMultiSelect">
|
||||
<!-- Title -->
|
||||
<div class="title-slot"><h2 translate>Motions</h2></div>
|
||||
|
||||
@ -17,154 +17,159 @@
|
||||
</os-head-bar>
|
||||
|
||||
<mat-drawer-container class="on-transition-fade">
|
||||
<os-sort-filter-bar [filterService]="filterService" [sortService]="sortService"
|
||||
(searchFieldChange)="searchFilter($event)">
|
||||
</os-sort-filter-bar>
|
||||
<os-sort-filter-bar [filterService]="filterService" [sortService]="sortService"
|
||||
(searchFieldChange)="searchFilter($event)">
|
||||
</os-sort-filter-bar>
|
||||
|
||||
<mat-table class="os-listview-table on-transition-fade" [dataSource]="dataSource" matSort>
|
||||
<!-- Selector column -->
|
||||
<ng-container matColumnDef="selector">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header class="checkbox-cell"></mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion" class="checkbox-cell">
|
||||
<mat-icon>{{ isSelected(motion) ? 'check_circle' : '' }}</mat-icon>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
<mat-table class="os-listview-table on-transition-fade" [dataSource]="dataSource" matSort>
|
||||
<!-- Selector column -->
|
||||
<ng-container matColumnDef="selector">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header class="checkbox-cell"></mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion" class="checkbox-cell">
|
||||
<mat-icon>{{ isSelected(motion) ? 'check_circle' : '' }}</mat-icon>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- identifier column -->
|
||||
<ng-container matColumnDef="identifier">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Identifier</mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion">
|
||||
<div class="innerTable">{{ motion.identifier }}</div>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
<!-- identifier column -->
|
||||
<ng-container matColumnDef="identifier">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Identifier</mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion">
|
||||
<div class="innerTable">{{ motion.identifier }}</div>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- title column -->
|
||||
<ng-container matColumnDef="title">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Title</mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion">
|
||||
<div class="innerTable">
|
||||
<span class="motion-list-title">{{ motion.title }}
|
||||
<span>
|
||||
<mat-icon inline>{{ motion.star ? 'star' : 'star_border' }}</mat-icon>
|
||||
<!-- title column -->
|
||||
<ng-container matColumnDef="title">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Title</mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion">
|
||||
<div class="innerTable">
|
||||
<span class="motion-list-title">{{ motion.title }}
|
||||
<span>
|
||||
<mat-icon inline>{{ motion.star ? 'star' : 'star_border' }}</mat-icon>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<!-- attachments -->
|
||||
<span class="attached-files" *ngIf="motion.hasAttachments()">
|
||||
<!-- <mat-basic-chip class="bluegrey"> <mat-icon>attach_file</mat-icon> </mat-basic-chip> -->
|
||||
<mat-icon>attach_file</mat-icon>
|
||||
</span>
|
||||
<!-- attachments -->
|
||||
<span class="attached-files" *ngIf="motion.hasAttachments()">
|
||||
<!-- <mat-basic-chip class="bluegrey"> <mat-icon>attach_file</mat-icon> </mat-basic-chip> -->
|
||||
<mat-icon>attach_file</mat-icon>
|
||||
</span>
|
||||
|
||||
<br />
|
||||
<span class="motion-list-from" *ngIf="motion.submitters.length">
|
||||
<span translate>by</span> {{ motion.submitters }}
|
||||
</span>
|
||||
<br *ngIf="motion.submitters.length" />
|
||||
<!-- state -->
|
||||
<mat-basic-chip
|
||||
*ngIf="motion.state"
|
||||
[ngClass]="{
|
||||
green: motion.state.css_class === 'success',
|
||||
red: motion.state.css_class === 'danger',
|
||||
grey: motion.state.css_class === 'default',
|
||||
lightblue: motion.state.css_class === 'primary'
|
||||
}"
|
||||
>
|
||||
{{ motion.state.name | translate }}
|
||||
</mat-basic-chip>
|
||||
<br />
|
||||
<span class="motion-list-from" *ngIf="motion.submitters.length">
|
||||
<span translate>by</span> {{ motion.submitters }}
|
||||
</span>
|
||||
<br *ngIf="motion.submitters.length" />
|
||||
<!-- state -->
|
||||
<mat-basic-chip
|
||||
*ngIf="motion.state"
|
||||
[ngClass]="{
|
||||
green: motion.state.css_class === 'success',
|
||||
red: motion.state.css_class === 'danger',
|
||||
grey: motion.state.css_class === 'default',
|
||||
lightblue: motion.state.css_class === 'primary'
|
||||
}"
|
||||
>
|
||||
{{ motion.state.name | translate }}
|
||||
</mat-basic-chip>
|
||||
|
||||
<!-- recommendation -->
|
||||
<span *ngIf="motion.recommendation">
|
||||
<mat-basic-chip class="bluegrey">{{
|
||||
motion.recommendation.recommendation_label | translate
|
||||
}}</mat-basic-chip>
|
||||
</span>
|
||||
</div>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- state column -->
|
||||
<ng-container matColumnDef="state">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>State</mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion">
|
||||
<div class="innerTable">
|
||||
<div class="small" *ngIf="motion.category">
|
||||
<mat-icon>device_hub</mat-icon>
|
||||
{{ motion.category }}
|
||||
<!-- recommendation -->
|
||||
<span *ngIf="motion.recommendation">
|
||||
<mat-basic-chip class="bluegrey">{{
|
||||
motion.recommendation.recommendation_label | translate
|
||||
}}</mat-basic-chip>
|
||||
</span>
|
||||
</div>
|
||||
<div class="small" *ngIf="motion.motion_block">
|
||||
<mat-icon>widgets</mat-icon>
|
||||
{{ motion.motion_block.title }}
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- state column -->
|
||||
<ng-container matColumnDef="state">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>State</mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion">
|
||||
<div class="innerTable">
|
||||
<div class="small" *ngIf="motion.category">
|
||||
<mat-icon>device_hub</mat-icon>
|
||||
{{ motion.category }}
|
||||
</div>
|
||||
<div class="small" *ngIf="motion.motion_block">
|
||||
<mat-icon>widgets</mat-icon>
|
||||
{{ motion.motion_block.title }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Speakers column -->
|
||||
<ng-container matColumnDef="speakers">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Speakers</mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion">
|
||||
<button mat-icon-button (click)="onSpeakerIcon(motion, $event)">
|
||||
<mat-icon
|
||||
[matBadge]="motion.agendaSpeakerAmount > 0 ? motion.agendaSpeakerAmount : null"
|
||||
matBadgeColor="accent"
|
||||
>
|
||||
mic
|
||||
</mat-icon>
|
||||
</button>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
<!-- Speakers column -->
|
||||
<ng-container matColumnDef="speakers">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Speakers</mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion">
|
||||
<button mat-icon-button (click)="onSpeakerIcon(motion, $event)">
|
||||
<mat-icon
|
||||
[matBadge]="motion.agendaSpeakerAmount > 0 ? motion.agendaSpeakerAmount : null"
|
||||
matBadgeColor="accent"
|
||||
>
|
||||
mic
|
||||
</mat-icon>
|
||||
</button>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<mat-header-row *matHeaderRowDef="getColumnDefinition()"></mat-header-row>
|
||||
<mat-row
|
||||
[ngClass]="selectedRows.indexOf(row) >= 0 ? 'selected' : ''"
|
||||
(click)="selectItem(row, $event)"
|
||||
*matRowDef="let row; columns: getColumnDefinition()"
|
||||
class="lg"
|
||||
>
|
||||
</mat-row>
|
||||
</mat-table>
|
||||
<mat-header-row *matHeaderRowDef="getColumnDefinition()"></mat-header-row>
|
||||
<mat-row
|
||||
[ngClass]="selectedRows.indexOf(row) >= 0 ? 'selected' : ''"
|
||||
(click)="selectItem(row, $event)"
|
||||
*matRowDef="let row; columns: getColumnDefinition()"
|
||||
class="lg"
|
||||
>
|
||||
</mat-row>
|
||||
</mat-table>
|
||||
|
||||
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator>
|
||||
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator>
|
||||
</mat-drawer-container>
|
||||
|
||||
<mat-menu #motionListMenu="matMenu">
|
||||
<div *ngIf="!isMultiSelect">
|
||||
<button mat-menu-item *osPerms="'motions.can_manage'" (click)="toggleMultiSelect()">
|
||||
<mat-icon>library_add</mat-icon>
|
||||
<span translate>Multiselect</span>
|
||||
</button>
|
||||
<button mat-menu-item *osPerms="'motions.can_manage'" routerLink="call-list">
|
||||
<mat-icon>sort</mat-icon>
|
||||
<span translate>Call list</span>
|
||||
</button>
|
||||
<button mat-menu-item routerLink="category">
|
||||
<mat-icon>device_hub</mat-icon>
|
||||
<span translate>Categories</span>
|
||||
</button>
|
||||
<button mat-menu-item routerLink="blocks">
|
||||
<mat-icon>widgets</mat-icon>
|
||||
<span translate>Motion blocks</span>
|
||||
</button>
|
||||
<button mat-menu-item routerLink="statute-paragraphs" *ngIf="statutesEnabled">
|
||||
<mat-icon>account_balance</mat-icon>
|
||||
<span translate>Statute</span>
|
||||
</button>
|
||||
<button mat-menu-item routerLink="comment-section">
|
||||
<mat-icon>speaker_notes</mat-icon>
|
||||
<span translate>Comment fields</span>
|
||||
</button>
|
||||
<button mat-menu-item routerLink="/tags" *osPerms="'core.can_manage_tags'">
|
||||
<mat-icon>local_offer</mat-icon>
|
||||
<span translate>Tags</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="csvExportMotionList()">
|
||||
<mat-icon>archive</mat-icon>
|
||||
<span translate>Export as CSV</span>
|
||||
</button>
|
||||
<button mat-menu-item *osPerms="'motions.can_manage'" routerLink="import">
|
||||
<mat-icon>save_alt</mat-icon>
|
||||
<span translate>Import</span><span> ...</span>
|
||||
</button>
|
||||
<div *ngIf="perms.isAllowed('change_metadata')">
|
||||
<button mat-menu-item (click)="toggleMultiSelect()">
|
||||
<mat-icon>library_add</mat-icon>
|
||||
<span translate>Multiselect</span>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="perms.isAllowed('manage')">
|
||||
<button mat-menu-item routerLink="call-list">
|
||||
<mat-icon>sort</mat-icon>
|
||||
<span translate>Call list</span>
|
||||
</button>
|
||||
<button mat-menu-item routerLink="category">
|
||||
<mat-icon>device_hub</mat-icon>
|
||||
<span translate>Categories</span>
|
||||
</button>
|
||||
<button mat-menu-item routerLink="blocks">
|
||||
<mat-icon>widgets</mat-icon>
|
||||
<span translate>Motion blocks</span>
|
||||
</button>
|
||||
<button mat-menu-item routerLink="statute-paragraphs" *ngIf="statutesEnabled">
|
||||
<mat-icon>account_balance</mat-icon>
|
||||
<span translate>Statute</span>
|
||||
</button>
|
||||
<button mat-menu-item routerLink="comment-section">
|
||||
<mat-icon>speaker_notes</mat-icon>
|
||||
<span translate>Comment fields</span>
|
||||
</button>
|
||||
<button mat-menu-item routerLink="/tags" *osPerms="'core.can_manage_tags'">
|
||||
<mat-icon>local_offer</mat-icon>
|
||||
<span translate>Tags</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="csvExportMotionList()">
|
||||
<mat-icon>archive</mat-icon>
|
||||
<span translate>Export as CSV</span>
|
||||
</button>
|
||||
<button mat-menu-item routerLink="import">
|
||||
<mat-icon>save_alt</mat-icon>
|
||||
<span translate>Import</span><span> ...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="isMultiSelect">
|
||||
<button mat-menu-item (click)="selectAll()">
|
||||
@ -175,7 +180,7 @@
|
||||
<mat-icon>clear</mat-icon>
|
||||
<span translate>Deselect all</span>
|
||||
</button>
|
||||
<div *osPerms="'motions.can_manage'">
|
||||
<div *ngIf="perms.isAllowed('change_metadata')">
|
||||
<mat-divider></mat-divider>
|
||||
<button mat-menu-item (click)="multiselectWrapper(multiselectService.setStateOfMultiple(selectedRows))">
|
||||
<mat-icon>label</mat-icon>
|
||||
@ -217,15 +222,17 @@
|
||||
<span translate>Move to agenda item</span>
|
||||
</button>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="red-warning-text"
|
||||
(click)="multiselectService.delete(selectedRows); toggleMultiSelect()"
|
||||
>
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span translate>Delete</span>
|
||||
</button>
|
||||
<div *ngIf="perms.isAllowed('manage')">
|
||||
<mat-divider></mat-divider>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="red-warning-text"
|
||||
(click)="multiselectService.delete(selectedRows); toggleMultiSelect()"
|
||||
>
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span translate>Delete</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-menu>
|
||||
</mat-drawer-container>
|
||||
|
||||
|
@ -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<ViewMotion> imple
|
||||
* @param userRepo
|
||||
* @param sortService
|
||||
* @param filterService
|
||||
* @param perms LocalPermissionService
|
||||
*/
|
||||
public constructor(
|
||||
titleService: Title,
|
||||
@ -90,7 +92,8 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
|
||||
private motionCsvExport: MotionCsvExportService,
|
||||
public multiselectService: MotionMultiselectService,
|
||||
public sortService: MotionSortListService,
|
||||
public filterService: MotionFilterListService
|
||||
public filterService: MotionFilterListService,
|
||||
public perms: LocalPermissionsService
|
||||
) {
|
||||
super(titleService, translate, matSnackBar);
|
||||
|
||||
|
@ -6,10 +6,13 @@
|
||||
<div *ngIf="poll.has_votes" class="on-transition-fade poll-result">
|
||||
<div *ngFor="let key of pollValues">
|
||||
<div class="poll-progress on-transition-fade" *ngIf="poll[key] !== undefined">
|
||||
<mat-icon class="main-nav-color" matTooltip="{{ getLabel(key) | translate }}"> {{ getIcon(key) }} </mat-icon>
|
||||
<mat-icon class="main-nav-color" matTooltip="{{ getLabel(key) | translate }}">
|
||||
{{ getIcon(key) }}
|
||||
</mat-icon>
|
||||
<div class="progress-container">
|
||||
<div>
|
||||
<span translate>{{ getLabel(key) }}</span>: {{ getNumber(key) }}
|
||||
<span translate>{{ getLabel(key) }}</span
|
||||
>: {{ getNumber(key) }}
|
||||
<span *ngIf="!isAbstractValue(key)">({{ getPercent(key) }}%)</span>
|
||||
</div>
|
||||
<div *ngIf="!isAbstractValue(key)" class="poll-progress-bar">
|
||||
@ -22,39 +25,53 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr *ngIf="key ==='abstain'" flex />
|
||||
<hr *ngIf="key === 'abstain'" flex />
|
||||
</div>
|
||||
<!-- quorum -->
|
||||
<div *ngIf="abstractPoll"><span translate>Quorum not calculable.</span></div>
|
||||
<div class="poll-quorum-line" *ngIf="!abstractPoll">
|
||||
<span>
|
||||
<span *ngIf="yesQuorum">
|
||||
<mat-icon color="warn" *ngIf="!quorumYesReached"> thumb_down </mat-icon>
|
||||
<mat-icon color="primary" *ngIf="quorumYesReached"> thumb_up </mat-icon>
|
||||
<div *osPerms="'motions.can_manage'">
|
||||
<div *ngIf="abstractPoll"><span translate>Quorum not calculable.</span></div>
|
||||
<div class="poll-quorum-line" *ngIf="!abstractPoll">
|
||||
<span>
|
||||
<span *ngIf="yesQuorum">
|
||||
<mat-icon color="warn" *ngIf="!quorumYesReached"> thumb_down </mat-icon>
|
||||
<mat-icon color="primary" *ngIf="quorumYesReached"> thumb_up </mat-icon>
|
||||
</span>
|
||||
<button mat-button [matMenuTriggerFor]="majorityMenu">
|
||||
<span translate>{{ getQuorumLabel() }}</span> <span
|
||||
*ngIf="majorityChoice !== 'disabled'"
|
||||
>({{ yesQuorum }})</span
|
||||
>
|
||||
</button>
|
||||
<span *ngIf="majorityChoice !== 'disabled'">
|
||||
<span *ngIf="quorumYesReached" translate> reached.</span>
|
||||
<span *ngIf="!quorumYesReached" translate> not reached.</span>
|
||||
</span>
|
||||
<span *ngIf="majorityChoice === 'disabled'"
|
||||
> — <span translate>No quorum calculated</span>
|
||||
</span>
|
||||
</span>
|
||||
<button mat-button [matMenuTriggerFor]="majorityMenu">
|
||||
<span translate>{{ getQuorumLabel() }}</span>
|
||||
<span *ngIf="majorityChoice !== 'disabled'">({{ yesQuorum }})</span>
|
||||
</button>
|
||||
<span *ngIf="majorityChoice !== 'disabled'">
|
||||
<span *ngIf="quorumYesReached" translate> reached.</span>
|
||||
<span *ngIf="!quorumYesReached" translate> not reached.</span>
|
||||
</span>
|
||||
<span *ngIf="majorityChoice === 'disabled'"
|
||||
> — <span translate>No quorum calculated</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container class="meta-text-block-action-row" *osPerms="'motions.can_manage'">
|
||||
<ng-container class="meta-text-block-action-row" *osPerms="'motions.can_manage_metadata'">
|
||||
<button mat-icon-button class="main-nav-color" matTooltip="{{ 'Edit poll' | translate }}" (click)="editPoll()">
|
||||
<mat-icon inline>edit</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button class="main-nav-color" matTooltip="{{ 'Print ballots' | translate }}" (click)="printBallots()">
|
||||
<button
|
||||
mat-icon-button
|
||||
class="main-nav-color"
|
||||
matTooltip="{{ 'Print ballots' | translate }}"
|
||||
(click)="printBallots()"
|
||||
>
|
||||
<mat-icon inline>local_printshop</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button class="main-nav-color" matTooltip="{{ 'Delete poll' | translate }}" (click)="deletePoll()">
|
||||
<button
|
||||
mat-icon-button
|
||||
class="main-nav-color"
|
||||
matTooltip="{{ 'Delete poll' | translate }}"
|
||||
(click)="deletePoll()"
|
||||
>
|
||||
<mat-icon inline>delete</mat-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -692,4 +692,13 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user