this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS)
) {
if (
- this.permissionsService.currentUserCan({
- action: PermissionAction.View,
- type: PermissionType.Document,
- })
+ this.permissionsService.currentUserCan(
+ PermissionAction.View,
+ PermissionType.Document
+ )
) {
this.toastService.show({
title: $localize`Document added`,
public get dragDropEnabled(): boolean {
return (
!this.router.url.includes('dashboard') &&
- this.permissionsService.currentUserCan({
- action: PermissionAction.Add,
- type: PermissionType.Document,
- })
+ this.permissionsService.currentUserCan(
+ PermissionAction.Add,
+ PermissionType.Document
+ )
)
}
import { PermissionsSelectComponent } from './components/common/permissions-select/permissions-select.component'
import { MailAccountEditDialogComponent } from './components/common/edit-dialog/mail-account-edit-dialog/mail-account-edit-dialog.component'
import { MailRuleEditDialogComponent } from './components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component'
+import { PermissionsUserComponent } from './components/common/input/permissions-user/permissions-user.component'
+import { PermissionsGroupComponent } from './components/common/input/permissions-group/permissions-group.component'
+import { IfOwnerDirective } from './directives/if-owner.directive'
+import { IfObjectPermissionsDirective } from './directives/if-object-permissions.directive'
import localeBe from '@angular/common/locales/be'
import localeCs from '@angular/common/locales/cs'
import localeSv from '@angular/common/locales/sv'
import localeTr from '@angular/common/locales/tr'
import localeZh from '@angular/common/locales/zh'
-import { ShareUserComponent } from './components/common/input/share-user/share-user.component'
-import { IfOwnerDirective } from './directives/if-owner.directive'
-import { IfObjectPermissionsDirective } from './directives/if-object-permissions.directive'
registerLocaleData(localeBe)
registerLocaleData(localeCs)
PermissionsSelectComponent,
MailAccountEditDialogComponent,
MailRuleEditDialogComponent,
- ShareUserComponent,
+ PermissionsUserComponent,
+ PermissionsGroupComponent,
IfOwnerDirective,
IfObjectPermissionsDirective,
],
<app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text>
<app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive" novalidate></app-input-check>
- <div *ifOwner="object?.owner">
+ <div *ifOwner="object">
<h5 i18n>Permissions</h5>
<div formGroupName="set_permissions">
- <app-share-user type="view" formControlName="view"></app-share-user>
- <app-share-user type="change" formControlName="change"></app-share-user>
+ <h6 i18n>View</h6>
+ <div formGroupName="view">
+ <app-permissions-user type="view" formControlName="users"></app-permissions-user>
+ <app-permissions-group type="view" formControlName="groups"></app-permissions-group>
+ </div>
+ <h6 i18n>Edit</h6>
+ <div formGroupName="change">
+ <app-permissions-user type="change" formControlName="users"></app-permissions-user>
+ <app-permissions-group type="change" formControlName="groups"></app-permissions-group>
+ </div>
</div>
</div>
match: new FormControl(''),
is_insensitive: new FormControl(true),
set_permissions: new FormGroup({
- view: new FormControl(null),
- change: new FormControl(null),
+ view: new FormGroup({
+ users: new FormControl(null),
+ groups: new FormControl(null),
+ }),
+ change: new FormGroup({
+ users: new FormControl(null),
+ groups: new FormControl(null),
+ }),
}),
})
}
<app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text>
<app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive"></app-input-check>
- <div *ifOwner="object?.owner">
+ <div *ifOwner="object">
<h5 i18n>Permissions</h5>
<div formGroupName="set_permissions">
- <app-share-user type="view" formControlName="view"></app-share-user>
- <app-share-user type="change" formControlName="change"></app-share-user>
+ <h6 i18n>View</h6>
+ <div formGroupName="view">
+ <app-permissions-user type="view" formControlName="users"></app-permissions-user>
+ <app-permissions-group type="view" formControlName="groups"></app-permissions-group>
+ </div>
+ <h6 i18n>Edit</h6>
+ <div formGroupName="change">
+ <app-permissions-user type="change" formControlName="users"></app-permissions-user>
+ <app-permissions-group type="change" formControlName="groups"></app-permissions-group>
+ </div>
</div>
</div>
match: new FormControl(''),
is_insensitive: new FormControl(true),
set_permissions: new FormGroup({
- view: new FormControl(null),
- change: new FormControl(null),
+ view: new FormGroup({
+ users: new FormControl(null),
+ groups: new FormControl(null),
+ }),
+ change: new FormGroup({
+ users: new FormControl(null),
+ groups: new FormControl(null),
+ }),
}),
})
}
ngOnInit(): void {
if (this.object != null) {
if (this.object['permissions']) {
- this.object['set_permissions'] = {
- view: (this.object as ObjectWithPermissions).permissions
- .filter((p) => (p[1] as string).includes('view'))
- .map((p) => p[0]),
- change: (this.object as ObjectWithPermissions).permissions
- .filter((p) => (p[1] as string).includes('change'))
- .map((p) => p[0]),
- }
+ this.object['set_permissions'] = this.object['permissions']
}
this.objectForm.patchValue(this.object)
}
<app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text>
<app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive"></app-input-check>
- <div *ifOwner="object?.owner">
+ <div *ifOwner="object">
<h5 i18n>Permissions</h5>
<div formGroupName="set_permissions">
- <app-share-user type="view" formControlName="view"></app-share-user>
- <app-share-user type="change" formControlName="change"></app-share-user>
+ <h6 i18n>View</h6>
+ <div formGroupName="view">
+ <app-permissions-user type="view" formControlName="users"></app-permissions-user>
+ <app-permissions-group type="view" formControlName="groups"></app-permissions-group>
+ </div>
+ <h6 i18n>Edit</h6>
+ <div formGroupName="change">
+ <app-permissions-user type="change" formControlName="users"></app-permissions-user>
+ <app-permissions-group type="change" formControlName="groups"></app-permissions-group>
+ </div>
</div>
</div>
match: new FormControl(''),
is_insensitive: new FormControl(true),
set_permissions: new FormGroup({
- view: new FormControl(null),
- change: new FormControl(null),
+ view: new FormGroup({
+ users: new FormControl(null),
+ groups: new FormControl(null),
+ }),
+ change: new FormGroup({
+ users: new FormControl(null),
+ groups: new FormControl(null),
+ }),
}),
})
}
<app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text>
<app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive"></app-input-check>
- <div *ifOwner="object?.owner">
+ <div *ifOwner="object">
<h5 i18n>Permissions</h5>
<div formGroupName="set_permissions">
- <app-share-user type="view" formControlName="view"></app-share-user>
- <app-share-user type="change" formControlName="change"></app-share-user>
+ <h6 i18n>View</h6>
+ <div formGroupName="view">
+ <app-permissions-user type="view" formControlName="users"></app-permissions-user>
+ <app-permissions-group type="view" formControlName="groups"></app-permissions-group>
+ </div>
+ <h6 i18n>Edit</h6>
+ <div formGroupName="change">
+ <app-permissions-user type="change" formControlName="users"></app-permissions-user>
+ <app-permissions-group type="change" formControlName="groups"></app-permissions-group>
+ </div>
</div>
</div>
match: new FormControl(''),
is_insensitive: new FormControl(true),
set_permissions: new FormGroup({
- view: new FormControl(null),
- change: new FormControl(null),
+ view: new FormGroup({
+ users: new FormControl(null),
+ groups: new FormControl(null),
+ }),
+ change: new FormGroup({
+ users: new FormControl(null),
+ groups: new FormControl(null),
+ }),
}),
})
}
--- /dev/null
+<div class="mb-3 paperless-input-select">
+ <label class="form-label" [for]="inputId">{{title}}</label>
+ <div>
+ <ng-select name="inputId" [(ngModel)]="value"
+ [disabled]="disabled"
+ clearable="true"
+ [items]="groups"
+ multiple="true"
+ bindLabel="name"
+ bindValue="id"
+ (change)="onChange(value)">
+ </ng-select>
+ </div>
+ <small *ngIf="hint" class="form-text text-muted">{{hint}}</small>
+ </div>
--- /dev/null
+import { Component, forwardRef, Input, OnInit } from '@angular/core'
+import { NG_VALUE_ACCESSOR } from '@angular/forms'
+import { first } from 'rxjs/operators'
+import { PaperlessGroup } from 'src/app/data/paperless-group'
+import { GroupService } from 'src/app/services/rest/group.service'
+import { SettingsService } from 'src/app/services/settings.service'
+import { AbstractInputComponent } from '../abstract-input'
+
+@Component({
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => PermissionsGroupComponent),
+ multi: true,
+ },
+ ],
+ selector: 'app-permissions-group',
+ templateUrl: './permissions-group.component.html',
+ styleUrls: ['./permissions-group.component.scss'],
+})
+export class PermissionsGroupComponent
+ extends AbstractInputComponent<PaperlessGroup>
+ implements OnInit
+{
+ groups: PaperlessGroup[]
+
+ @Input()
+ type: string
+
+ constructor(groupService: GroupService, settings: SettingsService) {
+ super()
+ groupService
+ .listAll()
+ .pipe(first())
+ .subscribe((result) => (this.groups = result.results))
+ }
+
+ ngOnInit(): void {
+ if (this.type == 'view') {
+ this.title = $localize`Groups can view`
+ } else if (this.type == 'change') {
+ this.title = $localize`Groups can edit`
+ this.hint = $localize`Edit permissions also grant viewing permissions`
+ }
+
+ super.ngOnInit()
+ }
+}
import { first } from 'rxjs/operators'
import { PaperlessUser } from 'src/app/data/paperless-user'
import { UserService } from 'src/app/services/rest/user.service'
+import { SettingsService } from 'src/app/services/settings.service'
import { AbstractInputComponent } from '../abstract-input'
@Component({
providers: [
{
provide: NG_VALUE_ACCESSOR,
- useExisting: forwardRef(() => ShareUserComponent),
+ useExisting: forwardRef(() => PermissionsUserComponent),
multi: true,
},
],
- selector: 'app-share-user',
- templateUrl: './share-user.component.html',
- styleUrls: ['./share-user.component.scss'],
+ selector: 'app-permissions-user',
+ templateUrl: './permissions-user.component.html',
+ styleUrls: ['./permissions-user.component.scss'],
})
-export class ShareUserComponent
+export class PermissionsUserComponent
extends AbstractInputComponent<PaperlessUser>
implements OnInit
{
@Input()
type: string
- constructor(userService: UserService) {
+ constructor(userService: UserService, settings: SettingsService) {
super()
userService
.listAll()
.pipe(first())
- .subscribe((result) => (this.users = result.results))
+ .subscribe(
+ (result) =>
+ (this.users = result.results.filter(
+ (u) => u.id !== settings.currentUser.id
+ ))
+ )
}
ngOnInit(): void {
if (this._inheritedPermissions.length == 0) return false
else if (actionKey) {
return this._inheritedPermissions.includes(
- this.permissionsService.getPermissionCode({
- action: PermissionAction[actionKey],
- type: PermissionType[typeKey],
- })
+ this.permissionsService.getPermissionCode(
+ PermissionAction[actionKey],
+ PermissionType[typeKey]
+ )
)
} else {
return Object.values(PermissionAction).every((action) => {
return this._inheritedPermissions.includes(
- this.permissionsService.getPermissionCode({
- action: action as PermissionAction,
- type: PermissionType[typeKey],
- })
+ this.permissionsService.getPermissionCode(
+ action as PermissionAction,
+ PermissionType[typeKey]
+ )
)
})
}
<div class="input-group-text" i18n>of {{previewNumPages}}</div>
</div>
- <button *ifOwner="document?.owner" type="button" class="btn btn-sm btn-outline-danger me-2 ms-auto" (click)="delete()">
+ <button *ifOwner="document" type="button" class="btn btn-sm btn-outline-danger me-2 ms-auto" (click)="delete()">
<svg class="buttonicon" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#trash" />
</svg><span class="d-none d-lg-inline ps-1" i18n>Delete</span>
</div>
- <button *ifOwner="document?.owner" type="button" class="btn btn-sm btn-outline-primary me-2" (click)="redoOcr()">
+ <button *ifOwner="document" type="button" class="btn btn-sm btn-outline-primary me-2" (click)="redoOcr()">
<svg class="buttonicon" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#arrow-counterclockwise" />
</svg><span class="d-none d-lg-inline ps-1" i18n>Redo OCR</span>
</ng-template>
</li>
- <li [ngbNavItem]="6" *ifOwner="document?.owner">
+ <li [ngbNavItem]="6" *ifOwner="document">
<a ngbNavLink i18n>Permissions</a>
<ng-template ngbNavContent>
<div formGroupName="set_permissions">
- <app-share-user type="view" formControlName="view"></app-share-user>
- <app-share-user type="change" formControlName="change"></app-share-user>
+ <h6 i18n>View</h6>
+ <div formGroupName="view">
+ <app-permissions-user type="view" formControlName="users"></app-permissions-user>
+ <app-permissions-group type="view" formControlName="groups"></app-permissions-group>
+ </div>
+ <h6 i18n>Edit</h6>
+ <div formGroupName="change">
+ <app-permissions-user type="change" formControlName="users"></app-permissions-user>
+ <app-permissions-group type="change" formControlName="groups"></app-permissions-group>
+ </div>
</div>
</ng-template>
</li>
<div [ngbNavOutlet]="nav" class="mt-2"></div>
- <ng-container action="PermissionAction.Change" *ifObjectPermissions="document">
+ <ng-container *ifObjectPermissions="{ object: document, action: PermissionAction.Change }">
<button type="button" class="btn btn-outline-secondary" (click)="discard()" i18n [disabled]="networkActive || !(isDirty$ | async)">Discard</button>
<button type="button" class="btn btn-outline-primary" (click)="saveEditNext()" *ngIf="hasNext()" i18n [disabled]="networkActive || !(isDirty$ | async) || error">Save & next</button>
<button type="submit" class="btn btn-primary" *ifPermissions="{ action: PermissionAction.Change, type: PermissionType.Document }" i18n [disabled]="networkActive || !(isDirty$ | async) || error">Save</button>
archive_serial_number: new FormControl(),
tags: new FormControl([]),
set_permissions: new FormGroup({
- view: new FormControl(null),
- change: new FormControl(null),
+ view: new FormGroup({
+ users: new FormControl(null),
+ groups: new FormControl(null),
+ }),
+ change: new FormGroup({
+ users: new FormControl(null),
+ groups: new FormControl(null),
+ }),
}),
})
storage_path: doc.storage_path,
archive_serial_number: doc.archive_serial_number,
tags: [...doc.tags],
- set_permissions: {
- view: doc.permissions
- .filter((p) => (p[1] as string).includes('view'))
- .map((p) => p[0]),
- change: doc.permissions
- .filter((p) => (p[1] as string).includes('change'))
- .map((p) => p[0]),
- },
+ set_permissions: doc.permissions,
})
this.isDirty$ = dirtyCheck(
},
})
this.title = this.documentTitlePipe.transform(doc.title)
- doc['set_permissions'] = {
- view: doc.permissions
- .filter((p) => (p[1] as string).includes('view'))
- .map((p) => p[0]),
- change: doc.permissions
- .filter((p) => (p[1] as string).includes('change'))
- .map((p) => p[0]),
- }
+ doc['set_permissions'] = doc.permissions
this.documentForm.patchValue(doc)
if (!this.userCanEdit) this.documentForm.disable()
}
get commentsEnabled(): boolean {
return (
this.settings.get(SETTINGS_KEYS.COMMENTS_ENABLED) &&
- this.permissionsService.currentUserCan({
- action: PermissionAction.View,
- type: PermissionType.Document,
- })
+ this.permissionsService.currentUserCan(
+ PermissionAction.View,
+ PermissionType.Document
+ )
)
}
}
userCanDelete(object: ObjectWithPermissions): boolean {
- return (
- !object.owner || this.permissionsService.currentUserIsOwner(object.owner)
- )
+ return this.permissionsService.currentUserOwnsObject(object)
}
userCanEdit(object: ObjectWithPermissions): boolean {
import { ObjectWithId } from './object-with-id'
import { PaperlessUser } from './paperless-user'
+export interface PermissionsObject {
+ view: {
+ users: Array<number>
+ groups: Array<number>
+ }
+ change: {
+ users: Array<number>
+ groups: Array<number>
+ }
+}
+
export interface ObjectWithPermissions extends ObjectWithId {
owner?: PaperlessUser
- permissions?: Array<[number, string]>
+ permissions?: PermissionsObject
}
import {
Directive,
+ EmbeddedViewRef,
Input,
OnChanges,
OnInit,
export class IfObjectPermissionsDirective implements OnInit, OnChanges {
// The role the user must have
@Input()
- ifObjectPermissions: ObjectWithPermissions
+ ifObjectPermissions: {
+ object: ObjectWithPermissions
+ action: PermissionAction
+ }
- @Input()
- action: PermissionAction
+ createdView: EmbeddedViewRef<any>
/**
* @param {ViewContainerRef} viewContainerRef -- The location where we need to render the templateRef
public ngOnInit(): void {
if (
- !this.ifObjectPermissions ||
+ !this.ifObjectPermissions?.object ||
this.permissionsService.currentUserHasObjectPermissions(
- this.action,
- this.ifObjectPermissions
+ this.ifObjectPermissions.action,
+ this.ifObjectPermissions.object
)
) {
- this.viewContainerRef.createEmbeddedView(this.templateRef)
+ if (!this.createdView)
+ this.createdView = this.viewContainerRef.createEmbeddedView(
+ this.templateRef
+ )
} else {
this.viewContainerRef.clear()
}
import {
Directive,
+ EmbeddedViewRef,
Input,
OnChanges,
OnInit,
TemplateRef,
ViewContainerRef,
} from '@angular/core'
-import { PaperlessUser } from '../data/paperless-user'
+import { ObjectWithPermissions } from '../data/object-with-permissions'
import { PermissionsService } from '../services/permissions.service'
@Directive({
export class IfOwnerDirective implements OnInit, OnChanges {
// The role the user must have
@Input()
- ifOwner: PaperlessUser
+ ifOwner: ObjectWithPermissions
+
+ createdView: EmbeddedViewRef<any>
/**
* @param {ViewContainerRef} viewContainerRef -- The location where we need to render the templateRef
) {}
public ngOnInit(): void {
- if (
- !this.ifOwner ||
- this.permissionsService.currentUserIsOwner(this.ifOwner)
- ) {
- this.viewContainerRef.createEmbeddedView(this.templateRef)
+ if (this.permissionsService.currentUserOwnsObject(this.ifOwner)) {
+ if (!this.createdView)
+ this.createdView = this.viewContainerRef.createEmbeddedView(
+ this.templateRef
+ )
} else {
this.viewContainerRef.clear()
}
TemplateRef,
} from '@angular/core'
import {
- PaperlessPermission,
+ PermissionAction,
PermissionsService,
+ PermissionType,
} from '../services/permissions.service'
@Directive({
selector: '[ifPermissions]',
})
export class IfPermissionsDirective implements OnInit {
- // The role the user must have
@Input()
- ifPermissions: Array<PaperlessPermission> | PaperlessPermission
+ ifPermissions:
+ | Array<{ action: PermissionAction; type: PermissionType }>
+ | { action: PermissionAction; type: PermissionType }
/**
* @param {ViewContainerRef} viewContainerRef -- The location where we need to render the templateRef
if (
[]
.concat(this.ifPermissions)
- .every((perm: PaperlessPermission) =>
- this.permissionsService.currentUserCan(perm)
+ .every((perm: { action: PermissionAction; type: PermissionType }) =>
+ this.permissionsService.currentUserCan(perm.action, perm.type)
)
) {
this.viewContainerRef.createEmbeddedView(this.templateRef)
state: RouterStateSnapshot
): boolean | UrlTree {
if (
- !this.permissionsService.currentUserCan(route.data.requiredPermission)
+ !this.permissionsService.currentUserCan(
+ route.data.requiredPermission.action,
+ route.data.requiredPermission.type
+ )
) {
this.toastService.showError(
$localize`You don't have permissions to do that`
Admin = '%s_logentry',
}
-export interface PaperlessPermission {
- action: PermissionAction
- type: PermissionType
-}
-
@Injectable({
providedIn: 'root',
})
this.currentUser = currentUser
}
- public currentUserCan(permission: PaperlessPermission): boolean {
- return this.permissions.includes(this.getPermissionCode(permission))
+ public currentUserCan(
+ action: PermissionAction,
+ type: PermissionType
+ ): boolean {
+ return this.permissions.includes(this.getPermissionCode(action, type))
}
- public currentUserIsOwner(owner: PaperlessUser): boolean {
- return owner?.id === this.currentUser.id
+ public currentUserOwnsObject(object: ObjectWithPermissions): boolean {
+ return !object || !object.owner || object.owner.id === this.currentUser.id
}
public currentUserHasObjectPermissions(
action: string,
object: ObjectWithPermissions
): boolean {
- return (object.permissions[action] as Array<number>)?.includes(
- this.currentUser.id
+ return (
+ this.currentUserOwnsObject(object) ||
+ (object.permissions[action]['users'] as Array<number>)?.includes(
+ this.currentUser.id
+ )
)
}
- public getPermissionCode(permission: PaperlessPermission): string {
- return permission.type.replace('%s', permission.action)
+ public getPermissionCode(
+ action: PermissionAction,
+ type: PermissionType
+ ): string {
+ return type.replace('%s', action)
}
public getPermissionKeys(permissionStr: string): {
from .models import PaperlessTask
from .parsers import is_mime_type_supported
-from guardian.models import UserObjectPermission
+from guardian.models import GroupObjectPermission
from guardian.shortcuts import assign_perm
from guardian.shortcuts import remove_perm
from guardian.shortcuts import get_users_with_perms
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User
+from django.contrib.auth.models import Group
+from django.contrib.auth.models import Permission
# https://www.django-rest-framework.org/api-guide/serializers/#example
return match
+def get_groups_with_only_permission(obj, codename):
+ ctype = ContentType.objects.get_for_model(obj)
+ permission = Permission.objects.get(content_type=ctype, codename=codename)
+ group_object_perm_group_ids = (
+ GroupObjectPermission.objects.filter(
+ object_pk=obj.pk,
+ content_type=ctype,
+ )
+ .filter(permission=permission)
+ .values_list("group_id")
+ )
+ return Group.objects.filter(id__in=group_object_perm_group_ids).distinct()
+
+
class OwnedObjectSerializer(serializers.ModelSerializer):
def get_permissions(self, obj):
- content_type = ContentType.objects.get_for_model(obj)
- user_object_perms = UserObjectPermission.objects.filter(
- object_pk=obj.pk,
- content_type=content_type,
- ).values_list("user", "permission__codename")
- return list(user_object_perms)
+ view_codename = f"view_{obj.__class__.__name__.lower()}"
+ change_codename = f"change_{obj.__class__.__name__.lower()}"
+ return {
+ "view": {
+ "users": get_users_with_perms(
+ obj,
+ only_with_perms_in=[view_codename],
+ ).values_list("id", flat=True),
+ "groups": get_groups_with_only_permission(
+ obj,
+ codename=view_codename,
+ ).values_list("id", flat=True),
+ },
+ "change": {
+ "users": get_users_with_perms(
+ obj,
+ only_with_perms_in=[change_codename],
+ ).values_list("id", flat=True),
+ "groups": get_groups_with_only_permission(
+ obj,
+ codename=change_codename,
+ ).values_list("id", flat=True),
+ },
+ }
permissions = SerializerMethodField(read_only=True)
)
return users
+ def _validate_group_ids(self, group_ids):
+ groups = Group.objects.none()
+ if group_ids is not None:
+ groups = Group.objects.filter(id__in=group_ids)
+ if not groups.count() == len(group_ids):
+ raise serializers.ValidationError(
+ "Some groups in don't exist or were specified twice.",
+ )
+ return groups
+
def validate_set_permissions(self, set_permissions):
- user_dict = {
- "view": User.objects.none(),
- "change": User.objects.none(),
+ permissions_dict = {
+ "view": {
+ "users": User.objects.none(),
+ "groups": Group.objects.none(),
+ },
+ "change": {
+ "users": User.objects.none(),
+ "groups": Group.objects.none(),
+ },
}
if set_permissions is not None:
- if "view" in set_permissions:
- view_list = set_permissions["view"]
- user_dict["view"] = self._validate_user_ids(view_list)
- if "change" in set_permissions:
- change_list = set_permissions["change"]
- user_dict["change"] = self._validate_user_ids(change_list)
- return user_dict
+ for action in permissions_dict:
+ users = set_permissions[action]["users"]
+ permissions_dict[action]["users"] = self._validate_user_ids(users)
+ groups = set_permissions[action]["groups"]
+ permissions_dict[action]["groups"] = self._validate_group_ids(groups)
+ return permissions_dict
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user", None)
def _set_permissions(self, permissions, object):
for action in permissions:
permission = f"{action}_{object.__class__.__name__.lower()}"
- users_to_add = permissions[action]
+ # users
+ users_to_add = permissions[action]["users"]
users_to_remove = get_users_with_perms(
object,
only_with_perms_in=[permission],
user,
object,
)
+ # groups
+ groups_to_add = permissions[action]["groups"]
+ groups_to_remove = get_groups_with_only_permission(
+ object,
+ permission,
+ ).difference(groups_to_add)
+ for group in groups_to_remove:
+ remove_perm(permission, group, object)
+ for group in groups_to_add:
+ assign_perm(permission, group, object)
+ if action == "change":
+ # change gives view too
+ assign_perm(
+ f"view_{object.__class__.__name__.lower()}",
+ group,
+ object,
+ )
def create(self, validated_data):
if self.user and (
response = self.client.get("/api/documents/?fields=", format="json")
self.assertEqual(response.status_code, 200)
results = response.data["results"]
- self.assertEqual(results_full, results)
+ self.assertEqual(len(results_full[0]), len(results[0]))
response = self.client.get("/api/documents/?fields=dgfhs", format="json")
self.assertEqual(response.status_code, 200)