package models import ( "database/sql" "errors" "fmt" "time" "github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx/types" "github.com/odwrtw/polochon/lib/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 u.*, tok.last_seen FROM users u LEFT OUTER JOIN ( SELECT username, MAX(last_used) AS last_seen FROM tokens GROUP BY username ) AS tok ON u.name = tok.username ORDER by u.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 { 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"` Polochon *Polochon `json:"polochon"` LastSeen *time.Time `json:"last_seen" db:"last_seen"` } // NewPapiClient creates a new papi client for the given user func (u *User) NewPapiClient(db *sqlx.DB) (*papi.Client, error) { polochon, err := u.GetPolochon(db) if err != nil { return nil, err } client, err := papi.New(polochon.URL) if err != nil { return nil, errors.New("error getting papi client") } if u.Token != "" { client.SetToken(u.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() { if err := rows.StructScan(u); err != nil { return err } } return nil } // Delete user from database or raise an error func (u *User) Delete(ex *sqlx.DB) error { _, err := ex.NamedExec(deleteUserQuery, u) return err } // 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 } // GetPolochon returns the user's polochon func (u *User) GetPolochon(db *sqlx.DB) (*Polochon, error) { return GetPolochonByID(db, u.PolochonID.String) }