2024-03-26 18:00:05 -04:00
|
|
|
package database
|
|
|
|
|
2024-03-27 17:02:31 -04:00
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"log"
|
|
|
|
"time"
|
2024-03-25 14:08:35 -04:00
|
|
|
|
2024-04-03 11:57:50 -04:00
|
|
|
"git.hatecomputers.club/hatecomputers/hatecomputers.club/utils"
|
2024-03-27 17:02:31 -04:00
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
ExpiryDuration = time.Hour * 24
|
|
|
|
)
|
|
|
|
|
2024-03-28 12:57:35 -04:00
|
|
|
type UserApiKey struct {
|
|
|
|
Key string `json:"key"`
|
|
|
|
UserID string `json:"user_id"`
|
|
|
|
CreatedAt time.Time `json:"created_at"`
|
|
|
|
}
|
|
|
|
|
2024-03-27 17:02:31 -04:00
|
|
|
type User struct {
|
|
|
|
ID string `json:"sub"`
|
|
|
|
Mail string `json:"email"`
|
|
|
|
Username string `json:"preferred_username"`
|
|
|
|
DisplayName string `json:"name"`
|
2024-04-08 19:04:19 -04:00
|
|
|
Bio string `json:"bio"`
|
|
|
|
Location string `json:"location"`
|
|
|
|
Website string `json:"website"`
|
2024-04-09 18:29:52 -04:00
|
|
|
Pronouns string `json:"pronouns"` // liberals!! :O
|
2024-04-08 19:04:19 -04:00
|
|
|
Avatar string `json:"avatar"`
|
2024-03-27 17:02:31 -04:00
|
|
|
CreatedAt time.Time `json:"created_at"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type UserSession struct {
|
|
|
|
ID string `json:"id"`
|
|
|
|
UserID string `json:"user_id"`
|
|
|
|
ExpireAt time.Time `json:"expire_at"`
|
|
|
|
}
|
|
|
|
|
2024-04-08 19:04:19 -04:00
|
|
|
func ListUsers(dbConn *sql.DB) ([]*User, error) {
|
|
|
|
log.Println("listing users")
|
|
|
|
|
2024-04-09 18:29:52 -04:00
|
|
|
rows, err := dbConn.Query(`SELECT id, mail, username, display_name, bio, location, website, avatar, pronouns, created_at FROM users;`)
|
2024-04-08 19:04:19 -04:00
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer rows.Close()
|
|
|
|
|
|
|
|
var users []*User
|
|
|
|
for rows.Next() {
|
|
|
|
var user User
|
2024-04-09 18:29:52 -04:00
|
|
|
err := rows.Scan(&user.ID, &user.Mail, &user.Username, &user.DisplayName, &user.Bio, &user.Location, &user.Website, &user.Avatar, &user.Pronouns, &user.CreatedAt)
|
2024-04-08 19:04:19 -04:00
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
users = append(users, &user)
|
|
|
|
}
|
|
|
|
|
|
|
|
return users, nil
|
|
|
|
}
|
|
|
|
|
2024-04-09 18:29:52 -04:00
|
|
|
func GetUser(dbConn *sql.DB, id string) (*User, error) {
|
|
|
|
log.Println("getting user", id)
|
|
|
|
|
|
|
|
row := dbConn.QueryRow(`SELECT id, mail, username, display_name, bio, location, website, avatar, pronouns, created_at FROM users WHERE id = ?;`, id)
|
|
|
|
|
|
|
|
var user User
|
|
|
|
err := row.Scan(&user.ID, &user.Mail, &user.Username, &user.DisplayName, &user.Bio, &user.Location, &user.Website, &user.Avatar, &user.Pronouns, &user.CreatedAt)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &user, nil
|
|
|
|
}
|
|
|
|
|
2024-04-08 19:04:19 -04:00
|
|
|
func FindOrSaveBaseUser(dbConn *sql.DB, user *User) (*User, error) {
|
2024-03-29 18:35:04 -04:00
|
|
|
log.Println("finding or saving user", user.ID)
|
|
|
|
|
2024-04-02 16:31:31 -04:00
|
|
|
_, err := dbConn.Exec(`INSERT INTO users (id, mail, username, display_name) VALUES (?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET mail = excluded.mail, username = excluded.username, display_name = excluded.display_name;`, user.ID, user.Mail, user.Username, user.DisplayName)
|
2024-04-02 14:55:22 -04:00
|
|
|
if err != nil {
|
2024-04-08 19:04:19 -04:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return user, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func SaveUser(dbConn *sql.DB, user *User) (*User, error) {
|
|
|
|
log.Println("saving user", user.ID)
|
|
|
|
|
2024-04-09 18:29:52 -04:00
|
|
|
_, err := dbConn.Exec(`INSERT INTO users (id, mail, username, display_name, bio, location, website, pronouns, avatar) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET mail = excluded.mail, username = excluded.username, display_name = excluded.display_name, bio = excluded.bio, location = excluded.location, website = excluded.website, pronouns = excluded.pronouns, avatar = excluded.avatar;`, user.ID, user.Mail, user.Username, user.DisplayName, user.Bio, user.Location, user.Website, user.Pronouns, user.Avatar)
|
2024-04-08 19:04:19 -04:00
|
|
|
if err != nil {
|
2024-04-02 14:55:22 -04:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-03-27 17:02:31 -04:00
|
|
|
return user, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func MakeUserSessionFor(dbConn *sql.DB, user *User) (*UserSession, error) {
|
2024-03-29 18:35:04 -04:00
|
|
|
log.Println("making session for user", user.ID)
|
|
|
|
|
2024-03-27 17:02:31 -04:00
|
|
|
expireAt := time.Now().Add(time.Hour * 12)
|
2024-04-03 11:57:50 -04:00
|
|
|
sessionId := utils.RandomId()
|
2024-03-27 17:02:31 -04:00
|
|
|
|
2024-04-03 11:57:50 -04:00
|
|
|
_, err := dbConn.Exec(`INSERT OR REPLACE INTO user_sessions (id, user_id, expire_at) VALUES (?, ?, ?);`, sessionId, user.ID, time.Now().Add(ExpiryDuration))
|
2024-03-27 17:02:31 -04:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &UserSession{
|
2024-04-03 11:57:50 -04:00
|
|
|
ID: sessionId,
|
2024-03-27 17:02:31 -04:00
|
|
|
UserID: user.ID,
|
|
|
|
ExpireAt: expireAt,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetSession(dbConn *sql.DB, sessionId string) (*UserSession, error) {
|
2024-03-29 18:35:04 -04:00
|
|
|
log.Println("getting session", sessionId)
|
|
|
|
|
2024-03-27 17:02:31 -04:00
|
|
|
row := dbConn.QueryRow(`SELECT id, user_id, expire_at FROM user_sessions WHERE id = ?;`, sessionId)
|
|
|
|
|
|
|
|
var id, userId string
|
|
|
|
var expireAt time.Time
|
|
|
|
err := row.Scan(&id, &userId, &expireAt)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &UserSession{
|
|
|
|
ID: id,
|
|
|
|
UserID: userId,
|
|
|
|
ExpireAt: expireAt,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DeleteSession(dbConn *sql.DB, sessionId string) error {
|
2024-03-29 18:35:04 -04:00
|
|
|
log.Println("deleting session", sessionId)
|
|
|
|
|
2024-03-27 17:02:31 -04:00
|
|
|
_, err := dbConn.Exec(`DELETE FROM user_sessions WHERE id = ?;`, sessionId)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-04-06 15:36:13 -04:00
|
|
|
func SaveSession(dbConn *sql.DB, session *UserSession) (*UserSession, error) {
|
|
|
|
log.Println("saving session", session.ID)
|
|
|
|
|
|
|
|
_, err := dbConn.Exec(`INSERT OR REPLACE INTO user_sessions (id, user_id, expire_at) VALUES (?, ?, ?);`, session.ID, session.UserID, session.ExpireAt)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return session, nil
|
|
|
|
}
|
|
|
|
|
2024-03-27 17:02:31 -04:00
|
|
|
func RefreshSession(dbConn *sql.DB, sessionId string) (*UserSession, error) {
|
|
|
|
newExpireAt := time.Now().Add(ExpiryDuration)
|
|
|
|
|
|
|
|
_, err := dbConn.Exec(`UPDATE user_sessions SET expire_at = ? WHERE id = ?;`, newExpireAt, sessionId)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
session, err := GetSession(dbConn, sessionId)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return session, nil
|
2024-03-25 14:08:35 -04:00
|
|
|
}
|
2024-03-27 17:10:39 -04:00
|
|
|
|
|
|
|
func DeleteExpiredSessions(dbConn *sql.DB) error {
|
|
|
|
_, err := dbConn.Exec(`DELETE FROM user_sessions WHERE expire_at < ?;`, time.Now())
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2024-03-28 12:57:35 -04:00
|
|
|
|
2024-03-29 18:35:04 -04:00
|
|
|
func CountUserAPIKeys(dbConn *sql.DB, userId string) (int, error) {
|
|
|
|
log.Println("counting api keys for user", userId)
|
|
|
|
|
|
|
|
row := dbConn.QueryRow(`SELECT COUNT(*) FROM api_keys WHERE user_id = ?;`, userId)
|
|
|
|
|
|
|
|
var count int
|
|
|
|
err := row.Scan(&count)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return count, nil
|
|
|
|
}
|
|
|
|
|
2024-03-28 12:57:35 -04:00
|
|
|
func ListUserAPIKeys(dbConn *sql.DB, userId string) ([]*UserApiKey, error) {
|
2024-03-29 18:35:04 -04:00
|
|
|
log.Println("listing api keys for user", userId)
|
|
|
|
|
2024-03-28 12:57:35 -04:00
|
|
|
rows, err := dbConn.Query(`SELECT key, user_id, created_at FROM api_keys WHERE user_id = ?;`, userId)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer rows.Close()
|
|
|
|
|
|
|
|
var apiKeys []*UserApiKey
|
|
|
|
for rows.Next() {
|
|
|
|
var apiKey UserApiKey
|
|
|
|
err := rows.Scan(&apiKey.Key, &apiKey.UserID, &apiKey.CreatedAt)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
apiKeys = append(apiKeys, &apiKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
return apiKeys, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func SaveAPIKey(dbConn *sql.DB, apiKey *UserApiKey) (*UserApiKey, error) {
|
2024-03-29 18:35:04 -04:00
|
|
|
log.Println("saving api key", apiKey.Key)
|
|
|
|
|
2024-03-28 12:57:35 -04:00
|
|
|
_, err := dbConn.Exec(`INSERT OR REPLACE INTO api_keys (key, user_id) VALUES (?, ?);`, apiKey.Key, apiKey.UserID)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
apiKey.CreatedAt = time.Now()
|
|
|
|
return apiKey, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetAPIKey(dbConn *sql.DB, key string) (*UserApiKey, error) {
|
2024-03-29 18:35:04 -04:00
|
|
|
log.Println("getting api key", key)
|
|
|
|
|
2024-03-28 12:57:35 -04:00
|
|
|
row := dbConn.QueryRow(`SELECT key, user_id, created_at FROM api_keys WHERE key = ?;`, key)
|
|
|
|
|
|
|
|
var apiKey UserApiKey
|
|
|
|
err := row.Scan(&apiKey.Key, &apiKey.UserID, &apiKey.CreatedAt)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &apiKey, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DeleteAPIKey(dbConn *sql.DB, key string) error {
|
2024-03-29 18:35:04 -04:00
|
|
|
log.Println("deleting api key", key)
|
|
|
|
|
2024-03-28 12:57:35 -04:00
|
|
|
_, err := dbConn.Exec(`DELETE FROM api_keys WHERE key = ?;`, key)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|