mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-29 11:09:27 -05:00
WIP: add asn prefix
This commit is contained in:
parent
aef68f0b41
commit
d974bc542e
@ -12,6 +12,14 @@
|
||||
</div>
|
||||
<div class="position-relative" [class.col-md-9]="horizontal">
|
||||
<div class="input-group" [class.is-invalid]="error">
|
||||
@if (prefix) {
|
||||
<ng-select class="form-control"
|
||||
[items]="prefix"
|
||||
bindLabel="name"
|
||||
bindValue="id"
|
||||
[(ngModel)]="prefixSelect"
|
||||
></ng-select>
|
||||
}
|
||||
<input #inputField type="number" class="form-control" [step]="step" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" [class.is-invalid]="error" [disabled]="disabled">
|
||||
@if (showAdd) {
|
||||
<button class="btn btn-outline-secondary" type="button" id="button-addon1" (click)="nextAsn()" [disabled]="disabled">+1</button>
|
||||
|
@ -2,11 +2,13 @@ import { Component, forwardRef, Input } from '@angular/core'
|
||||
import {
|
||||
FormsModule,
|
||||
NG_VALUE_ACCESSOR,
|
||||
ReactiveFormsModule,
|
||||
ReactiveFormsModule
|
||||
} from '@angular/forms'
|
||||
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
||||
import { DocumentService } from 'src/app/services/rest/document.service'
|
||||
import { AbstractInputComponent } from '../abstract-input'
|
||||
import { NgSelectModule } from '@ng-select/ng-select'
|
||||
import { AsnPrefix } from "../../../../data/asn-prefix";
|
||||
|
||||
@Component({
|
||||
providers: [
|
||||
@ -19,12 +21,18 @@ import { AbstractInputComponent } from '../abstract-input'
|
||||
selector: 'pngx-input-number',
|
||||
templateUrl: './number.component.html',
|
||||
styleUrls: ['./number.component.scss'],
|
||||
imports: [FormsModule, ReactiveFormsModule, NgxBootstrapIconsModule],
|
||||
imports: [FormsModule, ReactiveFormsModule, NgxBootstrapIconsModule, NgSelectModule],
|
||||
})
|
||||
export class NumberComponent extends AbstractInputComponent<number> {
|
||||
@Input()
|
||||
showAdd: boolean = true
|
||||
|
||||
@Input()
|
||||
prefix: AsnPrefix[]
|
||||
|
||||
@Input()
|
||||
prefixSelect: number
|
||||
|
||||
@Input()
|
||||
step: number = 1
|
||||
|
||||
|
@ -106,7 +106,7 @@
|
||||
<ng-template ngbNavContent>
|
||||
<div>
|
||||
<pngx-input-text #inputTitle i18n-title title="Title" formControlName="title" [horizontal]="true" (keyup)="titleKeyUp($event)" [error]="error?.title"></pngx-input-text>
|
||||
<pngx-input-number i18n-title title="Archive serial number" [error]="error?.archive_serial_number" [horizontal]="true" formControlName='archive_serial_number'></pngx-input-number>
|
||||
<pngx-input-number [prefix]="asnPrefix" [prefixSelect]="archive_serial_number_prefix" i18n-title title="Archive serial number" [error]="error?.archive_serial_number" [horizontal]="true" formControlName='archive_serial_number'></pngx-input-number>
|
||||
<pngx-input-date i18n-title title="Date created" formControlName="created_date" [suggestions]="suggestions?.dates" [showFilter]="true" [horizontal]="true" (filterDocuments)="filterDocuments($event)"
|
||||
[error]="error?.created_date"></pngx-input-date>
|
||||
<pngx-input-select [items]="correspondents" i18n-title title="Correspondent" formControlName="correspondent" [allowNull]="true" [showFilter]="true" [horizontal]="true" (filterDocuments)="filterDocuments($event, DataType.Correspondent)"
|
||||
|
@ -67,6 +67,7 @@ import {
|
||||
PermissionsService,
|
||||
PermissionType,
|
||||
} from 'src/app/services/permissions.service'
|
||||
import { AsnPrefixService } from 'src/app/services/rest/asn-prefix.service'
|
||||
import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
|
||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
||||
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
|
||||
@ -102,6 +103,7 @@ import { DocumentHistoryComponent } from '../document-history/document-history.c
|
||||
import { DocumentNotesComponent } from '../document-notes/document-notes.component'
|
||||
import { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
|
||||
import { MetadataCollapseComponent } from './metadata-collapse/metadata-collapse.component'
|
||||
import { AsnPrefix } from "../../data/asn-prefix";
|
||||
|
||||
enum DocumentDetailNavIDs {
|
||||
Details = 1,
|
||||
@ -171,8 +173,7 @@ enum ZoomSetting {
|
||||
})
|
||||
export class DocumentDetailComponent
|
||||
extends ComponentWithPermissions
|
||||
implements OnInit, OnDestroy, DirtyComponent
|
||||
{
|
||||
implements OnInit, OnDestroy, DirtyComponent {
|
||||
@ViewChild('inputTitle')
|
||||
titleInput: TextComponent
|
||||
|
||||
@ -200,6 +201,7 @@ export class DocumentDetailComponent
|
||||
tiffURL: string
|
||||
tiffError: string
|
||||
|
||||
asnPrefix: AsnPrefix[]
|
||||
correspondents: Correspondent[]
|
||||
documentTypes: DocumentType[]
|
||||
storagePaths: StoragePath[]
|
||||
@ -211,6 +213,7 @@ export class DocumentDetailComponent
|
||||
correspondent: new FormControl(),
|
||||
document_type: new FormControl(),
|
||||
storage_path: new FormControl(),
|
||||
archive_serial_number_prefix: new FormControl(),
|
||||
archive_serial_number: new FormControl(),
|
||||
tags: new FormControl([]),
|
||||
permissions_form: new FormControl(null),
|
||||
@ -258,6 +261,7 @@ export class DocumentDetailComponent
|
||||
constructor(
|
||||
private documentsService: DocumentService,
|
||||
private route: ActivatedRoute,
|
||||
private asnPrefixService: AsnPrefixService,
|
||||
private correspondentService: CorrespondentService,
|
||||
private documentTypeService: DocumentTypeService,
|
||||
private router: Router,
|
||||
@ -347,6 +351,17 @@ export class DocumentDetailComponent
|
||||
.pipe(first(), takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((result) => (this.correspondents = result.results))
|
||||
}
|
||||
if (
|
||||
this.permissionsService.currentUserCan(
|
||||
PermissionAction.View,
|
||||
PermissionType.AsnPrefix
|
||||
)
|
||||
) {
|
||||
this.asnPrefixService
|
||||
.listAll()
|
||||
.pipe(first(), takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((result) => (this.asnPrefix = result.results))
|
||||
}
|
||||
if (
|
||||
this.permissionsService.currentUserCan(
|
||||
PermissionAction.View,
|
||||
@ -403,9 +418,8 @@ export class DocumentDetailComponent
|
||||
this.previewText = res.toString()
|
||||
},
|
||||
error: (err) => {
|
||||
this.previewText = $localize`An error occurred loading content: ${
|
||||
err.message ?? err.toString()
|
||||
}`
|
||||
this.previewText = $localize`An error occurred loading content: ${err.message ?? err.toString()
|
||||
}`
|
||||
},
|
||||
})
|
||||
this.thumbUrl = this.documentsService.getThumbUrl(documentId)
|
||||
@ -449,7 +463,7 @@ export class DocumentDetailComponent
|
||||
this.documentForm.get('permissions_form').value['owner']
|
||||
openDocument['permissions'] =
|
||||
this.documentForm.get('permissions_form').value[
|
||||
'set_permissions'
|
||||
'set_permissions'
|
||||
]
|
||||
delete openDocument['permissions_form']
|
||||
}
|
||||
@ -494,6 +508,7 @@ export class DocumentDetailComponent
|
||||
correspondent: doc.correspondent,
|
||||
document_type: doc.document_type,
|
||||
storage_path: doc.storage_path,
|
||||
archive_serial_number_prefix: doc.archive_serial_number_prefix,
|
||||
archive_serial_number: doc.archive_serial_number,
|
||||
tags: [...doc.tags],
|
||||
permissions_form: {
|
||||
@ -793,7 +808,7 @@ export class DocumentDetailComponent
|
||||
|
||||
save(close: boolean = false) {
|
||||
this.networkActive = true
|
||||
;(document.activeElement as HTMLElement)?.dispatchEvent(new Event('change'))
|
||||
; (document.activeElement as HTMLElement)?.dispatchEvent(new Event('change'))
|
||||
this.documentsService
|
||||
.update(this.document)
|
||||
.pipe(first())
|
||||
@ -1046,7 +1061,7 @@ export class DocumentDetailComponent
|
||||
this.previewZoomScale = ZoomSetting.PageWidth
|
||||
this.previewZoomSetting =
|
||||
Object.values(ZoomSetting)[
|
||||
Math.min(Object.values(ZoomSetting).length - 1, currentIndex + 1)
|
||||
Math.min(Object.values(ZoomSetting).length - 1, currentIndex + 1)
|
||||
]
|
||||
}
|
||||
|
||||
|
9
src-ui/src/app/data/asn-prefix.ts
Normal file
9
src-ui/src/app/data/asn-prefix.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import {ObjectWithId} from "./object-with-id";
|
||||
|
||||
export interface AsnPrefix extends ObjectWithId {
|
||||
name?: string
|
||||
|
||||
slug?: string
|
||||
|
||||
document_count?: number
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import { Observable } from 'rxjs'
|
||||
import { AsnPrefix } from './asn-prefix'
|
||||
import { Correspondent } from './correspondent'
|
||||
import { CustomFieldInstance } from './custom-field-instance'
|
||||
import { DocumentNote } from './document-note'
|
||||
@ -118,6 +119,10 @@ export interface SearchHit {
|
||||
}
|
||||
|
||||
export interface Document extends ObjectWithPermissions {
|
||||
archive_serial_number_prefix$?: Observable<AsnPrefix>
|
||||
|
||||
archive_serial_number_prefix?: number
|
||||
|
||||
correspondent$?: Observable<Correspondent>
|
||||
|
||||
correspondent?: number
|
||||
|
@ -12,6 +12,7 @@ export enum PermissionAction {
|
||||
export enum PermissionType {
|
||||
Document = '%s_document',
|
||||
Tag = '%s_tag',
|
||||
AsnPrefix = '%s_asnprefix',
|
||||
Correspondent = '%s_correspondent',
|
||||
DocumentType = '%s_documenttype',
|
||||
StoragePath = '%s_storagepath',
|
||||
|
13
src-ui/src/app/services/rest/asn-prefix.service.ts
Normal file
13
src-ui/src/app/services/rest/asn-prefix.service.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { HttpClient } from '@angular/common/http'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { AsnPrefix } from 'src/app/data/asn-prefix'
|
||||
import { AbstractNameFilterService } from './abstract-name-filter-service'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AsnPrefixService extends AbstractNameFilterService<AsnPrefix> {
|
||||
constructor(http: HttpClient) {
|
||||
super(http, 'asn_prefix')
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from guardian.admin import GuardedModelAdmin
|
||||
|
||||
from documents.models import ArchiveSerialNumberPrefix
|
||||
from documents.models import Correspondent
|
||||
from documents.models import CustomField
|
||||
from documents.models import CustomFieldInstance
|
||||
@ -38,6 +39,10 @@ class DocumentTypeAdmin(GuardedModelAdmin):
|
||||
list_filter = ("matching_algorithm",)
|
||||
list_editable = ("match", "matching_algorithm")
|
||||
|
||||
class ArchiveSerialNumberPrefixAdmin(GuardedModelAdmin):
|
||||
list_display = ("name", "owner")
|
||||
list_filter = ("name",)
|
||||
#list_editable = ("name",)
|
||||
|
||||
class DocumentAdmin(GuardedModelAdmin):
|
||||
search_fields = ("correspondent__name", "title", "content", "tags__name")
|
||||
@ -60,6 +65,7 @@ class DocumentAdmin(GuardedModelAdmin):
|
||||
|
||||
list_filter = (
|
||||
("mime_type"),
|
||||
("archive_serial_number_prefix", admin.EmptyFieldListFilter),
|
||||
("archive_serial_number", admin.EmptyFieldListFilter),
|
||||
("archive_filename", admin.EmptyFieldListFilter),
|
||||
)
|
||||
@ -195,6 +201,7 @@ class CustomFieldInstancesAdmin(GuardedModelAdmin):
|
||||
admin.site.register(Correspondent, CorrespondentAdmin)
|
||||
admin.site.register(Tag, TagAdmin)
|
||||
admin.site.register(DocumentType, DocumentTypeAdmin)
|
||||
admin.site.register(ArchiveSerialNumberPrefix, ArchiveSerialNumberPrefixAdmin)
|
||||
admin.site.register(Document, DocumentAdmin)
|
||||
admin.site.register(SavedView, SavedViewAdmin)
|
||||
admin.site.register(StoragePath, StoragePathAdmin)
|
||||
|
@ -28,6 +28,7 @@ from rest_framework import serializers
|
||||
from rest_framework.filters import OrderingFilter
|
||||
from rest_framework_guardian.filters import ObjectPermissionsFilter
|
||||
|
||||
from documents.models import ArchiveSerialNumberPrefix
|
||||
from documents.models import Correspondent
|
||||
from documents.models import CustomField
|
||||
from documents.models import CustomFieldInstance
|
||||
@ -65,6 +66,14 @@ class TagFilterSet(FilterSet):
|
||||
}
|
||||
|
||||
|
||||
class ArchiveSerialNumberPrefixFilterSet(FilterSet):
|
||||
class Meta:
|
||||
model = ArchiveSerialNumberPrefix
|
||||
fields = {
|
||||
"id": ID_KWARGS,
|
||||
"name": CHAR_KWARGS,
|
||||
}
|
||||
|
||||
class DocumentTypeFilterSet(FilterSet):
|
||||
class Meta:
|
||||
model = DocumentType
|
||||
|
@ -245,6 +245,7 @@ class DelayedQuery:
|
||||
"title": "title",
|
||||
"correspondent__name": "correspondent",
|
||||
"document_type__name": "type",
|
||||
"archive_serial_number_prefix": "asn_prefix",
|
||||
"archive_serial_number": "asn",
|
||||
"num_notes": "num_notes",
|
||||
"owner": "owner",
|
||||
|
@ -0,0 +1,32 @@
|
||||
# Generated by Django 5.1.4 on 2025-01-05 16:53
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('documents', '1060_alter_customfieldinstance_value_select'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ArchiveSerialNumberPrefix',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=6, verbose_name='name')),
|
||||
('owner', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='owner')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='document',
|
||||
name='archive_serial_number_prefix',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='documents', to='documents.archiveserialnumberprefix', verbose_name='archive serial number prefix'),
|
||||
),
|
||||
]
|
@ -95,6 +95,13 @@ class MatchingModel(ModelWithOwner):
|
||||
return self.name
|
||||
|
||||
|
||||
class ArchiveSerialNumberPrefix(ModelWithOwner):
|
||||
name = models.CharField(_("name"), max_length=6)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Correspondent(MatchingModel):
|
||||
class Meta(MatchingModel.Meta):
|
||||
verbose_name = _("correspondent")
|
||||
@ -272,6 +279,15 @@ class Document(SoftDeleteModel, ModelWithOwner):
|
||||
help_text=_("The original name of the file when it was uploaded"),
|
||||
)
|
||||
|
||||
archive_serial_number_prefix = models.ForeignKey(
|
||||
ArchiveSerialNumberPrefix,
|
||||
blank=True,
|
||||
null=True,
|
||||
related_name="documents",
|
||||
on_delete=models.SET_NULL,
|
||||
verbose_name=_("archive serial number prefix"),
|
||||
)
|
||||
|
||||
ARCHIVE_SERIAL_NUMBER_MIN: Final[int] = 0
|
||||
ARCHIVE_SERIAL_NUMBER_MAX: Final[int] = 0xFF_FF_FF_FF
|
||||
|
||||
|
@ -34,6 +34,7 @@ if settings.AUDIT_LOG_ENABLED:
|
||||
|
||||
from documents import bulk_edit
|
||||
from documents.data_models import DocumentSource
|
||||
from documents.models import ArchiveSerialNumberPrefix
|
||||
from documents.models import Correspondent
|
||||
from documents.models import CustomField
|
||||
from documents.models import CustomFieldInstance
|
||||
@ -342,6 +343,22 @@ class OwnedObjectListSerializer(serializers.ListSerializer):
|
||||
return super().to_representation(documents)
|
||||
|
||||
|
||||
|
||||
class ArchiveSerialNumberPrefixSerializer(MatchingModelSerializer, OwnedObjectSerializer):
|
||||
class Meta:
|
||||
model = ArchiveSerialNumberPrefix
|
||||
fields = (
|
||||
"id",
|
||||
"slug",
|
||||
"name",
|
||||
"document_count",
|
||||
"owner",
|
||||
"permissions",
|
||||
"user_can_change",
|
||||
"set_permissions",
|
||||
)
|
||||
|
||||
|
||||
class CorrespondentSerializer(MatchingModelSerializer, OwnedObjectSerializer):
|
||||
last_correspondence = serializers.DateTimeField(read_only=True, required=False)
|
||||
|
||||
@ -362,7 +379,6 @@ class CorrespondentSerializer(MatchingModelSerializer, OwnedObjectSerializer):
|
||||
"set_permissions",
|
||||
)
|
||||
|
||||
|
||||
class DocumentTypeSerializer(MatchingModelSerializer, OwnedObjectSerializer):
|
||||
class Meta:
|
||||
model = DocumentType
|
||||
@ -474,6 +490,9 @@ class TagSerializer(MatchingModelSerializer, OwnedObjectSerializer):
|
||||
raise serializers.ValidationError(_("Invalid color."))
|
||||
return color
|
||||
|
||||
class ArchiveSerialNumberPrefixField(serializers.PrimaryKeyRelatedField):
|
||||
def get_queryset(self):
|
||||
return ArchiveSerialNumberPrefix.objects.all()
|
||||
|
||||
class CorrespondentField(serializers.PrimaryKeyRelatedField):
|
||||
def get_queryset(self):
|
||||
@ -778,6 +797,7 @@ class DocumentSerializer(
|
||||
NestedUpdateMixin,
|
||||
DynamicFieldsModelSerializer,
|
||||
):
|
||||
archive_serial_number_prefix = ArchiveSerialNumberPrefixField(allow_null=True)
|
||||
correspondent = CorrespondentField(allow_null=True)
|
||||
tags = TagsField(many=True)
|
||||
document_type = DocumentTypeField(allow_null=True)
|
||||
@ -832,6 +852,7 @@ class DocumentSerializer(
|
||||
and len(str(attrs["archive_serial_number"])) > 0
|
||||
and Document.deleted_objects.filter(
|
||||
archive_serial_number=attrs["archive_serial_number"],
|
||||
#archive_serial_number_prefix__prefix=attrs["archive_serial_number_prefix"], # TODO: asn type empty is allowed
|
||||
).exists()
|
||||
):
|
||||
raise serializers.ValidationError(
|
||||
@ -934,6 +955,7 @@ class DocumentSerializer(
|
||||
"modified",
|
||||
"added",
|
||||
"deleted_at",
|
||||
"archive_serial_number_prefix",
|
||||
"archive_serial_number",
|
||||
"original_file_name",
|
||||
"archived_file_name",
|
||||
|
@ -93,6 +93,7 @@ from documents.conditionals import thumbnail_last_modified
|
||||
from documents.data_models import ConsumableDocument
|
||||
from documents.data_models import DocumentMetadataOverrides
|
||||
from documents.data_models import DocumentSource
|
||||
from documents.filters import ArchiveSerialNumberPrefixFilterSet
|
||||
from documents.filters import CorrespondentFilterSet
|
||||
from documents.filters import CustomFieldFilterSet
|
||||
from documents.filters import DocumentFilterSet
|
||||
@ -107,6 +108,7 @@ from documents.matching import match_correspondents
|
||||
from documents.matching import match_document_types
|
||||
from documents.matching import match_storage_paths
|
||||
from documents.matching import match_tags
|
||||
from documents.models import ArchiveSerialNumberPrefix
|
||||
from documents.models import Correspondent
|
||||
from documents.models import CustomField
|
||||
from documents.models import Document
|
||||
@ -130,6 +132,7 @@ from documents.permissions import get_objects_for_user_owner_aware
|
||||
from documents.permissions import has_perms_owner_aware
|
||||
from documents.permissions import set_permissions_for_object
|
||||
from documents.serialisers import AcknowledgeTasksViewSerializer
|
||||
from documents.serialisers import ArchiveSerialNumberPrefixSerializer
|
||||
from documents.serialisers import BulkDownloadSerializer
|
||||
from documents.serialisers import BulkEditObjectsSerializer
|
||||
from documents.serialisers import BulkEditSerializer
|
||||
@ -258,6 +261,22 @@ class PermissionsAwareDocumentCountMixin(PassUserMixin):
|
||||
)
|
||||
|
||||
|
||||
class ArchiveSerialNumberPrefixViewSet(ModelViewSet, PermissionsAwareDocumentCountMixin):
|
||||
model = ArchiveSerialNumberPrefix
|
||||
|
||||
queryset = ArchiveSerialNumberPrefix.objects.select_related("owner").order_by(Lower("name"))
|
||||
|
||||
serializer_class = ArchiveSerialNumberPrefixSerializer
|
||||
pagination_class = StandardPagination
|
||||
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
||||
filter_backends = (
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
ObjectOwnedOrGrantedPermissionsFilter,
|
||||
)
|
||||
filterset_class = ArchiveSerialNumberPrefixFilterSet
|
||||
ordering_fields = ("name")
|
||||
|
||||
class CorrespondentViewSet(ModelViewSet, PermissionsAwareDocumentCountMixin):
|
||||
model = Correspondent
|
||||
|
||||
|
@ -17,6 +17,7 @@ from django.views.static import serve
|
||||
from rest_framework.authtoken import views
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
from documents.views import ArchiveSerialNumberPrefixViewSet
|
||||
from documents.views import BulkDownloadView
|
||||
from documents.views import BulkEditObjectsView
|
||||
from documents.views import BulkEditView
|
||||
@ -59,6 +60,7 @@ from paperless_mail.views import MailRuleViewSet
|
||||
from paperless_mail.views import OauthCallbackView
|
||||
|
||||
api_router = DefaultRouter()
|
||||
api_router.register(r"asn_prefix", ArchiveSerialNumberPrefixViewSet)
|
||||
api_router.register(r"correspondents", CorrespondentViewSet)
|
||||
api_router.register(r"document_types", DocumentTypeViewSet)
|
||||
api_router.register(r"documents", UnifiedSearchViewSet)
|
||||
|
Loading…
x
Reference in New Issue
Block a user