Implement WOPI integration for Collabora Online

- Add WOPI models (CheckFileInfoResponse, PutFileResponse, LockInfo)
- Implement WOPI handlers: CheckFileInfo, GetFile, PutFile, Lock operations
- Add file locking mechanism to prevent concurrent editing conflicts
- Add WOPI session endpoint for generating access tokens
- Add UpdateFileSize method to database
- Add WOPI routes (/wopi/files/* endpoints)
- Update Flutter document viewer to load Collabora via WOPI WOPISrc URL
- Implement WebView integration for Collabora Online viewer
- Add comprehensive logging for WOPI operations [WOPI-TOKEN], [WOPI-REQUEST], [WOPI-STORAGE], [WOPI-LOCK]
This commit is contained in:
Leon Bösche
2026-01-12 01:08:22 +01:00
parent 3e0094b11c
commit 1b20fe8b7f
5 changed files with 861 additions and 53 deletions

View File

@@ -98,6 +98,28 @@ func NewRouter(cfg *config.Config, db *database.DB, jwtManager *jwt.Manager, aut
// Health check
r.Get("/health", healthHandler)
// WOPI routes (public, token validation done per endpoint)
r.Route("/wopi", func(r chi.Router) {
r.Route("/files/{fileId}", func(r chi.Router) {
// CheckFileInfo: GET /wopi/files/{fileId}
r.Get("/", func(w http.ResponseWriter, req *http.Request) {
wopiCheckFileInfoHandler(w, req, db, jwtManager)
})
// GetFile: GET /wopi/files/{fileId}/contents
r.Get("/contents", func(w http.ResponseWriter, req *http.Request) {
wopiGetFileHandler(w, req, db, jwtManager, cfg)
})
// PutFile & Lock operations: POST /wopi/files/{fileId}/contents and POST /wopi/files/{fileId}
r.Post("/contents", func(w http.ResponseWriter, req *http.Request) {
wopiPutFileHandler(w, req, db, jwtManager)
})
// Lock operations: POST /wopi/files/{fileId}
r.Post("/", func(w http.ResponseWriter, req *http.Request) {
wopiLockHandler(w, req, db, jwtManager)
})
})
})
// Auth routes (no auth required)
r.Route("/auth", func(r chi.Router) {
r.Post("/refresh", func(w http.ResponseWriter, req *http.Request) {
@@ -159,6 +181,10 @@ func NewRouter(cfg *config.Config, db *database.DB, jwtManager *jwt.Manager, aut
r.Post("/user/files/move", func(w http.ResponseWriter, req *http.Request) {
moveUserFileHandler(w, req, db, auditLogger, cfg)
})
// WOPI session for user files
r.Post("/user/files/{fileId}/wopi-session", func(w http.ResponseWriter, req *http.Request) {
wopiSessionHandler(w, req, db, jwtManager, "https://of.b0esche.cloud")
})
// Org routes
r.Get("/orgs", func(w http.ResponseWriter, req *http.Request) {
@@ -211,6 +237,10 @@ func NewRouter(cfg *config.Config, db *database.DB, jwtManager *jwt.Manager, aut
r.Get("/meta", func(w http.ResponseWriter, req *http.Request) {
fileMetaHandler(w, req)
})
// WOPI session for org files
r.With(middleware.Permission(db, auditLogger, permission.DocumentView)).Post("/wopi-session", func(w http.ResponseWriter, req *http.Request) {
wopiSessionHandler(w, req, db, jwtManager, "https://of.b0esche.cloud")
})
})
r.Get("/activity", func(w http.ResponseWriter, req *http.Request) {
activityHandler(w, req, db)