swirl/biz/user.go
2021-12-15 17:26:45 +08:00

262 lines
6.2 KiB
Go

package biz
import (
"context"
"time"
"github.com/cuigh/auxo/data/guid"
"github.com/cuigh/auxo/errors"
"github.com/cuigh/auxo/net/web"
"github.com/cuigh/auxo/security/passwd"
"github.com/cuigh/swirl/dao"
"github.com/cuigh/swirl/misc"
"github.com/cuigh/swirl/model"
"github.com/jinzhu/copier"
)
const (
// UserTypeInternal is internal user of swirl
UserTypeInternal = "internal"
// UserTypeLDAP is external user of LDAP
UserTypeLDAP = "ldap"
)
const (
// UserStatusBlocked is the status which user is blocked
UserStatusBlocked = 0
// UserStatusActive is the normal status
UserStatusActive = 1
)
type User struct {
ID string `json:"id"`
Name string `json:"name" valid:"required"`
LoginName string `json:"loginName" valid:"required"`
Password string `json:"password,omitempty"`
Email string `json:"email" valid:"required"`
Admin bool `json:"admin"`
Type string `json:"type"`
Status int32 `json:"status,omitempty"`
Roles []string `json:"roles,omitempty"`
CreatedAt string `bson:"created_at" json:"createdAt,omitempty"`
UpdatedAt string `bson:"updated_at" json:"updatedAt,omitempty"`
}
type UserPrivacy struct {
ID string
Name string
Password string
Salt string
Type string
Status int32
}
func newUser(u *model.User) *User {
user := &User{
CreatedAt: formatTime(u.CreatedAt),
UpdatedAt: formatTime(u.UpdatedAt),
}
_ = copier.CopyWithOption(user, u, copier.Option{IgnoreEmpty: true, DeepCopy: true})
return user
}
type UserBiz interface {
Search(name, loginName, filter string, pageIndex, pageSize int) (users []*User, total int, err error)
Create(user *User, ctxUser web.User) (id string, err error)
Update(user *User, ctxUser web.User) (err error)
FindByID(id string) (user *User, err error)
FindByName(loginName string) (user *User, err error)
FindPrivacy(loginName string) (privacy *UserPrivacy, err error)
Count() (count int, err error)
Delete(id, name string, user web.User) (err error)
SetStatus(id string, status int32) (err error)
ModifyPassword(id, pwd, salt string) (err error)
ModifyProfile(user *User) (err error)
}
func NewUser(d dao.Interface, eb EventBiz) UserBiz {
return &userBiz{d: d, eb: eb}
}
type userBiz struct {
d dao.Interface
eb EventBiz
}
func (b *userBiz) Search(name, loginName, filter string, pageIndex, pageSize int) (users []*User, total int, err error) {
var (
list []*model.User
args = &model.UserSearchArgs{
Name: name,
LoginName: loginName,
Status: -1,
PageIndex: pageIndex,
PageSize: pageSize,
}
)
switch filter {
case "admins":
args.Admin = true
case "active":
args.Status = UserStatusActive
case "blocked":
args.Status = UserStatusBlocked
}
list, total, err = b.d.UserList(context.TODO(), args)
if err == nil {
for _, u := range list {
users = append(users, newUser(u))
}
}
return
}
func (b *userBiz) FindByID(id string) (user *User, err error) {
var u *model.User
u, err = b.d.UserGetByID(context.TODO(), id)
if u != nil {
user = newUser(u)
}
return
}
func (b *userBiz) FindByName(loginName string) (user *User, err error) {
var u *model.User
u, err = b.d.UserGetByName(context.TODO(), loginName)
if u != nil {
user = newUser(u)
}
return
}
func (b *userBiz) FindPrivacy(loginName string) (privacy *UserPrivacy, err error) {
var u *model.User
u, err = b.d.UserGetByName(context.TODO(), loginName)
if u != nil {
privacy = &UserPrivacy{
ID: u.ID,
Name: u.Name,
Password: u.Password,
Salt: u.Salt,
Type: u.Type,
Status: u.Status,
}
}
return
}
func (b *userBiz) Create(u *User, ctxUser web.User) (id string, err error) {
user := &model.User{
ID: createId(),
Name: u.Name,
LoginName: u.LoginName,
Email: u.Email,
Admin: u.Admin,
Type: u.Type,
Status: UserStatusActive,
Roles: u.Roles,
CreatedAt: time.Now(),
}
user.UpdatedAt = user.CreatedAt
if user.Type == UserTypeInternal {
user.Password, user.Salt, err = passwd.Generate(u.Password)
if err != nil {
return
}
}
if err = b.d.UserCreate(context.TODO(), user); err == nil && ctxUser != nil {
b.eb.CreateUser(EventActionCreate, user.LoginName, user.Name, ctxUser)
}
id = user.ID
return
}
func (b *userBiz) Update(u *User, ctxUser web.User) (err error) {
user := &model.User{
ID: u.ID,
Name: u.Name,
LoginName: u.LoginName,
Email: u.Email,
Admin: u.Admin,
Type: u.Type,
Roles: u.Roles,
UpdatedAt: time.Now(),
}
if err = b.d.UserUpdate(context.TODO(), user); err == nil {
b.eb.CreateUser(EventActionUpdate, u.LoginName, u.Name, ctxUser)
}
return
}
func (b *userBiz) SetStatus(id string, status int32) (err error) {
return b.d.UserSetStatus(context.TODO(), id, status)
}
func (b *userBiz) Delete(id, name string, user web.User) (err error) {
err = b.d.UserDelete(context.TODO(), id)
if err == nil {
b.eb.CreateUser(EventActionDelete, id, name, user)
}
return
}
func (b *userBiz) ModifyPassword(id, oldPwd, newPwd string) (err error) {
var (
user *model.User
pwd, salt string
)
user, err = b.d.UserGetByID(context.TODO(), id)
if err != nil {
return err
} else if user == nil {
return errors.Format("user not found: %s", id)
}
if !passwd.Validate(oldPwd, user.Password, user.Salt) {
return errors.Coded(misc.ErrOldPasswordIncorrect, "current password is incorrect")
}
pwd, salt, err = passwd.Generate(newPwd)
if err != nil {
return
}
err = b.d.UserModifyPassword(context.TODO(), id, pwd, salt)
return
}
func (b *userBiz) ModifyProfile(user *User) (err error) {
return b.d.UserModifyProfile(context.TODO(), &model.User{
ID: user.ID,
Name: user.Name,
LoginName: user.LoginName,
Email: user.Email,
})
}
func (b *userBiz) Count() (count int, err error) {
return b.d.UserCount(context.TODO())
}
func (b *userBiz) UpdateSession(id string) (token string, err error) {
session := &model.Session{
UserID: id,
Token: guid.New().String(),
UpdatedAt: time.Now(),
}
session.Expires = session.UpdatedAt.Add(time.Hour * 24)
err = b.d.SessionUpdate(context.TODO(), session)
if err == nil {
token = session.Token
}
return
}
func (b *userBiz) GetSession(token string) (session *model.Session, err error) {
return b.d.SessionGet(context.TODO(), token)
}