diff --git a/cmd/server/server.go b/cmd/server/server.go
index a7fa942..4c8853c 100644
--- a/cmd/server/server.go
+++ b/cmd/server/server.go
@@ -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) {
diff --git a/config.ini b/config.ini
index a18ab45..db3fe35 100644
--- a/config.ini
+++ b/config.ini
@@ -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"
diff --git a/config/config.go b/config/config.go
index 53f1787..28c3a38 100644
--- a/config/config.go
+++ b/config/config.go
@@ -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()
}
diff --git a/frontend/js/App.vue b/frontend/js/App.vue
index cd597a2..10331b4 100644
--- a/frontend/js/App.vue
+++ b/frontend/js/App.vue
@@ -13,7 +13,7 @@ import { BNavItem } from 'bootstrap-vue-next'
-
+
{{ route.name }}
diff --git a/frontend/js/router/index.js b/frontend/js/router/index.js
index 77ebb21..c8e5dd0 100644
--- a/frontend/js/router/index.js
+++ b/frontend/js/router/index.js
@@ -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')
+ },
]
})
diff --git a/frontend/js/views/CalcView.vue b/frontend/js/views/CalcView.vue
index e13714f..a372a25 100644
--- a/frontend/js/views/CalcView.vue
+++ b/frontend/js/views/CalcView.vue
@@ -1,15 +1,9 @@
-
-
+
+
+
-
-
diff --git a/frontend/scss/main.scss b/frontend/scss/main.scss
index 5a7401e..9c8620d 100644
--- a/frontend/scss/main.scss
+++ b/frontend/scss/main.scss
@@ -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;
}
diff --git a/web/controller/collabora/controller.go b/web/controller/collabora/controller.go
new file mode 100644
index 0000000..2edf181
--- /dev/null
+++ b/web/controller/collabora/controller.go
@@ -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(``)
+ 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)
+}
diff --git a/web/router/router.go b/web/router/router.go
index b97b9c1..7ed7db0 100644
--- a/web/router/router.go
+++ b/web/router/router.go
@@ -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)
}
diff --git a/web/view/template/collabora/iframe.templ b/web/view/template/collabora/iframe.templ
new file mode 100644
index 0000000..fea2798
--- /dev/null
+++ b/web/view/template/collabora/iframe.templ
@@ -0,0 +1,15 @@
+package collabora
+
+templ Iframe(url, token string) {
+
+
+
+
+
+
+}
diff --git a/web/view/template/collabora/iframe_templ.go b/web/view/template/collabora/iframe_templ.go
new file mode 100644
index 0000000..b546ff6
--- /dev/null
+++ b/web/view/template/collabora/iframe_templ.go
@@ -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("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return templ_7745c5c3_Err
+ })
+}
+
+var _ = templruntime.GeneratedTemplate