Multi-format document viewer: add image/text/office file type support

This commit is contained in:
Leon Bösche
2026-01-12 00:22:12 +01:00
parent 80411d9231
commit 923b0ede86
3 changed files with 229 additions and 27 deletions

View File

@@ -469,30 +469,33 @@ func viewerHandler(w http.ResponseWriter, r *http.Request, db *database.DB, jwtM
}
downloadPath := fmt.Sprintf("%s://%s/orgs/%s/files/download?path=%s&token=%s", scheme, host, orgID.String(), url.QueryEscape(file.Path), url.QueryEscape(viewerToken))
// Determine if it's a PDF based on file extension
// Determine file type based on extension
isPdf := strings.HasSuffix(strings.ToLower(file.Name), ".pdf")
mimeType := getMimeType(file.Name)
viewerSession := struct {
ViewUrl string `json:"viewUrl"`
Token string `json:"token"`
Capabilities struct {
CanEdit bool `json:"canEdit"`
CanAnnotate bool `json:"canAnnotate"`
IsPdf bool `json:"isPdf"`
CanEdit bool `json:"canEdit"`
CanAnnotate bool `json:"canAnnotate"`
IsPdf bool `json:"isPdf"`
MimeType string `json:"mimeType"`
} `json:"capabilities"`
ExpiresAt string `json:"expiresAt"`
}{
ViewUrl: downloadPath,
Token: viewerToken, // Long-lived JWT token for authenticating file download
Capabilities: struct {
CanEdit bool `json:"canEdit"`
CanAnnotate bool `json:"canAnnotate"`
IsPdf bool `json:"isPdf"`
}{CanEdit: false, CanAnnotate: isPdf, IsPdf: isPdf},
CanEdit bool `json:"canEdit"`
CanAnnotate bool `json:"canAnnotate"`
IsPdf bool `json:"isPdf"`
MimeType string `json:"mimeType"`
}{CanEdit: false, CanAnnotate: isPdf, IsPdf: isPdf, MimeType: mimeType},
ExpiresAt: time.Now().Add(24 * time.Hour).UTC().Format(time.RFC3339),
}
fmt.Printf("[VIEWER-SESSION] orgId=%s, fileId=%s, token_included=yes, isPdf=%v\n", orgID.String(), fileId, isPdf)
fmt.Printf("[VIEWER-SESSION] orgId=%s, fileId=%s, token_included=yes, isPdf=%v, mimeType=%s\n", orgID.String(), fileId, isPdf, mimeType)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(viewerSession)
@@ -552,34 +555,38 @@ func userViewerHandler(w http.ResponseWriter, r *http.Request, db *database.DB,
}
downloadPath := fmt.Sprintf("%s://%s/user/files/download?path=%s&token=%s", scheme, host, url.QueryEscape(file.Path), url.QueryEscape(viewerToken))
// Determine if it's a PDF based on file extension
// Determine file type based on extension
isPdf := strings.HasSuffix(strings.ToLower(file.Name), ".pdf")
mimeType := getMimeType(file.Name)
viewerSession := struct {
ViewUrl string `json:"viewUrl"`
Token string `json:"token"`
Capabilities struct {
CanEdit bool `json:"canEdit"`
CanAnnotate bool `json:"canAnnotate"`
IsPdf bool `json:"isPdf"`
CanEdit bool `json:"canEdit"`
CanAnnotate bool `json:"canAnnotate"`
IsPdf bool `json:"isPdf"`
MimeType string `json:"mimeType"`
} `json:"capabilities"`
ExpiresAt string `json:"expiresAt"`
}{
ViewUrl: downloadPath,
Token: viewerToken, // Long-lived JWT token for authenticating file download
Capabilities: struct {
CanEdit bool `json:"canEdit"`
CanAnnotate bool `json:"canAnnotate"`
IsPdf bool `json:"isPdf"`
CanEdit bool `json:"canEdit"`
CanAnnotate bool `json:"canAnnotate"`
IsPdf bool `json:"isPdf"`
MimeType string `json:"mimeType"`
}{
CanEdit: false,
CanAnnotate: isPdf,
IsPdf: isPdf,
MimeType: mimeType,
},
ExpiresAt: time.Now().Add(24 * time.Hour).UTC().Format(time.RFC3339),
}
fmt.Printf("[VIEWER-SESSION] userId=%s, fileId=%s, token_included=yes, isPdf=%v\n", userID.String(), fileId, isPdf)
fmt.Printf("[VIEWER-SESSION] userId=%s, fileId=%s, token_included=yes, isPdf=%v, mimeType=%s\n", userID.String(), fileId, isPdf, mimeType)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(viewerSession)
@@ -1765,3 +1772,38 @@ func downloadUserFileHandler(w http.ResponseWriter, r *http.Request, db *databas
io.Copy(w, resp.Body)
}
// getMimeType returns the MIME type based on file extension
func getMimeType(filename string) string {
lower := strings.ToLower(filename)
switch {
case strings.HasSuffix(lower, ".pdf"):
return "application/pdf"
case strings.HasSuffix(lower, ".png"):
return "image/png"
case strings.HasSuffix(lower, ".jpg"), strings.HasSuffix(lower, ".jpeg"):
return "image/jpeg"
case strings.HasSuffix(lower, ".gif"):
return "image/gif"
case strings.HasSuffix(lower, ".webp"):
return "image/webp"
case strings.HasSuffix(lower, ".svg"):
return "image/svg+xml"
case strings.HasSuffix(lower, ".txt"):
return "text/plain"
case strings.HasSuffix(lower, ".html"):
return "text/html"
case strings.HasSuffix(lower, ".json"):
return "application/json"
case strings.HasSuffix(lower, ".csv"):
return "text/csv"
case strings.HasSuffix(lower, ".doc"), strings.HasSuffix(lower, ".docx"):
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
case strings.HasSuffix(lower, ".xls"), strings.HasSuffix(lower, ".xlsx"):
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
case strings.HasSuffix(lower, ".ppt"), strings.HasSuffix(lower, ".pptx"):
return "application/vnd.openxmlformats-officedocument.presentationml.presentation"
default:
return "application/octet-stream"
}
}