This commit is contained in:
parent
a04246cddc
commit
3732fb2fa4
@ -9,6 +9,7 @@ import (
|
|||||||
"git.tijl.dev/tijl/tijl.dev/internal/db"
|
"git.tijl.dev/tijl/tijl.dev/internal/db"
|
||||||
"git.tijl.dev/tijl/tijl.dev/internal/i18n"
|
"git.tijl.dev/tijl/tijl.dev/internal/i18n"
|
||||||
"git.tijl.dev/tijl/tijl.dev/internal/oidc"
|
"git.tijl.dev/tijl/tijl.dev/internal/oidc"
|
||||||
|
"git.tijl.dev/tijl/tijl.dev/internal/sessions"
|
||||||
"git.tijl.dev/tijl/tijl.dev/modules/logger"
|
"git.tijl.dev/tijl/tijl.dev/modules/logger"
|
||||||
"git.tijl.dev/tijl/tijl.dev/static"
|
"git.tijl.dev/tijl/tijl.dev/static"
|
||||||
"git.tijl.dev/tijl/tijl.dev/views"
|
"git.tijl.dev/tijl/tijl.dev/views"
|
||||||
@ -110,7 +111,13 @@ func main() {
|
|||||||
|
|
||||||
// Common functions for in templating
|
// Common functions for in templating
|
||||||
func getCommon(c *fiber.Ctx) fiber.Map {
|
func getCommon(c *fiber.Ctx) fiber.Map {
|
||||||
|
_, err := sessions.GetSession(c)
|
||||||
|
signedIn := false
|
||||||
|
if err == nil {
|
||||||
|
signedIn = true
|
||||||
|
}
|
||||||
return fiber.Map{
|
return fiber.Map{
|
||||||
|
"SignedIn": signedIn,
|
||||||
"Path": c.Path(),
|
"Path": c.Path(),
|
||||||
"Language": i18n.GetLanguage(c),
|
"Language": i18n.GetLanguage(c),
|
||||||
"T": i18n.GetTranslations(i18n.GetLanguage(c)),
|
"T": i18n.GetTranslations(i18n.GetLanguage(c)),
|
||||||
|
@ -23,7 +23,7 @@ func Load() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err).Msg("failed to connect to database")
|
log.Fatal().Err(err).Msg("failed to connect to database")
|
||||||
}
|
}
|
||||||
defer DB.Close()
|
//defer DB.Close()
|
||||||
Queries = dbmanager.New(DB)
|
Queries = dbmanager.New(DB)
|
||||||
log.Debug().Msg("connected to database")
|
log.Debug().Msg("connected to database")
|
||||||
|
|
||||||
|
1
internal/middleware/session.go
Normal file
1
internal/middleware/session.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package middleware
|
@ -2,20 +2,20 @@ package oidc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"git.tijl.dev/tijl/tijl.dev/internal/db"
|
||||||
|
"git.tijl.dev/tijl/tijl.dev/internal/sessions"
|
||||||
"git.tijl.dev/tijl/tijl.dev/internal/utils"
|
"git.tijl.dev/tijl/tijl.dev/internal/utils"
|
||||||
|
"git.tijl.dev/tijl/tijl.dev/modules/database"
|
||||||
log "git.tijl.dev/tijl/tijl.dev/modules/logger"
|
log "git.tijl.dev/tijl/tijl.dev/modules/logger"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"golang.org/x/oauth2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func HandleRedirect(c *fiber.Ctx) error {
|
func HandleRedirect(c *fiber.Ctx) error {
|
||||||
state, err := utils.RandString(16)
|
state := utils.RandString(16)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
setCallbackCookie(c, "state", state)
|
setCallbackCookie(c, "state", state)
|
||||||
return c.Redirect(Config.AuthCodeURL(state), http.StatusFound)
|
return c.Redirect(Config.AuthCodeURL(state), http.StatusFound)
|
||||||
}
|
}
|
||||||
@ -40,14 +40,43 @@ func HandleCallback(c *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
userInfo, err := Provider.UserInfo(ctx, oauth2.StaticTokenSource(oauth2Token))
|
var claims struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
EmailVerified bool `json:"email_verified"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Username string `json:"preferred_username"`
|
||||||
|
}
|
||||||
|
if err := idToken.Claims(&claims); err != nil {
|
||||||
|
log.Error().Err(err).Msg("error getting claims")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.Queries.GetUser(ctx, idToken.Subject)
|
||||||
|
if err == nil {
|
||||||
|
db.Queries.UpdateUserData(ctx, database.UpdateUserDataParams{
|
||||||
|
Uid: idToken.Subject,
|
||||||
|
Email: claims.Email,
|
||||||
|
EmailVerified: claims.EmailVerified,
|
||||||
|
Username: claims.Username,
|
||||||
|
FullName: claims.Name,
|
||||||
|
})
|
||||||
|
} else if err == sql.ErrNoRows {
|
||||||
|
db.Queries.CreateUser(ctx, database.CreateUserParams{
|
||||||
|
Uid: idToken.Subject,
|
||||||
|
Email: claims.Email,
|
||||||
|
EmailVerified: claims.EmailVerified,
|
||||||
|
Username: claims.Username,
|
||||||
|
FullName: claims.Name,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
log.Error().Err(err).Msg("error getting user")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = sessions.NewSession(idToken.Subject, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Interface("userInfo", userInfo).Interface("idToken", idToken).Msg("data")
|
|
||||||
|
|
||||||
// now we can create a user account and session in the db
|
|
||||||
|
|
||||||
return c.Redirect("/")
|
return c.Redirect("/")
|
||||||
}
|
}
|
||||||
|
53
internal/sessions/sessions.go
Normal file
53
internal/sessions/sessions.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package sessions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.tijl.dev/tijl/tijl.dev/internal/db"
|
||||||
|
"git.tijl.dev/tijl/tijl.dev/internal/utils"
|
||||||
|
"git.tijl.dev/tijl/tijl.dev/modules/database"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewSession(uid string, c *fiber.Ctx) (string, error) {
|
||||||
|
createSessionParams := database.CreateSessionParams{
|
||||||
|
Uid: uid,
|
||||||
|
Token: utils.RandString(64),
|
||||||
|
}
|
||||||
|
err := db.Queries.CreateSession(context.TODO(), createSessionParams)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
c.Cookie(&fiber.Cookie{
|
||||||
|
Name: "session",
|
||||||
|
Value: createSessionParams.Token,
|
||||||
|
Secure: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
err = db.Queries.QuickUpdateSession(context.TODO(), database.QuickUpdateSessionParams{
|
||||||
|
Token: createSessionParams.Token,
|
||||||
|
IpAddress: c.IP(),
|
||||||
|
Agent: string(c.Context().UserAgent()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return createSessionParams.Token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSession(c *fiber.Ctx) (database.Session, error) {
|
||||||
|
err := db.Queries.QuickUpdateSession(context.TODO(), database.QuickUpdateSessionParams{
|
||||||
|
Token: c.Cookies("session"),
|
||||||
|
IpAddress: c.IP(),
|
||||||
|
Agent: string(c.Context().UserAgent()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return database.Session{}, err
|
||||||
|
}
|
||||||
|
session, err := db.Queries.GetSession(context.TODO(), c.Cookies("session"))
|
||||||
|
if err != nil {
|
||||||
|
return session, err
|
||||||
|
}
|
||||||
|
return session, nil
|
||||||
|
}
|
@ -4,12 +4,14 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
log "git.tijl.dev/tijl/tijl.dev/modules/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RandString(nByte int) (string, error) {
|
func RandString(nByte int) string {
|
||||||
b := make([]byte, nByte)
|
b := make([]byte, nByte)
|
||||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
||||||
return "", err
|
log.Fatal().Err(err)
|
||||||
}
|
}
|
||||||
return base64.RawURLEncoding.EncodeToString(b), nil
|
return base64.RawURLEncoding.EncodeToString(b)
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,31 @@
|
|||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
uid VARCHAR UNIQUE NOT NULL, -- username as unique identifier
|
uid VARCHAR UNIQUE NOT NULL, -- username as unique identifier
|
||||||
email VARCHAR UNIQUE,
|
email VARCHAR NOT NULL,
|
||||||
full_name VARCHAR,
|
email_verified BOOLEAN NOT NULL,
|
||||||
displayname VARCHAR,
|
full_name VARCHAR NOT NULL,
|
||||||
|
username VARCHAR NOT NULL,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE sessions (
|
CREATE TABLE sessions (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
user_id INTEGER NOT NULL,
|
uid VARCHAR NOT NULL,
|
||||||
title VARCHAR,
|
token VARCHAR NOT NULL UNIQUE NOT NULL,
|
||||||
token VARCHAR NOT NULL UNIQUE,
|
|
||||||
password VARCHAR,
|
|
||||||
last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
expires TIMESTAMP,
|
expires TIMESTAMP,
|
||||||
|
last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||||
FOREIGN KEY (user_id) REFERENCES users (id)
|
FOREIGN KEY (uid) REFERENCES users (uid)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE session_ips (
|
CREATE TABLE session_ips (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
session_id INTEGER NOT NULL,
|
session_id INTEGER NOT NULL,
|
||||||
ip_address INET NOT NULL,
|
ip_address VARCHAR NOT NULL,
|
||||||
access_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
agent VARCHAR NOT NULL,
|
||||||
FOREIGN KEY (session_id) REFERENCES sessions (id)
|
access_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||||
|
FOREIGN KEY (session_id) REFERENCES sessions (id),
|
||||||
|
CONSTRAINT session_ips_unique UNIQUE (session_id, ip_address)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -7,34 +7,32 @@ package database
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sqlc-dev/pqtype"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
ID int32
|
ID int32
|
||||||
UserID int32
|
Uid string
|
||||||
Title sql.NullString
|
|
||||||
Token string
|
Token string
|
||||||
Password sql.NullString
|
|
||||||
LastActivity sql.NullTime
|
|
||||||
Expires sql.NullTime
|
Expires sql.NullTime
|
||||||
|
LastActivity time.Time
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type SessionIp struct {
|
type SessionIp struct {
|
||||||
ID int32
|
ID int32
|
||||||
SessionID int32
|
SessionID int32
|
||||||
IpAddress pqtype.Inet
|
IpAddress string
|
||||||
AccessTime sql.NullTime
|
Agent string
|
||||||
|
AccessTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ID int32
|
ID int32
|
||||||
Uid string
|
Uid string
|
||||||
Email sql.NullString
|
Email string
|
||||||
FullName sql.NullString
|
EmailVerified bool
|
||||||
Displayname sql.NullString
|
FullName string
|
||||||
|
Username string
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt sql.NullTime
|
UpdatedAt time.Time
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,34 @@
|
|||||||
-- name: GetSesssion :one
|
-- name: GetSession :one
|
||||||
SELECT * FROM sessions WHERE token = $1;
|
SELECT * FROM sessions WHERE token = $1;
|
||||||
|
|
||||||
-- name: GetSessions :many
|
-- name: GetSessions :many
|
||||||
SELECT * FROM sessions WHERE user_id = $1 ORDER BY $2;
|
SELECT * FROM sessions WHERE uid = $1 ORDER BY $2;
|
||||||
|
|
||||||
-- name: GetActiveSessions :many
|
-- name: GetActiveSessions :many
|
||||||
SELECT * FROM sessions WHERE user_id = $1 AND (expires > CURRENT_TIMESTAMP OR expires IS NULL) ORDER BY $2;
|
SELECT * FROM sessions WHERE uid = $1 AND (expires > CURRENT_TIMESTAMP OR expires IS NULL) ORDER BY $2;
|
||||||
|
|
||||||
-- name: CreateSession :exec
|
-- name: CreateSession :exec
|
||||||
INSERT INTO sessions (user_id, title, token) VALUES ($1, $2, $3);
|
INSERT INTO sessions (uid, token, last_activity) VALUES ($1, $2, CURRENT_TIMESTAMP);
|
||||||
|
|
||||||
-- name: QuickUpdateSession :exec
|
-- name: QuickUpdateSession :exec
|
||||||
UPDATE sessions SET last_activity = GETDATE() WHERE id = $1;
|
WITH updated_session AS (
|
||||||
|
UPDATE sessions
|
||||||
|
SET last_activity = CURRENT_TIMESTAMP
|
||||||
|
WHERE token = $1
|
||||||
|
RETURNING id
|
||||||
|
)
|
||||||
|
INSERT INTO session_ips (session_id, ip_address, agent, access_time)
|
||||||
|
VALUES (
|
||||||
|
(SELECT id FROM updated_session),
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
)
|
||||||
|
ON CONFLICT (session_id, ip_address)
|
||||||
|
DO UPDATE SET
|
||||||
|
agent = EXCLUDED.agent,
|
||||||
|
access_time = CURRENT_TIMESTAMP;
|
||||||
|
|
||||||
-- name: ExpireSession :exec
|
-- name: ExpireSession :exec
|
||||||
UPDATE sessions SET expires = 1 WHERE id = $1;
|
UPDATE sessions SET expires = 1 WHERE token = $1;
|
||||||
|
|
||||||
|
@ -7,44 +7,42 @@ package database
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const createSession = `-- name: CreateSession :exec
|
const createSession = `-- name: CreateSession :exec
|
||||||
INSERT INTO sessions (user_id, title, token) VALUES ($1, $2, $3)
|
INSERT INTO sessions (uid, token, last_activity) VALUES ($1, $2, CURRENT_TIMESTAMP)
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateSessionParams struct {
|
type CreateSessionParams struct {
|
||||||
UserID int32
|
Uid string
|
||||||
Title sql.NullString
|
|
||||||
Token string
|
Token string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) error {
|
func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) error {
|
||||||
_, err := q.db.ExecContext(ctx, createSession, arg.UserID, arg.Title, arg.Token)
|
_, err := q.db.ExecContext(ctx, createSession, arg.Uid, arg.Token)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const expireSession = `-- name: ExpireSession :exec
|
const expireSession = `-- name: ExpireSession :exec
|
||||||
UPDATE sessions SET expires = 1 WHERE id = $1
|
UPDATE sessions SET expires = 1 WHERE token = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ExpireSession(ctx context.Context, id int32) error {
|
func (q *Queries) ExpireSession(ctx context.Context, token string) error {
|
||||||
_, err := q.db.ExecContext(ctx, expireSession, id)
|
_, err := q.db.ExecContext(ctx, expireSession, token)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const getActiveSessions = `-- name: GetActiveSessions :many
|
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
|
SELECT id, uid, token, expires, last_activity, created_at FROM sessions WHERE uid = $1 AND (expires > CURRENT_TIMESTAMP OR expires IS NULL) ORDER BY $2
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetActiveSessionsParams struct {
|
type GetActiveSessionsParams struct {
|
||||||
UserID int32
|
Uid string
|
||||||
Column2 interface{}
|
Column2 interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetActiveSessions(ctx context.Context, arg GetActiveSessionsParams) ([]Session, error) {
|
func (q *Queries) GetActiveSessions(ctx context.Context, arg GetActiveSessionsParams) ([]Session, error) {
|
||||||
rows, err := q.db.QueryContext(ctx, getActiveSessions, arg.UserID, arg.Column2)
|
rows, err := q.db.QueryContext(ctx, getActiveSessions, arg.Uid, arg.Column2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -54,12 +52,10 @@ func (q *Queries) GetActiveSessions(ctx context.Context, arg GetActiveSessionsPa
|
|||||||
var i Session
|
var i Session
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.UserID,
|
&i.Uid,
|
||||||
&i.Title,
|
|
||||||
&i.Token,
|
&i.Token,
|
||||||
&i.Password,
|
|
||||||
&i.LastActivity,
|
|
||||||
&i.Expires,
|
&i.Expires,
|
||||||
|
&i.LastActivity,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -75,72 +71,90 @@ func (q *Queries) GetActiveSessions(ctx context.Context, arg GetActiveSessionsPa
|
|||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSessions = `-- name: GetSessions :many
|
const getSession = `-- name: GetSession :one
|
||||||
SELECT id, user_id, title, token, password, last_activity, expires, created_at FROM sessions WHERE user_id = $1 ORDER BY $2
|
SELECT id, uid, token, expires, last_activity, created_at FROM sessions WHERE token = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetSessionsParams struct {
|
func (q *Queries) GetSession(ctx context.Context, token string) (Session, error) {
|
||||||
UserID int32
|
row := q.db.QueryRowContext(ctx, getSession, token)
|
||||||
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
|
var i Session
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.UserID,
|
&i.Uid,
|
||||||
&i.Title,
|
|
||||||
&i.Token,
|
&i.Token,
|
||||||
&i.Password,
|
|
||||||
&i.LastActivity,
|
|
||||||
&i.Expires,
|
&i.Expires,
|
||||||
|
&i.LastActivity,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const quickUpdateSession = `-- name: QuickUpdateSession :exec
|
const getSessions = `-- name: GetSessions :many
|
||||||
UPDATE sessions SET last_activity = GETDATE() WHERE id = $1
|
SELECT id, uid, token, expires, last_activity, created_at FROM sessions WHERE uid = $1 ORDER BY $2
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) QuickUpdateSession(ctx context.Context, id int32) error {
|
type GetSessionsParams struct {
|
||||||
_, err := q.db.ExecContext(ctx, quickUpdateSession, id)
|
Uid string
|
||||||
|
Column2 interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetSessions(ctx context.Context, arg GetSessionsParams) ([]Session, error) {
|
||||||
|
rows, err := q.db.QueryContext(ctx, getSessions, arg.Uid, 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.Uid,
|
||||||
|
&i.Token,
|
||||||
|
&i.Expires,
|
||||||
|
&i.LastActivity,
|
||||||
|
&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 quickUpdateSession = `-- name: QuickUpdateSession :exec
|
||||||
|
WITH updated_session AS (
|
||||||
|
UPDATE sessions
|
||||||
|
SET last_activity = CURRENT_TIMESTAMP
|
||||||
|
WHERE token = $1
|
||||||
|
RETURNING id
|
||||||
|
)
|
||||||
|
INSERT INTO session_ips (session_id, ip_address, agent, access_time)
|
||||||
|
VALUES (
|
||||||
|
(SELECT id FROM updated_session),
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
)
|
||||||
|
ON CONFLICT (session_id, ip_address)
|
||||||
|
DO UPDATE SET
|
||||||
|
agent = EXCLUDED.agent,
|
||||||
|
access_time = CURRENT_TIMESTAMP
|
||||||
|
`
|
||||||
|
|
||||||
|
type QuickUpdateSessionParams struct {
|
||||||
|
Token string
|
||||||
|
IpAddress string
|
||||||
|
Agent string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) QuickUpdateSession(ctx context.Context, arg QuickUpdateSessionParams) error {
|
||||||
|
_, err := q.db.ExecContext(ctx, quickUpdateSession, arg.Token, arg.IpAddress, arg.Agent)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -11,15 +11,16 @@ SELECT * FROM users WHERE id = $1 LIMIT 1;
|
|||||||
DELETE FROM users WHERE uid = $1;
|
DELETE FROM users WHERE uid = $1;
|
||||||
|
|
||||||
-- name: CreateUser :exec
|
-- name: CreateUser :exec
|
||||||
INSERT INTO users (uid, email, full_name, displayname)
|
INSERT INTO users (uid, email, email_verified, full_name, username)
|
||||||
VALUES ($1, $2, $3, $4)
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
RETURNING id;
|
RETURNING id;
|
||||||
|
|
||||||
-- name: UpdateUserData :exec
|
-- name: UpdateUserData :exec
|
||||||
UPDATE users
|
UPDATE users
|
||||||
SET email = COALESCE($2, email),
|
SET email = COALESCE($2, email),
|
||||||
full_name = COALESCE($3, full_name),
|
email_verified = COALESCE($3, email_verified),
|
||||||
displayname = COALESCE($4, displayname),
|
full_name = COALESCE($4, full_name),
|
||||||
|
username = COALESCE($5, username),
|
||||||
updated_at = CURRENT_TIMESTAMP
|
updated_at = CURRENT_TIMESTAMP
|
||||||
WHERE uid = $1;
|
WHERE uid = $1;
|
||||||
|
|
||||||
|
@ -7,28 +7,29 @@ package database
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const createUser = `-- name: CreateUser :exec
|
const createUser = `-- name: CreateUser :exec
|
||||||
INSERT INTO users (uid, email, full_name, displayname)
|
INSERT INTO users (uid, email, email_verified, full_name, username)
|
||||||
VALUES ($1, $2, $3, $4)
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
RETURNING id
|
RETURNING id
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateUserParams struct {
|
type CreateUserParams struct {
|
||||||
Uid string
|
Uid string
|
||||||
Email sql.NullString
|
Email string
|
||||||
FullName sql.NullString
|
EmailVerified bool
|
||||||
Displayname sql.NullString
|
FullName string
|
||||||
|
Username string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) error {
|
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) error {
|
||||||
_, err := q.db.ExecContext(ctx, createUser,
|
_, err := q.db.ExecContext(ctx, createUser,
|
||||||
arg.Uid,
|
arg.Uid,
|
||||||
arg.Email,
|
arg.Email,
|
||||||
|
arg.EmailVerified,
|
||||||
arg.FullName,
|
arg.FullName,
|
||||||
arg.Displayname,
|
arg.Username,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -43,7 +44,7 @@ func (q *Queries) DeleteUser(ctx context.Context, uid string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getUser = `-- name: GetUser :one
|
const getUser = `-- name: GetUser :one
|
||||||
SELECT id, uid, email, full_name, displayname, created_at, updated_at FROM users WHERE uid = $1 LIMIT 1
|
SELECT id, uid, email, email_verified, full_name, username, created_at, updated_at FROM users WHERE uid = $1 LIMIT 1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetUser(ctx context.Context, uid string) (User, error) {
|
func (q *Queries) GetUser(ctx context.Context, uid string) (User, error) {
|
||||||
@ -53,8 +54,9 @@ func (q *Queries) GetUser(ctx context.Context, uid string) (User, error) {
|
|||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Uid,
|
&i.Uid,
|
||||||
&i.Email,
|
&i.Email,
|
||||||
|
&i.EmailVerified,
|
||||||
&i.FullName,
|
&i.FullName,
|
||||||
&i.Displayname,
|
&i.Username,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
)
|
)
|
||||||
@ -62,7 +64,7 @@ func (q *Queries) GetUser(ctx context.Context, uid string) (User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getUserById = `-- name: GetUserById :one
|
const getUserById = `-- name: GetUserById :one
|
||||||
SELECT id, uid, email, full_name, displayname, created_at, updated_at FROM users WHERE id = $1 LIMIT 1
|
SELECT id, uid, email, email_verified, full_name, username, created_at, updated_at FROM users WHERE id = $1 LIMIT 1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetUserById(ctx context.Context, id int32) (User, error) {
|
func (q *Queries) GetUserById(ctx context.Context, id int32) (User, error) {
|
||||||
@ -72,8 +74,9 @@ func (q *Queries) GetUserById(ctx context.Context, id int32) (User, error) {
|
|||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Uid,
|
&i.Uid,
|
||||||
&i.Email,
|
&i.Email,
|
||||||
|
&i.EmailVerified,
|
||||||
&i.FullName,
|
&i.FullName,
|
||||||
&i.Displayname,
|
&i.Username,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
)
|
)
|
||||||
@ -94,25 +97,28 @@ func (q *Queries) GetUserUid(ctx context.Context, id int32) (string, error) {
|
|||||||
const updateUserData = `-- name: UpdateUserData :exec
|
const updateUserData = `-- name: UpdateUserData :exec
|
||||||
UPDATE users
|
UPDATE users
|
||||||
SET email = COALESCE($2, email),
|
SET email = COALESCE($2, email),
|
||||||
full_name = COALESCE($3, full_name),
|
email_verified = COALESCE($3, email_verified),
|
||||||
displayname = COALESCE($4, displayname),
|
full_name = COALESCE($4, full_name),
|
||||||
|
username = COALESCE($5, username),
|
||||||
updated_at = CURRENT_TIMESTAMP
|
updated_at = CURRENT_TIMESTAMP
|
||||||
WHERE uid = $1
|
WHERE uid = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateUserDataParams struct {
|
type UpdateUserDataParams struct {
|
||||||
Uid string
|
Uid string
|
||||||
Email sql.NullString
|
Email string
|
||||||
FullName sql.NullString
|
EmailVerified bool
|
||||||
Displayname sql.NullString
|
FullName string
|
||||||
|
Username string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateUserData(ctx context.Context, arg UpdateUserDataParams) error {
|
func (q *Queries) UpdateUserData(ctx context.Context, arg UpdateUserDataParams) error {
|
||||||
_, err := q.db.ExecContext(ctx, updateUserData,
|
_, err := q.db.ExecContext(ctx, updateUserData,
|
||||||
arg.Uid,
|
arg.Uid,
|
||||||
arg.Email,
|
arg.Email,
|
||||||
|
arg.EmailVerified,
|
||||||
arg.FullName,
|
arg.FullName,
|
||||||
arg.Displayname,
|
arg.Username,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
<h2>Welcome to My Go App</h2>
|
<h2>Welcome to My Go App</h2>
|
||||||
<p>This is the homepage.</p>
|
<p>This is the homepage.</p>
|
||||||
{{.T.about}}
|
<div>Signed In: {{.SignedIn}}</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user