add file list

This commit is contained in:
Simon Vieille 2024-09-25 11:21:23 +02:00
commit d60cb8fbe2
10 changed files with 256 additions and 12 deletions

View file

@ -8,7 +8,9 @@ secret = "e93865c991358ff7a14f9781fa33ba4f28c33bb8d1cf3490ce6fd68521513536"
[collabora]
url = "https://loolwsd.deblan.org"
budget_file = "_data/test.ods"
[file]
path = "./_data/"
[log]
; level = "debug"

View file

@ -30,6 +30,10 @@ type collabora struct {
BudgetFile string
}
type file struct {
Path string
}
func (c *collabora) HostingDiscoveryUrl() string {
return fmt.Sprintf("%s/hosting/discovery", c.Url)
}
@ -40,6 +44,7 @@ type Config struct {
Security security
Server server
Collabora collabora
File file
}
var config *Config
@ -66,5 +71,5 @@ func (c *Config) Load(file string) {
config.Server.Port, _ = cfg.Section("server").Key("port").Int()
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()
config.File.Path = cfg.Section("file").Key("path").String()
}

103
file/manager.go Normal file
View file

@ -0,0 +1,103 @@
package file
import (
"crypto/sha256"
"fmt"
"math"
"math/big"
"os"
"github.com/gabriel-vasile/mimetype"
)
type File struct {
Id string `json:"id"`
Name string `json:"name"`
Path string `json:"path"`
Size int64 `json:"size"`
Type string `json:"type"`
Extension string `json:"extension"`
}
type Tree struct {
Name string `json:"name"`
Directories []Tree `json:"directories"`
Path string `json:"path"`
Files []File `json:"files"`
IsRoot bool `json:"is_root"`
}
func getFileId(path string) string {
hash := sha256.New()
hash.Write([]byte(path))
hashBytes := hash.Sum(nil)
bInt := new(big.Int).SetBytes(hashBytes)
return fmt.Sprintf("%d", int(math.Abs(float64(bInt.Int64()))))
}
func GetTree(name, path string) Tree {
tree := Tree{
Name: name,
Directories: []Tree{},
Path: path,
Files: []File{},
IsRoot: name == "",
}
entries, err := os.ReadDir(path)
if err != nil {
return tree
}
for _, e := range entries {
if e.IsDir() {
tree.Directories = append(tree.Directories, GetTree(e.Name(), path+"/"+e.Name()))
} else {
p := path + "/" + e.Name()
fi, _ := os.Stat(p)
mtype, _ := mimetype.DetectFile(p)
tree.Files = append(tree.Files, File{
Id: getFileId(p),
Name: e.Name(),
Path: p,
Size: fi.Size(),
Type: mtype.Extension(),
Extension: mtype.Extension(),
})
}
}
return tree
}
func GetFiles(files *[]File, path string) *[]File {
entries, err := os.ReadDir(path)
if err != nil {
return files
}
for _, e := range entries {
p := path + "/" + e.Name()
if e.IsDir() {
GetFiles(files, p)
} else {
fi, _ := os.Stat(p)
mtype, _ := mimetype.DetectFile(p)
*files = append(*files, File{
Id: getFileId(p),
Name: e.Name(),
Path: p,
Size: fi.Size(),
Type: mtype.Extension(),
Extension: mtype.Extension(),
})
}
}
return files
}

View file

