mirror of
https://github.com/btouchard/ackify-ce.git
synced 2026-02-08 06:48:32 -06:00
fix: persist options when uploading documents & dynamic config OnlyAdminCanCreate
Reader options (readMode, allowDownload, requireFullRead, verifyChecksum) were not being saved during document upload. SimpleAuthorizer now reads the setting dynamically from ConfigService instead of using a static value set at startup. This allows admins to toggle document creation permissions via the settings UI without requiring a server restart. Fixes #14 Fixes #15
This commit is contained in:
@@ -55,6 +55,12 @@ type CreateDocumentRequest struct {
|
||||
Title string `json:"title"`
|
||||
CreatedBy string `json:"created_by,omitempty"`
|
||||
|
||||
// Reader options
|
||||
ReadMode string `json:"read_mode,omitempty"`
|
||||
AllowDownload *bool `json:"allow_download,omitempty"`
|
||||
RequireFullRead *bool `json:"require_full_read,omitempty"`
|
||||
VerifyChecksum *bool `json:"verify_checksum,omitempty"`
|
||||
|
||||
// Storage fields for uploaded files
|
||||
StorageKey string `json:"storage_key,omitempty"`
|
||||
StorageProvider string `json:"storage_provider,omitempty"`
|
||||
@@ -106,8 +112,12 @@ func (s *DocumentService) CreateDocument(ctx context.Context, req CreateDocument
|
||||
}
|
||||
|
||||
input := models.DocumentInput{
|
||||
Title: title,
|
||||
URL: url,
|
||||
Title: title,
|
||||
URL: url,
|
||||
ReadMode: req.ReadMode,
|
||||
AllowDownload: req.AllowDownload,
|
||||
RequireFullRead: req.RequireFullRead,
|
||||
VerifyChecksum: req.VerifyChecksum,
|
||||
}
|
||||
|
||||
// Handle storage fields if provided (for uploaded files)
|
||||
|
||||
@@ -160,6 +160,15 @@ func (h *Handler) HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
title = header.Filename
|
||||
}
|
||||
|
||||
// Get reader options from form
|
||||
readMode := r.FormValue("readMode")
|
||||
if readMode == "" {
|
||||
readMode = "integrated"
|
||||
}
|
||||
allowDownload := r.FormValue("allowDownload") == "true"
|
||||
requireFullRead := r.FormValue("requireFullRead") == "true"
|
||||
verifyChecksum := r.FormValue("verifyChecksum") != "false" // default true
|
||||
|
||||
// Detect content type from file content
|
||||
buffer := make([]byte, 512)
|
||||
n, err := file.Read(buffer)
|
||||
@@ -207,6 +216,10 @@ func (h *Handler) HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
Reference: storageKey,
|
||||
Title: title,
|
||||
CreatedBy: user.Email,
|
||||
ReadMode: readMode,
|
||||
AllowDownload: &allowDownload,
|
||||
RequireFullRead: &requireFullRead,
|
||||
VerifyChecksum: &verifyChecksum,
|
||||
StorageKey: storageKey,
|
||||
StorageProvider: h.provider.Type(),
|
||||
FileSize: header.Size,
|
||||
|
||||
@@ -5,18 +5,24 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/btouchard/ackify-ce/backend/pkg/models"
|
||||
"github.com/btouchard/ackify-ce/backend/pkg/providers"
|
||||
)
|
||||
|
||||
// ConfigProvider provides access to general configuration.
|
||||
type ConfigProvider interface {
|
||||
GetConfig() *models.MutableConfig
|
||||
}
|
||||
|
||||
// SimpleAuthorizer is an authorization implementation based on a list of admin emails.
|
||||
// This is the default authorizer for Community Edition.
|
||||
type SimpleAuthorizer struct {
|
||||
adminEmails map[string]bool
|
||||
onlyAdminCanCreate bool
|
||||
adminEmails map[string]bool
|
||||
configProvider ConfigProvider
|
||||
}
|
||||
|
||||
// NewSimpleAuthorizer creates a new simple authorizer.
|
||||
func NewSimpleAuthorizer(adminEmails []string, onlyAdminCanCreate bool) *SimpleAuthorizer {
|
||||
func NewSimpleAuthorizer(adminEmails []string, configProvider ConfigProvider) *SimpleAuthorizer {
|
||||
emailMap := make(map[string]bool, len(adminEmails))
|
||||
for _, email := range adminEmails {
|
||||
normalized := strings.ToLower(strings.TrimSpace(email))
|
||||
@@ -25,8 +31,8 @@ func NewSimpleAuthorizer(adminEmails []string, onlyAdminCanCreate bool) *SimpleA
|
||||
}
|
||||
}
|
||||
return &SimpleAuthorizer{
|
||||
adminEmails: emailMap,
|
||||
onlyAdminCanCreate: onlyAdminCanCreate,
|
||||
adminEmails: emailMap,
|
||||
configProvider: configProvider,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +44,8 @@ func (a *SimpleAuthorizer) IsAdmin(_ context.Context, userEmail string) bool {
|
||||
|
||||
// CanCreateDocument implements providers.Authorizer.
|
||||
func (a *SimpleAuthorizer) CanCreateDocument(ctx context.Context, userEmail string) bool {
|
||||
if !a.onlyAdminCanCreate {
|
||||
cfg := a.configProvider.GetConfig()
|
||||
if !cfg.General.OnlyAdminCanCreate {
|
||||
return true
|
||||
}
|
||||
return a.IsAdmin(ctx, userEmail)
|
||||
|
||||
@@ -225,7 +225,7 @@ func (b *ServerBuilder) setDefaultProviders() {
|
||||
})
|
||||
}
|
||||
if b.authorizer == nil {
|
||||
b.authorizer = webauth.NewSimpleAuthorizer(b.cfg.App.AdminEmails, b.cfg.App.OnlyAdminCanCreate)
|
||||
b.authorizer = webauth.NewSimpleAuthorizer(b.cfg.App.AdminEmails, b.configService)
|
||||
}
|
||||
if b.quotaEnforcer == nil {
|
||||
b.quotaEnforcer = NewNoLimitQuotaEnforcer()
|
||||
|
||||
@@ -159,7 +159,13 @@ async function handleSubmit() {
|
||||
isUploading.value = true
|
||||
const uploadResponse = await documentService.uploadDocument(
|
||||
selectedFile.value,
|
||||
title.value || undefined,
|
||||
{
|
||||
title: title.value || undefined,
|
||||
readMode: readMode.value,
|
||||
allowDownload: allowDownload.value,
|
||||
requireFullRead: requireFullRead.value,
|
||||
verifyChecksum: verifyChecksum.value,
|
||||
},
|
||||
(progress) => {
|
||||
uploadProgress.value = progress
|
||||
}
|
||||
|
||||
@@ -26,6 +26,14 @@ export interface UploadProgress {
|
||||
percent: number
|
||||
}
|
||||
|
||||
export interface UploadDocumentOptions {
|
||||
title?: string
|
||||
readMode?: 'integrated' | 'external'
|
||||
allowDownload?: boolean
|
||||
requireFullRead?: boolean
|
||||
verifyChecksum?: boolean
|
||||
}
|
||||
|
||||
export interface CreateDocumentResponse {
|
||||
docId: string
|
||||
url?: string
|
||||
@@ -139,13 +147,13 @@ export const documentService = {
|
||||
/**
|
||||
* Upload a file and create a document
|
||||
* @param file File to upload
|
||||
* @param title Optional title for the document
|
||||
* @param options Upload options including title and reader settings
|
||||
* @param onProgress Optional callback for upload progress
|
||||
* @returns Upload response with document info
|
||||
*/
|
||||
async uploadDocument(
|
||||
file: File,
|
||||
title?: string,
|
||||
options?: UploadDocumentOptions,
|
||||
onProgress?: (progress: UploadProgress) => void
|
||||
): Promise<UploadDocumentResponse> {
|
||||
// Get CSRF token first
|
||||
@@ -154,8 +162,20 @@ export const documentService = {
|
||||
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
if (title) {
|
||||
formData.append('title', title)
|
||||
if (options?.title) {
|
||||
formData.append('title', options.title)
|
||||
}
|
||||
if (options?.readMode) {
|
||||
formData.append('readMode', options.readMode)
|
||||
}
|
||||
if (options?.allowDownload !== undefined) {
|
||||
formData.append('allowDownload', String(options.allowDownload))
|
||||
}
|
||||
if (options?.requireFullRead !== undefined) {
|
||||
formData.append('requireFullRead', String(options.requireFullRead))
|
||||
}
|
||||
if (options?.verifyChecksum !== undefined) {
|
||||
formData.append('verifyChecksum', String(options.verifyChecksum))
|
||||
}
|
||||
|
||||
const response = await axios.post<ApiResponse<UploadDocumentResponse>>(
|
||||
|
||||
Reference in New Issue
Block a user