gophertype/pkg/models/users.go

107 lines
2.7 KiB
Go

package models
import (
"errors"
"fmt"
"log"
"strings"
"git.kirsle.net/apps/gophertype/pkg/constants"
"github.com/jinzhu/gorm"
"golang.org/x/crypto/bcrypt"
)
// User account for the site.
type User struct {
gorm.Model
Email string `json:"email" gorm:"unique_index"`
Name string `json:"name"`
HashedPassword string `json:"-"`
IsAdmin bool `json:"isAdmin" gorm:"index"`
}
// Validate the User object has everything filled in. Fixes what it can,
// returns an error if something is wrong. Ensures the HashedPassword is hashed.
func (u *User) Validate() error {
u.Email = strings.TrimSpace(strings.ToLower(u.Email))
u.Name = strings.TrimSpace(u.Name)
if len(u.Email) == 0 {
return errors.New("Email is required")
}
return nil
}
// AuthenticateUser checks a login for an email and password.
func AuthenticateUser(email string, password string) (User, error) {
user, err := GetUserByEmail(email)
if err != nil {
log.Printf("ERROR: AuthenticateUser: email %s not found: %s", email, err)
return User{}, errors.New("incorrect email or password")
}
if user.VerifyPassword(password) {
return user, nil
}
return User{}, errors.New("incorrect email or password")
}
// GetUserByID looks up a user by their ID.
func GetUserByID(id int) (User, error) {
var user User
r := DB.First(&user, id)
return user, r.Error
}
// GetUserByEmail looks up a user by their email address.
func GetUserByEmail(email string) (User, error) {
var user User
r := DB.Where("email = ?", strings.ToLower(email)).First(&user)
return user, r.Error
}
// SetPassword stores the hashed password for a user.
func (u *User) SetPassword(password string) error {
hash, err := bcrypt.GenerateFromPassword([]byte(password), constants.BcryptCost)
if err != nil {
return fmt.Errorf("SetPassword: %s", err)
}
u.HashedPassword = string(hash)
fmt.Printf("Set hashed password: %s", u.HashedPassword)
return nil
}
// VerifyPassword checks if the password matches the user's hashed password.
func (u *User) VerifyPassword(password string) bool {
if u.HashedPassword == "" {
fmt.Printf("ERROR: VerifyPassword: user has no HashedPassword")
return false
}
err := bcrypt.CompareHashAndPassword([]byte(u.HashedPassword), []byte(password))
if err == nil {
return true
}
log.Printf("ERROR: VerifyPassword: %s", err)
return false
}
// FirstAdmin returns the admin user with the lowest ID number.
func FirstAdmin() (User, error) {
var user User
r := DB.First(&user, "is_admin", true)
return user, r.Error
}
// CreateUser adds a new user to the database.
func CreateUser(u User) error {
if err := u.Validate(); err != nil {
return err
}
r := DB.Create(&u)
return r.Error
}