@ -1,9 +1,67 @@
<template>
<div>
<iframe src="/collabora" id="collabora"></iframe>
<div v-if="tree !== null && fileId === null" class="w-100">
<div v-if="!tree.is_root" class="p-3 border-bottom cursor" @click="cd(tree.parent)">
<span class="text-warning">
<i class="fa-solid fa-folder me-2"></i>
</span>
..
</div>
<div v-for="item in tree.directories" class="p-3 border-bottom cursor" @click="cd(item)">
<span class="text-warning">
<i class="fa-solid fa-folder me-2"></i>
</span>
{{ item.name }}
</div>
<div v-for="item in tree.files" class="p-3 border-bottom">
<div v-if="item.extension === '.ods'" class="cursor" @click="fileId = item.id">
<span class="text-success">
<i class="fa-solid fa-file-lines"></i>
</span>
{{ item.name }}
</div>
<div v-else class="text-secondary">
<i class="fa-regular fa-file"></i>
{{ item.name }}
</div>
</div>
</div>
<div v-if="fileId !== null" class="w-100">
<div class="text-end cursor p-2" @click="fileId = null">
<i class="fa-solid fa-xmark"></i>
</div>
<iframe :src="'/collabora/' + fileId" id="collabora"></iframe>
</div>
</template>
<script setup>
import { ref } from "vue"
import { ref, onMounted, watch } from 'vue'
const tree = ref(null)
const parent = ref(null)
const fileId = ref(null)
const cd = (directory) => {
tree.value = directory
}
const withParents = (tree) => {
tree.directories.forEach((subTree, key) => {
tree.directories[key].parent = tree
tree.directories[key] = withParents(tree.directories[key])
})
return tree
}
onMounted(() => {
fetch('/api/files')
.then((response) => response.json())
.then((data) => {
tree.value = withParents(data)
console.log(tree.value)
})
})
</script>

View file

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

2
go.mod
View file

@ -18,7 +18,7 @@ require (
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/daaku/go.zipexe v1.0.2 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator v9.31.0+incompatible // indirect

2
go.sum
View file

@ -21,6 +21,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=

View file

@ -14,6 +14,7 @@ import (
"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/web/view"
tpl "gitnet.fr/deblan/budget/web/view/template/collabora"
)
@ -45,7 +46,7 @@ func New(e *echo.Echo) *Controller {
Token: getToken(),
}
e.GET("/collabora", c.Iframe)
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)
@ -77,7 +78,7 @@ func (ctrl *Controller) Iframe(c echo.Context) error {
wopiSrc := fmt.Sprintf(
"%s%s",
config.Get().Server.BaseUrl,
"/wopi/1",
"/wopi/"+c.Param("id"),
)
url := items[1] + "WOPISrc=" + wopiSrc
@ -90,7 +91,21 @@ func (ctrl *Controller) Info(c echo.Context) error {
return c.JSON(403, nil)
}
fi, _ := os.Stat(config.Get().Collabora.BudgetFile)
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
@ -112,7 +127,21 @@ func (ctrl *Controller) WopiContentGet(c echo.Context) error {
return c.JSON(403, nil)
}
content, _ := os.ReadFile(config.Get().Collabora.BudgetFile)
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)
}
@ -122,9 +151,23 @@ func (ctrl *Controller) WopiContentPost(c echo.Context) error {
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(config.Get().Collabora.BudgetFile, data, 0600)
err := os.WriteFile(file, data, 0600)
if err != nil {
return err

View file

@ -0,0 +1,29 @@
package file
import (
"github.com/labstack/echo/v4"
"gitnet.fr/deblan/budget/config"
"gitnet.fr/deblan/budget/database/model"
f "gitnet.fr/deblan/budget/file"
)
type Controller struct {
}
func New(e *echo.Echo) *Controller {
c := Controller{}
e.GET("/api/files", c.Files)
return &c
}
func (ctrl *Controller) Files(c echo.Context) error {
if nil == model.LoadSessionUser(c) {
return c.Redirect(302, "/login")
}
tree := f.GetTree("", config.Get().File.Path)
return c.JSON(200, tree)
}

View file

@ -7,6 +7,7 @@ import (
"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/file"
"gitnet.fr/deblan/budget/web/controller/saving_account"
"gitnet.fr/deblan/budget/web/controller/transaction"
"gitnet.fr/deblan/budget/web/controller/user"
@ -21,4 +22,5 @@ func RegisterControllers(e *echo.Echo) {
category.New(e)
transaction.New(e)
collabora.New(e)
file.New(e)
}