Files
assetx/webapp-back/users/models.go

155 lines
4.7 KiB
Go
Raw Normal View History

package users
import (
"errors"
"github.com/gothinkster/golang-gin-realworld-example-app/common"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
// Models should only be concerned with database schema, more strict checking should be put in validator.
//
// More detail you can find here: http://jinzhu.me/gorm/models.html#model-definition
//
// HINT: If you want to split null and "", you should use *string instead of string.
type UserModel struct {
ID uint `gorm:"primaryKey"`
Username string `gorm:"column:username"`
Email string `gorm:"column:email;uniqueIndex"`
Bio string `gorm:"column:bio;size:1024"`
Image *string `gorm:"column:image"`
PasswordHash string `gorm:"column:password;not null"`
}
// A hack way to save ManyToMany relationship,
// gorm will build the alias as FollowingBy <-> FollowingByID <-> "following_by_id".
//
// DB schema looks like: id, created_at, updated_at, deleted_at, following_id, followed_by_id.
//
// Retrieve them by:
//
// db.Where(FollowModel{ FollowingID: v.ID, FollowedByID: u.ID, }).First(&follow)
// db.Where(FollowModel{ FollowedByID: u.ID, }).Find(&follows)
//
// More details about gorm.Model: http://jinzhu.me/gorm/models.html#conventions
type FollowModel struct {
gorm.Model
Following UserModel
FollowingID uint
FollowedBy UserModel
FollowedByID uint
}
// Migrate the schema of database if needed
func AutoMigrate() {
db := common.GetDB()
db.AutoMigrate(&UserModel{})
db.AutoMigrate(&FollowModel{})
}
// What's bcrypt? https://en.wikipedia.org/wiki/Bcrypt
// Golang bcrypt doc: https://godoc.org/golang.org/x/crypto/bcrypt
// You can change the value in bcrypt.DefaultCost to adjust the security index.
//
// err := userModel.setPassword("password0")
func (u *UserModel) setPassword(password string) error {
if len(password) == 0 {
return errors.New("password should not be empty!")
}
bytePassword := []byte(password)
// Make sure the second param `bcrypt generator cost` between [4, 32)
passwordHash, _ := bcrypt.GenerateFromPassword(bytePassword, bcrypt.DefaultCost)
u.PasswordHash = string(passwordHash)
return nil
}
// Database will only save the hashed string, you should check it by util function.
//
// if err := serModel.checkPassword("password0"); err != nil { password error }
func (u *UserModel) checkPassword(password string) error {
bytePassword := []byte(password)
byteHashedPassword := []byte(u.PasswordHash)
return bcrypt.CompareHashAndPassword(byteHashedPassword, bytePassword)
}
// You could input the conditions and it will return an UserModel in database with error info.
//
// userModel, err := FindOneUser(&UserModel{Username: "username0"})
func FindOneUser(condition interface{}) (UserModel, error) {
db := common.GetDB()
var model UserModel
err := db.Where(condition).First(&model).Error
return model, err
}
// You could input an UserModel which will be saved in database returning with error info
//
// if err := SaveOne(&userModel); err != nil { ... }
func SaveOne(data interface{}) error {
db := common.GetDB()
err := db.Save(data).Error
return err
}
// You could update properties of an UserModel to database returning with error info.
//
// err := db.Model(userModel).Updates(UserModel{Username: "wangzitian0"}).Error
func (model *UserModel) Update(data interface{}) error {
db := common.GetDB()
err := db.Model(model).Updates(data).Error
return err
}
// You could add a following relationship as userModel1 following userModel2
//
// err = userModel1.following(userModel2)
func (u UserModel) following(v UserModel) error {
db := common.GetDB()
var follow FollowModel
err := db.FirstOrCreate(&follow, &FollowModel{
FollowingID: v.ID,
FollowedByID: u.ID,
}).Error
return err
}
// You could check whether userModel1 following userModel2
//
// followingBool = myUserModel.isFollowing(self.UserModel)
func (u UserModel) isFollowing(v UserModel) bool {
db := common.GetDB()
var follow FollowModel
db.Where(FollowModel{
FollowingID: v.ID,
FollowedByID: u.ID,
}).First(&follow)
return follow.ID != 0
}
// You could delete a following relationship as userModel1 following userModel2
//
// err = userModel1.unFollowing(userModel2)
func (u UserModel) unFollowing(v UserModel) error {
db := common.GetDB()
err := db.Where("following_id = ? AND followed_by_id = ?", v.ID, u.ID).Delete(&FollowModel{}).Error
return err
}
// You could get a following list of userModel
//
// followings := userModel.GetFollowings()
func (u UserModel) GetFollowings() []UserModel {
db := common.GetDB()
var follows []FollowModel
var followings []UserModel
db.Preload("Following").Where(FollowModel{
FollowedByID: u.ID,
}).Find(&follows)
for _, follow := range follows {
followings = append(followings, follow.Following)
}
return followings
}