canape/users/users.go

152 lines
3.4 KiB
Go

package users
import (
"fmt"
"github.com/jmoiron/sqlx"
"gitlab.quimbo.fr/odwrtw/canape-sql/random"
"gitlab.quimbo.fr/odwrtw/canape-sql/sqly"
)
const (
addUserQuery = `INSERT INTO users (name, hash, admin) VALUES ($1, $2, $3) RETURNING id;`
getUserQuery = `SELECT * FROM users WHERE name=$1;`
updateUserQuery = `UPDATE users SET name=:name, hash=:hash, admin=:admin RETURNING *;`
deleteUseQuery = `DELETE FROM users WHERE id=:id;`
addTokenQuery = `INSERT INTO tokens (value, user_id) VALUES ($1, $2) RETURNING id;`
getTokensQuery = `SELECT id, value FROM tokens WHERE user_id=$1;`
checkTokenQuery = `SELECT count(*) FROM tokens WHERE user_id=$1 AND value=$2;`
deleteTokenQuery = `DELETE FROM tokens WHERE user_id=$1 AND value=$2;`
)
const (
UserRole = "user"
AdminRole = "admin"
)
// ErrUnknownUser returned web a user does'nt exist
var ErrUnknownUser = fmt.Errorf("users: user does'nt exist")
// User represents an user
type User struct {
sqly.BaseModel
Name string
Hash string
Admin bool
}
// Token represents a token
type Token struct {
sqly.BaseModel
Value string
}
// Get returns user with specified name
func Get(q sqlx.Queryer, name string) (*User, error) {
u := &User{}
err := q.QueryRowx(getUserQuery, name).StructScan(u)
if err != nil {
if err.Error() == "sql: no rows in result set" {
return nil, ErrUnknownUser
}
return nil, err
}
return u, nil
}
// Add user to database or raises an error
func (u *User) Add(q sqlx.Queryer) error {
var id string
err := q.QueryRowx(addUserQuery, u.Name, u.Hash, u.Admin).Scan(&id)
if err != nil {
return err
}
u.ID = id
return nil
}
// Update user on database or raise an error
func (u *User) Update(ex *sqlx.DB) error {
rows, err := ex.NamedQuery(updateUserQuery, u)
if err != nil {
return err
}
for rows.Next() {
rows.StructScan(u)
}
return nil
}
// Delete user from database or raise an error
func (u *User) Delete(ex *sqlx.DB) error {
_, err := ex.NamedExec(deleteUseQuery, u)
if err != nil {
return err
}
return nil
}
// GetTokens returns all tokens owned by the user
func (u *User) GetTokens(ex *sqlx.DB) ([]*Token, error) {
tokens := []*Token{}
err := ex.Select(&tokens, getTokensQuery, u.ID)
if err != nil {
return nil, err
}
return tokens, nil
}
// NewToken generates a new token for the user
func (u *User) NewToken(ex *sqlx.DB) (*Token, error) {
t := &Token{
Value: random.String(50),
}
var id string
err := ex.QueryRowx(addTokenQuery, t.Value, u.ID).Scan(&id)
if err != nil {
return nil, err
}
t.ID = id
return t, nil
}
// CheckToken checks if specified value exists in token's values for the user
func (u *User) CheckToken(ex *sqlx.DB, value string) (bool, error) {
var count int
err := ex.QueryRowx(checkTokenQuery, u.ID, value).Scan(&count)
if err != nil {
return false, err
}
if count != 1 {
return false, nil
}
return true, nil
}
// DeleteToken delete token by value
func (u *User) DeleteToken(ex *sqlx.DB, value string) error {
r, err := ex.Exec(deleteTokenQuery, u.ID, value)
if err != nil {
return err
}
count, _ := r.RowsAffected()
if count != 1 {
return fmt.Errorf("Unexpected number of row deleted: %d", count)
}
return nil
}
// GetHash implements auth.User interface
func (u *User) GetHash() string {
return u.Hash
}
func (u *User) HasRole(role string) bool {
if role == AdminRole && !u.Admin {
return false
}
return true
}