package models import ( "database/sql" "encoding/json" "errors" "fmt" "git.quimbo.fr/odwrtw/canape/backend/config" "git.quimbo.fr/odwrtw/canape/backend/sqly" "github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx/types" "github.com/odwrtw/papi" ) const ( addUserQuery = `INSERT INTO users (name, hash, admin, polochon_id, token) VALUES ($1, $2, $3, $4, $5) 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, polochon_id=:polochon_id, token=:token, polochon_activated=:polochon_activated WHERE id=:id RETURNING *;` deleteUserQuery = `DELETE FROM users WHERE id=:id;` getAllUsersQuery = `SELECT * FROM users order by created_at;` getPolochonUsersQuery = `SELECT * FROM users WHERE polochon_id = $1;` ) const ( // UserRole represents the user's role UserRole = "user" // AdminRole represents the admin's role AdminRole = "admin" ) // ErrUnknownUser returned when 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 `json:"name"` Hash string `json:"-"` Admin bool `json:"admin"` RawConfig types.JSONText `json:"raw_config"` Token string `json:"token"` Activated bool `json:"activated"` PolochonID sql.NullString `json:"polochon_id" db:"polochon_id"` PolochonActivated bool `json:"polochon_activated" db:"polochon_activated"` } // 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 } // GetUser returns user with specified name func GetUser(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 } // GetUserByID returns user using its id func GetUserByID(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 } // GetAllUsers returns all the users func GetAllUsers(db *sqlx.DB) ([]*User, error) { users := []*User{} err := db.Select(&users, getAllUsersQuery) if err != nil { return nil, err } return users, nil } // GetPolochonUsers returns all the users of a polochon func GetPolochonUsers(db *sqlx.DB, id string) ([]*User, error) { users := []*User{} err := db.Select(&users, getPolochonUsersQuery, id) 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.PolochonID, u.Token).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(deleteUserQuery, u) if err != nil { return err } return nil } // 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 }