109 lines
2.7 KiB
Go
109 lines
2.7 KiB
Go
package models
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.kirsle.net/apps/gophertype/pkg/console"
|
|
"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 `gorm:"unique_index"`
|
|
Name string
|
|
HashedPassword string `json:"-"`
|
|
IsAdmin bool `gorm:"index"`
|
|
|
|
// Relationships
|
|
Posts []Post `gorm:"foreignkey:AuthorID"`
|
|
}
|
|
|
|
// 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 {
|
|
console.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)
|
|
return nil
|
|
}
|
|
|
|
// VerifyPassword checks if the password matches the user's hashed password.
|
|
func (u *User) VerifyPassword(password string) bool {
|
|
if u.HashedPassword == "" {
|
|
console.Error("ERROR: VerifyPassword: user %s has no HashedPassword", u.Email)
|
|
return false
|
|
}
|
|
|
|
err := bcrypt.CompareHashAndPassword([]byte(u.HashedPassword), []byte(password))
|
|
if err == nil {
|
|
return true
|
|
}
|
|
console.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
|
|
}
|