canape/backend/users/users.go

211 lines
4.6 KiB
Go

package users
import (
"database/sql"
"encoding/json"
"errors"
"fmt"
"github.com/jmoiron/sqlx"
"github.com/jmoiron/sqlx/types"
"github.com/odwrtw/papi"
"git.quimbo.fr/odwrtw/canape/backend/config"
"git.quimbo.fr/odwrtw/canape/backend/sqly"
)
const (
addUserQuery = `INSERT INTO users (name, hash, admin, rawconfig) VALUES ($1, $2, $3, $4) RETURNING id;`
getUserQuery = `SELECT * FROM users WHERE name=$1;`
getUserByIDQuery = `SELECT * FROM users WHERE id=$1;`
updateUserQuery = `UPDATE users SET name=:name, hash=:hash, admin=:admin, activated=:activated, rawconfig=:rawconfig WHERE id=:id RETURNING *;`
deleteUseQuery = `DELETE FROM users WHERE id=:id;`
getAllUsersQuery = `SELECT * FROM users order by created_at;`
)
const (
// UserRole represents the user's role
UserRole = "user"
// AdminRole represents the admin's role
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
Activated bool
RawConfig types.JSONText
}
// GetConfig unmarshal json from specified config key into v
func (u *User) GetConfig(key string, v interface{}) error {
var configMap map[string]*json.RawMessage
err := u.RawConfig.Unmarshal(&configMap)
if err != nil {
return err
}
if raw, ok := configMap[key]; ok {
return json.Unmarshal(*raw, v)
}
return nil
}
// SetConfig marshal v into json for specified config key
func (u *User) SetConfig(key string, v interface{}) error {
var configMap map[string]*json.RawMessage
if err := u.RawConfig.Unmarshal(&configMap); err != nil {
return err
}
b, err := json.Marshal(v)
if err != nil {
return err
}
if configMap == nil {
configMap = map[string]*json.RawMessage{}
}
r := json.RawMessage(b)
configMap[key] = &r
b, err = json.Marshal(configMap)
if err != nil {
return err
}
return u.RawConfig.UnmarshalJSON(b)
}
// NewConfig creates a new empty config
func (u *User) NewConfig() error {
configMap := make(map[string]*json.RawMessage)
b, err := json.Marshal(configMap)
if err != nil {
return err
}
return u.RawConfig.UnmarshalJSON(b)
}
// NewPapiClient creates a new papi client for the given user
func (u *User) NewPapiClient() (*papi.Client, error) {
var polochonConfig config.UserPolochon
err := u.GetConfig("polochon", &polochonConfig)
if err != nil {
return nil, errors.New("missing polochon config")
}
client, err := papi.New(polochonConfig.URL)
if err != nil {
return nil, errors.New("error getting papi client")
}
if polochonConfig.Token != "" {
client.SetToken(polochonConfig.Token)
}
return client, nil
}
// 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 == sql.ErrNoRows {
return nil, ErrUnknownUser
}
return nil, err
}
return u, nil
}
// GetByID returns user using its id
func GetByID(q sqlx.Queryer, id string) (*User, error) {
u := &User{}
err := q.QueryRowx(getUserByIDQuery, id).StructScan(u)
if err != nil {
if err == sql.ErrNoRows {
return nil, ErrUnknownUser
}
return nil, err
}
return u, nil
}
// GetAll returns all the users
func GetAll(db *sqlx.DB) ([]*User, error) {
users := []*User{}
err := db.Select(&users, getAllUsersQuery)
if err != nil {
return nil, err
}
return users, 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, u.RawConfig).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
}
// GetHash implements auth.User interface
func (u *User) GetHash() string {
return u.Hash
}
// GetName implements auth.User interface
func (u *User) GetName() string {
return u.Name
}
// HasRole checks if a user as a role
func (u *User) HasRole(role string) bool {
if role == AdminRole && !u.Admin {
return false
}
return true
}
// IsAdmin checks if a user is admin
func (u *User) IsAdmin() bool {
return u.HasRole(AdminRole)
}
// IsActivated checks if a user is activated
func (u *User) IsActivated() bool {
return u.Activated
}