feat(documents): add delete button to document edit form
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled
- DELETE /api/documents/{id} endpoint (204 No Content, WRITE_ALL required)
- DocumentService.deleteDocument() — throws 404 if not found, cascades
via DB foreign keys (versions, annotations, comments all ON DELETE CASCADE)
- Delete form action in edit page server: redirects to / on success
- Two-step confirmation in the save bar: first click reveals inline
"Wirklich löschen?" + confirm/cancel, avoiding native browser dialogs
- i18n key doc_delete_confirm added to de/en/es
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,7 @@ import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@@ -105,6 +106,15 @@ public class DocumentController {
|
||||
}
|
||||
}
|
||||
|
||||
// --- DELETE ---
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@RequirePermission(Permission.WRITE_ALL)
|
||||
public ResponseEntity<Void> deleteDocument(@PathVariable UUID id) {
|
||||
documentService.deleteDocument(id);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
// --- QUICK UPLOAD ---
|
||||
|
||||
private static final Set<String> ALLOWED_CONTENT_TYPES = Set.of(
|
||||
|
||||
@@ -277,6 +277,14 @@ public class DocumentService {
|
||||
return documentRepository.findConversation(senderId, receiverId, dateFrom, dateTo, sort);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteDocument(UUID id) {
|
||||
if (!documentRepository.existsById(id)) {
|
||||
throw DomainException.notFound(ErrorCode.DOCUMENT_NOT_FOUND, "Document not found: " + id);
|
||||
}
|
||||
documentRepository.deleteById(id);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteTagCascading(UUID tagId) {
|
||||
documentRepository.findByTags_Id(tagId).forEach(doc -> {
|
||||
|
||||
@@ -121,6 +121,32 @@ class DocumentControllerTest {
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
// ─── DELETE /api/documents/{id} ──────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void deleteDocument_returns401_whenUnauthenticated() throws Exception {
|
||||
mockMvc.perform(org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
.delete("/api/documents/" + UUID.randomUUID()))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void deleteDocument_returns403_whenMissingWritePermission() throws Exception {
|
||||
mockMvc.perform(org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
.delete("/api/documents/" + UUID.randomUUID()))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "WRITE_ALL")
|
||||
void deleteDocument_returns204_whenHasWritePermission() throws Exception {
|
||||
UUID id = UUID.randomUUID();
|
||||
mockMvc.perform(org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
.delete("/api/documents/" + id))
|
||||
.andExpect(status().isNoContent());
|
||||
}
|
||||
|
||||
// ─── POST /api/documents/quick-upload ────────────────────────────────────
|
||||
|
||||
@Test
|
||||
|
||||
@@ -35,6 +35,29 @@ class DocumentServiceTest {
|
||||
@Mock AnnotationService annotationService;
|
||||
@InjectMocks DocumentService documentService;
|
||||
|
||||
// ─── deleteDocument ───────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void deleteDocument_deletesById_whenExists() {
|
||||
UUID id = UUID.randomUUID();
|
||||
when(documentRepository.existsById(id)).thenReturn(true);
|
||||
|
||||
documentService.deleteDocument(id);
|
||||
|
||||
verify(documentRepository).deleteById(id);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteDocument_throwsNotFound_whenMissing() {
|
||||
UUID id = UUID.randomUUID();
|
||||
when(documentRepository.existsById(id)).thenReturn(false);
|
||||
|
||||
assertThatThrownBy(() -> documentService.deleteDocument(id))
|
||||
.isInstanceOf(DomainException.class)
|
||||
.hasMessageContaining(id.toString());
|
||||
verify(documentRepository, never()).deleteById(any());
|
||||
}
|
||||
|
||||
// ─── getDocumentById ──────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user