add possibility to disable delete and upload of books

This commit is contained in:
Adrien
2026-04-06 14:09:17 +02:00
parent 5c641f4bcc
commit e5d53b4e80
7 changed files with 41 additions and 2 deletions
+13
View File
@@ -151,6 +151,8 @@ npm run dev
### Environment Variables
#### Backend
| Variable | Required | Description |
|----------|----------|-------------|
| `OPENAI_API_KEY` | Yes | OpenAI API key for embeddings and chat |
@@ -159,3 +161,14 @@ npm run dev
| `DB_USERNAME` | Yes | Database username |
| `DB_PASSWORD` | Yes | Database password |
| `FIGURE_STORAGE_PATH` | No | Base path for uploaded PDFs and extracted figures (default: `./uploads`) |
| `UPLOAD_ENABLED` | No | Set to `false` to disable the book upload endpoint (default: `true`) |
| `DELETE_ENABLED` | No | Set to `false` to disable the book delete endpoint (default: `true`) |
#### Frontend
| Variable | Required | Description |
|----------|----------|-------------|
| `VITE_API_URL` | No | Backend API base URL (default: `/api/v1`) |
| `VITE_APP_PASSWORD` | Yes | Shared password for HTTP Basic auth (must match `APP_PASSWORD`) |
| `VITE_UPLOAD_ENABLED` | No | Set to `false` to hide the upload UI (default: `true`) |
| `VITE_DELETE_ENABLED` | No | Set to `false` to hide the delete button (default: `true`) |
@@ -3,6 +3,7 @@ package com.aiteacher.book;
import com.aiteacher.document.FigureEntity;
import com.aiteacher.document.FigureRepository;
import com.aiteacher.document.MarkdownStorageService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@@ -22,6 +23,12 @@ public class BookController {
private final FigureRepository figureRepository;
private final MarkdownStorageService markdownStorageService;
@Value("${app.features.upload-enabled:true}")
private boolean uploadEnabled;
@Value("${app.features.delete-enabled:true}")
private boolean deleteEnabled;
public BookController(BookService bookService, FigureRepository figureRepository,
MarkdownStorageService markdownStorageService) {
this.bookService = bookService;
@@ -31,6 +38,7 @@ public class BookController {
@PostMapping(consumes = "multipart/form-data")
public ResponseEntity<?> upload(@RequestParam("file") MultipartFile file) throws IOException {
if (!uploadEnabled) return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED).build();
Book book = bookService.upload(file);
return ResponseEntity.status(HttpStatus.ACCEPTED).body(toSummaryResponse(book));
}
@@ -51,6 +59,7 @@ public class BookController {
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable UUID id) {
if (!deleteEnabled) return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED).build();
bookService.delete(id);
return ResponseEntity.noContent().build();
}
@@ -52,6 +52,9 @@ logging:
"[org.apache.pdfbox]": ERROR
app:
features:
upload-enabled: ${UPLOAD_ENABLED:true}
delete-enabled: ${DELETE_ENABLED:true}
auth:
password: ${APP_PASSWORD:changeme}
figure-storage:
+6
View File
@@ -5,3 +5,9 @@ VITE_API_URL=/api/v1
# Shared password for HTTP Basic auth (must match APP_PASSWORD on the backend).
VITE_APP_PASSWORD=changeme
# Set to 'false' to hide the upload UI (frontend). Also set UPLOAD_ENABLED=false on the backend to block the endpoint.
VITE_UPLOAD_ENABLED=true
# Set to 'false' to hide the delete button (frontend). Also set DELETE_ENABLED=false on the backend to block the endpoint.
VITE_DELETE_ENABLED=true
+2
View File
@@ -41,6 +41,7 @@
Read
</router-link>
<button
v-if="deleteEnabled"
class="btn btn-danger"
:disabled="book.status === 'PROCESSING' || deleting"
@click="$emit('delete', book.id)"
@@ -59,6 +60,7 @@ import type { Book } from '@/stores/bookStore'
const props = defineProps<{
book: Book
deleting?: boolean
deleteEnabled?: boolean
}>()
defineEmits<{
+2
View File
@@ -3,6 +3,8 @@
interface ImportMetaEnv {
readonly VITE_API_URL: string
readonly VITE_APP_PASSWORD: string
readonly VITE_UPLOAD_ENABLED: string
readonly VITE_DELETE_ENABLED: string
}
interface ImportMeta {
+6 -2
View File
@@ -1,10 +1,10 @@
<template>
<div class="upload-view">
<h1 class="page-title">Book Library</h1>
<p class="page-subtitle">Upload medical textbooks (PDF) to build the knowledge base.</p>
<p v-if="uploadEnabled" class="page-subtitle">Upload medical textbooks (PDF) to build the knowledge base.</p>
<!-- Upload Section -->
<div class="upload-section card">
<div v-if="uploadEnabled" class="upload-section card">
<h2 class="section-title">Upload a Book</h2>
<div
@@ -87,6 +87,7 @@
:key="book.id"
:book="book"
:deleting="deletingId === book.id"
:delete-enabled="deleteEnabled"
@delete="handleDelete"
/>
</div>
@@ -99,6 +100,9 @@ import { ref, onMounted, onUnmounted, inject } from 'vue'
import { useBookStore } from '@/stores/bookStore'
import BookCard from '@/components/BookCard.vue'
const uploadEnabled = import.meta.env.VITE_UPLOAD_ENABLED !== 'false'
const deleteEnabled = import.meta.env.VITE_DELETE_ENABLED !== 'false'
const bookStore = useBookStore()
const showToast = inject<(msg: string, type?: 'error' | 'success') => void>('showToast')