From da44d18375c4b328c2f4656cf0c450667778cfb3 Mon Sep 17 00:00:00 2001 From: Simon Vieille Date: Sun, 16 Feb 2025 19:14:28 +0100 Subject: [PATCH] add api-key authentication --- backend/controller/app/controller.go | 7 ++- backend/controller/auth/controller.go | 11 +++- backend/controller/bank_account/controller.go | 22 ++++---- backend/controller/category/controller.go | 22 ++++---- backend/controller/collabora/controller.go | 9 +-- backend/controller/file/controller.go | 22 ++++---- .../controller/saving_account/controller.go | 22 ++++---- backend/controller/transaction/controller.go | 18 +++--- backend/controller/user/controller.go | 22 ++++---- backend/view/template/app/page.templ | 9 ++- backend/view/template/app/page_templ.go | 22 +++++++- database/model/user.go | 55 +++++++++++++++++++ frontend/js/lib/renderers.js | 27 +++++---- frontend/js/lib/request.js | 16 ++++++ frontend/js/views/BankAccountsView.vue | 10 ++-- frontend/js/views/CategoriesView.vue | 12 ++-- frontend/js/views/DashboardView.vue | 9 +-- frontend/js/views/FilesView.vue | 15 ++--- frontend/js/views/SavingAccountsView.vue | 10 ++-- frontend/js/views/TransactionsView.vue | 13 +++-- frontend/js/views/UsersView.vue | 16 ++++-- 21 files changed, 245 insertions(+), 124 deletions(-) create mode 100644 frontend/js/lib/request.js diff --git a/backend/controller/app/controller.go b/backend/controller/app/controller.go index 6865bd8..0fc9126 100644 --- a/backend/controller/app/controller.go +++ b/backend/controller/app/controller.go @@ -2,9 +2,9 @@ package app import ( "github.com/labstack/echo/v4" - "gitnet.fr/deblan/budget/database/model" "gitnet.fr/deblan/budget/backend/view" "gitnet.fr/deblan/budget/backend/view/template/app" + "gitnet.fr/deblan/budget/database/model" ) type Controller struct { @@ -19,9 +19,10 @@ func New(e *echo.Echo) *Controller { } func (ctrl *Controller) HomeGet(c echo.Context) error { - if nil == model.LoadSessionUser(c) { + user := model.LoadSessionUser(c) + if nil == user { return c.Redirect(302, "/login") } - return view.Render(c, 200, app.Page()) + return view.Render(c, 200, app.Page(*user)) } diff --git a/backend/controller/auth/controller.go b/backend/controller/auth/controller.go index 5fb6c6c..e87f52d 100644 --- a/backend/controller/auth/controller.go +++ b/backend/controller/auth/controller.go @@ -1,13 +1,15 @@ package auth import ( + "time" + "github.com/gorilla/sessions" "github.com/labstack/echo-contrib/session" "github.com/labstack/echo/v4" - "gitnet.fr/deblan/budget/database/manager" - "gitnet.fr/deblan/budget/database/model" "gitnet.fr/deblan/budget/backend/view" "gitnet.fr/deblan/budget/backend/view/template/auth" + "gitnet.fr/deblan/budget/database/manager" + "gitnet.fr/deblan/budget/database/model" ) type Controller struct { @@ -40,10 +42,13 @@ func (ctrl *Controller) LoginPost(c echo.Context) error { db.Db.Model(model.User{}).Where("username = ?", username).Find(&user) if user.HasPassword(password) { + user.LoggedAt = time.Now() + db.Db.Save(user) + sess, _ := session.Get("session", c) sess.Options = &sessions.Options{ Path: "/", - MaxAge: 86400 * 7, + MaxAge: 3600 * 24 * 2, HttpOnly: true, } sess.Values["user"] = user.ID diff --git a/backend/controller/bank_account/controller.go b/backend/controller/bank_account/controller.go index 12fed67..90834c9 100644 --- a/backend/controller/bank_account/controller.go +++ b/backend/controller/bank_account/controller.go @@ -2,8 +2,8 @@ package bank_account import ( "github.com/labstack/echo/v4" - "gitnet.fr/deblan/budget/database/model" "gitnet.fr/deblan/budget/backend/controller/crud" + "gitnet.fr/deblan/budget/database/model" "gorm.io/gorm" ) @@ -39,32 +39,32 @@ func New(e *echo.Echo) *Controller { } func (ctrl *Controller) List(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).List(c) } func (ctrl *Controller) Show(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).Show(c) } func (ctrl *Controller) Delete(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).Delete(c) } func (ctrl *Controller) Create(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } type body struct { @@ -83,8 +83,8 @@ func (ctrl *Controller) Create(c echo.Context) error { } func (ctrl *Controller) Update(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } type body struct { diff --git a/backend/controller/category/controller.go b/backend/controller/category/controller.go index 019f615..adf0d5d 100644 --- a/backend/controller/category/controller.go +++ b/backend/controller/category/controller.go @@ -2,9 +2,9 @@ package category import ( "github.com/labstack/echo/v4" + "gitnet.fr/deblan/budget/backend/controller/crud" "gitnet.fr/deblan/budget/database/manager" "gitnet.fr/deblan/budget/database/model" - "gitnet.fr/deblan/budget/backend/controller/crud" "gorm.io/gorm" ) @@ -46,32 +46,32 @@ func New(e *echo.Echo) *Controller { } func (ctrl *Controller) List(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).List(c) } func (ctrl *Controller) Show(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).Show(c) } func (ctrl *Controller) Delete(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).Delete(c) } func (ctrl *Controller) Create(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } type body struct { @@ -93,8 +93,8 @@ func (ctrl *Controller) Create(c echo.Context) error { } func (ctrl *Controller) Update(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } type body struct { diff --git a/backend/controller/collabora/controller.go b/backend/controller/collabora/controller.go index 83f592a..48f1518 100644 --- a/backend/controller/collabora/controller.go +++ b/backend/controller/collabora/controller.go @@ -12,11 +12,12 @@ import ( "time" "github.com/labstack/echo/v4" + "gitnet.fr/deblan/budget/backend/controller/crud" + "gitnet.fr/deblan/budget/backend/view" + tpl "gitnet.fr/deblan/budget/backend/view/template/collabora" "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 { @@ -55,8 +56,8 @@ func New(e *echo.Echo) *Controller { } func (ctrl *Controller) Iframe(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } resp, err := http.Get(config.Get().Collabora.HostingDiscoveryUrl()) diff --git a/backend/controller/file/controller.go b/backend/controller/file/controller.go index 661ba4e..31efba5 100644 --- a/backend/controller/file/controller.go +++ b/backend/controller/file/controller.go @@ -8,10 +8,10 @@ import ( "strings" "github.com/labstack/echo/v4" + "gitnet.fr/deblan/budget/backend/controller/crud" "gitnet.fr/deblan/budget/config" "gitnet.fr/deblan/budget/database/model" f "gitnet.fr/deblan/budget/file" - "gitnet.fr/deblan/budget/backend/controller/crud" ) type Controller struct { @@ -30,8 +30,8 @@ func New(e *echo.Echo) *Controller { } func (ctrl *Controller) List(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } tree := f.GetTree("", config.Get().File.Path) @@ -40,8 +40,8 @@ func (ctrl *Controller) List(c echo.Context) error { } func (ctrl *Controller) CreateFile(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } file, err := c.FormFile("file") @@ -76,8 +76,8 @@ func (ctrl *Controller) CreateFile(c echo.Context) error { } func (ctrl *Controller) CreateDirectory(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } type body struct { @@ -125,8 +125,8 @@ func (ctrl *Controller) CreateDirectory(c echo.Context) error { } func (ctrl *Controller) Download(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } var file string @@ -152,8 +152,8 @@ func (ctrl *Controller) Download(c echo.Context) error { } func (ctrl *Controller) Delete(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } var file string diff --git a/backend/controller/saving_account/controller.go b/backend/controller/saving_account/controller.go index b19d201..03ac10e 100644 --- a/backend/controller/saving_account/controller.go +++ b/backend/controller/saving_account/controller.go @@ -2,8 +2,8 @@ package saving_account import ( "github.com/labstack/echo/v4" - "gitnet.fr/deblan/budget/database/model" "gitnet.fr/deblan/budget/backend/controller/crud" + "gitnet.fr/deblan/budget/database/model" "gorm.io/gorm" ) @@ -39,32 +39,32 @@ func New(e *echo.Echo) *Controller { } func (ctrl *Controller) List(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).List(c) } func (ctrl *Controller) Show(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).Show(c) } func (ctrl *Controller) Delete(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).Delete(c) } func (ctrl *Controller) Create(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } type body struct { @@ -85,8 +85,8 @@ func (ctrl *Controller) Create(c echo.Context) error { } func (ctrl *Controller) Update(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } type body struct { diff --git a/backend/controller/transaction/controller.go b/backend/controller/transaction/controller.go index ee9ecb5..1c94964 100644 --- a/backend/controller/transaction/controller.go +++ b/backend/controller/transaction/controller.go @@ -6,9 +6,9 @@ import ( "strconv" "github.com/labstack/echo/v4" + "gitnet.fr/deblan/budget/backend/controller/crud" "gitnet.fr/deblan/budget/database/manager" "gitnet.fr/deblan/budget/database/model" - "gitnet.fr/deblan/budget/backend/controller/crud" "gorm.io/gorm" ) @@ -49,24 +49,24 @@ func New(e *echo.Echo) *Controller { } func (ctrl *Controller) List(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).List(c) } func (ctrl *Controller) Show(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).Show(c) } func (ctrl *Controller) UpdateCategories(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } datas := model.UpdateTransactionsCategories() @@ -75,8 +75,8 @@ func (ctrl *Controller) UpdateCategories(c echo.Context) error { } func (ctrl *Controller) Create(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } db := manager.Get().Db diff --git a/backend/controller/user/controller.go b/backend/controller/user/controller.go index 55c6423..b8d4ff7 100644 --- a/backend/controller/user/controller.go +++ b/backend/controller/user/controller.go @@ -2,8 +2,8 @@ package user import ( "github.com/labstack/echo/v4" - "gitnet.fr/deblan/budget/database/model" "gitnet.fr/deblan/budget/backend/controller/crud" + "gitnet.fr/deblan/budget/database/model" "gorm.io/gorm" ) @@ -38,32 +38,32 @@ func New(e *echo.Echo) *Controller { } func (ctrl *Controller) List(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).List(c) } func (ctrl *Controller) Show(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).Show(c) } func (ctrl *Controller) Delete(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } return ctrl.crud.With(ctrl.Config()).Delete(c) } func (ctrl *Controller) Create(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } type body struct { @@ -83,8 +83,8 @@ func (ctrl *Controller) Create(c echo.Context) error { } func (ctrl *Controller) Update(c echo.Context) error { - if nil == model.LoadSessionUser(c) { - return c.Redirect(302, "/login") + if nil == model.LoadApiUser(c) { + return c.JSON(403, crud.Error{Code: 403, Message: "Login required"}) } type body struct { diff --git a/backend/view/template/app/page.templ b/backend/view/template/app/page.templ index 0f52e8c..b209ae9 100644 --- a/backend/view/template/app/page.templ +++ b/backend/view/template/app/page.templ @@ -1,10 +1,13 @@ package app -import "gitnet.fr/deblan/budget/backend/view/template" +import ( + "gitnet.fr/deblan/budget/backend/view/template" + "gitnet.fr/deblan/budget/database/model" +) -templ Page() { +templ Page(user model.User) { - + @template.Head("Budget")
diff --git a/backend/view/template/app/page_templ.go b/backend/view/template/app/page_templ.go index 1ff522d..dcc91dd 100644 --- a/backend/view/template/app/page_templ.go +++ b/backend/view/template/app/page_templ.go @@ -8,9 +8,12 @@ package app import "github.com/a-h/templ" import templruntime "github.com/a-h/templ/runtime" -import "gitnet.fr/deblan/budget/backend/view/template" +import ( + "gitnet.fr/deblan/budget/backend/view/template" + "gitnet.fr/deblan/budget/database/model" +) -func Page() templ.Component { +func Page(user model.User) 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 { @@ -31,7 +34,20 @@ func Page() templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/database/model/user.go b/database/model/user.go index f5e1c61..5f050a8 100644 --- a/database/model/user.go +++ b/database/model/user.go @@ -1,6 +1,9 @@ package model import ( + "crypto/rand" + "encoding/base64" + "strings" "time" "github.com/labstack/echo-contrib/session" @@ -14,6 +17,8 @@ type User struct { Username string `gorm:"unique;not null" json:"username"` Password string `gorm:"not null" json:"-"` DisplayName string `gorm:"not null" json:"display_name"` + ApiKey string `json:"api_key"` + LoggedAt time.Time `json:"logged_at"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } @@ -29,6 +34,13 @@ func NewUser(username, password, displayName string) *User { return &user } +func (u *User) GenerateApiKey() { + buffer := make([]byte, 64) + rand.Read(buffer) + + u.ApiKey = base64.URLEncoding.EncodeToString(buffer)[:64] +} + func (u *User) UpdatePassword(password string) { hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) @@ -39,6 +51,44 @@ func (u *User) HasPassword(password string) bool { return bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password)) == nil } +func LoadUser(c echo.Context) *User { + user := LoadApiUser(c) + + if user == nil { + user = LoadSessionUser(c) + } + + return user +} + +func LoadApiUser(c echo.Context) *User { + headers := c.Request().Header + apiKey := "" + + for key, values := range headers { + if strings.ToLower(key) == "x-api-key" { + apiKey = values[0] + } + } + + if apiKey == "" { + return nil + } + + var count int64 + db := manager.Get() + db.Db.Model(User{}).Where("api_key = ?", apiKey).Count(&count) + + if count == 0 { + return nil + } + + var user User + manager.Get().Db.Model(User{}).Where("api_key = ?", apiKey).Find(&user) + + return &user +} + func LoadSessionUser(c echo.Context) *User { sess, err := session.Get("session", c) @@ -65,5 +115,10 @@ func LoadSessionUser(c echo.Context) *User { var user User manager.Get().Db.Model(User{}).Where("id = ?", id).Find(&user) + if user.ApiKey == "" { + user.GenerateApiKey() + db.Db.Save(user) + } + return &user } diff --git a/frontend/js/lib/renderers.js b/frontend/js/lib/renderers.js index 96e7ab2..12ea285 100644 --- a/frontend/js/lib/renderers.js +++ b/frontend/js/lib/renderers.js @@ -1,21 +1,27 @@ +const addZero = (value) => { + if (value < 10) { + value = `0${value}` + } + + return value +} + const renderDate = (value) => { const d = new Date(value) - let day = d.getUTCDate() - let month = d.getUTCMonth() + 1 + let day = addZero(d.getUTCDate()) + let month = addZero(d.getUTCMonth() + 1) const year = d.getUTCFullYear() - if (month < 10) { - month = `0${month}` - } - - if (day < 10) { - day = `0${day}` - } - return `${day}/${month}/${year}` } +const renderDateTime = (value) => { + const d = new Date(value) + + return `${renderDate(value)} ${addZero(d.getHours())}:${addZero(d.getMinutes())}` +} + const renderCategory = (item) => { if (item !== null) { return `  ${item.label}` @@ -58,6 +64,7 @@ const renderLabelWithSum = (label, rows, key) => { export { renderDate, + renderDateTime, renderCategory, renderBankAccount, renderEuro, diff --git a/frontend/js/lib/request.js b/frontend/js/lib/request.js new file mode 100644 index 0000000..3be5112 --- /dev/null +++ b/frontend/js/lib/request.js @@ -0,0 +1,16 @@ +const createRequestOptions = (options) => { + options = options || {} + + const apiKey = document.querySelector('html').getAttribute('data-api-key') + + if (apiKey) { + options['headers'] = options['headers'] || {} + options['headers']['x-api-key'] = apiKey + } + + return options +} + +export { + createRequestOptions +} diff --git a/frontend/js/views/BankAccountsView.vue b/frontend/js/views/BankAccountsView.vue index 79d19e1..1d2e092 100644 --- a/frontend/js/views/BankAccountsView.vue +++ b/frontend/js/views/BankAccountsView.vue @@ -159,6 +159,7 @@ import Header from './../components/crud/Header.vue' import Pager from './../components/crud/Pager.vue' import {ref, onMounted, watch} from 'vue' import {getStorage, saveStorage} from '../lib/storage' +import {createRequestOptions} from '../lib/request' const endpoint = `/api/bank_account` const order = ref(getStorage(`${endpoint}:order`)) @@ -183,6 +184,7 @@ const refresh = () => { page: page.value, limit: limit.value, })}`, + createRequestOptions() ) .then((response) => { return response.json() @@ -246,13 +248,13 @@ const doDelete = () => { return } - fetch(`${endpoint}/${form.value.data.id}`, { + fetch(`${endpoint}/${form.value.data.id}`, createRequestOptions({ method: 'DELETE', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, - }).then(() => { + })).then(() => { formShow.value = false refresh() }) @@ -265,14 +267,14 @@ const doSave = (e) => { ? `${endpoint}/${form.value.data.id}` : endpoint - fetch(url, { + fetch(url, createRequestOptions({ method: form.value.method, headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify(form.value.data), - }) + })) .then((response) => { return response.json() }) diff --git a/frontend/js/views/CategoriesView.vue b/frontend/js/views/CategoriesView.vue index c56d77b..39cda66 100644 --- a/frontend/js/views/CategoriesView.vue +++ b/frontend/js/views/CategoriesView.vue @@ -289,6 +289,7 @@ import Pager from './../components/crud/Pager.vue' import {ref, onMounted, watch, useTemplateRef} from 'vue' import {getStorage, saveStorage} from '../lib/storage' import {renderCategory, renderEuro, renderLabelWithSum} from '../lib/renderers' +import {createRequestOptions} from '../lib/request' const endpoint = `/api/category` const order = ref(getStorage(`${endpoint}:order`)) @@ -345,7 +346,7 @@ const doAddRule = (item) => { const doApply = () => { applyInProgress.value = true - fetch('/api/transactions/update_categories', {method: 'POST'}).then(() => { + fetch('/api/transactions/update_categories', createRequestOptions({method: 'POST'})).then(() => { applyInProgress.value = false }) } @@ -358,6 +359,7 @@ const refresh = () => { page: page.value, limit: limit.value, })}`, + createRequestOptions() ) .then((response) => { return response.json() @@ -517,13 +519,13 @@ const doDelete = () => { return } - fetch(`${endpoint}/${form.value.data.id}`, { + fetch(`${endpoint}/${form.value.data.id}`, createRequestOptions({ method: 'DELETE', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, - }).then(() => { + })).then(() => { formShow.value = false refresh() }) @@ -584,14 +586,14 @@ const doSave = (e) => { } }) - fetch(url, { + fetch(url, createRequestOptions({ method: form.value.method, headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify(form.value.data), - }) + })) .then((response) => { return response.json() }) diff --git a/frontend/js/views/DashboardView.vue b/frontend/js/views/DashboardView.vue index 16cd020..344968f 100644 --- a/frontend/js/views/DashboardView.vue +++ b/frontend/js/views/DashboardView.vue @@ -118,6 +118,7 @@ import MonthThresholds from './../components/dashboard/MonthThresholds.vue' import DiffCreditDebit from './../components/dashboard/DiffCreditDebit.vue' import CategoriesStats from './../components/dashboard/CategoriesStats.vue' import {VueDraggableNext as Draggable} from 'vue-draggable-next' +import {createRequestOptions} from '../lib/request' const data = ref(null) const isLoading = ref(true) @@ -207,7 +208,7 @@ const refresh = () => { query['bank_account_id__eq'] = account.value } - fetch(`/api/transaction?${new URLSearchParams(query)}`) + fetch(`/api/transaction?${new URLSearchParams(query)}`, createRequestOptions()) .then((response) => response.json()) .then((value) => { data.value = value.rows.filter( @@ -222,20 +223,20 @@ onMounted(() => { refresh() - fetch('/api/category?order=label&sort=asc&ignore_transactions__eq=0') + fetch('/api/category?order=label&sort=asc&ignore_transactions__eq=0', createRequestOptions()) .then((response) => response.json()) .then((data) => { categories.value = data.rows categories.value.push({id: -1, label: 'Sans catégorie', color: '#cccccc'}) }) - fetch('/api/bank_account') + fetch('/api/bank_account', createRequestOptions()) .then((response) => response.json()) .then((data) => { accounts.value = data.rows }) - fetch('/api/saving_account') + fetch('/api/saving_account', createRequestOptions()) .then((response) => response.json()) .then((data) => { savingAccounts.value = data.rows diff --git a/frontend/js/views/FilesView.vue b/frontend/js/views/FilesView.vue index e9f42f3..fb13025 100644 --- a/frontend/js/views/FilesView.vue +++ b/frontend/js/views/FilesView.vue @@ -188,6 +188,7 @@ import { BDropdown, BDropdownItem, } from 'bootstrap-vue-next' +import {createRequestOptions} from '../lib/request' let formFile = false const tree = ref(null) @@ -271,9 +272,9 @@ const doDelete = (item) => { return } - fetch(`/api/filemanager/file/${item.id}`, { + fetch(`/api/filemanager/file/${item.id}`, createRequestOptions({ method: 'DELETE', - }).then(() => { + })).then(() => { refresh({current: tree.value.id}) }) } @@ -286,13 +287,13 @@ const doSave = (e) => { payload.append('file', form.value.data.file) payload.append('path', tree.value.id) - fetch(`/api/filemanager/file`, { + fetch(`/api/filemanager/file`, createRequestOptions({ method: form.value.method, headers: { Accept: 'application/json', }, body: payload, - }) + })) .then((response) => { return response.json() }) @@ -309,14 +310,14 @@ const doSave = (e) => { form.value.error = `Une erreur s'est produite : ${err}` }) } else { - fetch(`/api/filemanager/directory`, { + fetch(`/api/filemanager/directory`, createRequestOptions({ method: form.value.method, headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify(form.value.data), - }) + })) .then((response) => { return response.json() }) @@ -338,7 +339,7 @@ const doSave = (e) => { const refresh = (options) => { options = options || {} - fetch('/api/filemanager/files') + fetch('/api/filemanager/files', createRequestOptions()) .then((response) => response.json()) .then((data) => { tree.value = withParents(data) diff --git a/frontend/js/views/SavingAccountsView.vue b/frontend/js/views/SavingAccountsView.vue index 2c2a37f..a8da9b4 100644 --- a/frontend/js/views/SavingAccountsView.vue +++ b/frontend/js/views/SavingAccountsView.vue @@ -161,6 +161,7 @@ import Pager from './../components/crud/Pager.vue' import {ref, onMounted, watch} from 'vue' import {getStorage, saveStorage} from '../lib/storage' import {renderDate, renderEuro, renderLabelWithSum} from '../lib/renderers' +import {createRequestOptions} from '../lib/request' const endpoint = `/api/saving_account` const order = ref(getStorage(`${endpoint}:order`)) @@ -185,6 +186,7 @@ const refresh = () => { page: page.value, limit: limit.value, })}`, + createRequestOptions() ) .then((response) => { return response.json() @@ -268,13 +270,13 @@ const doDelete = () => { return } - fetch(`${endpoint}/${form.value.data.id}`, { + fetch(`${endpoint}/${form.value.data.id}`, createRequestOptions({ method: 'DELETE', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, - }).then(() => { + })).then(() => { formShow.value = false refresh() }) @@ -290,14 +292,14 @@ const doSave = (e) => { form.value.data.released_amount = parseFloat(form.value.data.released_amount) form.value.data.blocked_amount = parseFloat(form.value.data.blocked_amount) - fetch(url, { + fetch(url, createRequestOptions({ method: form.value.method, headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify(form.value.data), - }) + })) .then((response) => { return response.json() }) diff --git a/frontend/js/views/TransactionsView.vue b/frontend/js/views/TransactionsView.vue index 7e8cca0..c26ae9f 100644 --- a/frontend/js/views/TransactionsView.vue +++ b/frontend/js/views/TransactionsView.vue @@ -267,6 +267,7 @@ import { } from '../lib/renderers' import {queryFilters, appendRequestQueryFilters} from '../lib/filter' import {useRoute} from 'vue-router' +import {createRequestOptions} from '../lib/request' const endpoint = `/api/transaction` const order = ref(getStorage(`${endpoint}:order`)) @@ -311,7 +312,7 @@ const refresh = () => { query = appendRequestQueryFilters(query, route) - fetch(`${endpoint}?${new URLSearchParams(query)}`) + fetch(`${endpoint}?${new URLSearchParams(query)}`, createRequestOptions()) .then((response) => { return response.json() }) @@ -328,7 +329,7 @@ const refresh = () => { const doAdd = () => { const data = {category_id: null, file: null, format: 'caisse_epargne'} - fetch(`/api/bank_account?order=label`) + fetch(`/api/bank_account?order=label`, createRequestOptions()) .then((response) => { return response.json() }) @@ -387,13 +388,13 @@ const doSave = (e) => { payload.append('file', form.value.data.file) payload.append('format', form.value.data.format) - fetch(`/api/transactions`, { + fetch(`/api/transactions`, createRequestOptions({ method: form.value.method, headers: { Accept: 'application/json', }, body: payload, - }) + })) .then((response) => { return response.json() }) @@ -487,7 +488,7 @@ onMounted(() => { route = useRoute() refresh() - fetch('/api/category') + fetch('/api/category', createRequestOptions()) .then((response) => response.json()) .then((data) => { filtersFields.value.forEach((value, key) => { @@ -502,7 +503,7 @@ onMounted(() => { }) }) - fetch('/api/bank_account') + fetch('/api/bank_account', createRequestOptions()) .then((response) => response.json()) .then((data) => { filtersFields.value.forEach((value, key) => { diff --git a/frontend/js/views/UsersView.vue b/frontend/js/views/UsersView.vue index acdaa87..8950c52 100644 --- a/frontend/js/views/UsersView.vue +++ b/frontend/js/views/UsersView.vue @@ -157,6 +157,8 @@ import Header from './../components/crud/Header.vue' import Pager from './../components/crud/Pager.vue' import {ref, onMounted, watch} from 'vue' import {getStorage, saveStorage} from '../lib/storage' +import {createRequestOptions} from '../lib/request' +import {renderDateTime} from '../lib/renderers' const endpoint = `/api/user` const order = ref(getStorage(`${endpoint}:order`)) @@ -181,6 +183,7 @@ const refresh = () => { page: page.value, limit: limit.value, })}`, + createRequestOptions() ) .then((response) => { return response.json() @@ -268,13 +271,13 @@ const doDelete = () => { return } - fetch(`${endpoint}/${form.value.data.id}`, { + fetch(`${endpoint}/${form.value.data.id}`, createRequestOptions({ method: 'DELETE', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, - }).then(() => { + })).then(() => { formShow.value = false refresh() }) @@ -287,14 +290,14 @@ const doSave = (e) => { ? `${endpoint}/${form.value.data.id}` : endpoint - fetch(url, { + fetch(url, createRequestOptions({ method: form.value.method, headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify(form.value.data), - }) + })) .then((response) => { return response.json() }) @@ -336,6 +339,11 @@ const fields = [ key: 'username', label: 'Utilisateur', }, + { + key: 'logged_at', + label: 'Dernière connexion', + render: (item) => renderDateTime(item.logged_at), + }, ] onMounted(() => {