This commit is contained in:
Victor Lacasse-Beaudoin 2024-12-30 19:13:05 -05:00
parent abda13d070
commit 7f3901ddc2
8 changed files with 46 additions and 57 deletions

View file

@ -11,5 +11,6 @@ services:
- '5432:5432' - '5432:5432'
volumes: volumes:
- 'db-data:/var/lib/postgresql/data/' - 'db-data:/var/lib/postgresql/data/'
- '/etc/localtime:/etc/localtime:ro'
volumes: volumes:
db-data: db-data:

11
db.go
View file

@ -3,7 +3,9 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"git.agecem.com/bottin/agendas/queries"
"github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/pgxpool"
) )
@ -27,8 +29,13 @@ func (d DBClient) Ping(ctx context.Context) error {
func (d DBClient) Init(ctx context.Context) error { func (d DBClient) Init(ctx context.Context) error {
//TODO check context is not closed //TODO check context is not closed
//TODO check *DB is not nil //TODO check *DB is not nil
//TODO Init log.Println("warning: DBClient [Init] not properly checked")
return fmt.Errorf("db: Init not implemented") // Init
if _, err := d.Pool.Exec(ctx, queries.SQLSchema()); err != nil {
return err
}
return nil
} }
func (d DBClient) CreateTransaction(ctx context.Context, transaction Transaction) error { func (d DBClient) CreateTransaction(ctx context.Context, transaction Transaction) error {

2
go.mod
View file

@ -5,6 +5,7 @@ go 1.23.4
require ( require (
codeberg.org/vlbeaudoin/voki/v3 v3.0.1 codeberg.org/vlbeaudoin/voki/v3 v3.0.1
git.agecem.com/bottin/bottin/v10 v10.4.1 git.agecem.com/bottin/bottin/v10 v10.4.1
github.com/jackc/pgx/v5 v5.7.1
github.com/labstack/echo/v4 v4.13.3 github.com/labstack/echo/v4 v4.13.3
github.com/spf13/cobra v1.8.1 github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
@ -18,7 +19,6 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.1 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/labstack/gommon v0.4.2 // indirect github.com/labstack/gommon v0.4.2 // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/magiconair/properties v1.8.7 // indirect

View file

@ -17,6 +17,7 @@ func UIIndex(ctx context.Context, bottinClient *bottin.APIClient, dbClient *DBCl
Error string Error string
BottinHealthResponse bottin.ReadHealthResponse BottinHealthResponse bottin.ReadHealthResponse
IsDBUp bool IsDBUp bool
Result string
} }
return c.Render(http.StatusOK, "index", func() (d data) { return c.Render(http.StatusOK, "index", func() (d data) {
@ -62,47 +63,6 @@ func UIIndex(ctx context.Context, bottinClient *bottin.APIClient, dbClient *DBCl
} }
} }
func UIReadMembre(ctx context.Context, bottinClient *bottin.APIClient) echo.HandlerFunc {
return func(c echo.Context) error {
type data struct {
Error string
BottinMembreResponse bottin.ReadMembreResponse
}
return c.Render(http.StatusOK, "index", func() (d data) {
if err := func() error {
select {
case <-ctx.Done():
return fmt.Errorf("Impossible de contacter le serveur: %s", ctx.Err())
default:
// Check client
if bottinClient == nil {
return fmt.Errorf("Impossible de contacter le serveur, le client API est nil")
}
var err error
// Check membre
d.BottinMembreResponse, err = bottinClient.ReadMembre(ctx, c.QueryParam("m"))
if err != nil {
return err
}
// No errors
return nil
}
}(); err != nil {
// Send error to user
d.Error = err.Error()
// Log error
log.Println("err:", d.Error)
}
return
}())
}
}
/* /*
UICreateTransaction gère la création des transactions UICreateTransaction gère la création des transactions
@ -113,9 +73,9 @@ TODO:
func UICreateTransaction(ctx context.Context, cfg Config, bottinClient *bottin.APIClient, dbClient *DBClient) echo.HandlerFunc { func UICreateTransaction(ctx context.Context, cfg Config, bottinClient *bottin.APIClient, dbClient *DBClient) echo.HandlerFunc {
return func(c echo.Context) error { return func(c echo.Context) error {
type data struct { type data struct {
BottinHealth bottin.ReadHealthResponse
Error string Error string
Result string Result string
//BottinHealth bottin.ReadHealthResponse
} }
return c.Render(http.StatusOK, "index", func() (d data) { return c.Render(http.StatusOK, "index", func() (d data) {
@ -124,12 +84,14 @@ func UICreateTransaction(ctx context.Context, cfg Config, bottinClient *bottin.A
return fmt.Errorf("Cannot operate on nil *bottin.APIClient") return fmt.Errorf("Cannot operate on nil *bottin.APIClient")
} }
/*
bottinReadHealthResponse, err := bottinClient.ReadHealth(ctx) bottinReadHealthResponse, err := bottinClient.ReadHealth(ctx)
if err != nil { if err != nil {
return err return err
} }
d.BottinHealth = bottinReadHealthResponse d.BottinHealth = bottinReadHealthResponse
*/
isPerpetual := c.FormValue("is_perpetual") == "on" isPerpetual := c.FormValue("is_perpetual") == "on"
membreID := c.FormValue("membre_id") membreID := c.FormValue("membre_id")

10
queries/queries.go Normal file
View file

@ -0,0 +1,10 @@
package queries
import _ "embed"
//go:embed schema.sql
var sqlSchema string
func SQLSchema() string {
return sqlSchema
}

7
queries/schema.sql Normal file
View file

@ -0,0 +1,7 @@
-- Schema
CREATE TABLE IF NOT EXISTS transactions (
given_at TIMESTAMP DEFAULT current_timestamp,
membre_id VARCHAR(7) NOT NULL CHECK (length(membre_id) > 0),
is_perpetual BOOLEAN NOT NULL,
PRIMARY KEY (membre_id, is_perpetual)
);

View file

@ -25,6 +25,10 @@ func RunServer(ctx context.Context, cfg Config, bottinClient *bottin.APIClient,
return fmt.Errorf("nil dbClient") return fmt.Errorf("nil dbClient")
} }
if err := dbClient.Init(ctx); err != nil {
return err
}
e := echo.New() e := echo.New()
r := ui.NewRenderer() r := ui.NewRenderer()
@ -42,7 +46,7 @@ func RunServer(ctx context.Context, cfg Config, bottinClient *bottin.APIClient,
return fmt.Errorf("UI requires at least one credential (config key `Credentials` of type map[string]string)") return fmt.Errorf("UI requires at least one credential (config key `Credentials` of type map[string]string)")
} }
e.Use(middleware.BasicAuth( e.Pre(middleware.BasicAuth(
func(username, password string, c echo.Context) (bool, error) { func(username, password string, c echo.Context) (bool, error) {
for validUser, validPass := range cfg.Credentials { for validUser, validPass := range cfg.Credentials {
userOK := subtle.ConstantTimeCompare([]byte(username), []byte(validUser)) == 1 userOK := subtle.ConstantTimeCompare([]byte(username), []byte(validUser)) == 1
@ -62,8 +66,6 @@ func RunServer(ctx context.Context, cfg Config, bottinClient *bottin.APIClient,
//e.GET("/transaction/", UIReadTransaction //e.GET("/transaction/", UIReadTransaction
e.POST("/transaction/", UICreateTransaction(ctx, cfg, bottinClient, dbClient)) e.POST("/transaction/", UICreateTransaction(ctx, cfg, bottinClient, dbClient))
//e.GET("/membre/", UIReadMembre(ctx, bottinClient))
address := fmt.Sprintf(":%d", cfg.Port) address := fmt.Sprintf(":%d", cfg.Port)
if cfg.TLS.Enabled { if cfg.TLS.Enabled {

View file

@ -113,7 +113,7 @@ button {
</form> </form>
{{ if .Error }}<p class="result">Erreur: {{ .Error }}</p>{{ end }} {{ if .Error }}<p class="result">Erreur: {{ .Error }}</p>{{ end }}
<p class="result">{{ .Result }}</p> {{ if .Result }}<p class="result">{{ .Result }}</p>{{ end }}
</body> </body>
</html> </html>