This commit is contained in:
Simon Vieille 2024-09-23 22:07:49 +02:00
commit d4a97b193c
11 changed files with 255 additions and 27 deletions

View file

@ -13,6 +13,7 @@ import (
"github.com/gorilla/sessions"
"github.com/labstack/echo-contrib/session"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"gitnet.fr/deblan/budget/config"
"gitnet.fr/deblan/budget/database/manager"
"gitnet.fr/deblan/budget/database/model"
@ -49,7 +50,7 @@ func main() {
assetHandler := http.FileServer(rice.MustFindBox("../../web/view/static").HTTPBox())
e.GET("/static/*", echo.WrapHandler(http.StripPrefix("/static/", assetHandler)))
e.Use(middleware.Logger())
router.RegisterControllers(e)
if err := e.Start(fmt.Sprintf("%s:%d", conf.Server.Address, conf.Server.Port)); err != nil && !errors.Is(err, http.ErrServerClosed) {

View file

@ -1,12 +1,14 @@
[server]
port = 1324
address = "0.0.0.0"
base_url = "http://10.0.0.2:1324"
[security]
secret = "e93865c991358ff7a14f9781fa33ba4f28c33bb8d1cf3490ce6fd68521513536"
[calc]
url = "https://deblan.cloud/index.php/apps/files/files/1402577?dir=%2FAdministratif%2FProjet+de+construction&openfile=true"
[collabora]
url = "https://loolwsd.deblan.org"
budget_file = "_data/test.ods"
[log]
; level = "debug"

View file

@ -1,6 +1,7 @@
package config
import (
"fmt"
"log"
"gopkg.in/ini.v1"
@ -19,20 +20,26 @@ type security struct {
}
type server struct {
BaseUrl string
Address string
Port int
}
type calc struct {
Url string
type collabora struct {
Url string
BudgetFile string
}
func (c *collabora) HostingDiscoveryUrl() string {
return fmt.Sprintf("%s/hosting/discovery", c.Url)
}
type Config struct {
Database database
Log logging
Security security
Server server
Calc calc
Database database
Log logging
Security security
Server server
Collabora collabora
}
var config *Config
@ -57,5 +64,7 @@ func (c *Config) Load(file string) {
config.Security.Secret = cfg.Section("security").Key("secret").String()
config.Server.Address = cfg.Section("server").Key("address").String()
config.Server.Port, _ = cfg.Section("server").Key("port").Int()
config.Calc.Url = cfg.Section("calc").Key("url").String()
config.Server.BaseUrl = cfg.Section("server").Key("base_url").String()
config.Collabora.Url = cfg.Section("collabora").Key("url").String()
config.Collabora.BudgetFile = cfg.Section("collabora").Key("budget_file").String()
}

View file

@ -13,7 +13,7 @@ import { BNavItem } from 'bootstrap-vue-next'
</span>
</a>
<ul class="nav nav-pills flex-column mb-auto">
<RouterLink v-for="url in ['/', '/transactions', '/categories', '/bank_accounts', '/saving_accounts', 'users']" :to="url" custom v-slot="{ href, route, navigate, isActive, isExactActive }">
<RouterLink v-for="url in ['/', '/transactions', '/categories', '/bank_accounts', '/saving_accounts', '/calc', 'users']" :to="url" custom v-slot="{ href, route, navigate, isActive, isExactActive }">
<BNavItem :href="href" :active="isActive" :linkClass="{'text-white': !isActive}">
<i class="me-2" :class="route.meta.icon"></i>
<span class="nav-item-label">{{ route.name }}</span>

View file

@ -39,12 +39,12 @@ const router = createRouter({
meta: { icon: ['fa-solid', 'fa-piggy-bank'] },
component: () => import('../views/SavingAccountsView.vue')
},
// {
// path: '/calc',
// name: 'Tableur',
// meta: { icon: ['fa-solid', 'fa-table'] },
// component: () => import('../views/CalcView.vue')
// },
{
path: '/calc',
name: 'Tableur',
meta: { icon: ['fa-solid', 'fa-table'] },
component: () => import('../views/CalcView.vue')
},
]
})

View file

@ -1,15 +1,9 @@
<template>
<BContainer fluid class="p-0">
</BContainer>
<div>
<iframe src="/collabora" id="collabora"></iframe>
</div>
</template>
<script setup>
import { ref } from "vue"
</script>
<style scoped>
iframe {
width: 100%;
height: 100vh;
}
</style>

View file

@ -59,7 +59,16 @@ $nav-size-sm: 50px;
overflow: scroll;
}
#collabora {
width: 100%;
height: 100vh;
}
@media screen and (max-width: 980px) {
#collabora {
height: calc(100vh - 70px);
}
#app-name {
display: none;
}

View file

@ -0,0 +1,134 @@
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"
"gitnet.fr/deblan/budget/web/view"
tpl "gitnet.fr/deblan/budget/web/view/template/collabora"
)
func getToken() string {
now := time.Now()
dateString := fmt.Sprintf(
"%04d-%02d-%02d-%d",
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", 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(`<action default="true" ext="ods" name="edit" urlsrc="([^"]+)"/>`)
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/1",
)
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)
}
fi, _ := os.Stat(config.Get().Collabora.BudgetFile)
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)
}
content, _ := os.ReadFile(config.Get().Collabora.BudgetFile)
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)
}
data, _ := ioutil.ReadAll(c.Request().Body)
err := os.WriteFile(config.Get().Collabora.BudgetFile, data, 0600)
if err != nil {
return err
}
return c.JSON(200, nil)
}

View file

@ -6,6 +6,7 @@ import (
"gitnet.fr/deblan/budget/web/controller/auth"
"gitnet.fr/deblan/budget/web/controller/bank_account"
"gitnet.fr/deblan/budget/web/controller/category"
"gitnet.fr/deblan/budget/web/controller/collabora"
"gitnet.fr/deblan/budget/web/controller/saving_account"
"gitnet.fr/deblan/budget/web/controller/transaction"
"gitnet.fr/deblan/budget/web/controller/user"
@ -19,4 +20,5 @@ func RegisterControllers(e *echo.Echo) {
saving_account.New(e)
category.New(e)
transaction.New(e)
collabora.New(e)
}

View file

@ -0,0 +1,15 @@
package collabora
templ Iframe(url, token string) {
<html>
<body>
<form action={ templ.URL(url) } enctype="multipart/form-data" method="post" target="_self" id="form">
<input name="access_token" value={ token } type="hidden"/>
<input type="submit" value="Load Collabora Online"/>
</form>
<script>
document.getElementById('form').submit()
</script>
</body>
</html>
}

View file

@ -0,0 +1,62 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package collabora
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func Iframe(url, token string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<html><body><form action=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 templ.SafeURL = templ.URL(url)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var2)))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" enctype=\"multipart/form-data\" method=\"post\" target=\"_self\" id=\"form\"><input name=\"access_token\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(token)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/view/template/collabora/iframe.templ`, Line: 7, Col: 45}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" type=\"hidden\"> <input type=\"submit\" value=\"Load Collabora Online\"></form><script>\n\t\t\t\tdocument.getElementById('form').submit()\n\t\t\t</script></body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate