add api-key authentication

This commit is contained in:
Simon Vieille 2025-02-16 19:14:28 +01:00
commit da44d18375
21 changed files with 244 additions and 123 deletions

View file

@ -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))
}

View file

@ -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

View file

@ -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 {

View file

@ -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 {

View file

@ -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())

View file

@ -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

View file

@ -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 {

View file

@ -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

View file

@ -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 {

View file

@ -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) {
<!doctype html>
<html>
<html data-api-key={ user.ApiKey }>
@template.Head("Budget")
<body>
<div id="app"></div>

View file

@ -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("<!doctype html><html>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html data-api-key=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(user.ApiKey)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `backend/view/template/app/page.templ`, Line: 10, Col: 33}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View file

@ -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
}

View file

@ -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 `<span class="badge" style="background: ${item.color}">&nbsp;</span> ${item.label}`
@ -58,6 +64,7 @@ const renderLabelWithSum = (label, rows, key) => {
export {
renderDate,
renderDateTime,
renderCategory,
renderBankAccount,
renderEuro,

View file

@ -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
}

View file

@ -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()
})

View file

@ -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()
})

View file

@ -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

View file

@ -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)

View file

@ -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()
})

View file

@ -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) => {

View file

@ -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(() => {