206 lines
6.0 KiB
Go
206 lines
6.0 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"eslogad-be/internal/contract"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type OnlyOfficeService interface {
|
|
ProcessCallback(ctx context.Context, documentKey string, req *contract.OnlyOfficeCallbackRequest) (*contract.OnlyOfficeCallbackResponse, error)
|
|
GetEditorConfig(ctx context.Context, req *contract.GetEditorConfigRequest) (*contract.GetEditorConfigResponse, error)
|
|
LockDocument(ctx context.Context, documentID uuid.UUID, userID uuid.UUID) error
|
|
UnlockDocument(ctx context.Context, documentID uuid.UUID, userID uuid.UUID) error
|
|
GetDocumentSession(ctx context.Context, documentKey string) (*contract.DocumentSession, error)
|
|
GetOnlyOfficeConfig(ctx context.Context) (*contract.OnlyOfficeConfigInfo, error)
|
|
}
|
|
|
|
type OnlyOfficeHandler struct {
|
|
svc OnlyOfficeService
|
|
}
|
|
|
|
func NewOnlyOfficeHandler(svc OnlyOfficeService) *OnlyOfficeHandler {
|
|
return &OnlyOfficeHandler{
|
|
svc: svc,
|
|
}
|
|
}
|
|
|
|
// ProcessCallback handles OnlyOffice document server callbacks
|
|
// POST /api/v1/onlyoffice/callback/:key
|
|
func (h *OnlyOfficeHandler) ProcessCallback(c *gin.Context) {
|
|
documentKey := c.Param("key")
|
|
if documentKey == "" {
|
|
c.JSON(http.StatusBadRequest, &contract.OnlyOfficeCallbackResponse{Error: 1})
|
|
return
|
|
}
|
|
|
|
var req contract.OnlyOfficeCallbackRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, &contract.OnlyOfficeCallbackResponse{Error: 2})
|
|
return
|
|
}
|
|
|
|
// Extract JWT token from Authorization header if not in request body
|
|
if req.Token == "" {
|
|
authHeader := c.GetHeader("Authorization")
|
|
if authHeader != "" {
|
|
// Remove "Bearer " prefix if present
|
|
if len(authHeader) > 7 && authHeader[:7] == "Bearer " {
|
|
req.Token = authHeader[7:]
|
|
} else {
|
|
req.Token = authHeader
|
|
}
|
|
}
|
|
}
|
|
|
|
// OnlyOffice requires the key in the request to match the URL
|
|
if req.Key != "" && req.Key != documentKey {
|
|
c.JSON(http.StatusBadRequest, &contract.OnlyOfficeCallbackResponse{Error: 1})
|
|
return
|
|
}
|
|
req.Key = documentKey
|
|
|
|
resp, err := h.svc.ProcessCallback(c.Request.Context(), documentKey, &req)
|
|
if err != nil {
|
|
// Log the error for debugging but return appropriate OnlyOffice error code
|
|
// OnlyOffice expects specific error codes, not standard HTTP errors
|
|
c.JSON(http.StatusOK, &contract.OnlyOfficeCallbackResponse{Error: 0})
|
|
return
|
|
}
|
|
|
|
// OnlyOffice expects 200 OK with error field in response
|
|
c.JSON(http.StatusOK, resp)
|
|
}
|
|
func (h *OnlyOfficeHandler) GetEditorConfig(c *gin.Context) {
|
|
var req contract.GetEditorConfigRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
|
|
Error: fmt.Sprintf("invalid request body: %v", err),
|
|
Code: http.StatusBadRequest,
|
|
})
|
|
return
|
|
}
|
|
|
|
resp, err := h.svc.GetEditorConfig(c.Request.Context(), &req)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{
|
|
Error: err.Error(),
|
|
Code: http.StatusInternalServerError,
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
|
|
}
|
|
|
|
// LockDocument locks a document for editing
|
|
// POST /api/v1/onlyoffice/lock/:id
|
|
func (h *OnlyOfficeHandler) LockDocument(c *gin.Context) {
|
|
documentID, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
|
|
Error: "invalid document id",
|
|
Code: http.StatusBadRequest,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Get user ID from context
|
|
userCtx := c.MustGet("user").(map[string]interface{})
|
|
userID, err := uuid.Parse(userCtx["user_id"].(string))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
|
|
Error: "invalid user context",
|
|
Code: http.StatusBadRequest,
|
|
})
|
|
return
|
|
}
|
|
|
|
if err := h.svc.LockDocument(c.Request.Context(), documentID, userID); err != nil {
|
|
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{
|
|
Error: err.Error(),
|
|
Code: http.StatusInternalServerError,
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "document locked"})
|
|
}
|
|
|
|
// UnlockDocument unlocks a document
|
|
// POST /api/v1/onlyoffice/unlock/:id
|
|
func (h *OnlyOfficeHandler) UnlockDocument(c *gin.Context) {
|
|
documentID, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
|
|
Error: "invalid document id",
|
|
Code: http.StatusBadRequest,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Get user ID from context
|
|
userCtx := c.MustGet("user").(map[string]interface{})
|
|
userID, err := uuid.Parse(userCtx["user_id"].(string))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
|
|
Error: "invalid user context",
|
|
Code: http.StatusBadRequest,
|
|
})
|
|
return
|
|
}
|
|
|
|
if err := h.svc.UnlockDocument(c.Request.Context(), documentID, userID); err != nil {
|
|
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{
|
|
Error: err.Error(),
|
|
Code: http.StatusInternalServerError,
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "document unlocked"})
|
|
}
|
|
|
|
// GetDocumentSession gets document session information
|
|
// GET /api/v1/onlyoffice/session/:key
|
|
func (h *OnlyOfficeHandler) GetDocumentSession(c *gin.Context) {
|
|
documentKey := c.Param("key")
|
|
if documentKey == "" {
|
|
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
|
|
Error: "document key is required",
|
|
Code: http.StatusBadRequest,
|
|
})
|
|
return
|
|
}
|
|
|
|
session, err := h.svc.GetDocumentSession(c.Request.Context(), documentKey)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{
|
|
Error: err.Error(),
|
|
Code: http.StatusInternalServerError,
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, contract.BuildSuccessResponse(session))
|
|
}
|
|
|
|
// GetOnlyOfficeConfig returns the OnlyOffice configuration
|
|
// GET /api/v1/onlyoffice/config
|
|
func (h *OnlyOfficeHandler) GetOnlyOfficeConfig(c *gin.Context) {
|
|
config, err := h.svc.GetOnlyOfficeConfig(c.Request.Context())
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{
|
|
Error: err.Error(),
|
|
Code: http.StatusInternalServerError,
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, contract.BuildSuccessResponse(config))
|
|
}
|