mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-04-14 12:08:51 +00:00
Compare commits
6 Commits
feature-di
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ed7297939 | ||
|
|
3b6edcdd8e | ||
|
|
b27d10646e | ||
|
|
8c1225e120 | ||
|
|
54d5269145 | ||
|
|
f5729811fe |
1
.github/workflows/ci-backend.yml
vendored
1
.github/workflows/ci-backend.yml
vendored
@@ -165,6 +165,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
env:
|
env:
|
||||||
DEFAULT_PYTHON: "3.12"
|
DEFAULT_PYTHON: "3.12"
|
||||||
|
PAPERLESS_SECRET_KEY: "ci-typing-not-a-real-secret"
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|||||||
2
.github/workflows/ci-release.yml
vendored
2
.github/workflows/ci-release.yml
vendored
@@ -88,6 +88,7 @@ jobs:
|
|||||||
uv export --quiet --no-dev --all-extras --format requirements-txt --output-file requirements.txt
|
uv export --quiet --no-dev --all-extras --format requirements-txt --output-file requirements.txt
|
||||||
- name: Compile messages
|
- name: Compile messages
|
||||||
env:
|
env:
|
||||||
|
PAPERLESS_SECRET_KEY: "ci-release-not-a-real-secret"
|
||||||
PYTHON_VERSION: ${{ steps.setup-python.outputs.python-version }}
|
PYTHON_VERSION: ${{ steps.setup-python.outputs.python-version }}
|
||||||
run: |
|
run: |
|
||||||
cd src/
|
cd src/
|
||||||
@@ -96,6 +97,7 @@ jobs:
|
|||||||
manage.py compilemessages
|
manage.py compilemessages
|
||||||
- name: Collect static files
|
- name: Collect static files
|
||||||
env:
|
env:
|
||||||
|
PAPERLESS_SECRET_KEY: "ci-release-not-a-real-secret"
|
||||||
PYTHON_VERSION: ${{ steps.setup-python.outputs.python-version }}
|
PYTHON_VERSION: ${{ steps.setup-python.outputs.python-version }}
|
||||||
run: |
|
run: |
|
||||||
cd src/
|
cd src/
|
||||||
|
|||||||
2
.github/workflows/translate-strings.yml
vendored
2
.github/workflows/translate-strings.yml
vendored
@@ -36,6 +36,8 @@ jobs:
|
|||||||
--group dev \
|
--group dev \
|
||||||
--frozen
|
--frozen
|
||||||
- name: Generate backend translation strings
|
- name: Generate backend translation strings
|
||||||
|
env:
|
||||||
|
PAPERLESS_SECRET_KEY: "ci-translate-not-a-real-secret"
|
||||||
run: cd src/ && uv run manage.py makemessages -l en_US -i "samples*"
|
run: cd src/ && uv run manage.py makemessages -l en_US -i "samples*"
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -79,6 +79,7 @@ virtualenv
|
|||||||
/docker-compose.env
|
/docker-compose.env
|
||||||
/docker-compose.yml
|
/docker-compose.yml
|
||||||
.ruff_cache/
|
.ruff_cache/
|
||||||
|
.mypy_cache/
|
||||||
|
|
||||||
# Used for development
|
# Used for development
|
||||||
scripts/import-for-development
|
scripts/import-for-development
|
||||||
@@ -111,4 +112,6 @@ celerybeat-schedule*
|
|||||||
|
|
||||||
# ignore pnpm package store folder created when setting up the devcontainer
|
# ignore pnpm package store folder created when setting up the devcontainer
|
||||||
.pnpm-store/
|
.pnpm-store/
|
||||||
|
|
||||||
|
# Git worktree local folder
|
||||||
.worktrees
|
.worktrees
|
||||||
|
|||||||
1958
.mypy-baseline.txt
1958
.mypy-baseline.txt
File diff suppressed because it is too large
Load Diff
12316
.pyrefly-baseline.json
12316
.pyrefly-baseline.json
File diff suppressed because one or more lines are too long
@@ -24,7 +24,7 @@ dependencies = [
|
|||||||
"dateparser~=1.2",
|
"dateparser~=1.2",
|
||||||
# WARNING: django does not use semver.
|
# WARNING: django does not use semver.
|
||||||
# Only patch versions are guaranteed to not introduce breaking changes.
|
# Only patch versions are guaranteed to not introduce breaking changes.
|
||||||
"django~=5.2.10",
|
"django~=5.2.13",
|
||||||
"django-allauth[mfa,socialaccount]~=65.15.0",
|
"django-allauth[mfa,socialaccount]~=65.15.0",
|
||||||
"django-auditlog~=3.4.1",
|
"django-auditlog~=3.4.1",
|
||||||
"django-cachalot~=2.9.0",
|
"django-cachalot~=2.9.0",
|
||||||
|
|||||||
@@ -650,6 +650,10 @@ class ConsumerPlugin(
|
|||||||
# If we get here, it was successful. Proceed with post-consume
|
# If we get here, it was successful. Proceed with post-consume
|
||||||
# hooks. If they fail, nothing will get changed.
|
# hooks. If they fail, nothing will get changed.
|
||||||
|
|
||||||
|
document = Document.objects.prefetch_related("versions").get(
|
||||||
|
pk=document.pk,
|
||||||
|
)
|
||||||
|
|
||||||
document_consumption_finished.send(
|
document_consumption_finished.send(
|
||||||
sender=self.__class__,
|
sender=self.__class__,
|
||||||
document=document,
|
document=document,
|
||||||
|
|||||||
@@ -381,7 +381,10 @@ class Document(SoftDeleteModel, ModelWithOwner): # type: ignore[django-manager-
|
|||||||
if isinstance(prefetched_cache, dict)
|
if isinstance(prefetched_cache, dict)
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
if prefetched_versions:
|
if prefetched_versions is not None:
|
||||||
|
# Empty list means prefetch ran and found no versions — use own content.
|
||||||
|
if not prefetched_versions:
|
||||||
|
return self.content
|
||||||
latest_prefetched = max(prefetched_versions, key=lambda doc: doc.id)
|
latest_prefetched = max(prefetched_versions, key=lambda doc: doc.id)
|
||||||
return latest_prefetched.content
|
return latest_prefetched.content
|
||||||
|
|
||||||
|
|||||||
@@ -182,8 +182,9 @@ def _check_thumbnail(
|
|||||||
present_files: set[Path],
|
present_files: set[Path],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Verify the thumbnail exists and is readable."""
|
"""Verify the thumbnail exists and is readable."""
|
||||||
thumbnail_path: Final[Path] = Path(doc.thumbnail_path).resolve()
|
# doc.thumbnail_path already returns a resolved Path; no need to re-resolve.
|
||||||
if not thumbnail_path.exists() or not thumbnail_path.is_file():
|
thumbnail_path: Final[Path] = doc.thumbnail_path
|
||||||
|
if not thumbnail_path.is_file():
|
||||||
messages.error(doc.pk, "Thumbnail of document does not exist.")
|
messages.error(doc.pk, "Thumbnail of document does not exist.")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -200,8 +201,9 @@ def _check_original(
|
|||||||
present_files: set[Path],
|
present_files: set[Path],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Verify the original file exists, is readable, and has matching checksum."""
|
"""Verify the original file exists, is readable, and has matching checksum."""
|
||||||
source_path: Final[Path] = Path(doc.source_path).resolve()
|
# doc.source_path already returns a resolved Path; no need to re-resolve.
|
||||||
if not source_path.exists() or not source_path.is_file():
|
source_path: Final[Path] = doc.source_path
|
||||||
|
if not source_path.is_file():
|
||||||
messages.error(doc.pk, "Original of document does not exist.")
|
messages.error(doc.pk, "Original of document does not exist.")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -237,8 +239,9 @@ def _check_archive(
|
|||||||
elif doc.has_archive_version:
|
elif doc.has_archive_version:
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
assert isinstance(doc.archive_path, Path)
|
assert isinstance(doc.archive_path, Path)
|
||||||
archive_path: Final[Path] = Path(doc.archive_path).resolve()
|
# doc.archive_path already returns a resolved Path; no need to re-resolve.
|
||||||
if not archive_path.exists() or not archive_path.is_file():
|
archive_path: Final[Path] = doc.archive_path # type: ignore[assignment]
|
||||||
|
if not archive_path.is_file():
|
||||||
messages.error(doc.pk, "Archived version of document does not exist.")
|
messages.error(doc.pk, "Archived version of document does not exist.")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -314,7 +317,15 @@ def check_sanity(
|
|||||||
messages = SanityCheckMessages()
|
messages = SanityCheckMessages()
|
||||||
present_files = _build_present_files()
|
present_files = _build_present_files()
|
||||||
|
|
||||||
documents = Document.global_objects.all()
|
documents = Document.global_objects.only(
|
||||||
|
"pk",
|
||||||
|
"filename",
|
||||||
|
"mime_type",
|
||||||
|
"checksum",
|
||||||
|
"archive_checksum",
|
||||||
|
"archive_filename",
|
||||||
|
"content",
|
||||||
|
).iterator(chunk_size=500)
|
||||||
for doc in iter_wrapper(documents):
|
for doc in iter_wrapper(documents):
|
||||||
_check_document(doc, messages, present_files)
|
_check_document(doc, messages, present_files)
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ logger = logging.getLogger("paperless.serializers")
|
|||||||
|
|
||||||
|
|
||||||
# https://www.django-rest-framework.org/api-guide/serializers/#example
|
# https://www.django-rest-framework.org/api-guide/serializers/#example
|
||||||
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
|
class DynamicFieldsModelSerializer(serializers.ModelSerializer[Any]):
|
||||||
"""
|
"""
|
||||||
A ModelSerializer that takes an additional `fields` argument that
|
A ModelSerializer that takes an additional `fields` argument that
|
||||||
controls which fields should be displayed.
|
controls which fields should be displayed.
|
||||||
@@ -121,7 +121,7 @@ class DynamicFieldsModelSerializer(serializers.ModelSerializer):
|
|||||||
self.fields.pop(field_name)
|
self.fields.pop(field_name)
|
||||||
|
|
||||||
|
|
||||||
class MatchingModelSerializer(serializers.ModelSerializer):
|
class MatchingModelSerializer(serializers.ModelSerializer[Any]):
|
||||||
document_count = serializers.IntegerField(read_only=True)
|
document_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
def get_slug(self, obj) -> str:
|
def get_slug(self, obj) -> str:
|
||||||
@@ -261,7 +261,7 @@ class SetPermissionsSerializer(serializers.DictField):
|
|||||||
|
|
||||||
class OwnedObjectSerializer(
|
class OwnedObjectSerializer(
|
||||||
SerializerWithPerms,
|
SerializerWithPerms,
|
||||||
serializers.ModelSerializer,
|
serializers.ModelSerializer[Any],
|
||||||
SetPermissionsMixin,
|
SetPermissionsMixin,
|
||||||
):
|
):
|
||||||
def __init__(self, *args, **kwargs) -> None:
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
@@ -469,7 +469,7 @@ class OwnedObjectSerializer(
|
|||||||
return super().update(instance, validated_data)
|
return super().update(instance, validated_data)
|
||||||
|
|
||||||
|
|
||||||
class OwnedObjectListSerializer(serializers.ListSerializer):
|
class OwnedObjectListSerializer(serializers.ListSerializer[Any]):
|
||||||
def to_representation(self, documents):
|
def to_representation(self, documents):
|
||||||
self.child.context["shared_object_pks"] = self.child.get_shared_object_pks(
|
self.child.context["shared_object_pks"] = self.child.get_shared_object_pks(
|
||||||
documents,
|
documents,
|
||||||
@@ -682,27 +682,27 @@ class TagSerializer(MatchingModelSerializer, OwnedObjectSerializer):
|
|||||||
return super().validate(attrs)
|
return super().validate(attrs)
|
||||||
|
|
||||||
|
|
||||||
class CorrespondentField(serializers.PrimaryKeyRelatedField):
|
class CorrespondentField(serializers.PrimaryKeyRelatedField[Correspondent]):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return Correspondent.objects.all()
|
return Correspondent.objects.all()
|
||||||
|
|
||||||
|
|
||||||
class TagsField(serializers.PrimaryKeyRelatedField):
|
class TagsField(serializers.PrimaryKeyRelatedField[Tag]):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return Tag.objects.all()
|
return Tag.objects.all()
|
||||||
|
|
||||||
|
|
||||||
class DocumentTypeField(serializers.PrimaryKeyRelatedField):
|
class DocumentTypeField(serializers.PrimaryKeyRelatedField[DocumentType]):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return DocumentType.objects.all()
|
return DocumentType.objects.all()
|
||||||
|
|
||||||
|
|
||||||
class StoragePathField(serializers.PrimaryKeyRelatedField):
|
class StoragePathField(serializers.PrimaryKeyRelatedField[StoragePath]):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return StoragePath.objects.all()
|
return StoragePath.objects.all()
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldSerializer(serializers.ModelSerializer):
|
class CustomFieldSerializer(serializers.ModelSerializer[CustomField]):
|
||||||
data_type = serializers.ChoiceField(
|
data_type = serializers.ChoiceField(
|
||||||
choices=CustomField.FieldDataType,
|
choices=CustomField.FieldDataType,
|
||||||
read_only=False,
|
read_only=False,
|
||||||
@@ -816,7 +816,7 @@ def validate_documentlink_targets(user, doc_ids):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldInstanceSerializer(serializers.ModelSerializer):
|
class CustomFieldInstanceSerializer(serializers.ModelSerializer[CustomFieldInstance]):
|
||||||
field = serializers.PrimaryKeyRelatedField(queryset=CustomField.objects.all())
|
field = serializers.PrimaryKeyRelatedField(queryset=CustomField.objects.all())
|
||||||
value = ReadWriteSerializerMethodField(allow_null=True)
|
value = ReadWriteSerializerMethodField(allow_null=True)
|
||||||
|
|
||||||
@@ -922,14 +922,14 @@ class CustomFieldInstanceSerializer(serializers.ModelSerializer):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class BasicUserSerializer(serializers.ModelSerializer):
|
class BasicUserSerializer(serializers.ModelSerializer[User]):
|
||||||
# Different than paperless.serializers.UserSerializer
|
# Different than paperless.serializers.UserSerializer
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ["id", "username", "first_name", "last_name"]
|
fields = ["id", "username", "first_name", "last_name"]
|
||||||
|
|
||||||
|
|
||||||
class NotesSerializer(serializers.ModelSerializer):
|
class NotesSerializer(serializers.ModelSerializer[Note]):
|
||||||
user = BasicUserSerializer(read_only=True)
|
user = BasicUserSerializer(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -1256,7 +1256,7 @@ class DocumentSerializer(
|
|||||||
list_serializer_class = OwnedObjectListSerializer
|
list_serializer_class = OwnedObjectListSerializer
|
||||||
|
|
||||||
|
|
||||||
class SearchResultListSerializer(serializers.ListSerializer):
|
class SearchResultListSerializer(serializers.ListSerializer[Document]):
|
||||||
def to_representation(self, hits):
|
def to_representation(self, hits):
|
||||||
document_ids = [hit["id"] for hit in hits]
|
document_ids = [hit["id"] for hit in hits]
|
||||||
# Fetch all Document objects in the list in one SQL query.
|
# Fetch all Document objects in the list in one SQL query.
|
||||||
@@ -1313,7 +1313,7 @@ class SearchResultSerializer(DocumentSerializer):
|
|||||||
list_serializer_class = SearchResultListSerializer
|
list_serializer_class = SearchResultListSerializer
|
||||||
|
|
||||||
|
|
||||||
class SavedViewFilterRuleSerializer(serializers.ModelSerializer):
|
class SavedViewFilterRuleSerializer(serializers.ModelSerializer[SavedViewFilterRule]):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SavedViewFilterRule
|
model = SavedViewFilterRule
|
||||||
fields = ["rule_type", "value"]
|
fields = ["rule_type", "value"]
|
||||||
@@ -2401,7 +2401,7 @@ class StoragePathSerializer(MatchingModelSerializer, OwnedObjectSerializer):
|
|||||||
return super().update(instance, validated_data)
|
return super().update(instance, validated_data)
|
||||||
|
|
||||||
|
|
||||||
class UiSettingsViewSerializer(serializers.ModelSerializer):
|
class UiSettingsViewSerializer(serializers.ModelSerializer[UiSettings]):
|
||||||
settings = serializers.DictField(required=False, allow_null=True)
|
settings = serializers.DictField(required=False, allow_null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -2760,7 +2760,7 @@ class BulkEditObjectsSerializer(SerializerWithPerms, SetPermissionsMixin):
|
|||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class WorkflowTriggerSerializer(serializers.ModelSerializer):
|
class WorkflowTriggerSerializer(serializers.ModelSerializer[WorkflowTrigger]):
|
||||||
id = serializers.IntegerField(required=False, allow_null=True)
|
id = serializers.IntegerField(required=False, allow_null=True)
|
||||||
sources = fields.MultipleChoiceField(
|
sources = fields.MultipleChoiceField(
|
||||||
choices=WorkflowTrigger.DocumentSourceChoices.choices,
|
choices=WorkflowTrigger.DocumentSourceChoices.choices,
|
||||||
@@ -2870,7 +2870,7 @@ class WorkflowTriggerSerializer(serializers.ModelSerializer):
|
|||||||
return super().update(instance, validated_data)
|
return super().update(instance, validated_data)
|
||||||
|
|
||||||
|
|
||||||
class WorkflowActionEmailSerializer(serializers.ModelSerializer):
|
class WorkflowActionEmailSerializer(serializers.ModelSerializer[WorkflowActionEmail]):
|
||||||
id = serializers.IntegerField(allow_null=True, required=False)
|
id = serializers.IntegerField(allow_null=True, required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -2884,7 +2884,9 @@ class WorkflowActionEmailSerializer(serializers.ModelSerializer):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class WorkflowActionWebhookSerializer(serializers.ModelSerializer):
|
class WorkflowActionWebhookSerializer(
|
||||||
|
serializers.ModelSerializer[WorkflowActionWebhook],
|
||||||
|
):
|
||||||
id = serializers.IntegerField(allow_null=True, required=False)
|
id = serializers.IntegerField(allow_null=True, required=False)
|
||||||
|
|
||||||
def validate_url(self, url):
|
def validate_url(self, url):
|
||||||
@@ -2905,7 +2907,7 @@ class WorkflowActionWebhookSerializer(serializers.ModelSerializer):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class WorkflowActionSerializer(serializers.ModelSerializer):
|
class WorkflowActionSerializer(serializers.ModelSerializer[WorkflowAction]):
|
||||||
id = serializers.IntegerField(required=False, allow_null=True)
|
id = serializers.IntegerField(required=False, allow_null=True)
|
||||||
assign_correspondent = CorrespondentField(allow_null=True, required=False)
|
assign_correspondent = CorrespondentField(allow_null=True, required=False)
|
||||||
assign_tags = TagsField(many=True, allow_null=True, required=False)
|
assign_tags = TagsField(many=True, allow_null=True, required=False)
|
||||||
@@ -3027,7 +3029,7 @@ class WorkflowActionSerializer(serializers.ModelSerializer):
|
|||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class WorkflowSerializer(serializers.ModelSerializer):
|
class WorkflowSerializer(serializers.ModelSerializer[Workflow]):
|
||||||
order = serializers.IntegerField(required=False)
|
order = serializers.IntegerField(required=False)
|
||||||
|
|
||||||
triggers = WorkflowTriggerSerializer(many=True)
|
triggers = WorkflowTriggerSerializer(many=True)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ class IndexView(TemplateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class PassUserMixin(GenericAPIView):
|
class PassUserMixin(GenericAPIView[Any]):
|
||||||
"""
|
"""
|
||||||
Pass a user object to serializer
|
Pass a user object to serializer
|
||||||
"""
|
"""
|
||||||
@@ -457,7 +457,10 @@ class PermissionsAwareDocumentCountMixin(BulkPermissionMixin, PassUserMixin):
|
|||||||
|
|
||||||
|
|
||||||
@extend_schema_view(**generate_object_with_permissions_schema(CorrespondentSerializer))
|
@extend_schema_view(**generate_object_with_permissions_schema(CorrespondentSerializer))
|
||||||
class CorrespondentViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet):
|
class CorrespondentViewSet(
|
||||||
|
PermissionsAwareDocumentCountMixin,
|
||||||
|
ModelViewSet[Correspondent],
|
||||||
|
):
|
||||||
model = Correspondent
|
model = Correspondent
|
||||||
|
|
||||||
queryset = Correspondent.objects.select_related("owner").order_by(Lower("name"))
|
queryset = Correspondent.objects.select_related("owner").order_by(Lower("name"))
|
||||||
@@ -494,7 +497,7 @@ class CorrespondentViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet):
|
|||||||
|
|
||||||
|
|
||||||
@extend_schema_view(**generate_object_with_permissions_schema(TagSerializer))
|
@extend_schema_view(**generate_object_with_permissions_schema(TagSerializer))
|
||||||
class TagViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet):
|
class TagViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet[Tag]):
|
||||||
model = Tag
|
model = Tag
|
||||||
serializer_class = TagSerializer
|
serializer_class = TagSerializer
|
||||||
document_count_through = Document.tags.through
|
document_count_through = Document.tags.through
|
||||||
@@ -573,7 +576,10 @@ class TagViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet):
|
|||||||
|
|
||||||
|
|
||||||
@extend_schema_view(**generate_object_with_permissions_schema(DocumentTypeSerializer))
|
@extend_schema_view(**generate_object_with_permissions_schema(DocumentTypeSerializer))
|
||||||
class DocumentTypeViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet):
|
class DocumentTypeViewSet(
|
||||||
|
PermissionsAwareDocumentCountMixin,
|
||||||
|
ModelViewSet[DocumentType],
|
||||||
|
):
|
||||||
model = DocumentType
|
model = DocumentType
|
||||||
|
|
||||||
queryset = DocumentType.objects.select_related("owner").order_by(Lower("name"))
|
queryset = DocumentType.objects.select_related("owner").order_by(Lower("name"))
|
||||||
@@ -808,7 +814,7 @@ class DocumentViewSet(
|
|||||||
UpdateModelMixin,
|
UpdateModelMixin,
|
||||||
DestroyModelMixin,
|
DestroyModelMixin,
|
||||||
ListModelMixin,
|
ListModelMixin,
|
||||||
GenericViewSet,
|
GenericViewSet[Document],
|
||||||
):
|
):
|
||||||
model = Document
|
model = Document
|
||||||
queryset = Document.objects.all()
|
queryset = Document.objects.all()
|
||||||
@@ -1248,7 +1254,10 @@ class DocumentViewSet(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
def suggestions(self, request, pk=None):
|
def suggestions(self, request, pk=None):
|
||||||
doc = get_object_or_404(Document.objects.select_related("owner"), pk=pk)
|
doc = get_object_or_404(
|
||||||
|
Document.objects.select_related("owner").prefetch_related("versions"),
|
||||||
|
pk=pk,
|
||||||
|
)
|
||||||
if request.user is not None and not has_perms_owner_aware(
|
if request.user is not None and not has_perms_owner_aware(
|
||||||
request.user,
|
request.user,
|
||||||
"view_document",
|
"view_document",
|
||||||
@@ -1952,7 +1961,7 @@ class ChatStreamingSerializer(serializers.Serializer):
|
|||||||
],
|
],
|
||||||
name="dispatch",
|
name="dispatch",
|
||||||
)
|
)
|
||||||
class ChatStreamingView(GenericAPIView):
|
class ChatStreamingView(GenericAPIView[Any]):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
serializer_class = ChatStreamingSerializer
|
serializer_class = ChatStreamingSerializer
|
||||||
|
|
||||||
@@ -2278,7 +2287,7 @@ class LogViewSet(ViewSet):
|
|||||||
|
|
||||||
|
|
||||||
@extend_schema_view(**generate_object_with_permissions_schema(SavedViewSerializer))
|
@extend_schema_view(**generate_object_with_permissions_schema(SavedViewSerializer))
|
||||||
class SavedViewViewSet(BulkPermissionMixin, PassUserMixin, ModelViewSet):
|
class SavedViewViewSet(BulkPermissionMixin, PassUserMixin, ModelViewSet[SavedView]):
|
||||||
model = SavedView
|
model = SavedView
|
||||||
|
|
||||||
queryset = SavedView.objects.select_related("owner").prefetch_related(
|
queryset = SavedView.objects.select_related("owner").prefetch_related(
|
||||||
@@ -2756,7 +2765,7 @@ class RemovePasswordDocumentsView(DocumentOperationPermissionMixin):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
class PostDocumentView(GenericAPIView):
|
class PostDocumentView(GenericAPIView[Any]):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
serializer_class = PostDocumentSerializer
|
serializer_class = PostDocumentSerializer
|
||||||
parser_classes = (parsers.MultiPartParser,)
|
parser_classes = (parsers.MultiPartParser,)
|
||||||
@@ -2877,7 +2886,7 @@ class PostDocumentView(GenericAPIView):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
class SelectionDataView(GenericAPIView):
|
class SelectionDataView(GenericAPIView[Any]):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
serializer_class = DocumentListSerializer
|
serializer_class = DocumentListSerializer
|
||||||
parser_classes = (parsers.MultiPartParser, parsers.JSONParser)
|
parser_classes = (parsers.MultiPartParser, parsers.JSONParser)
|
||||||
@@ -2981,7 +2990,7 @@ class SelectionDataView(GenericAPIView):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
class SearchAutoCompleteView(GenericAPIView):
|
class SearchAutoCompleteView(GenericAPIView[Any]):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
|
|
||||||
def get(self, request, format=None):
|
def get(self, request, format=None):
|
||||||
@@ -3262,7 +3271,7 @@ class GlobalSearchView(PassUserMixin):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
class StatisticsView(GenericAPIView):
|
class StatisticsView(GenericAPIView[Any]):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
|
|
||||||
def get(self, request, format=None):
|
def get(self, request, format=None):
|
||||||
@@ -3364,7 +3373,7 @@ class StatisticsView(GenericAPIView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BulkDownloadView(DocumentSelectionMixin, GenericAPIView):
|
class BulkDownloadView(DocumentSelectionMixin, GenericAPIView[Any]):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
serializer_class = BulkDownloadSerializer
|
serializer_class = BulkDownloadSerializer
|
||||||
parser_classes = (parsers.JSONParser,)
|
parser_classes = (parsers.JSONParser,)
|
||||||
@@ -3417,7 +3426,7 @@ class BulkDownloadView(DocumentSelectionMixin, GenericAPIView):
|
|||||||
|
|
||||||
|
|
||||||
@extend_schema_view(**generate_object_with_permissions_schema(StoragePathSerializer))
|
@extend_schema_view(**generate_object_with_permissions_schema(StoragePathSerializer))
|
||||||
class StoragePathViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet):
|
class StoragePathViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet[StoragePath]):
|
||||||
model = StoragePath
|
model = StoragePath
|
||||||
|
|
||||||
queryset = StoragePath.objects.select_related("owner").order_by(
|
queryset = StoragePath.objects.select_related("owner").order_by(
|
||||||
@@ -3481,7 +3490,7 @@ class StoragePathViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet):
|
|||||||
return Response(result)
|
return Response(result)
|
||||||
|
|
||||||
|
|
||||||
class UiSettingsView(GenericAPIView):
|
class UiSettingsView(GenericAPIView[Any]):
|
||||||
queryset = UiSettings.objects.all()
|
queryset = UiSettings.objects.all()
|
||||||
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
||||||
serializer_class = UiSettingsViewSerializer
|
serializer_class = UiSettingsViewSerializer
|
||||||
@@ -3579,7 +3588,7 @@ class UiSettingsView(GenericAPIView):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
class RemoteVersionView(GenericAPIView):
|
class RemoteVersionView(GenericAPIView[Any]):
|
||||||
cache_key = "remote_version_view_latest_release"
|
cache_key = "remote_version_view_latest_release"
|
||||||
|
|
||||||
def get(self, request, format=None):
|
def get(self, request, format=None):
|
||||||
@@ -3656,7 +3665,7 @@ class RemoteVersionView(GenericAPIView):
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
class TasksViewSet(ReadOnlyModelViewSet):
|
class TasksViewSet(ReadOnlyModelViewSet[PaperlessTask]):
|
||||||
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
||||||
serializer_class = TasksViewSerializer
|
serializer_class = TasksViewSerializer
|
||||||
filter_backends = (
|
filter_backends = (
|
||||||
@@ -3730,7 +3739,7 @@ class TasksViewSet(ReadOnlyModelViewSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ShareLinkViewSet(ModelViewSet, PassUserMixin):
|
class ShareLinkViewSet(PassUserMixin, ModelViewSet[ShareLink]):
|
||||||
model = ShareLink
|
model = ShareLink
|
||||||
|
|
||||||
queryset = ShareLink.objects.all()
|
queryset = ShareLink.objects.all()
|
||||||
@@ -3747,7 +3756,7 @@ class ShareLinkViewSet(ModelViewSet, PassUserMixin):
|
|||||||
ordering_fields = ("created", "expiration", "document")
|
ordering_fields = ("created", "expiration", "document")
|
||||||
|
|
||||||
|
|
||||||
class ShareLinkBundleViewSet(ModelViewSet, PassUserMixin):
|
class ShareLinkBundleViewSet(PassUserMixin, ModelViewSet[ShareLinkBundle]):
|
||||||
model = ShareLinkBundle
|
model = ShareLinkBundle
|
||||||
|
|
||||||
queryset = ShareLinkBundle.objects.all()
|
queryset = ShareLinkBundle.objects.all()
|
||||||
@@ -4104,7 +4113,7 @@ class BulkEditObjectsView(PassUserMixin):
|
|||||||
return Response({"result": "OK"})
|
return Response({"result": "OK"})
|
||||||
|
|
||||||
|
|
||||||
class WorkflowTriggerViewSet(ModelViewSet):
|
class WorkflowTriggerViewSet(ModelViewSet[WorkflowTrigger]):
|
||||||
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
||||||
|
|
||||||
serializer_class = WorkflowTriggerSerializer
|
serializer_class = WorkflowTriggerSerializer
|
||||||
@@ -4122,7 +4131,7 @@ class WorkflowTriggerViewSet(ModelViewSet):
|
|||||||
return super().partial_update(request, *args, **kwargs)
|
return super().partial_update(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class WorkflowActionViewSet(ModelViewSet):
|
class WorkflowActionViewSet(ModelViewSet[WorkflowAction]):
|
||||||
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
||||||
|
|
||||||
serializer_class = WorkflowActionSerializer
|
serializer_class = WorkflowActionSerializer
|
||||||
@@ -4147,7 +4156,7 @@ class WorkflowActionViewSet(ModelViewSet):
|
|||||||
return super().partial_update(request, *args, **kwargs)
|
return super().partial_update(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class WorkflowViewSet(ModelViewSet):
|
class WorkflowViewSet(ModelViewSet[Workflow]):
|
||||||
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
||||||
|
|
||||||
serializer_class = WorkflowSerializer
|
serializer_class = WorkflowSerializer
|
||||||
@@ -4165,7 +4174,7 @@ class WorkflowViewSet(ModelViewSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet):
|
class CustomFieldViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet[CustomField]):
|
||||||
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
||||||
|
|
||||||
serializer_class = CustomFieldSerializer
|
serializer_class = CustomFieldSerializer
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -74,7 +74,7 @@ class PaperlessAuthTokenSerializer(AuthTokenSerializer):
|
|||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class UserSerializer(PasswordValidationMixin, serializers.ModelSerializer):
|
class UserSerializer(PasswordValidationMixin, serializers.ModelSerializer[User]):
|
||||||
password = ObfuscatedPasswordField(required=False)
|
password = ObfuscatedPasswordField(required=False)
|
||||||
user_permissions = serializers.SlugRelatedField(
|
user_permissions = serializers.SlugRelatedField(
|
||||||
many=True,
|
many=True,
|
||||||
@@ -142,7 +142,7 @@ class UserSerializer(PasswordValidationMixin, serializers.ModelSerializer):
|
|||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
class GroupSerializer(serializers.ModelSerializer):
|
class GroupSerializer(serializers.ModelSerializer[Group]):
|
||||||
permissions = serializers.SlugRelatedField(
|
permissions = serializers.SlugRelatedField(
|
||||||
many=True,
|
many=True,
|
||||||
queryset=Permission.objects.exclude(content_type__app_label="admin"),
|
queryset=Permission.objects.exclude(content_type__app_label="admin"),
|
||||||
@@ -158,7 +158,7 @@ class GroupSerializer(serializers.ModelSerializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SocialAccountSerializer(serializers.ModelSerializer):
|
class SocialAccountSerializer(serializers.ModelSerializer[SocialAccount]):
|
||||||
name = serializers.SerializerMethodField()
|
name = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -176,7 +176,7 @@ class SocialAccountSerializer(serializers.ModelSerializer):
|
|||||||
return "Unknown App"
|
return "Unknown App"
|
||||||
|
|
||||||
|
|
||||||
class ProfileSerializer(PasswordValidationMixin, serializers.ModelSerializer):
|
class ProfileSerializer(PasswordValidationMixin, serializers.ModelSerializer[User]):
|
||||||
email = serializers.EmailField(allow_blank=True, required=False)
|
email = serializers.EmailField(allow_blank=True, required=False)
|
||||||
password = ObfuscatedPasswordField(required=False, allow_null=False)
|
password = ObfuscatedPasswordField(required=False, allow_null=False)
|
||||||
auth_token = serializers.SlugRelatedField(read_only=True, slug_field="key")
|
auth_token = serializers.SlugRelatedField(read_only=True, slug_field="key")
|
||||||
@@ -209,7 +209,9 @@ class ProfileSerializer(PasswordValidationMixin, serializers.ModelSerializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ApplicationConfigurationSerializer(serializers.ModelSerializer):
|
class ApplicationConfigurationSerializer(
|
||||||
|
serializers.ModelSerializer[ApplicationConfiguration],
|
||||||
|
):
|
||||||
user_args = serializers.JSONField(binary=True, allow_null=True)
|
user_args = serializers.JSONField(binary=True, allow_null=True)
|
||||||
barcode_tag_mapping = serializers.JSONField(binary=True, allow_null=True)
|
barcode_tag_mapping = serializers.JSONField(binary=True, allow_null=True)
|
||||||
llm_api_key = ObfuscatedPasswordField(
|
llm_api_key = ObfuscatedPasswordField(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from allauth.mfa import signals
|
from allauth.mfa import signals
|
||||||
from allauth.mfa.adapter import get_adapter as get_mfa_adapter
|
from allauth.mfa.adapter import get_adapter as get_mfa_adapter
|
||||||
@@ -114,7 +115,7 @@ class FaviconView(View):
|
|||||||
return HttpResponseNotFound("favicon.ico not found")
|
return HttpResponseNotFound("favicon.ico not found")
|
||||||
|
|
||||||
|
|
||||||
class UserViewSet(ModelViewSet):
|
class UserViewSet(ModelViewSet[User]):
|
||||||
_BOOL_NOT_PROVIDED = object()
|
_BOOL_NOT_PROVIDED = object()
|
||||||
model = User
|
model = User
|
||||||
|
|
||||||
@@ -216,7 +217,7 @@ class UserViewSet(ModelViewSet):
|
|||||||
return HttpResponseNotFound("TOTP not found")
|
return HttpResponseNotFound("TOTP not found")
|
||||||
|
|
||||||
|
|
||||||
class GroupViewSet(ModelViewSet):
|
class GroupViewSet(ModelViewSet[Group]):
|
||||||
model = Group
|
model = Group
|
||||||
|
|
||||||
queryset = Group.objects.order_by(Lower("name"))
|
queryset = Group.objects.order_by(Lower("name"))
|
||||||
@@ -229,7 +230,7 @@ class GroupViewSet(ModelViewSet):
|
|||||||
ordering_fields = ("name",)
|
ordering_fields = ("name",)
|
||||||
|
|
||||||
|
|
||||||
class ProfileView(GenericAPIView):
|
class ProfileView(GenericAPIView[Any]):
|
||||||
"""
|
"""
|
||||||
User profile view, only available when logged in
|
User profile view, only available when logged in
|
||||||
"""
|
"""
|
||||||
@@ -288,7 +289,7 @@ class ProfileView(GenericAPIView):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
class TOTPView(GenericAPIView):
|
class TOTPView(GenericAPIView[Any]):
|
||||||
"""
|
"""
|
||||||
TOTP views
|
TOTP views
|
||||||
"""
|
"""
|
||||||
@@ -368,7 +369,7 @@ class TOTPView(GenericAPIView):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
class GenerateAuthTokenView(GenericAPIView):
|
class GenerateAuthTokenView(GenericAPIView[Any]):
|
||||||
"""
|
"""
|
||||||
Generates (or re-generates) an auth token, requires a logged in user
|
Generates (or re-generates) an auth token, requires a logged in user
|
||||||
unlike the default DRF endpoint
|
unlike the default DRF endpoint
|
||||||
@@ -397,7 +398,7 @@ class GenerateAuthTokenView(GenericAPIView):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
class ApplicationConfigurationViewSet(ModelViewSet):
|
class ApplicationConfigurationViewSet(ModelViewSet[ApplicationConfiguration]):
|
||||||
model = ApplicationConfiguration
|
model = ApplicationConfiguration
|
||||||
|
|
||||||
queryset = ApplicationConfiguration.objects
|
queryset = ApplicationConfiguration.objects
|
||||||
@@ -450,7 +451,7 @@ class ApplicationConfigurationViewSet(ModelViewSet):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
class DisconnectSocialAccountView(GenericAPIView):
|
class DisconnectSocialAccountView(GenericAPIView[Any]):
|
||||||
"""
|
"""
|
||||||
Disconnects a social account provider from the user account
|
Disconnects a social account provider from the user account
|
||||||
"""
|
"""
|
||||||
@@ -476,7 +477,7 @@ class DisconnectSocialAccountView(GenericAPIView):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
class SocialAccountProvidersView(GenericAPIView):
|
class SocialAccountProvidersView(GenericAPIView[Any]):
|
||||||
"""
|
"""
|
||||||
List of social account providers
|
List of social account providers
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class MailAccountSerializer(OwnedObjectSerializer):
|
|||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
class AccountField(serializers.PrimaryKeyRelatedField):
|
class AccountField(serializers.PrimaryKeyRelatedField[MailAccount]):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return MailAccount.objects.all().order_by("-id")
|
return MailAccount.objects.all().order_by("-id")
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from django.http import HttpResponseBadRequest
|
from django.http import HttpResponseBadRequest
|
||||||
from django.http import HttpResponseForbidden
|
from django.http import HttpResponseForbidden
|
||||||
@@ -65,7 +66,7 @@ from paperless_mail.tasks import process_mail_accounts
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
class MailAccountViewSet(ModelViewSet, PassUserMixin):
|
class MailAccountViewSet(PassUserMixin, ModelViewSet[MailAccount]):
|
||||||
model = MailAccount
|
model = MailAccount
|
||||||
|
|
||||||
queryset = MailAccount.objects.all().order_by("pk")
|
queryset = MailAccount.objects.all().order_by("pk")
|
||||||
@@ -159,7 +160,7 @@ class MailAccountViewSet(ModelViewSet, PassUserMixin):
|
|||||||
return Response({"result": "OK"})
|
return Response({"result": "OK"})
|
||||||
|
|
||||||
|
|
||||||
class ProcessedMailViewSet(ReadOnlyModelViewSet, PassUserMixin):
|
class ProcessedMailViewSet(PassUserMixin, ReadOnlyModelViewSet[ProcessedMail]):
|
||||||
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
||||||
serializer_class = ProcessedMailSerializer
|
serializer_class = ProcessedMailSerializer
|
||||||
pagination_class = StandardPagination
|
pagination_class = StandardPagination
|
||||||
@@ -187,7 +188,7 @@ class ProcessedMailViewSet(ReadOnlyModelViewSet, PassUserMixin):
|
|||||||
return Response({"result": "OK", "deleted_mail_ids": mail_ids})
|
return Response({"result": "OK", "deleted_mail_ids": mail_ids})
|
||||||
|
|
||||||
|
|
||||||
class MailRuleViewSet(ModelViewSet, PassUserMixin):
|
class MailRuleViewSet(PassUserMixin, ModelViewSet[MailRule]):
|
||||||
model = MailRule
|
model = MailRule
|
||||||
|
|
||||||
queryset = MailRule.objects.all().order_by("order")
|
queryset = MailRule.objects.all().order_by("order")
|
||||||
@@ -203,7 +204,7 @@ class MailRuleViewSet(ModelViewSet, PassUserMixin):
|
|||||||
responses={200: None},
|
responses={200: None},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
class OauthCallbackView(GenericAPIView):
|
class OauthCallbackView(GenericAPIView[Any]):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
|
|
||||||
def get(self, request, format=None):
|
def get(self, request, format=None):
|
||||||
|
|||||||
8
uv.lock
generated
8
uv.lock
generated
@@ -875,15 +875,15 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "django"
|
name = "django"
|
||||||
version = "5.2.12"
|
version = "5.2.13"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "asgiref", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
{ name = "asgiref", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||||
{ name = "sqlparse", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
{ name = "sqlparse", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/bd/55/b9445fc0695b03746f355c05b2eecc54c34e05198c686f4fc4406b722b52/django-5.2.12.tar.gz", hash = "sha256:6b809af7165c73eff5ce1c87fdae75d4da6520d6667f86401ecf55b681eb1eeb", size = 10860574, upload-time = "2026-03-03T13:56:05.509Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/1f/c5/c69e338eb2959f641045802e5ea87ca4bf5ac90c5fd08953ca10742fad51/django-5.2.13.tar.gz", hash = "sha256:a31589db5188d074c63f0945c3888fad104627dfcc236fb2b97f71f89da33bc4", size = 10890368, upload-time = "2026-04-07T14:02:15.072Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/4e/32/4b144e125678efccf5d5b61581de1c4088d6b0286e46096e3b8de0d556c8/django-5.2.12-py3-none-any.whl", hash = "sha256:4853482f395c3a151937f6991272540fcbf531464f254a347bf7c89f53c8cff7", size = 8310245, upload-time = "2026-03-03T13:56:01.174Z" },
|
{ url = "https://files.pythonhosted.org/packages/59/b1/51ab36b2eefcf8cdb9338c7188668a157e29e30306bfc98a379704c9e10d/django-5.2.13-py3-none-any.whl", hash = "sha256:5788fce61da23788a8ce6f02583765ab060d396720924789f97fa42119d37f7a", size = 8310982, upload-time = "2026-04-07T14:02:08.883Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3014,7 +3014,7 @@ requires-dist = [
|
|||||||
{ name = "channels-redis", specifier = "~=4.2" },
|
{ name = "channels-redis", specifier = "~=4.2" },
|
||||||
{ name = "concurrent-log-handler", specifier = "~=0.9.25" },
|
{ name = "concurrent-log-handler", specifier = "~=0.9.25" },
|
||||||
{ name = "dateparser", specifier = "~=1.2" },
|
{ name = "dateparser", specifier = "~=1.2" },
|
||||||
{ name = "django", specifier = "~=5.2.10" },
|
{ name = "django", specifier = "~=5.2.13" },
|
||||||
{ name = "django-allauth", extras = ["mfa", "socialaccount"], specifier = "~=65.15.0" },
|
{ name = "django-allauth", extras = ["mfa", "socialaccount"], specifier = "~=65.15.0" },
|
||||||
{ name = "django-auditlog", specifier = "~=3.4.1" },
|
{ name = "django-auditlog", specifier = "~=3.4.1" },
|
||||||
{ name = "django-cachalot", specifier = "~=2.9.0" },
|
{ name = "django-cachalot", specifier = "~=2.9.0" },
|
||||||
|
|||||||
Reference in New Issue
Block a user