192 lines
5.1 KiB
Go
192 lines
5.1 KiB
Go
package model
|
||
|
||
import (
|
||
"context"
|
||
"time"
|
||
|
||
"spark-server/internal/module/user/entity"
|
||
"spark-server/internal/pkg/errs"
|
||
)
|
||
|
||
// User maps table users: account row, Snowflake uid, mutable spark_id.
|
||
type User struct {
|
||
ID int64 `gorm:"column:id;primaryKey;comment:Snowflake 用户 id(uid),时间有序,非自增"`
|
||
SparkID string `gorm:"column:spark_id;comment:对外展示的账号,用户可改,全局唯一"`
|
||
Nickname string `gorm:"column:nickname;comment:昵称"`
|
||
Avatar string `gorm:"column:avatar;comment:头像对象存储 key 或 URL,不存图片二进制"`
|
||
QRCode string `gorm:"column:qrcode;comment:个人二维码扫描票据,随机生成,不含 uid 或 spark_id"`
|
||
Birthday *time.Time `gorm:"column:birthday;type:date;comment:生日,未填为空"`
|
||
Gender int `gorm:"column:gender;comment:0=未知 1=男 2=女"`
|
||
Status int `gorm:"column:status;comment:1=正常 0=禁用"`
|
||
LastLoginAt *time.Time `gorm:"column:last_login_at;comment:最近一次登录时间"`
|
||
LastActiveAt *time.Time `gorm:"column:last_active_at;comment:最近一次活跃时间(登录、心跳、发消息等)"`
|
||
CreatedAt time.Time `gorm:"column:created_at;comment:注册时间(create_time)"`
|
||
UpdatedAt time.Time `gorm:"column:updated_at;comment:资料最近更新时间(update_time)"`
|
||
}
|
||
|
||
func (User) TableName() string { return "t_users" }
|
||
|
||
func (r *User) entity() *entity.User {
|
||
if r == nil {
|
||
return nil
|
||
}
|
||
return &entity.User{
|
||
ID: r.ID,
|
||
SparkID: r.SparkID,
|
||
Nickname: r.Nickname,
|
||
Avatar: r.Avatar,
|
||
QRCode: r.QRCode,
|
||
Birthday: timeOrZero(r.Birthday),
|
||
Gender: entity.Gender(r.Gender),
|
||
Status: entity.Status(r.Status),
|
||
LastLoginAt: timeOrZero(r.LastLoginAt),
|
||
LastActiveAt: timeOrZero(r.LastActiveAt),
|
||
CreatedAt: r.CreatedAt,
|
||
UpdatedAt: r.UpdatedAt,
|
||
}
|
||
}
|
||
|
||
func fromEntity(u *entity.User) User {
|
||
row := User{
|
||
ID: u.ID,
|
||
SparkID: u.SparkID,
|
||
Nickname: u.Nickname,
|
||
Avatar: u.Avatar,
|
||
QRCode: u.QRCode,
|
||
Gender: int(u.Gender),
|
||
Status: int(u.Status),
|
||
CreatedAt: u.CreatedAt,
|
||
UpdatedAt: u.UpdatedAt,
|
||
}
|
||
row.Birthday = timePtr(u.Birthday)
|
||
row.LastLoginAt = timePtr(u.LastLoginAt)
|
||
row.LastActiveAt = timePtr(u.LastActiveAt)
|
||
return row
|
||
}
|
||
|
||
func timeOrZero(t *time.Time) time.Time {
|
||
if t == nil {
|
||
return time.Time{}
|
||
}
|
||
return *t
|
||
}
|
||
|
||
func timePtr(t time.Time) *time.Time {
|
||
if t.IsZero() {
|
||
return nil
|
||
}
|
||
return &t
|
||
}
|
||
|
||
func (m *Repo) GetByID(ctx context.Context, id int64) (*entity.User, error) {
|
||
db, err := m.session(ctx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var row User
|
||
if err := db.Where("id = ?", id).Take(&row).Error; err != nil {
|
||
return nil, mapDBErr(err)
|
||
}
|
||
return row.entity(), nil
|
||
}
|
||
|
||
func (m *Repo) GetBySparkID(ctx context.Context, sparkID string) (*entity.User, error) {
|
||
db, err := m.session(ctx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var row User
|
||
if err := db.Where("spark_id = ?", sparkID).Take(&row).Error; err != nil {
|
||
return nil, mapDBErr(err)
|
||
}
|
||
return row.entity(), nil
|
||
}
|
||
|
||
func (m *Repo) GetByQRCode(ctx context.Context, qrcode string) (*entity.User, error) {
|
||
db, err := m.session(ctx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var row User
|
||
if err := db.Where("qrcode = ?", qrcode).Take(&row).Error; err != nil {
|
||
return nil, mapDBErr(err)
|
||
}
|
||
return row.entity(), nil
|
||
}
|
||
|
||
func (m *Repo) UpdateSparkID(ctx context.Context, userID int64, sparkID string) error {
|
||
db, err := m.session(ctx)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
res := db.Model(&User{}).Where("id = ?", userID).Updates(map[string]any{
|
||
"spark_id": sparkID,
|
||
"updated_at": time.Now(),
|
||
})
|
||
if res.Error != nil {
|
||
return mapDBErr(res.Error)
|
||
}
|
||
if res.RowsAffected == 0 {
|
||
return errs.ErrNotFound
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (m *Repo) UpdateQRCode(ctx context.Context, userID int64, qrcode string) error {
|
||
db, err := m.session(ctx)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
res := db.Model(&User{}).Where("id = ?", userID).Update("qrcode", qrcode)
|
||
if res.Error != nil {
|
||
return mapDBErr(res.Error)
|
||
}
|
||
if res.RowsAffected == 0 {
|
||
return errs.ErrNotFound
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (m *Repo) UpdateProfile(ctx context.Context, u *entity.User) error {
|
||
if u == nil || u.ID <= 0 {
|
||
return errs.ErrInvalidArgument
|
||
}
|
||
db, err := m.session(ctx)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
res := db.Model(&User{}).Where("id = ?", u.ID).Select("spark_id", "nickname", "avatar", "gender", "birthday", "updated_at").Updates(map[string]any{
|
||
"spark_id": u.SparkID,
|
||
"nickname": u.Nickname,
|
||
"avatar": u.Avatar,
|
||
"gender": int(u.Gender),
|
||
"birthday": timePtr(u.Birthday),
|
||
"updated_at": u.UpdatedAt,
|
||
})
|
||
if res.Error != nil {
|
||
return mapDBErr(res.Error)
|
||
}
|
||
if res.RowsAffected == 0 {
|
||
return errs.ErrNotFound
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (m *Repo) TouchLogin(ctx context.Context, userID int64, at time.Time) error {
|
||
db, err := m.session(ctx)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
res := db.Model(&User{}).Where("id = ?", userID).Updates(map[string]any{
|
||
"last_login_at": at,
|
||
"last_active_at": at,
|
||
})
|
||
if res.Error != nil {
|
||
return mapDBErr(res.Error)
|
||
}
|
||
if res.RowsAffected == 0 {
|
||
return errs.ErrNotFound
|
||
}
|
||
return nil
|
||
}
|