canape/backend/tokens/tokens.go

100 lines
2.4 KiB
Go

package tokens
import (
"database/sql"
"errors"
"fmt"
"time"
"github.com/jmoiron/sqlx"
"git.quimbo.fr/odwrtw/canape/backend/sqly"
)
const (
addTokenQuery = `INSERT INTO tokens (token, username, ip, description) VALUES ($1, $2, $3, $4);`
getTokenQuery = `SELECT * FROM tokens WHERE token=$1;`
getUserTokenQuery = `SELECT * FROM tokens WHERE username=$1 and token=$2;`
getUserTokensQuery = `SELECT * FROM tokens WHERE username=$1;`
deleteTokenQuery = `DELETE FROM tokens WHERE username=$1 AND token=$2;`
updateTokenQuery = `UPDATE tokens SET description=:description, user_agent=:user_agent, ip=:ip, last_used=now() WHERE token=:token RETURNING *;`
)
// Custom errors
var (
ErrTokenNotFound = errors.New("tokens: token not found")
)
// Token represents a token
type Token struct {
sqly.BaseModel
Username string `db:"username" json:"username"`
Token string `db:"token" json:"token"`
Description string `db:"description" json:"description"`
UserAgent string `db:"user_agent" json:"user_agent"`
IP string `db:"ip" json:"ip"`
LastUsed time.Time `db:"last_used" json:"last_used"`
}
// Add a token to the database
func (t *Token) Add(db *sqlx.DB) error {
_, err := db.Queryx(addTokenQuery, t.Token, t.Username, t.IP, t.Description)
if err != nil {
return err
}
return nil
}
// GetUserToken returns the token linked to a user
func GetUserToken(db *sqlx.DB, username, token string) (*Token, error) {
t := &Token{}
err := db.QueryRowx(getUserTokenQuery, username, token).StructScan(t)
if err != nil {
if err == sql.ErrNoRows {
return nil, ErrTokenNotFound
}
return nil, err
}
return t, nil
}
// DeleteToken deletes a token
func DeleteToken(db *sqlx.DB, username, token string) error {
r, err := db.Exec(deleteTokenQuery, username, token)
if err != nil {
return err
}
count, err := r.RowsAffected()
if err != nil {
return err
}
if count != 1 {
return fmt.Errorf("Unexpected number of row deleted: %d", count)
}
return nil
}
// GetUserTokens returns all tokens owned by the user
func GetUserTokens(db *sqlx.DB, username string) ([]*Token, error) {
tokens := []*Token{}
err := db.Select(&tokens, getUserTokensQuery, username)
if err != nil {
return nil, err
}
return tokens, nil
}
// Update updates a token
func (t *Token) Update(db *sqlx.DB) error {
rows, err := db.NamedQuery(updateTokenQuery, t)
if err != nil {
return err
}
for rows.Next() {
rows.StructScan(t)
}
return nil
}