Support default permissions for object creation via frontend (#4233)

This commit is contained in:
shamoon
2023-09-21 16:28:22 -07:00
committed by GitHub
parent cdfe953c06
commit a7e632de16
18 changed files with 653 additions and 284 deletions

View File

@@ -11,14 +11,14 @@
<form [formGroup]="settingsForm" (ngSubmit)="saveSettings()">
<ul ngbNav #nav="ngbNav" (navChange)="onNavChange($event)" [(activeId)]="activeNavID" class="nav-tabs">
<li [ngbNavItem]="SettingsNavIDs.General">
<li [ngbNavItem]="SettingsNavIDs.General" (mouseover)="maybeInitializeTab(SettingsNavIDs.General)">
<a ngbNavLink i18n>General</a>
<ng-template ngbNavContent>
<h4 i18n>Appearance</h4>
<div class="row mb-3">
<div class="col-md-3 col-form-label">
<div class="col-md-3 col-form-label pt-0">
<span i18n>Display language</span>
</div>
<div class="col">
@@ -33,7 +33,7 @@
</div>
<div class="row mb-3">
<div class="col-md-3 col-form-label">
<div class="col-md-3 col-form-label pt-0">
<span i18n>Date display</span>
</div>
<div class="col">
@@ -46,7 +46,7 @@
</div>
<div class="row mb-3">
<div class="col-md-3 col-form-label">
<div class="col-md-3 col-form-label pt-0">
<span i18n>Date format</span>
</div>
<div class="col">
@@ -68,7 +68,7 @@
</div>
<div class="row mb-3">
<div class="col-md-3 col-form-label">
<div class="col-md-3 col-form-label pt-0">
<span i18n>Items per page</span>
</div>
<div class="col">
@@ -84,7 +84,7 @@
</div>
<div class="row mb-3">
<div class="col-md-3 col-form-label">
<div class="col-md-3 col-form-label pt-0">
<span i18n>Document editor</span>
</div>
<div class="col">
@@ -95,7 +95,7 @@
</div>
<div class="row mb-3">
<div class="col-md-3 col-form-label">
<div class="col-md-3 col-form-label pt-0">
<span i18n>Sidebar</span>
</div>
<div class="col">
@@ -106,7 +106,7 @@
</div>
<div class="row mb-3">
<div class="col-md-3 col-form-label">
<div class="col-md-3 col-form-label pt-0">
<span i18n>Dark mode</span>
</div>
<div class="col">
@@ -117,7 +117,7 @@
</div>
<div class="row mb-3">
<div class="col-md-3 col-form-label">
<div class="col-md-3 col-form-label pt-0">
<span i18n>Theme Color</span>
</div>
<div class="col col-md-3">
@@ -132,6 +132,82 @@
</div>
</div>
<h4 i18n>Permissions</h4>
<div class="row mb-3">
<div class="offset-md-3 col">
<p i18n>
Settings apply to this user account for objects (Tags, Mail Rules, etc.) created via the web UI
</p>
</div>
</div>
<div class="row mb-3">
<div class="col-md-3 col-form-label pt-0">
<span i18n>Default Owner</span>
</div>
<div class="col-md-4">
<pngx-input-select [items]="users" bindLabel="username" formControlName="defaultPermsOwner" [allowNull]="true"></pngx-input-select>
<small class="form-text text-muted text-end d-block mt-n2" i18n>Objects without an owner can be viewed and edited by all users</small>
</div>
</div>
<div class="row mb-3">
<div class="col-md-3 col-form-label pt-0">
<span i18n>Default View Permissions</span>
</div>
<div class="col-md-4">
<div class="row">
<div class="col-2">
<span class="d-block pt-1" i18n>Users:</span>
</div>
<div class="col">
<ng-container *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.User }">
<pngx-permissions-user type="view" formControlName="defaultPermsViewUsers"></pngx-permissions-user>
</ng-container>
</div>
</div>
<div class="row">
<div class="col-2">
<span class="d-block pt-1" i18n>Groups:</span>
</div>
<div class="col">
<ng-container *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Group }">
<pngx-permissions-group type="view" formControlName="defaultPermsViewGroups"></pngx-permissions-group>
</ng-container>
</div>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-3 col-form-label pt-0">
<span i18n>Default Edit Permissions</span>
</div>
<div class="col-md-4">
<div class="row">
<div class="col-2">
<span class="d-block pt-1" i18n>Users:</span>
</div>
<div class="col">
<ng-container *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.User }">
<pngx-permissions-user type="view" formControlName="defaultPermsEditUsers"></pngx-permissions-user>
</ng-container>
</div>
</div>
<div class="row">
<div class="col-2">
<span class="d-block pt-1" i18n>Groups:</span>
</div>
<div class="col">
<ng-container *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Group }">
<pngx-permissions-group type="view" formControlName="defaultPermsEditGroups"></pngx-permissions-group>
</ng-container>
</div>
</div>
<div class="row">
<small class="form-text text-muted text-end d-block" i18n>Edit permissions also grant viewing permissions</small>
</div>
</div>
</div>
<h4 class="mt-4" id="update-checking" i18n>Update checking</h4>
<div class="row mb-3">

