All checks were successful
Server Check Build (NixCN CMS) TeamCity build finished
Options Signed-off-by: Asai Neko <sugar@sne.moe>
250 lines
6.2 KiB
Go
250 lines
6.2 KiB
Go
package data
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type User struct {
|
|
Id uint `json:"id" gorm:"primarykey;autoincrement"`
|
|
UUID uuid.UUID `json:"uuid" gorm:"type:uuid;uniqueindex;not null"`
|
|
UserId uuid.UUID `json:"user_id" gorm:"type:uuid;uniqueindex;not null"`
|
|
Email string `json:"email" gorm:"type:varchar(255);uniqueindex;not null"`
|
|
Username string `json:"username" gorm:"type:varchar(255);uniqueindex;not null"`
|
|
Nickname string `json:"nickname" gorm:"type:text"`
|
|
Subtitle string `json:"subtitle" gorm:"type:text"`
|
|
Avatar string `json:"avatar" gorm:"type:text"`
|
|
Bio string `json:"bio" gorm:"type:text"`
|
|
PermissionLevel uint `json:"permission_level" gorm:"default:10;not null"`
|
|
AllowPublic bool `json:"allow_public" gorm:"default:false;not null"`
|
|
KycInfo string `json:"kyc_info" gorm:"type:text"`
|
|
}
|
|
|
|
type UserIndexDoc struct {
|
|
UserId string `json:"user_id" validate:"required"`
|
|
Email string `json:"email" validate:"required"`
|
|
Username string `json:"username" validate:"required"`
|
|
Nickname string `json:"nickname"`
|
|
Subtitle string `json:"subtitle"`
|
|
Avatar string `json:"avatar"`
|
|
}
|
|
|
|
type UserAdminDoc struct {
|
|
UserId string `json:"user_id"`
|
|
Email string `json:"email"`
|
|
Username string `json:"username"`
|
|
Nickname string `json:"nickname"`
|
|
Subtitle string `json:"subtitle"`
|
|
Avatar string `json:"avatar"`
|
|
PermissionLevel uint `json:"permission_level"`
|
|
}
|
|
|
|
type UserListOptions struct {
|
|
PermissionLevel *uint
|
|
SortBy string // "id" | "permission_level"
|
|
SortOrder string // "asc" | "desc"
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
type userOpts struct {
|
|
Email *string
|
|
Username *string
|
|
Nickname *string
|
|
Subtitle *string
|
|
Avatar *string
|
|
Bio *string
|
|
PermissionLevel *uint
|
|
AllowPublic *bool
|
|
}
|
|
|
|
type UserOption func(*userOpts)
|
|
|
|
func WithEmail(v string) UserOption { return func(o *userOpts) { o.Email = &v } }
|
|
func WithUsername(v string) UserOption { return func(o *userOpts) { o.Username = &v } }
|
|
func WithNickname(v string) UserOption { return func(o *userOpts) { o.Nickname = &v } }
|
|
func WithSubtitle(v string) UserOption { return func(o *userOpts) { o.Subtitle = &v } }
|
|
func WithAvatar(v string) UserOption { return func(o *userOpts) { o.Avatar = &v } }
|
|
func WithBio(v string) UserOption { return func(o *userOpts) { o.Bio = &v } }
|
|
func WithPermissionLevel(v uint) UserOption { return func(o *userOpts) { o.PermissionLevel = &v } }
|
|
func WithAllowPublic(v bool) UserOption { return func(o *userOpts) { o.AllowPublic = &v } }
|
|
|
|
func applyUserOpts(opts []UserOption) *userOpts {
|
|
o := &userOpts{}
|
|
for _, opt := range opts {
|
|
opt(o)
|
|
}
|
|
return o
|
|
}
|
|
|
|
func NewUser(opts ...UserOption) *User {
|
|
o := applyUserOpts(opts)
|
|
u := &User{}
|
|
if o.Email != nil {
|
|
u.Email = *o.Email
|
|
}
|
|
if o.Username != nil {
|
|
u.Username = *o.Username
|
|
}
|
|
if o.Nickname != nil {
|
|
u.Nickname = *o.Nickname
|
|
}
|
|
if o.Subtitle != nil {
|
|
u.Subtitle = *o.Subtitle
|
|
}
|
|
if o.Avatar != nil {
|
|
u.Avatar = *o.Avatar
|
|
}
|
|
if o.Bio != nil {
|
|
u.Bio = *o.Bio
|
|
}
|
|
if o.PermissionLevel != nil {
|
|
u.PermissionLevel = *o.PermissionLevel
|
|
}
|
|
if o.AllowPublic != nil {
|
|
u.AllowPublic = *o.AllowPublic
|
|
}
|
|
return u
|
|
}
|
|
|
|
func (self *User) GetByEmail(ctx context.Context, email *string) (*User, error) {
|
|
var user User
|
|
|
|
err := Database.WithContext(ctx).
|
|
Where("email = ?", email).
|
|
First(&user).Error
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &user, nil
|
|
}
|
|
|
|
func (self *User) GetByUserId(ctx context.Context, userId *uuid.UUID) (*User, error) {
|
|
var user User
|
|
|
|
err := Database.WithContext(ctx).
|
|
Where("user_id = ?", userId).
|
|
First(&user).Error
|
|
|
|
if err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
return &user, err
|
|
}
|
|
|
|
func (self *User) Create(ctx context.Context) error {
|
|
self.UUID = uuid.New()
|
|
self.UserId = uuid.New()
|
|
|
|
if err := Database.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
return tx.Create(self).Error
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (self *User) PatchByUserId(ctx context.Context, userId uuid.UUID, opts ...UserOption) error {
|
|
o := applyUserOpts(opts)
|
|
updates := make(map[string]any)
|
|
|
|
if o.Email != nil {
|
|
updates["email"] = *o.Email
|
|
}
|
|
if o.Username != nil {
|
|
updates["username"] = *o.Username
|
|
}
|
|
if o.Nickname != nil {
|
|
updates["nickname"] = *o.Nickname
|
|
}
|
|
if o.Subtitle != nil {
|
|
updates["subtitle"] = *o.Subtitle
|
|
}
|
|
if o.Avatar != nil {
|
|
updates["avatar"] = *o.Avatar
|
|
}
|
|
if o.Bio != nil {
|
|
updates["bio"] = *o.Bio
|
|
}
|
|
if o.PermissionLevel != nil {
|
|
updates["permission_level"] = *o.PermissionLevel
|
|
}
|
|
if o.AllowPublic != nil {
|
|
updates["allow_public"] = *o.AllowPublic
|
|
}
|
|
|
|
if len(updates) == 0 {
|
|
return nil
|
|
}
|
|
|
|
return Database.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
return tx.Model(&User{}).
|
|
Where("user_id = ?", userId).
|
|
Updates(updates).Error
|
|
})
|
|
}
|
|
|
|
func (self *User) FastListUsers(ctx context.Context, limit, offset *int) (*[]UserIndexDoc, error) {
|
|
var results []UserIndexDoc
|
|
|
|
query := Database.WithContext(ctx).Model(&User{})
|
|
|
|
err := query.Select("user_id", "email", "username", "nickname", "subtitle", "avatar").
|
|
Limit(*limit).
|
|
Offset(*offset).
|
|
Scan(&results).Error
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &results, nil
|
|
}
|
|
|
|
func (self *User) ListUsersFiltered(ctx context.Context, opts UserListOptions) (*[]UserAdminDoc, int64, error) {
|
|
var results []UserAdminDoc
|
|
var total int64
|
|
|
|
base := Database.WithContext(ctx).Model(&User{})
|
|
|
|
if opts.PermissionLevel != nil {
|
|
base = base.Where("permission_level = ?", *opts.PermissionLevel)
|
|
}
|
|
|
|
if err := base.Count(&total).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
sortField := "id"
|
|
if opts.SortBy == "permission_level" {
|
|
sortField = "permission_level"
|
|
}
|
|
|
|
sortOrder := "ASC"
|
|
if opts.SortOrder == "desc" {
|
|
sortOrder = "DESC"
|
|
}
|
|
|
|
err := base.
|
|
Select("user_id", "email", "username", "nickname", "subtitle", "avatar", "permission_level").
|
|
Order(sortField + " " + sortOrder).
|
|
Limit(opts.Limit).
|
|
Offset(opts.Offset).
|
|
Scan(&results).Error
|
|
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
return &results, total, nil
|
|
}
|