init: 初始化 AssetX 项目仓库
包含 webapp(Next.js 用户端)、webapp-back(Go 后端)、 antdesign(管理后台)、landingpage(营销落地页)、 数据库 SQL 和配置文件。
This commit is contained in:
154
webapp-back/users/models.go
Normal file
154
webapp-back/users/models.go
Normal file
@@ -0,0 +1,154 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user