View File

@@ -13,10 +13,11 @@ import { RouterTestingModule } from '@angular/router/testing'
import {
NgbModal,
NgbModule,
NgbAlertModule,
NgbNavLink,
NgbModalRef,
NgbAlertModule,
} from '@ng-bootstrap/ng-bootstrap'
import { NgSelectModule } from '@ng-select/ng-select'
import { of, throwError } from 'rxjs'
import { routes } from 'src/app/app-routing.module'
import { PaperlessMailAccount } from 'src/app/data/paperless-mail-account'
@@ -26,6 +27,7 @@ import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { PermissionsService } from 'src/app/services/permissions.service'
import { GroupService } from 'src/app/services/rest/group.service'
import { MailAccountService } from 'src/app/services/rest/mail-account.service'
@@ -41,15 +43,15 @@ import { MailRuleEditDialogComponent } from '../../common/edit-dialog/mail-rule-
import { UserEditDialogComponent } from '../../common/edit-dialog/user-edit-dialog/user-edit-dialog.component'
import { CheckComponent } from '../../common/input/check/check.component'
import { ColorComponent } from '../../common/input/color/color.component'
import { NumberComponent } from '../../common/input/number/number.component'
import { PasswordComponent } from '../../common/input/password/password.component'
import { PermissionsGroupComponent } from '../../common/input/permissions/permissions-group/permissions-group.component'
import { PermissionsUserComponent } from '../../common/input/permissions/permissions-user/permissions-user.component'
import { SelectComponent } from '../../common/input/select/select.component'
import { TagsComponent } from '../../common/input/tags/tags.component'
import { TextComponent } from '../../common/input/text/text.component'
import { PageHeaderComponent } from '../../common/page-header/page-header.component'
import { SettingsComponent } from './settings.component'
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { SelectComponent } from '../../common/input/select/select.component'
import { TextComponent } from '../../common/input/text/text.component'
import { PasswordComponent } from '../../common/input/password/password.component'
import { NumberComponent } from '../../common/input/number/number.component'
import { TagsComponent } from '../../common/input/tags/tags.component'
import { NgSelectModule } from '@ng-select/ng-select'
const savedViews = [
{ id: 1, name: 'view1' },
@@ -106,6 +108,8 @@ describe('SettingsComponent', () => {
TagsComponent,
MailAccountEditDialogComponent,
MailRuleEditDialogComponent,
PermissionsUserComponent,
PermissionsGroupComponent,
],
providers: [CustomDatePipe, DatePipe, PermissionsGuard],
imports: [
@@ -125,6 +129,7 @@ describe('SettingsComponent', () => {
viewportScroller = TestBed.inject(ViewportScroller)
toastService = TestBed.inject(ToastService)
settingsService = TestBed.inject(SettingsService)
settingsService.currentUser = { id: 99, username: 'user99' }
userService = TestBed.inject(UserService)
permissionsService = TestBed.inject(PermissionsService)
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
@@ -247,11 +252,11 @@ describe('SettingsComponent', () => {
)
expect(component.mailAccounts).not.toBeUndefined()
expect(component.users).toBeUndefined()
expect(component.groups).toBeUndefined()
tabButtons[4].nativeElement.dispatchEvent(
new MouseEvent('mouseover', { bubbles: true })
)
expect(component.users).not.toBeUndefined()
expect(component.groups).not.toBeUndefined()
})
it('should support save saved views, show error', () => {
@@ -301,7 +306,7 @@ describe('SettingsComponent', () => {
expect(toastErrorSpy).toHaveBeenCalled()
expect(storeSpy).toHaveBeenCalled()
expect(appearanceSettingsSpy).not.toHaveBeenCalled()
expect(setSpy).toHaveBeenCalledTimes(19)
expect(setSpy).toHaveBeenCalledTimes(24)
// succeed
storeSpy.mockReturnValueOnce(of(true))

View File

@@ -48,6 +48,7 @@ import { EditDialogMode } from '../../common/edit-dialog/edit-dialog.component'
import { ObjectWithPermissions } from 'src/app/data/object-with-permissions'
import {
PermissionAction,
PermissionType,
PermissionsService,
} from 'src/app/services/permissions.service'
@@ -93,6 +94,11 @@ export class SettingsComponent
dateFormat: new FormControl(null),
notesEnabled: new FormControl(null),
updateCheckingEnabled: new FormControl(null),
defaultPermsOwner: new FormControl(null),
defaultPermsViewUsers: new FormControl(null),
defaultPermsViewGroups: new FormControl(null),
defaultPermsEditUsers: new FormControl(null),
defaultPermsEditGroups: new FormControl(null),
notificationsConsumerNewDocument: new FormControl(null),
notificationsConsumerSuccess: new FormControl(null),
@@ -159,6 +165,16 @@ export class SettingsComponent
this.activatedRoute.paramMap.subscribe((paramMap) => {
const section = paramMap.get('section')
if (section === null) {
if (
this.permissionsService.currentUserCan(
PermissionAction.View,
PermissionType.User
)
) {
this.getUsers()
}
}
if (section) {
const navIDKey: string = Object.keys(SettingsNavIDs).find(
(navID) => navID.toLowerCase() == section
@@ -222,6 +238,19 @@ export class SettingsComponent
savedViewsWarnOnUnsavedChange: this.settings.get(
SETTINGS_KEYS.SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE
),
defaultPermsOwner: this.settings.get(SETTINGS_KEYS.DEFAULT_PERMS_OWNER),
defaultPermsViewUsers: this.settings.get(
SETTINGS_KEYS.DEFAULT_PERMS_VIEW_USERS
),
defaultPermsViewGroups: this.settings.get(
SETTINGS_KEYS.DEFAULT_PERMS_VIEW_GROUPS
),
defaultPermsEditUsers: this.settings.get(
SETTINGS_KEYS.DEFAULT_PERMS_EDIT_USERS
),
defaultPermsEditGroups: this.settings.get(
SETTINGS_KEYS.DEFAULT_PERMS_EDIT_GROUPS
),
usersGroup: {},
groupsGroup: {},
savedViews: {},
@@ -256,33 +285,21 @@ export class SettingsComponent
this.initialize(false)
})
} else if (
navID == SettingsNavIDs.UsersGroups &&
(navID == SettingsNavIDs.UsersGroups ||
navID == SettingsNavIDs.General) &&
(!this.users || !this.groups)
) {
this.usersService
if (!this.users) this.getUsers()
this.groupsService
.listAll()
.pipe(first())
.subscribe({
next: (r) => {
this.users = r.results
this.groupsService
.listAll()
.pipe(first())
.subscribe({
next: (r) => {
this.groups = r.results
this.initialize(false)
},
error: (e) => {
this.toastService.showError(
$localize`Error retrieving groups`,
e
)
},
})
this.groups = r.results
this.initialize(false)
},
error: (e) => {
this.toastService.showError($localize`Error retrieving users`, e)
this.toastService.showError($localize`Error retrieving groups`, e)
},
})
} else if (
@@ -322,6 +339,20 @@ export class SettingsComponent
}
}
private getUsers() {
this.usersService
.listAll()
.pipe(first())
.subscribe({
next: (r) => {
this.users = r.results
},
error: (e) => {
this.toastService.showError($localize`Error retrieving users`, e)
},
})
}
initialize(resetSettings: boolean = true) {
this.unsubscribeNotifier.next(true)
@@ -611,6 +642,26 @@ export class SettingsComponent
SETTINGS_KEYS.SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE,
this.settingsForm.value.savedViewsWarnOnUnsavedChange
)
this.settings.set(
SETTINGS_KEYS.DEFAULT_PERMS_OWNER,
this.settingsForm.value.defaultPermsOwner
)
this.settings.set(
SETTINGS_KEYS.DEFAULT_PERMS_VIEW_USERS,
this.settingsForm.value.defaultPermsViewUsers
)
this.settings.set(
SETTINGS_KEYS.DEFAULT_PERMS_VIEW_GROUPS,
this.settingsForm.value.defaultPermsViewGroups
)
this.settings.set(
SETTINGS_KEYS.DEFAULT_PERMS_EDIT_USERS,
this.settingsForm.value.defaultPermsEditUsers
)
this.settings.set(
SETTINGS_KEYS.DEFAULT_PERMS_EDIT_GROUPS,
this.settingsForm.value.defaultPermsEditGroups
)
this.settings.setLanguage(this.settingsForm.value.displayLanguage)
this.settings
.storeSettings()