budget-go/backend/controller/collabora/controller.go
2025-02-08 20:19:26 +01:00

180 lines
3.3 KiB
Go

package collabora
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"regexp"
"time"
"github.com/labstack/echo/v4"
"gitnet.fr/deblan/budget/config"
"gitnet.fr/deblan/budget/database/model"
f "gitnet.fr/deblan/budget/file"
"gitnet.fr/deblan/budget/backend/view"
tpl "gitnet.fr/deblan/budget/backend/view/template/collabora"
)
func getToken() string {
now := time.Now()
dateString := fmt.Sprintf(
"%04d-%02d-%02d-%s",
now.Year(),
now.Month(), now.Day(),
config.Get().Security.Secret,
)
hash := sha256.New()
hash.Write([]byte(dateString))
hashedBytes := hash.Sum(nil)
hashedString := hex.EncodeToString(hashedBytes)
return hashedString[:32]
}
type Controller struct {
Token string
}
func New(e *echo.Echo) *Controller {
c := Controller{
Token: getToken(),
}
e.GET("/collabora/:id", c.Iframe)
e.GET("/wopi/:id", c.Info)
e.GET("/wopi/:id/contents", c.WopiContentGet)
e.POST("/wopi/:id/contents", c.WopiContentPost)
return &c
}
func (ctrl *Controller) Iframe(c echo.Context) error {
if nil == model.LoadSessionUser(c) {
return c.Redirect(302, "/login")
}
resp, err := http.Get(config.Get().Collabora.HostingDiscoveryUrl())
if err != nil {
return err
}
defer resp.Body.Close()
regex, _ := regexp.Compile(fmt.Sprintf(
`<action default="true" ext="%s" name="edit" urlsrc="([^"]+)"/>`,
c.Param("extension"),
))
body, _ := io.ReadAll(resp.Body)
items := regex.FindStringSubmatch(string(body))
if len(items) == 0 {
return nil
}
wopiSrc := fmt.Sprintf(
"%s%s",
config.Get().Server.BaseUrl,
"/wopi/"+c.Param("id"),
)
url := items[1] + "WOPISrc=" + wopiSrc
return view.Render(c, 200, tpl.Iframe(url, ctrl.Token))
}
func (ctrl *Controller) Info(c echo.Context) error {
if c.QueryParam("access_token") != ctrl.Token {
return c.JSON(403, nil)
}
var file string
files := []f.File{}
f.GetFiles(&files, config.Get().File.Path)
for _, f := range files {
if f.Id == c.Param("id") {
file = f.Path
}
}
if file == "" {
return c.JSON(404, "File not found")
}
fi, _ := os.Stat(file)
type res struct {
BaseFileName string
Size int64
UserId uint
UserCanWrite bool
}
return c.JSON(200, res{
BaseFileName: fi.Name(),
Size: fi.Size(),
UserId: 1, // User.ID,
UserCanWrite: true,
})
}
func (ctrl *Controller) WopiContentGet(c echo.Context) error {
if c.QueryParam("access_token") != ctrl.Token {
return c.JSON(403, nil)
}
var file string
files := []f.File{}
f.GetFiles(&files, config.Get().File.Path)
for _, f := range files {
if f.Id == c.Param("id") {
file = f.Path
}
}
if file == "" {
return c.JSON(404, "File not found")
}
content, _ := os.ReadFile(file)
return c.Blob(200, "application/vnd.oasis.opendocument.spreadsheet", content)
}
func (ctrl *Controller) WopiContentPost(c echo.Context) error {
if c.QueryParam("access_token") != ctrl.Token {
return c.JSON(403, nil)
}
var file string
files := []f.File{}
f.GetFiles(&files, config.Get().File.Path)
for _, f := range files {
if f.Id == c.Param("id") {
file = f.Path
}
}
if file == "" {
return c.JSON(404, "File not found")
}
data, _ := ioutil.ReadAll(c.Request().Body)
err := os.WriteFile(file, data, 0600)
if err != nil {
return err
}
return c.JSON(200, nil)
}