mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-02 18:47:10 -05:00 
			
		
		
		
	Merge pull request #3347 from paperless-ngx/fix/issue-3346
Fix: default frontend to current owner, allow setting no owner on create
This commit is contained in:
		
						commit
						f78f212a77
					
				@ -6,6 +6,7 @@ import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model'
 | 
				
			|||||||
import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'
 | 
					import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'
 | 
				
			||||||
import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
 | 
					import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
 | 
				
			||||||
import { UserService } from 'src/app/services/rest/user.service'
 | 
					import { UserService } from 'src/app/services/rest/user.service'
 | 
				
			||||||
 | 
					import { SettingsService } from 'src/app/services/settings.service'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-correspondent-edit-dialog',
 | 
					  selector: 'app-correspondent-edit-dialog',
 | 
				
			||||||
@ -16,9 +17,10 @@ export class CorrespondentEditDialogComponent extends EditDialogComponent<Paperl
 | 
				
			|||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    service: CorrespondentService,
 | 
					    service: CorrespondentService,
 | 
				
			||||||
    activeModal: NgbActiveModal,
 | 
					    activeModal: NgbActiveModal,
 | 
				
			||||||
    userService: UserService
 | 
					    userService: UserService,
 | 
				
			||||||
 | 
					    settingsService: SettingsService
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    super(service, activeModal, userService)
 | 
					    super(service, activeModal, userService, settingsService)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getCreateTitle() {
 | 
					  getCreateTitle() {
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model'
 | 
				
			|||||||
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'
 | 
					import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'
 | 
				
			||||||
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
 | 
					import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
 | 
				
			||||||
import { UserService } from 'src/app/services/rest/user.service'
 | 
					import { UserService } from 'src/app/services/rest/user.service'
 | 
				
			||||||
 | 
					import { SettingsService } from 'src/app/services/settings.service'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-document-type-edit-dialog',
 | 
					  selector: 'app-document-type-edit-dialog',
 | 
				
			||||||
@ -16,9 +17,10 @@ export class DocumentTypeEditDialogComponent extends EditDialogComponent<Paperle
 | 
				
			|||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    service: DocumentTypeService,
 | 
					    service: DocumentTypeService,
 | 
				
			||||||
    activeModal: NgbActiveModal,
 | 
					    activeModal: NgbActiveModal,
 | 
				
			||||||
    userService: UserService
 | 
					    userService: UserService,
 | 
				
			||||||
 | 
					    settingsService: SettingsService
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    super(service, activeModal, userService)
 | 
					    super(service, activeModal, userService, settingsService)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getCreateTitle() {
 | 
					  getCreateTitle() {
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ import { PaperlessUser } from 'src/app/data/paperless-user'
 | 
				
			|||||||
import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service'
 | 
					import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service'
 | 
				
			||||||
import { UserService } from 'src/app/services/rest/user.service'
 | 
					import { UserService } from 'src/app/services/rest/user.service'
 | 
				
			||||||
import { PermissionsFormObject } from '../input/permissions/permissions-form/permissions-form.component'
 | 
					import { PermissionsFormObject } from '../input/permissions/permissions-form/permissions-form.component'
 | 
				
			||||||
 | 
					import { SettingsService } from 'src/app/services/settings.service'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Directive()
 | 
					@Directive()
 | 
				
			||||||
export abstract class EditDialogComponent<
 | 
					export abstract class EditDialogComponent<
 | 
				
			||||||
@ -22,7 +23,8 @@ export abstract class EditDialogComponent<
 | 
				
			|||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    protected service: AbstractPaperlessService<T>,
 | 
					    protected service: AbstractPaperlessService<T>,
 | 
				
			||||||
    private activeModal: NgbActiveModal,
 | 
					    private activeModal: NgbActiveModal,
 | 
				
			||||||
    private userService: UserService
 | 
					    private userService: UserService,
 | 
				
			||||||
 | 
					    private settingsService: SettingsService
 | 
				
			||||||
  ) {}
 | 
					  ) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  users: PaperlessUser[]
 | 
					  users: PaperlessUser[]
 | 
				
			||||||
@ -64,7 +66,14 @@ export abstract class EditDialogComponent<
 | 
				
			|||||||
      this.closeEnabled = true
 | 
					      this.closeEnabled = true
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.userService.listAll().subscribe((r) => (this.users = r.results))
 | 
					    this.userService.listAll().subscribe((r) => {
 | 
				
			||||||
 | 
					      this.users = r.results
 | 
				
			||||||
 | 
					      if (this.dialogMode === 'create') {
 | 
				
			||||||
 | 
					        this.objectForm.get('permissions_form').setValue({
 | 
				
			||||||
 | 
					          owner: this.settingsService.currentUser.id,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getCreateTitle() {
 | 
					  getCreateTitle() {
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-
 | 
				
			|||||||
import { PaperlessGroup } from 'src/app/data/paperless-group'
 | 
					import { PaperlessGroup } from 'src/app/data/paperless-group'
 | 
				
			||||||
import { GroupService } from 'src/app/services/rest/group.service'
 | 
					import { GroupService } from 'src/app/services/rest/group.service'
 | 
				
			||||||
import { UserService } from 'src/app/services/rest/user.service'
 | 
					import { UserService } from 'src/app/services/rest/user.service'
 | 
				
			||||||
 | 
					import { SettingsService } from 'src/app/services/settings.service'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-group-edit-dialog',
 | 
					  selector: 'app-group-edit-dialog',
 | 
				
			||||||
@ -15,9 +16,10 @@ export class GroupEditDialogComponent extends EditDialogComponent<PaperlessGroup
 | 
				
			|||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    service: GroupService,
 | 
					    service: GroupService,
 | 
				
			||||||
    activeModal: NgbActiveModal,
 | 
					    activeModal: NgbActiveModal,
 | 
				
			||||||
    userService: UserService
 | 
					    userService: UserService,
 | 
				
			||||||
 | 
					    settingsService: SettingsService
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    super(service, activeModal, userService)
 | 
					    super(service, activeModal, userService, settingsService)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getCreateTitle() {
 | 
					  getCreateTitle() {
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,7 @@ import {
 | 
				
			|||||||
} from 'src/app/data/paperless-mail-account'
 | 
					} from 'src/app/data/paperless-mail-account'
 | 
				
			||||||
import { MailAccountService } from 'src/app/services/rest/mail-account.service'
 | 
					import { MailAccountService } from 'src/app/services/rest/mail-account.service'
 | 
				
			||||||
import { UserService } from 'src/app/services/rest/user.service'
 | 
					import { UserService } from 'src/app/services/rest/user.service'
 | 
				
			||||||
 | 
					import { SettingsService } from 'src/app/services/settings.service'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const IMAP_SECURITY_OPTIONS = [
 | 
					const IMAP_SECURITY_OPTIONS = [
 | 
				
			||||||
  { id: IMAPSecurity.None, name: $localize`No encryption` },
 | 
					  { id: IMAPSecurity.None, name: $localize`No encryption` },
 | 
				
			||||||
@ -30,9 +31,10 @@ export class MailAccountEditDialogComponent extends EditDialogComponent<Paperles
 | 
				
			|||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    service: MailAccountService,
 | 
					    service: MailAccountService,
 | 
				
			||||||
    activeModal: NgbActiveModal,
 | 
					    activeModal: NgbActiveModal,
 | 
				
			||||||
    userService: UserService
 | 
					    userService: UserService,
 | 
				
			||||||
 | 
					    settingsService: SettingsService
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    super(service, activeModal, userService)
 | 
					    super(service, activeModal, userService, settingsService)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getCreateTitle() {
 | 
					  getCreateTitle() {
 | 
				
			||||||
 | 
				
			|||||||
@ -19,6 +19,7 @@ import { DocumentTypeService } from 'src/app/services/rest/document-type.service
 | 
				
			|||||||
import { MailAccountService } from 'src/app/services/rest/mail-account.service'
 | 
					import { MailAccountService } from 'src/app/services/rest/mail-account.service'
 | 
				
			||||||
import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
 | 
					import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
 | 
				
			||||||
import { UserService } from 'src/app/services/rest/user.service'
 | 
					import { UserService } from 'src/app/services/rest/user.service'
 | 
				
			||||||
 | 
					import { SettingsService } from 'src/app/services/settings.service'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ATTACHMENT_TYPE_OPTIONS = [
 | 
					const ATTACHMENT_TYPE_OPTIONS = [
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
@ -115,9 +116,10 @@ export class MailRuleEditDialogComponent extends EditDialogComponent<PaperlessMa
 | 
				
			|||||||
    accountService: MailAccountService,
 | 
					    accountService: MailAccountService,
 | 
				
			||||||
    correspondentService: CorrespondentService,
 | 
					    correspondentService: CorrespondentService,
 | 
				
			||||||
    documentTypeService: DocumentTypeService,
 | 
					    documentTypeService: DocumentTypeService,
 | 
				
			||||||
    userService: UserService
 | 
					    userService: UserService,
 | 
				
			||||||
 | 
					    settingsService: SettingsService
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    super(service, activeModal, userService)
 | 
					    super(service, activeModal, userService, settingsService)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    accountService
 | 
					    accountService
 | 
				
			||||||
      .listAll()
 | 
					      .listAll()
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model'
 | 
				
			|||||||
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
 | 
					import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
 | 
				
			||||||
import { StoragePathService } from 'src/app/services/rest/storage-path.service'
 | 
					import { StoragePathService } from 'src/app/services/rest/storage-path.service'
 | 
				
			||||||
import { UserService } from 'src/app/services/rest/user.service'
 | 
					import { UserService } from 'src/app/services/rest/user.service'
 | 
				
			||||||
 | 
					import { SettingsService } from 'src/app/services/settings.service'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-storage-path-edit-dialog',
 | 
					  selector: 'app-storage-path-edit-dialog',
 | 
				
			||||||
@ -16,9 +17,10 @@ export class StoragePathEditDialogComponent extends EditDialogComponent<Paperles
 | 
				
			|||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    service: StoragePathService,
 | 
					    service: StoragePathService,
 | 
				
			||||||
    activeModal: NgbActiveModal,
 | 
					    activeModal: NgbActiveModal,
 | 
				
			||||||
    userService: UserService
 | 
					    userService: UserService,
 | 
				
			||||||
 | 
					    settingsService: SettingsService
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    super(service, activeModal, userService)
 | 
					    super(service, activeModal, userService, settingsService)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get pathHint() {
 | 
					  get pathHint() {
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,7 @@ import { TagService } from 'src/app/services/rest/tag.service'
 | 
				
			|||||||
import { randomColor } from 'src/app/utils/color'
 | 
					import { randomColor } from 'src/app/utils/color'
 | 
				
			||||||
import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model'
 | 
					import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model'
 | 
				
			||||||
import { UserService } from 'src/app/services/rest/user.service'
 | 
					import { UserService } from 'src/app/services/rest/user.service'
 | 
				
			||||||
 | 
					import { SettingsService } from 'src/app/services/settings.service'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-tag-edit-dialog',
 | 
					  selector: 'app-tag-edit-dialog',
 | 
				
			||||||
@ -17,9 +18,10 @@ export class TagEditDialogComponent extends EditDialogComponent<PaperlessTag> {
 | 
				
			|||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    service: TagService,
 | 
					    service: TagService,
 | 
				
			||||||
    activeModal: NgbActiveModal,
 | 
					    activeModal: NgbActiveModal,
 | 
				
			||||||
    userService: UserService
 | 
					    userService: UserService,
 | 
				
			||||||
 | 
					    settingsService: SettingsService
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    super(service, activeModal, userService)
 | 
					    super(service, activeModal, userService, settingsService)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getCreateTitle() {
 | 
					  getCreateTitle() {
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,7 @@ import { PaperlessGroup } from 'src/app/data/paperless-group'
 | 
				
			|||||||
import { PaperlessUser } from 'src/app/data/paperless-user'
 | 
					import { PaperlessUser } from 'src/app/data/paperless-user'
 | 
				
			||||||
import { GroupService } from 'src/app/services/rest/group.service'
 | 
					import { GroupService } from 'src/app/services/rest/group.service'
 | 
				
			||||||
import { UserService } from 'src/app/services/rest/user.service'
 | 
					import { UserService } from 'src/app/services/rest/user.service'
 | 
				
			||||||
 | 
					import { SettingsService } from 'src/app/services/settings.service'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-user-edit-dialog',
 | 
					  selector: 'app-user-edit-dialog',
 | 
				
			||||||
@ -23,9 +24,10 @@ export class UserEditDialogComponent
 | 
				
			|||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    service: UserService,
 | 
					    service: UserService,
 | 
				
			||||||
    activeModal: NgbActiveModal,
 | 
					    activeModal: NgbActiveModal,
 | 
				
			||||||
    groupsService: GroupService
 | 
					    groupsService: GroupService,
 | 
				
			||||||
 | 
					    settingsService: SettingsService
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    super(service, activeModal, service)
 | 
					    super(service, activeModal, service, settingsService)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    groupsService
 | 
					    groupsService
 | 
				
			||||||
      .listAll()
 | 
					      .listAll()
 | 
				
			||||||
 | 
				
			|||||||
@ -220,6 +220,8 @@ class OwnedObjectSerializer(serializers.ModelSerializer, SetPermissionsMixin):
 | 
				
			|||||||
        permissions = None
 | 
					        permissions = None
 | 
				
			||||||
        if "set_permissions" in validated_data:
 | 
					        if "set_permissions" in validated_data:
 | 
				
			||||||
            permissions = validated_data.pop("set_permissions")
 | 
					            permissions = validated_data.pop("set_permissions")
 | 
				
			||||||
 | 
					            if "user" not in permissions or permissions["user"] is None:
 | 
				
			||||||
 | 
					                validated_data["owner"] = None
 | 
				
			||||||
        instance = super().create(validated_data)
 | 
					        instance = super().create(validated_data)
 | 
				
			||||||
        if permissions is not None:
 | 
					        if permissions is not None:
 | 
				
			||||||
            self._set_permissions(permissions, instance)
 | 
					            self._set_permissions(permissions, instance)
 | 
				
			||||||
 | 
				
			|||||||
@ -3550,6 +3550,77 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
 | 
				
			|||||||
            status.HTTP_404_NOT_FOUND,
 | 
					            status.HTTP_404_NOT_FOUND,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_api_set_permissions(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        GIVEN:
 | 
				
			||||||
 | 
					            - API request to create an object (Tag) that supplies set_permissions object
 | 
				
			||||||
 | 
					        WHEN:
 | 
				
			||||||
 | 
					            - owner is passed as null or as a user id
 | 
				
			||||||
 | 
					            - view > users is set
 | 
				
			||||||
 | 
					        THEN:
 | 
				
			||||||
 | 
					            - Object permissions are set appropriately
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        user1 = User.objects.create_superuser(username="user1")
 | 
				
			||||||
 | 
					        user2 = User.objects.create(username="user2")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.client.force_authenticate(user1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            "/api/tags/",
 | 
				
			||||||
 | 
					            json.dumps(
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "name": "test1",
 | 
				
			||||||
 | 
					                    "matching_algorithm": MatchingModel.MATCH_AUTO,
 | 
				
			||||||
 | 
					                    "set_permissions": {
 | 
				
			||||||
 | 
					                        "owner": None,
 | 
				
			||||||
 | 
					                        "view": {
 | 
				
			||||||
 | 
					                            "users": None,
 | 
				
			||||||
 | 
					                            "groups": None,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        "change": {
 | 
				
			||||||
 | 
					                            "users": None,
 | 
				
			||||||
 | 
					                            "groups": None,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            content_type="application/json",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tag1 = Tag.objects.filter(name="test1").first()
 | 
				
			||||||
 | 
					        self.assertEqual(tag1.owner, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            "/api/tags/",
 | 
				
			||||||
 | 
					            json.dumps(
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "name": "test2",
 | 
				
			||||||
 | 
					                    "matching_algorithm": MatchingModel.MATCH_AUTO,
 | 
				
			||||||
 | 
					                    "set_permissions": {
 | 
				
			||||||
 | 
					                        "owner": user1.id,
 | 
				
			||||||
 | 
					                        "view": {
 | 
				
			||||||
 | 
					                            "users": [user2.id],
 | 
				
			||||||
 | 
					                            "groups": None,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        "change": {
 | 
				
			||||||
 | 
					                            "users": None,
 | 
				
			||||||
 | 
					                            "groups": None,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            content_type="application/json",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tag2 = Tag.objects.filter(name="test2").first()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        from guardian.core import ObjectPermissionChecker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        checker = ObjectPermissionChecker(user2)
 | 
				
			||||||
 | 
					        self.assertEqual(checker.has_perm("view_tag", tag2), True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_dynamic_permissions_fields(self):
 | 
					    def test_dynamic_permissions_fields(self):
 | 
				
			||||||
        user1 = User.objects.create_user(username="user1")
 | 
					        user1 = User.objects.create_user(username="user1")
 | 
				
			||||||
        user1.user_permissions.add(*Permission.objects.filter(codename="view_document"))
 | 
					        user1.user_permissions.add(*Permission.objects.filter(codename="view_document"))
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user