Merge pull request #3996 from FinnStutzenstein/client_perms_for_motion

can_manage_metadata and categories on motion create
This commit is contained in:
Jochen Saalfeld 2018-11-08 15:56:28 +01:00 committed by GitHub
commit a2d736bae9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 109 additions and 43 deletions

View File

@ -1,6 +1,6 @@
import { Component, OnInit, Input, ViewChild } from '@angular/core';
import { Component, OnInit, Input, ViewChild, OnDestroy } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { Subject, ReplaySubject, BehaviorSubject } from 'rxjs';
import { Subject, ReplaySubject, BehaviorSubject, Subscription } from 'rxjs';
import { MatSelect } from '@angular/material';
import { takeUntil } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core';
@ -35,7 +35,7 @@ import { Selectable } from '../selectable';
templateUrl: './search-value-selector.component.html',
styleUrls: ['./search-value-selector.component.scss']
})
export class SearchValueSelectorComponent implements OnInit {
export class SearchValueSelectorComponent implements OnInit, OnDestroy {
/**
* ngModel variable - Deprecated with Angular 7
* DO NOT USE: READ AT remove() FUNCTION!
@ -52,6 +52,16 @@ export class SearchValueSelectorComponent implements OnInit {
*/
public filteredItems: ReplaySubject<Selectable[]> = new ReplaySubject<Selectable[]>(1);
/**
* The inputlist subject.
*/
private _inputListSubject: BehaviorSubject<Selectable[]>;
/**
* Saves the current subscription to _inputListSubject.
*/
private _inputListSubscription: Subscription = null;
/**
* Decide if this should be a single or multi-select-field
*/
@ -59,10 +69,20 @@ export class SearchValueSelectorComponent implements OnInit {
public multiple: boolean;
/**
* The Input List Values
* The inputlist subject. Subscribes to it and updates the selector, if the subject
* changes its values.
*/
@Input()
public InputListValues: BehaviorSubject<Selectable[]>;
public set InputListValues(value: BehaviorSubject<Selectable[]>) {
// unsubscribe to old subscription.
if (this._inputListSubscription) {
this._inputListSubscription.unsubscribe();
}
this._inputListSubject = value;
this._inputListSubscription = this._inputListSubject.subscribe(values => {
this.filterItems();
});
}
/**
* Placeholder of the List
@ -111,31 +131,43 @@ export class SearchValueSelectorComponent implements OnInit {
* onInit with filter ans subscription on filter
*/
public ngOnInit(): void {
this.filteredItems.next(this.InputListValues.getValue());
if (this._inputListSubject) {
this.filteredItems.next(this._inputListSubject.getValue());
}
// listen to value changes
this.filterControl.valueChanges.pipe(takeUntil(this._onDestroy)).subscribe(() => {
this.filterItems();
});
}
/**
* Unsubscribe on destroing.
*/
public ngOnDestroy(): void {
if (this._inputListSubscription) {
this._inputListSubscription.unsubscribe();
}
this._onDestroy.next();
}
/**
* the filter function itself
*/
private filterItems(): void {
if (!this.InputListValues) {
if (!this._inputListSubject) {
return;
}
// get the search keyword
let search = this.filterControl.value;
if (!search) {
this.filteredItems.next(this.InputListValues.getValue());
this.filteredItems.next(this._inputListSubject.getValue());
return;
} else {
search = search.toLowerCase();
}
// filter the values
this.filteredItems.next(
this.InputListValues.getValue().filter(
this._inputListSubject.getValue().filter(
selectedItem =>
selectedItem
.toString()

View File

@ -39,6 +39,13 @@ export class PermsDirective extends OpenSlidesComponent {
*/
private alternative: boolean;
/**
* Switch, to invert the result of checkPermission. Usefull for using osPerms as if-else:
* For one element you can use `*osPerms="'perm'"` and for the else-element use
* `*osPerms="'perm';complement: true"`.
*/
private complement: boolean;
/**
* Constructs the directive once. Observes the operator for it's groups so the
* directive can perform changes dynamically
@ -85,6 +92,15 @@ export class PermsDirective extends OpenSlidesComponent {
this.updateView();
}
/**
* COmes from the view.
*/
@Input('osPermsComplement')
public set osPermsComplement(value: boolean) {
this.complement = value;
this.updateView();
}
/**
* Shows or hides certain content in the view.
*/
@ -108,6 +124,11 @@ export class PermsDirective extends OpenSlidesComponent {
* Returns true if the users permissions fit.
*/
private checkPermissions(): boolean {
return this.permissions.length === 0 || this.operator.hasPerms(...this.permissions);
const hasPerms = this.permissions.length === 0 || this.operator.hasPerms(...this.permissions);
if (this.complement) {
return !hasPerms;
} else {
return hasPerms;
}
}
}

View File

@ -94,8 +94,8 @@
</div>
</mat-expansion-panel>
<os-motion-comments [motion]="motion"></os-motion-comments>
<os-personal-note [motion]="motion"></os-personal-note>
<os-motion-comments *ngIf="!newMotion" [motion]="motion"></os-motion-comments>
<os-personal-note *ngIf="!newMotion" [motion]="motion"></os-personal-note>
<!-- Content -->
<mat-expansion-panel #contentPanel [expanded]='true'>
@ -122,8 +122,8 @@
<ng-container *ngTemplateOutlet="metaInfoTemplate"></ng-container>
</div>
<os-motion-comments [motion]="motion"></os-motion-comments>
<os-personal-note [motion]="motion"></os-personal-note>
<os-motion-comments *ngIf="!newMotion" [motion]="motion"></os-motion-comments>
<os-personal-note *ngIf="!newMotion" [motion]="motion"></os-personal-note>
</div>
<div class="desktop-right ">
@ -153,8 +153,8 @@
<!-- Submitter -->
<div *ngIf="motion && motion.submitters || editMotion">
<div *ngIf="editMotion && newMotion">
<div *ngIf="motion && editMotion">
<div *ngIf="editMotion">
<div *osPerms="['motions.can_manage', 'motions.can_manage_metadata']">
<os-search-value-selector ngDefaultControl [form]="metaInfoForm" [formControl]="this.metaInfoForm.get('submitters_id')"
[multiple]="true" listname="Submitter" [InputListValues]="this.submitterObserver"></os-search-value-selector>
</div>
@ -171,7 +171,7 @@
<div *ngIf='motion && motion.hasSupporters() || editMotion'>
<!-- print all motion supporters -->
<div *ngIf="editMotion">
<div *ngIf="motion && editMotion">
<div *osPerms="['motions.can_manage', 'motions.can_manage_metadata']">
<os-search-value-selector ngDefaultControl [form]="metaInfoForm" [formControl]="this.metaInfoForm.get('supporters_id')"
[multiple]="true" listname="Supporter" [InputListValues]="this.supporterObserver"></os-search-value-selector>
</div>
@ -179,24 +179,33 @@
<div *ngIf="!editMotion && motion.hasSupporters()">
<h3 translate>Supporters</h3>
<ul *ngFor="let supporter of motion.supporters">
<li>{{supporter.full_name}}</li>
<li>{{ supporter.full_name }}</li>
</ul>
</div>
</div>
<!-- State -->
<div *ngIf='motion && motion.state'>
<mat-form-field *ngIf="!editMotion && !newMotion">
<mat-select placeholder='State' formControlName='state_id' (selectionChange)="onChangeState($event)">
<mat-option [value]="motion.state_id">{{motion.state}}</mat-option>
<mat-divider></mat-divider>
<mat-option *ngFor="let state of motion.nextStates" [value]="state.id">{{state}}</mat-option>
<mat-divider></mat-divider>
<mat-option [value]="null">
<mat-icon>replay</mat-icon><span translate>Reset State</span>
</mat-option>
</mat-select>
</mat-form-field>
<div *osPerms="['motions.can_manage', 'motions.can_manage_metadata'];complement:true">
<ng-container *ngIf="!newMotion">
<h3 translate>State</h3>
{{ motion.state }}
</ng-container>
</div>
<div *ngIf="!editMotion">
<mat-form-field *osPerms="['motions.can_manage', 'motions.can_manage_metadata']">
<mat-select placeholder='State' formControlName='state_id' (selectionChange)="onChangeState($event)">
<mat-option [value]="motion.state_id">{{ motion.state }}</mat-option>
<mat-divider></mat-divider>
<mat-option *ngFor="let state of motion.nextStates" [value]="state.id">{{ state }}</mat-option>
<mat-divider></mat-divider>
<mat-option [value]="null">
<mat-icon>replay</mat-icon>
<span translate>Reset State</span>
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<!-- Recommendation -->
@ -204,7 +213,7 @@
<div *ngIf='motion && motion.state && recommender'>
<mat-form-field *ngIf="!editMotion && !newMotion">
<mat-select [placeholder]=recommender formControlName='recommendation_id' (selectionChange)="onChangerRecommenderState($event)">
<mat-option *ngFor="let state of motion.possibleRecommendations" [value]="state.id">{{state}}</mat-option>
<mat-option *ngFor="let recommendation of motion.possibleRecommendations" [value]="recommendation.id">{{ recommendation }}</mat-option>
</mat-select>
</mat-form-field>
</div>
@ -215,7 +224,7 @@
<h3 translate>Category</h3>
{{motion.category}}
</div>
<div *ngIf="editMotion">
<div *ngIf="editMotion || newMotion">
<os-search-value-selector ngDefaultControl [form]="metaInfoForm" [formControl]="this.metaInfoForm.get('category_id')"
[multiple]="false" listname="Category" [InputListValues]="this.categoryObserver"></os-search-value-selector>
</div>
@ -225,11 +234,13 @@
<div *ngIf="motion && motion.origin || editMotion">
<div *ngIf='!editMotion'>
<h3 translate> Origin</h3>
{{motion.origin}}
{{ motion.origin }}
</div>
<div *osPerms="['motions.can_manage', 'motions.can_manage_metadata']">
<mat-form-field *ngIf="editMotion">
<input matInput placeholder='Origin' formControlName='origin' [value]='motionCopy.origin'>
</mat-form-field>
</div>
<mat-form-field *ngIf="editMotion">
<input matInput placeholder='Origin' formControlName='origin' [value]='motionCopy.origin'>
</mat-form-field>
</div>
<!-- Voting -->
@ -258,7 +269,8 @@
<h4>{{motion.title}}</h4>
</div>
<mat-form-field *ngIf="editMotion" class="wide-form">
<input matInput osAutofocus placeholder='Title' formControlName='title' [value]='motionCopy.title'>
<input matInput osAutofocus placeholder='Title' formControlName='title' [value]='motionCopy.title'
required>
</mat-form-field>
</div>
@ -278,7 +290,7 @@
[scrollToChange]="scrollToChange" (createChangeRecommendation)="createChangeRecommendation($event)"></os-motion-detail-diff>
</ng-container>
<mat-form-field *ngIf="motion && editMotion" class="wide-form">
<textarea matInput placeholder='Motion Text' formControlName='text' [value]='motionCopy.text'></textarea>
<textarea matInput placeholder='Motion Text' formControlName='text' [value]='motionCopy.text' required></textarea>
</mat-form-field>

View File

@ -105,17 +105,17 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
/**
* Subject for the Categories
*/
public categoryObserver: BehaviorSubject<Array<Category>>;
public categoryObserver: BehaviorSubject<Category[]>;
/**
* Subject for the Submitters
*/
public submitterObserver: BehaviorSubject<Array<User>>;
public submitterObserver: BehaviorSubject<User[]>;
/**
* Subject for the Supporters
*/
public supporterObserver: BehaviorSubject<Array<User>>;
public supporterObserver: BehaviorSubject<User[]>;
/**
* Value for os-motion-detail-diff: when this is set, that component scrolls to the given change
@ -503,7 +503,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
* Determine if the user has the correct requirements to alter the motion
*/
public opCanEdit(): boolean {
return this.op.hasPerms('motions.can_manage');
return this.op.hasPerms('motions.can_manage', 'motions.can_manage_metadata');
}
/**

View File

@ -134,14 +134,15 @@ class MotionViewSet(ModelViewSet):
'title',
'text',
'reason',
'category_id',
]
if parent_motion is not None:
# For creating amendments.
whitelist.extend([
'parent_id',
'amendment_paragraphs',
'category_id', # This will be set to the matching
'motion_block_id', # values from parent_motion.
'motion_block_id', # This and the category_id will be set to the matching
# values from parent_motion.
])
request.data['category_id'] = parent_motion.category_id
request.data['motion_block_id'] = parent_motion.motion_block_id