parent
e6d6ba4041
commit
c6dc9cd110
@ -6,34 +6,43 @@ import (
|
||||
"git.tijl.dev/tijl/tijl.dev/internal/assets"
|
||||
"git.tijl.dev/tijl/tijl.dev/internal/config"
|
||||
"git.tijl.dev/tijl/tijl.dev/internal/i18n"
|
||||
"git.tijl.dev/tijl/tijl.dev/modules/logger"
|
||||
"git.tijl.dev/tijl/tijl.dev/static"
|
||||
"git.tijl.dev/tijl/tijl.dev/views"
|
||||
"github.com/gofiber/contrib/fiberzerolog"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
||||
"github.com/gofiber/template/html/v2"
|
||||
"github.com/mikhail-bigun/fiberlogrus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
// Load config
|
||||
config.Load()
|
||||
|
||||
// Load assets
|
||||
assets.Load()
|
||||
// Load translations
|
||||
i18n.Load()
|
||||
|
||||
engine := html.NewFileSystem(http.FS(views.Embed), ".html")
|
||||
// Todo load db, migrations and plugins
|
||||
|
||||
// Init templating engine
|
||||
engine := html.NewFileSystem(http.FS(views.Embed), ".html")
|
||||
engine.AddFunc("icon", assets.Svg)
|
||||
|
||||
// Init fiber
|
||||
app := fiber.New(fiber.Config{
|
||||
Views: engine,
|
||||
DisableStartupMessage: true,
|
||||
})
|
||||
app.Use(fiberzerolog.New(fiberzerolog.Config{
|
||||
Logger: &log.Logger,
|
||||
}))
|
||||
|
||||
app.Use(fiberlogrus.New())
|
||||
|
||||
/*
|
||||
Routes
|
||||
*/
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
data := getCommon(c)
|
||||
data["Title"] = i18n.Translate(c, "home")
|
||||
@ -70,18 +79,24 @@ func main() {
|
||||
return nil
|
||||
})
|
||||
|
||||
// Static routes
|
||||
app.Use("/static", filesystem.New(filesystem.Config{
|
||||
Root: http.FS(static.Embed),
|
||||
}))
|
||||
|
||||
// 404
|
||||
app.Use(func(c *fiber.Ctx) error {
|
||||
data := getCommon(c)
|
||||
return c.Render("404", data, "layouts/base")
|
||||
})
|
||||
|
||||
log.Fatal(app.Listen(":3000"))
|
||||
// Listen web server
|
||||
if err := app.Listen(":3000"); err != nil {
|
||||
log.Fatal().Err(err).Msg("Fiber app error")
|
||||
}
|
||||
}
|
||||
|
||||
// Common functions for in templating
|
||||
func getCommon(c *fiber.Ctx) fiber.Map {
|
||||
return fiber.Map{
|
||||
"Path": c.Path(),
|
||||
|
3
go.mod
3
go.mod
@ -7,13 +7,16 @@ require (
|
||||
github.com/gofiber/fiber/v2 v2.52.5
|
||||
github.com/gofiber/template/html/v2 v2.1.2
|
||||
github.com/mikhail-bigun/fiberlogrus v0.1.3
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/sqlc-dev/pqtype v0.3.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
||||
github.com/gofiber/contrib/fiberzerolog v1.0.2 // indirect
|
||||
github.com/gofiber/template v1.8.3 // indirect
|
||||
github.com/gofiber/utils v1.1.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
|
12
go.sum
12
go.sum
@ -2,11 +2,15 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI=
|
||||
github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk=
|
||||
github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofiber/contrib/fiberzerolog v1.0.2 h1:LMa/luarQVeINoRwZLHtLQYepLPDIwUNB5OmdZKk+s8=
|
||||
github.com/gofiber/contrib/fiberzerolog v1.0.2/go.mod h1:aTPsgArSgxRWcUeJ/K6PiICz3mbQENR1QOR426QwOoQ=
|
||||
github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
|
||||
github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
|
||||
github.com/gofiber/template v1.8.3 h1:hzHdvMwMo/T2kouz2pPCA0zGiLCeMnoGsQZBTSYgZxc=
|
||||
@ -24,19 +28,26 @@ github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ib
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mikhail-bigun/fiberlogrus v0.1.3 h1:2aVtFSfMr/T8J2p4228TwV6txvUEOQxKlu5LpcKyym0=
|
||||
github.com/mikhail-bigun/fiberlogrus v0.1.3/go.mod h1:Tt0FrmLd2maF8VSHsx1pfiWNRTrjyBrKfDA2JW5hvmY=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sqlc-dev/pqtype v0.3.0 h1:b09TewZ3cSnO5+M1Kqq05y0+OjqIptxELaSayg7bmqk=
|
||||
github.com/sqlc-dev/pqtype v0.3.0/go.mod h1:oyUjp5981ctiL9UYvj1bVvCKi8OXkCa0u645hce7CAs=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
@ -54,6 +65,7 @@ golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbht
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"git.tijl.dev/tijl/tijl.dev/modules/logger"
|
||||
)
|
||||
|
||||
var SVGData map[string]string
|
||||
@ -18,13 +18,13 @@ func loadSVGs() {
|
||||
|
||||
files, err := filepath.Glob(filepath.Join(dir, "*.svg"))
|
||||
if err != nil {
|
||||
log.Fatalf("Error loading SVG files: %v", err)
|
||||
log.Fatal().Err(err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
data, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
log.Warnf("Error reading SVG file %s: %v", file, err)
|
||||
log.Fatal().Err(err)
|
||||
continue
|
||||
}
|
||||
filename := filepath.Base(file)
|
||||
@ -32,7 +32,7 @@ func loadSVGs() {
|
||||
SVGData[key] = string(data)
|
||||
}
|
||||
|
||||
log.Debug("Loaded SVG files")
|
||||
log.Debug().Msg("Loaded SVG files")
|
||||
}
|
||||
|
||||
func Svg(name string) template.HTML {
|
||||
|
@ -3,7 +3,7 @@ package config
|
||||
import (
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
log "git.tijl.dev/tijl/tijl.dev/modules/logger"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@ -17,15 +17,15 @@ func Load() {
|
||||
|
||||
indexFile, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatal().Err(err)
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(indexFile, &Config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatal().Err(err)
|
||||
}
|
||||
|
||||
log.Debug("loaded config")
|
||||
log.Debug().Msg("loaded config")
|
||||
}
|
||||
|
||||
type ConfigType struct {
|
||||
|
@ -2,11 +2,11 @@ package i18n
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
log "git.tijl.dev/tijl/tijl.dev/modules/logger"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
var translations map[string]map[string]string
|
||||
@ -19,7 +19,7 @@ func Load() {
|
||||
dir := "locales"
|
||||
files, err := filepath.Glob(filepath.Join(dir, "*.json"))
|
||||
if err != nil {
|
||||
log.Fatalf("Error loading language files: %v", err)
|
||||
log.Fatal().Err(err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
@ -28,20 +28,20 @@ func Load() {
|
||||
|
||||
file, err := os.Open(file)
|
||||
if err != nil {
|
||||
log.Errorf("Error opening translation file %s: %v", file, err)
|
||||
log.Error().Err(err)
|
||||
continue
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var messages map[string]string
|
||||
if err := json.NewDecoder(file).Decode(&messages); err != nil {
|
||||
log.Errorf("Error decoding translation file %s: %v", file, err)
|
||||
log.Error().Err(err)
|
||||
continue
|
||||
}
|
||||
translations[lang] = messages
|
||||
}
|
||||
|
||||
log.Debug("Loaded translations")
|
||||
log.Debug().Msg("Loaded translations")
|
||||
}
|
||||
|
||||
func Translate(c *fiber.Ctx, key string) string {
|
||||
|
@ -1,7 +1,5 @@
|
||||
package oidc
|
||||
|
||||
import "github.com/coreos/go-oidc/v3/oidc"
|
||||
|
||||
func Setup() {
|
||||
}
|
||||
|
||||
|
5
justfile
5
justfile
@ -7,8 +7,11 @@ npm-build-css:
|
||||
npm-build:
|
||||
npm run build
|
||||
|
||||
generate-sqlc:
|
||||
sqlc generate
|
||||
|
||||
go-build:
|
||||
go build -o tijl.dev cmd/server/main.go
|
||||
|
||||
build: npm-build-css npm-build go-build
|
||||
build: npm-build-css npm-build generate-sqlc go-build
|
||||
|
||||
|
30
migrations/00000001_init.up.sql
Normal file
30
migrations/00000001_init.up.sql
Normal file
@ -0,0 +1,30 @@
|
||||
CREATE TABLE users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
uid VARCHAR UNIQUE NOT NULL, -- username as unique identifier
|
||||
email VARCHAR UNIQUE,
|
||||
full_name VARCHAR,
|
||||
displayname VARCHAR,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE sessions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL,
|
||||
title VARCHAR,
|
||||
token VARCHAR NOT NULL UNIQUE,
|
||||
password VARCHAR,
|
||||
last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
expires TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (user_id) REFERENCES users (id)
|
||||
);
|
||||
|
||||
CREATE TABLE session_ips (
|
||||
id SERIAL PRIMARY KEY,
|
||||
session_id INTEGER NOT NULL,
|
||||
ip_address INET NOT NULL,
|
||||
access_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (session_id) REFERENCES sessions (id)
|
||||
);
|
||||
|
3
migrations/0000001_init.down.sql
Normal file
3
migrations/0000001_init.down.sql
Normal file
@ -0,0 +1,3 @@
|
||||
DROP TABLE IF EXISTS session_ips;
|
||||
DROP TABLE IF EXISTS sessions;
|
||||
DROP TABLE IF EXISTS users;
|
6
migrations/migrations.go
Normal file
6
migrations/migrations.go
Normal file
@ -0,0 +1,6 @@
|
||||
package migrations
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed *
|
||||
var Embed embed.FS
|
31
modules/db/db.go
Normal file
31
modules/db/db.go
Normal file
@ -0,0 +1,31 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.27.0
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
type DBTX interface {
|
||||
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
|
||||
PrepareContext(context.Context, string) (*sql.Stmt, error)
|
||||
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
|
||||
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
|
||||
}
|
||||
|
||||
func New(db DBTX) *Queries {
|
||||
return &Queries{db: db}
|
||||
}
|
||||
|
||||
type Queries struct {
|
||||
db DBTX
|
||||
}
|
||||
|
||||
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
||||
return &Queries{
|
||||
db: tx,
|
||||
}
|
||||
}
|
40
modules/db/models.go
Normal file
40
modules/db/models.go
Normal file
@ -0,0 +1,40 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.27.0
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/sqlc-dev/pqtype"
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
ID int32
|
||||
UserID int32
|
||||
Title sql.NullString
|
||||
Token string
|
||||
Password sql.NullString
|
||||
LastActivity sql.NullTime
|
||||
Expires sql.NullTime
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type SessionIp struct {
|
||||
ID int32
|
||||
SessionID int32
|
||||
IpAddress pqtype.Inet
|
||||
AccessTime sql.NullTime
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID int32
|
||||
Uid string
|
||||
Email sql.NullString
|
||||
FullName sql.NullString
|
||||
Displayname sql.NullString
|
||||
CreatedAt time.Time
|
||||
UpdatedAt sql.NullTime
|
||||
}
|
18
modules/db/sessions.sql
Normal file
18
modules/db/sessions.sql
Normal file
@ -0,0 +1,18 @@
|
||||
-- name: GetSesssion :one
|
||||
SELECT * FROM sessions WHERE token = $1;
|
||||
|
||||
-- name: GetSessions :many
|
||||
SELECT * FROM sessions WHERE user_id = $1 ORDER BY $2;
|
||||
|
||||
-- name: GetActiveSessions :many
|
||||
SELECT * FROM sessions WHERE user_id = $1 AND (expires > CURRENT_TIMESTAMP OR expires IS NULL) ORDER BY $2;
|
||||
|
||||
-- name: CreateSession :exec
|
||||
INSERT INTO sessions (user_id, title, token) VALUES ($1, $2, $3);
|
||||
|
||||
-- name: QuickUpdateSession :exec
|
||||
UPDATE sessions SET last_activity = GETDATE() WHERE id = $1;
|
||||
|
||||
-- name: ExpireSession :exec
|
||||
UPDATE sessions SET expires = 1 WHERE id = $1;
|
||||
|
146
modules/db/sessions.sql.go
Normal file
146
modules/db/sessions.sql.go
Normal file
@ -0,0 +1,146 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.27.0
|
||||
// source: sessions.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
const createSession = `-- name: CreateSession :exec
|
||||
INSERT INTO sessions (user_id, title, token) VALUES ($1, $2, $3)
|
||||
`
|
||||
|
||||
type CreateSessionParams struct {
|
||||
UserID int32
|
||||
Title sql.NullString
|
||||
Token string
|
||||
}
|
||||
|
||||
func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) error {
|
||||
_, err := q.db.ExecContext(ctx, createSession, arg.UserID, arg.Title, arg.Token)
|
||||
return err
|
||||
}
|
||||
|
||||
const expireSession = `-- name: ExpireSession :exec
|
||||
UPDATE sessions SET expires = 1 WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) ExpireSession(ctx context.Context, id int32) error {
|
||||
_, err := q.db.ExecContext(ctx, expireSession, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const getActiveSessions = `-- name: GetActiveSessions :many
|
||||
SELECT id, user_id, title, token, password, last_activity, expires, created_at FROM sessions WHERE user_id = $1 AND (expires > CURRENT_TIMESTAMP OR expires IS NULL) ORDER BY $2
|
||||
`
|
||||
|
||||
type GetActiveSessionsParams struct {
|
||||
UserID int32
|
||||
Column2 interface{}
|
||||
}
|
||||
|
||||
func (q *Queries) GetActiveSessions(ctx context.Context, arg GetActiveSessionsParams) ([]Session, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getActiveSessions, arg.UserID, arg.Column2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Session
|
||||
for rows.Next() {
|
||||
var i Session
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.UserID,
|
||||
&i.Title,
|
||||
&i.Token,
|
||||
&i.Password,
|
||||
&i.LastActivity,
|
||||
&i.Expires,
|
||||
&i.CreatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getSessions = `-- name: GetSessions :many
|
||||
SELECT id, user_id, title, token, password, last_activity, expires, created_at FROM sessions WHERE user_id = $1 ORDER BY $2
|
||||
`
|
||||
|
||||
type GetSessionsParams struct {
|
||||
UserID int32
|
||||
Column2 interface{}
|
||||
}
|
||||
|
||||
func (q *Queries) GetSessions(ctx context.Context, arg GetSessionsParams) ([]Session, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getSessions, arg.UserID, arg.Column2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Session
|
||||
for rows.Next() {
|
||||
var i Session
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.UserID,
|
||||
&i.Title,
|
||||
&i.Token,
|
||||
&i.Password,
|
||||
&i.LastActivity,
|
||||
&i.Expires,
|
||||
&i.CreatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getSesssion = `-- name: GetSesssion :one
|
||||
SELECT id, user_id, title, token, password, last_activity, expires, created_at FROM sessions WHERE token = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetSesssion(ctx context.Context, token string) (Session, error) {
|
||||
row := q.db.QueryRowContext(ctx, getSesssion, token)
|
||||
var i Session
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.UserID,
|
||||
&i.Title,
|
||||
&i.Token,
|
||||
&i.Password,
|
||||
&i.LastActivity,
|
||||
&i.Expires,
|
||||
&i.CreatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const quickUpdateSession = `-- name: QuickUpdateSession :exec
|
||||
UPDATE sessions SET last_activity = GETDATE() WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) QuickUpdateSession(ctx context.Context, id int32) error {
|
||||
_, err := q.db.ExecContext(ctx, quickUpdateSession, id)
|
||||
return err
|
||||
}
|
25
modules/db/users.sql
Normal file
25
modules/db/users.sql
Normal file
@ -0,0 +1,25 @@
|
||||
-- name: GetUser :one
|
||||
SELECT * FROM users WHERE uid = $1 LIMIT 1;
|
||||
|
||||
-- name: GetUserUid :one
|
||||
SELECT uid FROM users WHERE id = $1 LIMIT 1;
|
||||
|
||||
-- name: GetUserById :one
|
||||
SELECT * FROM users WHERE id = $1 LIMIT 1;
|
||||
|
||||
-- name: DeleteUser :exec
|
||||
DELETE FROM users WHERE uid = $1;
|
||||
|
||||
-- name: CreateUser :exec
|
||||
INSERT INTO users (uid, email, full_name, displayname)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING id;
|
||||
|
||||
-- name: UpdateUserData :exec
|
||||
UPDATE users
|
||||
SET email = COALESCE($2, email),
|
||||
full_name = COALESCE($3, full_name),
|
||||
displayname = COALESCE($4, displayname),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE uid = $1;
|
||||
|
118
modules/db/users.sql.go
Normal file
118
modules/db/users.sql.go
Normal file
@ -0,0 +1,118 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.27.0
|
||||
// source: users.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
const createUser = `-- name: CreateUser :exec
|
||||
INSERT INTO users (uid, email, full_name, displayname)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING id
|
||||
`
|
||||
|
||||
type CreateUserParams struct {
|
||||
Uid string
|
||||
Email sql.NullString
|
||||
FullName sql.NullString
|
||||
Displayname sql.NullString
|
||||
}
|
||||
|
||||
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) error {
|
||||
_, err := q.db.ExecContext(ctx, createUser,
|
||||
arg.Uid,
|
||||
arg.Email,
|
||||
arg.FullName,
|
||||
arg.Displayname,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteUser = `-- name: DeleteUser :exec
|
||||
DELETE FROM users WHERE uid = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteUser(ctx context.Context, uid string) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteUser, uid)
|
||||
return err
|
||||
}
|
||||
|
||||
const getUser = `-- name: GetUser :one
|
||||
SELECT id, uid, email, full_name, displayname, created_at, updated_at FROM users WHERE uid = $1 LIMIT 1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUser(ctx context.Context, uid string) (User, error) {
|
||||
row := q.db.QueryRowContext(ctx, getUser, uid)
|
||||
var i User
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Uid,
|
||||
&i.Email,
|
||||
&i.FullName,
|
||||
&i.Displayname,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getUserById = `-- name: GetUserById :one
|
||||
SELECT id, uid, email, full_name, displayname, created_at, updated_at FROM users WHERE id = $1 LIMIT 1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserById(ctx context.Context, id int32) (User, error) {
|
||||
row := q.db.QueryRowContext(ctx, getUserById, id)
|
||||
var i User
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Uid,
|
||||
&i.Email,
|
||||
&i.FullName,
|
||||
&i.Displayname,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getUserUid = `-- name: GetUserUid :one
|
||||
SELECT uid FROM users WHERE id = $1 LIMIT 1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserUid(ctx context.Context, id int32) (string, error) {
|
||||
row := q.db.QueryRowContext(ctx, getUserUid, id)
|
||||
var uid string
|
||||
err := row.Scan(&uid)
|
||||
return uid, err
|
||||
}
|
||||
|
||||
const updateUserData = `-- name: UpdateUserData :exec
|
||||
UPDATE users
|
||||
SET email = COALESCE($2, email),
|
||||
full_name = COALESCE($3, full_name),
|
||||
displayname = COALESCE($4, displayname),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE uid = $1
|
||||
`
|
||||
|
||||
type UpdateUserDataParams struct {
|
||||
Uid string
|
||||
Email sql.NullString
|
||||
FullName sql.NullString
|
||||
Displayname sql.NullString
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateUserData(ctx context.Context, arg UpdateUserDataParams) error {
|
||||
_, err := q.db.ExecContext(ctx, updateUserData,
|
||||
arg.Uid,
|
||||
arg.Email,
|
||||
arg.FullName,
|
||||
arg.Displayname,
|
||||
)
|
||||
return err
|
||||
}
|
35
modules/logger/logger.go
Normal file
35
modules/logger/logger.go
Normal file
@ -0,0 +1,35 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
var (
|
||||
Logger zerolog.Logger
|
||||
)
|
||||
|
||||
func init() {
|
||||
Logger = zerolog.New(os.Stderr).With().Timestamp().Logger()
|
||||
}
|
||||
|
||||
func Info() *zerolog.Event {
|
||||
return Logger.Info()
|
||||
}
|
||||
|
||||
func Error() *zerolog.Event {
|
||||
return Logger.Error()
|
||||
}
|
||||
|
||||
func Debug() *zerolog.Event {
|
||||
return Logger.Debug()
|
||||
}
|
||||
|
||||
func Fatal() *zerolog.Event {
|
||||
return Logger.Fatal()
|
||||
}
|
||||
|
||||
func SetLevel(level zerolog.Level) {
|
||||
Logger = Logger.Level(level)
|
||||
}
|
10
sqlc.yaml
Normal file
10
sqlc.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
version: "2"
|
||||
sql:
|
||||
- engine: "postgresql"
|
||||
queries: "modules/db/*.sql"
|
||||
schema: "migrations/*.sql"
|
||||
gen:
|
||||
go:
|
||||
package: "db"
|
||||
out: "modules/db/"
|
||||
sql_package: "database/sql"
|
@ -1,87 +1,3 @@
|
||||
<h2>Welcome to My Go App</h2>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
<p>This is the homepage.</p>
|
||||
{{.T.about}}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="static/css/styles.css" />
|
||||
<link rel="stylesheet" href="/static/css/styles.css" />
|
||||
<link rel="icon" href="/static/assets/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#f28c18" />
|
||||
|
Loading…
Reference in New Issue
Block a user