Add deletion after split

This commit is contained in:
Dominik Bruhn 2024-06-08 12:20:14 +02:00
parent 486e08dbcd
commit 3d60a83f6c
8 changed files with 89 additions and 31 deletions

View File

@ -2302,11 +2302,11 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1151</context> <context context-type="linenumber">1160</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1192</context> <context context-type="linenumber">1201</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@ -2970,7 +2970,7 @@
<context context-type="linenumber">24</context> <context context-type="linenumber">24</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2519605321077387027" datatype="html"> <trans-unit id="5612366187076076264" datatype="html">
<source>Delete original documents after successful merge</source> <source>Delete original documents after successful merge</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/confirm-dialog/merge-confirm-dialog/merge-confirm-dialog.component.html</context> <context context-type="sourcefile">src/app/components/common/confirm-dialog/merge-confirm-dialog/merge-confirm-dialog.component.html</context>
@ -2998,6 +2998,13 @@
<context context-type="linenumber">28</context> <context context-type="linenumber">28</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="492847770415850840" datatype="html">
<source>Delete original document after successful split</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/confirm-dialog/split-confirm-dialog/split-confirm-dialog.component.html</context>
<context context-type="linenumber">49</context>
</context-group>
</trans-unit>
<trans-unit id="2509141182388535183" datatype="html"> <trans-unit id="2509141182388535183" datatype="html">
<source>View</source> <source>View</source>
<context-group purpose="location"> <context-group purpose="location">
@ -5482,7 +5489,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1169</context> <context context-type="linenumber">1178</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context> <context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context>
@ -5960,25 +5967,32 @@
<context context-type="linenumber">1113</context> <context context-type="linenumber">1113</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7955772432945257011" datatype="html">
<source>Split operation will begin in the background. After its completion, the document will be deleted.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1130</context>
</context-group>
</trans-unit>
<trans-unit id="4158171846914923744" datatype="html"> <trans-unit id="4158171846914923744" datatype="html">
<source>Split operation will begin in the background.</source> <source>Split operation will begin in the background.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1128</context> <context context-type="linenumber">1136</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3235014591864339926" datatype="html"> <trans-unit id="3235014591864339926" datatype="html">
<source>Error executing split operation</source> <source>Error executing split operation</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1137</context> <context context-type="linenumber">1146</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6555329262222566158" datatype="html"> <trans-unit id="6555329262222566158" datatype="html">
<source>Rotate confirm</source> <source>Rotate confirm</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1149</context> <context context-type="linenumber">1158</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@ -5989,49 +6003,49 @@
<source>This operation will permanently rotate the original version of the current document.</source> <source>This operation will permanently rotate the original version of the current document.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1150</context> <context context-type="linenumber">1159</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4069543875319587651" datatype="html"> <trans-unit id="4069543875319587651" datatype="html">
<source>Rotation will begin in the background. Close and re-open the document after the operation has completed to see the changes.</source> <source>Rotation will begin in the background. Close and re-open the document after the operation has completed to see the changes.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1166</context> <context context-type="linenumber">1175</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2962674215361798818" datatype="html"> <trans-unit id="2962674215361798818" datatype="html">
<source>Error executing rotate operation</source> <source>Error executing rotate operation</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1178</context> <context context-type="linenumber">1187</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3539261415918606512" datatype="html"> <trans-unit id="3539261415918606512" datatype="html">
<source>Delete pages confirm</source> <source>Delete pages confirm</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1190</context> <context context-type="linenumber">1199</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5854352498125813866" datatype="html"> <trans-unit id="5854352498125813866" datatype="html">
<source>This operation will permanently delete the selected pages from the original document.</source> <source>This operation will permanently delete the selected pages from the original document.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1191</context> <context context-type="linenumber">1200</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8617528702531167646" datatype="html"> <trans-unit id="8617528702531167646" datatype="html">
<source>Delete pages operation will begin in the background. Close and re-open or reload this document after the operation has completed to see the changes.</source> <source>Delete pages operation will begin in the background. Close and re-open or reload this document after the operation has completed to see the changes.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1206</context> <context context-type="linenumber">1215</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1249139200486584973" datatype="html"> <trans-unit id="1249139200486584973" datatype="html">
<source>Error executing delete pages operation</source> <source>Error executing delete pages operation</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1215</context> <context context-type="linenumber">1224</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4958946940233632319" datatype="html"> <trans-unit id="4958946940233632319" datatype="html">

