mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-10-18 13:58:12 +00:00
Feature: document file versions (#12061)
This commit is contained in:
1 parent
c9278f88ca
commit
ceee769e26
35 files changed
+4068
-365
No files matched your search
@@ -165,6 +165,14 @@ describe(`DocumentService`, () => {
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for versioned metadata', () => {
|
||||
subscription = service.getMetadata(documents[0].id, 123).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/metadata/?version=123`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for getting selection data', () => {
|
||||
const ids = [documents[0].id]
|
||||
subscription = service.getSelectionData(ids).subscribe()
|
||||
@@ -233,11 +241,22 @@ describe(`DocumentService`, () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('should return the correct preview URL for a specific version', () => {
|
||||
const url = service.getPreviewUrl(documents[0].id, false, 123)
|
||||
expect(url).toEqual(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/preview/?version=123`
|
||||
)
|
||||
})
|
||||
|
||||
it('should return the correct thumb URL for a single document', () => {
|
||||
let url = service.getThumbUrl(documents[0].id)
|
||||
expect(url).toEqual(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/thumb/`
|
||||
)
|
||||
url = service.getThumbUrl(documents[0].id, 123)
|
||||
expect(url).toEqual(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/thumb/?version=123`
|
||||
)
|
||||
})
|
||||
|
||||
it('should return the correct download URL for a single document', () => {
|
||||
@@ -249,6 +268,22 @@ describe(`DocumentService`, () => {
|
||||
expect(url).toEqual(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/download/?original=true`
|
||||
)
|
||||
url = service.getDownloadUrl(documents[0].id, false, 123)
|
||||
expect(url).toEqual(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/download/?version=123`
|
||||
)
|
||||
url = service.getDownloadUrl(documents[0].id, true, 123)
|
||||
expect(url).toEqual(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/download/?original=true&version=123`
|
||||
)
|
||||
})
|
||||
|
||||
it('should pass optional get params for version and fields', () => {
|
||||
subscription = service.get(documents[0].id, 123, 'content').subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/?full_perms=true&version=123&fields=content`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('should set search query', () => {
|
||||
@@ -283,12 +318,77 @@ describe(`DocumentService`, () => {
|
||||
expect(req.request.body.remove_inbox_tags).toEqual(true)
|
||||
})
|
||||
|
||||
it('should pass selected version to patch when provided', () => {
|
||||
subscription = service.patch(documents[0], 123).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/?version=123`
|
||||
)
|
||||
expect(req.request.method).toEqual('PATCH')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for getting audit log', () => {
|
||||
subscription = service.getHistory(documents[0].id).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/history/`
|
||||
)
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for getting root document id', () => {
|
||||
subscription = service.getRootId(documents[0].id).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/root/`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush({ root_id: documents[0].id })
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for getting document versions', () => {
|
||||
subscription = service.getVersions(documents[0].id).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/?fields=id,versions`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for deleting a document version', () => {
|
||||
subscription = service.deleteVersion(documents[0].id, 10).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/versions/10/`
|
||||
)
|
||||
expect(req.request.method).toEqual('DELETE')
|
||||
req.flush({ result: 'OK', current_version_id: documents[0].id })
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for updating a document version label', () => {
|
||||
subscription = service
|
||||
.updateVersionLabel(documents[0].id, 10, 'Updated label')
|
||||
.subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/versions/10/`
|
||||
)
|
||||
expect(req.request.method).toEqual('PATCH')
|
||||
expect(req.request.body).toEqual({ version_label: 'Updated label' })
|
||||
req.flush({ id: 10, version_label: 'Updated label', is_root: false })
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for uploading a new version', () => {
|
||||
const file = new File(['hello'], 'test.pdf', { type: 'application/pdf' })
|
||||
|
||||
subscription = service
|
||||
.uploadVersion(documents[0].id, file, 'Label')
|
||||
.subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/update_version/`
|
||||
)
|
||||
expect(req.request.method).toEqual('POST')
|
||||
expect(req.request.body).toBeInstanceOf(FormData)
|
||||
|
||||
const body = req.request.body as FormData
|
||||
expect(body.get('version_label')).toEqual('Label')
|
||||
expect(body.get('document')).toBeInstanceOf(File)
|
||||
|
||||
req.flush('task-id')
|
||||
})
|
||||
})
|
||||
|
||||
it('should construct sort fields respecting permissions', () => {
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
DOCUMENT_SORT_FIELDS,
|
||||
DOCUMENT_SORT_FIELDS_FULLTEXT,
|
||||
Document,
|
||||
DocumentVersionInfo,
|
||||
} from 'src/app/data/document'
|
||||
import { DocumentMetadata } from 'src/app/data/document-metadata'
|
||||
import { DocumentSuggestions } from 'src/app/data/document-suggestions'
|
||||
@@ -155,44 +156,119 @@ export class DocumentService extends AbstractPaperlessService<Document> {
|
||||
}).pipe(map((response) => response.results.map((doc) => doc.id)))
|
||||
}
|
||||
|
||||
get(id: number): Observable<Document> {
|
||||
get(
|
||||
id: number,
|
||||
versionID: number = null,
|
||||
fields: string = null
|
||||
): Observable<Document> {
|
||||
const params: { full_perms: boolean; version?: string; fields?: string } = {
|
||||
full_perms: true,
|
||||
}
|
||||
if (versionID) {
|
||||
params.version = versionID.toString()
|
||||
}
|
||||
if (fields) {
|
||||
params.fields = fields
|
||||
}
|
||||
return this.http.get<Document>(this.getResourceUrl(id), {
|
||||
params: {
|
||||
full_perms: true,
|
||||
},
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
getPreviewUrl(id: number, original: boolean = false): string {
|
||||
getPreviewUrl(
|
||||
id: number,
|
||||
original: boolean = false,
|
||||
versionID: number = null
|
||||
): string {
|
||||
let url = new URL(this.getResourceUrl(id, 'preview'))
|
||||
if (this._searchQuery) url.hash = `#search="${this.searchQuery}"`
|
||||
if (original) {
|
||||
url.searchParams.append('original', 'true')
|
||||
}
|
||||
if (versionID) {
|
||||
url.searchParams.append('version', versionID.toString())
|
||||
}
|
||||
return url.toString()
|
||||
}
|
||||
|
||||
getThumbUrl(id: number): string {
|
||||
return this.getResourceUrl(id, 'thumb')
|
||||
getThumbUrl(id: number, versionID: number = null): string {
|
||||
let url = new URL(this.getResourceUrl(id, 'thumb'))
|
||||
if (versionID) {
|
||||
url.searchParams.append('version', versionID.toString())
|
||||
}
|
||||
return url.toString()
|
||||
}
|
||||
|
||||
getDownloadUrl(id: number, original: boolean = false): string {
|
||||
let url = this.getResourceUrl(id, 'download')
|
||||
getDownloadUrl(
|
||||
id: number,
|
||||
original: boolean = false,
|
||||
versionID: number = null
|
||||
): string {
|
||||
let url = new URL(this.getResourceUrl(id, 'download'))
|
||||
if (original) {
|
||||
url += '?original=true'
|
||||
url.searchParams.append('original', 'true')
|
||||
}
|
||||
return url
|
||||
if (versionID) {
|
||||
url.searchParams.append('version', versionID.toString())
|
||||
}
|
||||
return url.toString()
|
||||
}
|
||||
|
||||
uploadVersion(documentId: number, file: File, versionLabel?: string) {
|
||||
const formData = new FormData()
|
||||
formData.append('document', file, file.name)
|
||||
if (versionLabel) {
|
||||
formData.append('version_label', versionLabel)
|
||||
}
|
||||
return this.http.post<string>(
|
||||
this.getResourceUrl(documentId, 'update_version'),
|
||||
formData
|
||||
)
|
||||
}
|
||||
|
||||
getVersions(documentId: number): Observable<Document> {
|
||||
return this.http.get<Document>(this.getResourceUrl(documentId), {
|
||||
params: {
|
||||
fields: 'id,versions',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
getRootId(documentId: number) {
|
||||
return this.http.get<{ root_id: number }>(
|
||||
this.getResourceUrl(documentId, 'root')
|
||||
)
|
||||
}
|
||||
|
||||
deleteVersion(rootDocumentId: number, versionId: number) {
|
||||
return this.http.delete<{ result: string; current_version_id: number }>(
|
||||
this.getResourceUrl(rootDocumentId, `versions/${versionId}`)
|
||||
)
|
||||
}
|
||||
|
||||
updateVersionLabel(
|
||||
rootDocumentId: number,
|
||||
versionId: number,
|
||||
versionLabel: string | null
|
||||
): Observable<DocumentVersionInfo> {
|
||||
return this.http.patch<DocumentVersionInfo>(
|
||||
this.getResourceUrl(rootDocumentId, `versions/${versionId}`),
|
||||
{ version_label: versionLabel }
|
||||
)
|
||||
}
|
||||
|
||||
getNextAsn(): Observable<number> {
|
||||
return this.http.get<number>(this.getResourceUrl(null, 'next_asn'))
|
||||
}
|
||||
|
||||
patch(o: Document): Observable<Document> {
|
||||
patch(o: Document, versionID: number = null): Observable<Document> {
|
||||
o.remove_inbox_tags = !!this.settingsService.get(
|
||||
SETTINGS_KEYS.DOCUMENT_EDITING_REMOVE_INBOX_TAGS
|
||||
)
|
||||
return super.patch(o)
|
||||
this.clearCache()
|
||||
return this.http.patch<Document>(this.getResourceUrl(o.id), o, {
|
||||
params: versionID ? { version: versionID.toString() } : {},
|
||||
})
|
||||
}
|
||||
|
||||
uploadDocument(formData) {
|
||||
@@ -203,8 +279,15 @@ export class DocumentService extends AbstractPaperlessService<Document> {
|
||||
)
|
||||
}
|
||||
|
||||
getMetadata(id: number): Observable<DocumentMetadata> {
|
||||
return this.http.get<DocumentMetadata>(this.getResourceUrl(id, 'metadata'))
|
||||
getMetadata(
|
||||
id: number,
|
||||
versionID: number = null
|
||||
): Observable<DocumentMetadata> {
|
||||
let url = new URL(this.getResourceUrl(id, 'metadata'))
|
||||
if (versionID) {
|
||||
url.searchParams.append('version', versionID.toString())
|
||||
}
|
||||
return this.http.get<DocumentMetadata>(url.toString())
|
||||
}
|
||||
|
||||
bulkEdit(ids: number[], method: string, args: any) {
|
||||
|
||||
@@ -89,6 +89,13 @@ export class FileStatus {
|
||||
}
|
||||
}
|
||||
|
||||
export enum UploadState {
|
||||
Idle = 'idle',
|
||||
Uploading = 'uploading',
|
||||
Processing = 'processing',
|
||||
Failed = 'failed',
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
|
||||
Reference in new issue
Block a user