package models import ( "database/sql" "encoding/json" "errors" "regexp" "github.com/thermokarst/bactdb/Godeps/_workspace/src/golang.org/x/crypto/bcrypt" "github.com/thermokarst/bactdb/helpers" "github.com/thermokarst/bactdb/types" ) var ( ErrUserNotFound = errors.New("User not found") ErrUserNotUpdated = errors.New("User not updated") ErrInvalidEmailOrPassword = errors.New("Invalid email or password") ErrEmailAddressTaken = errors.New("Email address already registered") ) func init() { DB.AddTableWithName(UserBase{}, "users").SetKeys(true, "Id") } type UserBase struct { Id int64 `json:"id,omitempty"` Email string `db:"email" json:"email"` Password string `db:"password" json:"password,omitempty"` Name string `db:"name" json:"name"` Role string `db:"role" json:"role"` Verified bool `db:"verified" json:"-"` CreatedAt types.NullTime `db:"created_at" json:"createdAt"` UpdatedAt types.NullTime `db:"updated_at" json:"updatedAt"` DeletedAt types.NullTime `db:"deleted_at" json:"deletedAt"` } type User struct { *UserBase CanEdit bool `db:"-" json:"canEdit"` } type UserValidation struct { Email []string `json:"email,omitempty"` Password []string `json:"password,omitempty"` Name []string `json:"name,omitempty"` Role []string `json:"role,omitempty"` } func (uv UserValidation) Error() string { errs, err := json.Marshal(struct { UserValidation `json:"errors"` }{uv}) if err != nil { return err.Error() } return string(errs) } type Users []*User type UserJSON struct { User *User `json:"user"` } type UsersJSON struct { Users *Users `json:"users"` } type UserMeta struct { CanAdd bool `json:"canAdd"` } func (u *Users) Marshal() ([]byte, error) { return json.Marshal(&UsersJSON{Users: u}) } func (u *User) Validate() error { var uv UserValidation validationError := false if u.Name == "" { uv.Name = append(uv.Name, helpers.MustProvideAValue) validationError = true } if u.Email == "" { uv.Email = append(uv.Email, helpers.MustProvideAValue) validationError = true } regex, _ := regexp.Compile(`(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})`) if u.Email != "" && !regex.MatchString(u.Email) { uv.Email = append(uv.Email, "Must provide a valid email address") validationError = true } if len(u.Password) < 8 { uv.Password = append(uv.Password, "Password must be at least 8 characters") validationError = true } if validationError { return uv } return nil } // for thermokarst/jwt: authentication callback func DbAuthenticate(email string, password string) error { var user User q := `SELECT * FROM users WHERE lower(email)=lower($1) AND verified IS TRUE AND deleted_at IS NULL;` if err := DBH.SelectOne(&user, q, email); err != nil { return ErrInvalidEmailOrPassword } if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil { return ErrInvalidEmailOrPassword } return nil } func DbGetUserById(id int64) (*User, error) { var user User q := `SELECT * FROM users WHERE id=$1 AND verified IS TRUE AND deleted_at IS NULL;` if err := DBH.SelectOne(&user, q, id); err != nil { if err == sql.ErrNoRows { return nil, ErrUserNotFound } return nil, err } return &user, nil } // for thermokarst/jwt: setting user in claims bundle func DbGetUserByEmail(email string) (*User, error) { var user User q := `SELECT * FROM users WHERE lower(email)=lower($1) AND verified IS TRUE AND deleted_at IS NULL;` if err := DBH.SelectOne(&user, q, email); err != nil { if err == sql.ErrNoRows { return nil, ErrUserNotFound } return nil, err } return &user, nil }