View File

@ -5,6 +5,7 @@ import { DocumentService } from 'src/app/services/rest/document.service'
import { PermissionsService } from 'src/app/services/permissions.service' import { PermissionsService } from 'src/app/services/permissions.service'
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop' import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'
import { Subject, takeUntil } from 'rxjs' import { Subject, takeUntil } from 'rxjs'
import { tap } from 'rxjs/operators'
import { Document } from 'src/app/data/document' import { Document } from 'src/app/data/document'
@Component({ @Component({

View File

@ -44,6 +44,10 @@
</ul> </ul>
</div> </div>
</div> </div>
<div class="form-check form-switch mt-4">
<input class="form-check-input" type="checkbox" role="switch" id="deleteOriginalSwitch" [(ngModel)]="deleteOriginal" [disabled]="!userOwnsDocument">
<label class="form-check-label" for="deleteOriginalSwitch" i18n>Delete original document after successful split</label>
</div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn" [class]="cancelBtnClass" (click)="cancel()" [disabled]="!buttonsEnabled"> <button type="button" class="btn" [class]="cancelBtnClass" (click)="cancel()" [disabled]="!buttonsEnabled">

View File

@ -1,7 +1,9 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { ConfirmDialogComponent } from '../confirm-dialog.component' import { ConfirmDialogComponent } from '../confirm-dialog.component'
import { Document } from 'src/app/data/document'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { DocumentService } from 'src/app/services/rest/document.service' import { DocumentService } from 'src/app/services/rest/document.service'
import { PermissionsService } from 'src/app/services/permissions.service'
import { PDFDocumentProxy } from 'ng2-pdf-viewer' import { PDFDocumentProxy } from 'ng2-pdf-viewer'
@Component({ @Component({
@ -31,17 +33,19 @@ export class SplitConfirmDialogComponent extends ConfirmDialogComponent {
private pages: Set<number> = new Set() private pages: Set<number> = new Set()
public documentID: number public document: Document
public page: number = 1 public page: number = 1
public totalPages: number public totalPages: number
public deleteOriginal: boolean = false
public get pdfSrc(): string { public get pdfSrc(): string {
return this.documentService.getPreviewUrl(this.documentID) return this.documentService.getPreviewUrl(this.document.id)
} }
constructor( constructor(
activeModal: NgbActiveModal, activeModal: NgbActiveModal,
private documentService: DocumentService private documentService: DocumentService,
private permissionService: PermissionsService
) { ) {
super(activeModal) super(activeModal)
this.confirmButtonEnabled = this.pages.size > 0 this.confirmButtonEnabled = this.pages.size > 0
@ -63,4 +67,8 @@ export class SplitConfirmDialogComponent extends ConfirmDialogComponent {
this.pages.delete(page) this.pages.delete(page)
this.confirmButtonEnabled = this.pages.size > 0 this.confirmButtonEnabled = this.pages.size > 0
} }
get userOwnsDocument(): boolean {
return this.permissionService.currentUserOwnsObject(this.document)
}
} }

View File

@ -1112,7 +1112,7 @@ export class DocumentDetailComponent
modal.componentInstance.title = $localize`Split confirm` modal.componentInstance.title = $localize`Split confirm`
modal.componentInstance.messageBold = $localize`This operation will split the selected document(s) into new documents.` modal.componentInstance.messageBold = $localize`This operation will split the selected document(s) into new documents.`
modal.componentInstance.btnCaption = $localize`Proceed` modal.componentInstance.btnCaption = $localize`Proceed`
modal.componentInstance.documentID = this.document.id modal.componentInstance.document = this.document
modal.componentInstance.confirmClicked modal.componentInstance.confirmClicked
.pipe(takeUntil(this.unsubscribeNotifier)) .pipe(takeUntil(this.unsubscribeNotifier))
.subscribe(() => { .subscribe(() => {
@ -1120,14 +1120,23 @@ export class DocumentDetailComponent
this.documentsService this.documentsService
.bulkEdit([this.document.id], 'split', { .bulkEdit([this.document.id], 'split', {
pages: modal.componentInstance.pagesString, pages: modal.componentInstance.pagesString,
delete_originals: modal.componentInstance.deleteOriginal,
}) })
.pipe(first(), takeUntil(this.unsubscribeNotifier)) .pipe(first(), takeUntil(this.unsubscribeNotifier))
.subscribe({ .subscribe({
next: () => { next: () => {
if (modal.componentInstance.deleteOriginal) {
this.toastService.showInfo(
$localize`Split operation will begin in the background. After its completion, the document will be deleted.`
)
modal.close()
this.close()
} else {
this.toastService.showInfo( this.toastService.showInfo(
$localize`Split operation will begin in the background.` $localize`Split operation will begin in the background.`
) )
modal.close() modal.close()
}
}, },
error: (error) => { error: (error) => {
if (modal) { if (modal) {

View File

@ -6,6 +6,7 @@ from typing import Optional
from celery import chain from celery import chain
from celery import chord from celery import chord
from celery import group
from django.conf import settings from django.conf import settings
from django.db.models import Q from django.db.models import Q
@ -293,7 +294,9 @@ def merge(
) )
if delete_originals: if delete_originals:
logger.info("Queueing removal of original documents after consumption of merged document") logger.info(
"Queueing removal of original documents after consumption of merged document",
)
chain(consume_task, delete_documents.si(affected_docs)).delay() chain(consume_task, delete_documents.si(affected_docs)).delay()
else: else:
consume_task.delay() consume_task.delay()
@ -301,13 +304,15 @@ def merge(
return "OK" return "OK"
def split(doc_ids: list[int], pages: list[list[int]]): def split(doc_ids: list[int], pages: list[list[int]], delete_originals: bool = False):
logger.info( logger.info(
f"Attempting to split document {doc_ids[0]} into {len(pages)} documents", f"Attempting to split document {doc_ids[0]} into {len(pages)} documents",
) )
doc = Document.objects.get(id=doc_ids[0]) doc = Document.objects.get(id=doc_ids[0])
import pikepdf import pikepdf
consume_tasks = []
try: try:
with pikepdf.open(doc.source_path) as pdf: with pikepdf.open(doc.source_path) as pdf:
for idx, split_doc in enumerate(pages): for idx, split_doc in enumerate(pages):
@ -327,13 +332,24 @@ def split(doc_ids: list[int], pages: list[list[int]]):
logger.info( logger.info(
f"Adding split document with pages {split_doc} to the task queue.", f"Adding split document with pages {split_doc} to the task queue.",
) )
consume_file.delay( consume_tasks.append(
consume_file.s(
ConsumableDocument( ConsumableDocument(
source=DocumentSource.ConsumeFolder, source=DocumentSource.ConsumeFolder,
original_file=filepath, original_file=filepath,
), ),
overrides, overrides,
),
) )
if delete_originals:
logger.info(
"Queueing removal of original document after consumption of the split documents",
)
chord(header=consume_tasks, body=delete_documents.si([doc.id])).delay()
else:
group(consume_tasks).delay()
except Exception as e: except Exception as e:
logger.exception(f"Error splitting document {doc.id}: {e}") logger.exception(f"Error splitting document {doc.id}: {e}")

View File

@ -1131,6 +1131,12 @@ class BulkEditSerializer(
except ValueError: except ValueError:
raise serializers.ValidationError("invalid pages specified") raise serializers.ValidationError("invalid pages specified")
if "delete_originals" in parameters:
if not isinstance(parameters["delete_originals"], bool):
raise serializers.ValidationError("delete_originals must be a boolean")
else:
parameters["delete_originals"] = False
def _validate_parameters_delete_pages(self, parameters): def _validate_parameters_delete_pages(self, parameters):
if "pages" not in parameters: if "pages" not in parameters:
raise serializers.ValidationError("pages not specified") raise serializers.ValidationError("pages not specified")

View File

@ -984,7 +984,7 @@ class BulkEditView(PassUserMixin):
) )
if ( if (
method == bulk_edit.merge method in [bulk_edit.merge, bulk_edit.split]
and parameters["delete_originals"] and parameters["delete_originals"]
and not user_is_owner_of_all_documents and not user_is_owner_of_all_documents
): ):