database + auth
Some checks failed
build / build (push) Failing after 0s

This commit is contained in:
Tijl 2024-08-21 17:31:03 +02:00
parent a04246cddc
commit 3732fb2fa4
Signed by: tijl
GPG Key ID: DAE24BFCD722F053
14 changed files with 269 additions and 141 deletions

View File

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

View File

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

View File

@ -0,0 +1 @@
package middleware

View File

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

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

View File

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

View File

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

View File

@ -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
CreatedAt time.Time Username string
UpdatedAt sql.NullTime CreatedAt time.Time
UpdatedAt time.Time
} }

View File

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

View File

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

View File

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

View File

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

View File

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