Merge branch 'feature/loffice' into develop
This commit is contained in:
commit
b59d870a14
11 changed files with 260 additions and 27 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -29,6 +29,11 @@ $nav-size-sm: 50px;
|
|||
|
||||
#nav {
|
||||
width: $nav-size;
|
||||
|
||||
i {
|
||||
width: 20px;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.crud {
|
||||
|
|
@ -59,7 +64,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;
|
||||
}
|
||||
|
|
|
|||
134
web/controller/collabora/controller.go
Normal file
134
web/controller/collabora/controller.go
Normal 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)
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
15
web/view/template/collabora/iframe.templ
Normal file
15
web/view/template/collabora/iframe.templ
Normal 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>
|
||||
}
|
||||
62
web/view/template/collabora/iframe_templ.go
Normal file
62
web/view/template/collabora/iframe_templ.go
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue