mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-02 13:45:10 -05:00
feat: add users and groups API routes
This commit is contained in:
parent
96a29883cd
commit
4333bd58cf
9
src-ui/src/app/data/paperless-group.ts
Normal file
9
src-ui/src/app/data/paperless-group.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { ObjectWithId } from './object-with-id'
|
||||||
|
|
||||||
|
export interface PaperlessGroup extends ObjectWithId {
|
||||||
|
name?: string
|
||||||
|
|
||||||
|
user_count?: number // not implemented yet
|
||||||
|
|
||||||
|
permissions?: string[]
|
||||||
|
}
|
15
src-ui/src/app/data/paperless-user.ts
Normal file
15
src-ui/src/app/data/paperless-user.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { PaperlessGroup } from 'src/app/data/paperless-group'
|
||||||
|
import { ObjectWithId } from './object-with-id'
|
||||||
|
|
||||||
|
export interface PaperlessUser extends ObjectWithId {
|
||||||
|
username?: string
|
||||||
|
first_name?: string
|
||||||
|
last_name?: string
|
||||||
|
date_joined?: Date
|
||||||
|
is_staff?: boolean
|
||||||
|
is_active?: boolean
|
||||||
|
is_superuser?: boolean
|
||||||
|
groups?: PaperlessGroup[]
|
||||||
|
permissions?: string[]
|
||||||
|
inherited_permissions?: string[]
|
||||||
|
}
|
13
src-ui/src/app/services/rest/group.service.ts
Normal file
13
src-ui/src/app/services/rest/group.service.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http'
|
||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { PaperlessGroup } from 'src/app/data/paperless-group'
|
||||||
|
import { AbstractNameFilterService } from './abstract-name-filter-service'
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class GroupService extends AbstractNameFilterService<PaperlessGroup> {
|
||||||
|
constructor(http: HttpClient) {
|
||||||
|
super(http, 'groups')
|
||||||
|
}
|
||||||
|
}
|
13
src-ui/src/app/services/rest/user.service.ts
Normal file
13
src-ui/src/app/services/rest/user.service.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http'
|
||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { PaperlessUser } from 'src/app/data/paperless-user'
|
||||||
|
import { AbstractNameFilterService } from './abstract-name-filter-service'
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class UserService extends AbstractNameFilterService<PaperlessUser> {
|
||||||
|
constructor(http: HttpClient) {
|
||||||
|
super(http, 'users')
|
||||||
|
}
|
||||||
|
}
|
20
src/paperless/filters.py
Normal file
20
src/paperless/filters.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from django.contrib.auth.models import Group
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django_filters.rest_framework import FilterSet
|
||||||
|
|
||||||
|
CHAR_KWARGS = ["istartswith", "iendswith", "icontains", "iexact"]
|
||||||
|
ID_KWARGS = ["in", "exact"]
|
||||||
|
INT_KWARGS = ["exact", "gt", "gte", "lt", "lte", "isnull"]
|
||||||
|
DATE_KWARGS = ["year", "month", "day", "date__gt", "gt", "date__lt", "lt"]
|
||||||
|
|
||||||
|
|
||||||
|
class UserFilterSet(FilterSet):
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = {"username": CHAR_KWARGS}
|
||||||
|
|
||||||
|
|
||||||
|
class GroupFilterSet(FilterSet):
|
||||||
|
class Meta:
|
||||||
|
model = Group
|
||||||
|
fields = {"name": CHAR_KWARGS}
|
64
src/paperless/serialisers.py
Normal file
64
src/paperless/serialisers.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
from django.contrib.auth.models import Group
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class UserSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
groups = serializers.SerializerMethodField()
|
||||||
|
permissions = serializers.SerializerMethodField()
|
||||||
|
inherited_permissions = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = (
|
||||||
|
"id",
|
||||||
|
"username",
|
||||||
|
"first_name",
|
||||||
|
"last_name",
|
||||||
|
"date_joined",
|
||||||
|
"is_staff",
|
||||||
|
"is_active",
|
||||||
|
"is_superuser",
|
||||||
|
"groups",
|
||||||
|
"permissions",
|
||||||
|
"inherited_permissions",
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_groups(self, obj):
|
||||||
|
return list(obj.groups.values_list("name", flat=True))
|
||||||
|
|
||||||
|
def get_permissions(self, obj):
|
||||||
|
# obj.get_user_permissions() returns more permissions than desired
|
||||||
|
permission_natural_keys = []
|
||||||
|
permissions = obj.user_permissions.all()
|
||||||
|
for permission in permissions:
|
||||||
|
permission_natural_keys.append(
|
||||||
|
permission.natural_key()[1] + "." + permission.natural_key()[0],
|
||||||
|
)
|
||||||
|
return permission_natural_keys
|
||||||
|
|
||||||
|
def get_inherited_permissions(self, obj):
|
||||||
|
return obj.get_group_permissions()
|
||||||
|
|
||||||
|
|
||||||
|
class GroupSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
permissions = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Group
|
||||||
|
fields = (
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"permissions",
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_permissions(self, obj):
|
||||||
|
permission_natural_keys = []
|
||||||
|
permissions = obj.permissions.all()
|
||||||
|
for permission in permissions:
|
||||||
|
permission_natural_keys.append(
|
||||||
|
permission.natural_key()[1] + "." + permission.natural_key()[0],
|
||||||
|
)
|
||||||
|
return permission_natural_keys
|
@ -27,6 +27,8 @@ from documents.views import UiSettingsView
|
|||||||
from documents.views import UnifiedSearchViewSet
|
from documents.views import UnifiedSearchViewSet
|
||||||
from paperless.consumers import StatusConsumer
|
from paperless.consumers import StatusConsumer
|
||||||
from paperless.views import FaviconView
|
from paperless.views import FaviconView
|
||||||
|
from paperless.views import GroupViewSet
|
||||||
|
from paperless.views import UserViewSet
|
||||||
from rest_framework.authtoken import views
|
from rest_framework.authtoken import views
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
@ -39,6 +41,8 @@ api_router.register(r"tags", TagViewSet)
|
|||||||
api_router.register(r"saved_views", SavedViewViewSet)
|
api_router.register(r"saved_views", SavedViewViewSet)
|
||||||
api_router.register(r"storage_paths", StoragePathViewSet)
|
api_router.register(r"storage_paths", StoragePathViewSet)
|
||||||
api_router.register(r"tasks", TasksViewSet, basename="tasks")
|
api_router.register(r"tasks", TasksViewSet, basename="tasks")
|
||||||
|
api_router.register(r"users", UserViewSet, basename="users")
|
||||||
|
api_router.register(r"groups", GroupViewSet, basename="groups")
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
@ -1,8 +1,19 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
from django.contrib.auth.models import Group
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.db.models.functions import Lower
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
|
from paperless.filters import GroupFilterSet
|
||||||
|
from paperless.filters import UserFilterSet
|
||||||
|
from paperless.serialisers import GroupSerializer
|
||||||
|
from paperless.serialisers import UserSerializer
|
||||||
|
from rest_framework.filters import OrderingFilter
|
||||||
from rest_framework.pagination import PageNumberPagination
|
from rest_framework.pagination import PageNumberPagination
|
||||||
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
|
|
||||||
class StandardPagination(PageNumberPagination):
|
class StandardPagination(PageNumberPagination):
|
||||||
@ -22,3 +33,29 @@ class FaviconView(View):
|
|||||||
)
|
)
|
||||||
with open(favicon, "rb") as f:
|
with open(favicon, "rb") as f:
|
||||||
return HttpResponse(f, content_type="image/x-icon")
|
return HttpResponse(f, content_type="image/x-icon")
|
||||||
|
|
||||||
|
|
||||||
|
class UserViewSet(ModelViewSet):
|
||||||
|
model = User
|
||||||
|
|
||||||
|
queryset = User.objects.order_by(Lower("username"))
|
||||||
|
|
||||||
|
serializer_class = UserSerializer
|
||||||
|
pagination_class = StandardPagination
|
||||||
|
permission_classes = (IsAuthenticated,)
|
||||||
|
filter_backends = (DjangoFilterBackend, OrderingFilter)
|
||||||
|
filterset_class = UserFilterSet
|
||||||
|
ordering_fields = ("username",)
|
||||||
|
|
||||||
|
|
||||||
|
class GroupViewSet(ModelViewSet):
|
||||||
|
model = Group
|
||||||
|
|
||||||
|
queryset = Group.objects.order_by(Lower("name"))
|
||||||
|
|
||||||
|
serializer_class = GroupSerializer
|
||||||
|
pagination_class = StandardPagination
|
||||||
|
permission_classes = (IsAuthenticated,)
|
||||||
|
filter_backends = (DjangoFilterBackend, OrderingFilter)
|
||||||
|
filterset_class = GroupFilterSet
|
||||||
|
ordering_fields = ("name",)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user