Files
SproutGate/sproutgate-backend/internal/models/user.go
2026-05-13 12:19:36 +08:00

176 lines
7.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package models
import (
"strings"
"time"
)
type UserRecord struct {
Account string `json:"account"`
PasswordHash string `json:"passwordHash"`
Username string `json:"username"`
Email string `json:"email"`
Level int `json:"level"`
SproutCoins int `json:"sproutCoins"`
LastCheckInDate string `json:"lastCheckInDate,omitempty"`
LastCheckInAt string `json:"lastCheckInAt,omitempty"`
LastVisitDate string `json:"lastVisitDate,omitempty"`
LastVisitAt string `json:"lastVisitAt,omitempty"`
LastVisitIP string `json:"lastVisitIp,omitempty"`
LastVisitDisplayLocation string `json:"lastVisitDisplayLocation,omitempty"`
CheckInTimes []string `json:"checkInTimes,omitempty"`
VisitTimes []string `json:"visitTimes,omitempty"`
SecondaryEmails []string `json:"secondaryEmails,omitempty"`
Phone string `json:"phone,omitempty"`
AvatarURL string `json:"avatarUrl,omitempty"`
WebsiteURL string `json:"websiteUrl,omitempty"`
Bio string `json:"bio,omitempty"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
Banned bool `json:"banned"`
BanReason string `json:"banReason,omitempty"`
BannedAt string `json:"bannedAt,omitempty"`
TokenEpoch int64 `json:"-"` // 递增使用户此前签发的 JWT 全局失效;不对外 JSON 序列化
AuthClients []AuthClientEntry `json:"authClients,omitempty"`
GitHubUserID string `json:"-"` // OAuth 子;不直接序列化到通用 JSON
GiteaUserID string `json:"-"`
LinuxdoUserID string `json:"-"`
GoogleUserID string `json:"-"`
MicrosoftUserID string `json:"-"`
}
type UserPublic struct {
Account string `json:"account"`
Username string `json:"username"`
Email string `json:"email"`
Level int `json:"level"`
SproutCoins int `json:"sproutCoins"`
LastCheckInDate string `json:"lastCheckInDate,omitempty"`
LastCheckInAt string `json:"lastCheckInAt,omitempty"`
LastVisitDate string `json:"lastVisitDate,omitempty"`
CheckInDays int `json:"checkInDays"`
CheckInStreak int `json:"checkInStreak"`
LastVisitAt string `json:"lastVisitAt,omitempty"`
LastVisitIP string `json:"lastVisitIp,omitempty"`
LastVisitDisplayLocation string `json:"lastVisitDisplayLocation,omitempty"`
VisitDays int `json:"visitDays"`
VisitStreak int `json:"visitStreak"`
SecondaryEmails []string `json:"secondaryEmails,omitempty"`
Phone string `json:"phone,omitempty"`
AvatarURL string `json:"avatarUrl,omitempty"`
CustomAvatarURL string `json:"customAvatarUrl,omitempty"` // 用户自选头像链接;为空时 avatarUrl 可能为 QQ 邮箱推断头像
WebsiteURL string `json:"websiteUrl,omitempty"`
Bio string `json:"bio,omitempty"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
Banned bool `json:"banned,omitempty"`
BanReason string `json:"banReason,omitempty"`
BannedAt string `json:"bannedAt,omitempty"`
AuthClients []AuthClientEntry `json:"authClients,omitempty"`
GitHubLinked bool `json:"githubLinked,omitempty"`
GiteaLinked bool `json:"giteaLinked,omitempty"`
LinuxdoLinked bool `json:"linuxdoLinked,omitempty"`
GoogleLinked bool `json:"googleLinked,omitempty"`
MicrosoftLinked bool `json:"microsoftLinked,omitempty"`
}
func (u UserRecord) Public() UserPublic {
checkInDays, checkInStreak, lastCheckInAt := ActivitySummary(u.CheckInTimes, u.LastCheckInDate)
visitDays, visitStreak, lastVisitAt := ActivitySummary(u.VisitTimes, u.LastVisitDate)
if strings.TrimSpace(u.LastCheckInAt) != "" {
lastCheckInAt = u.LastCheckInAt
}
if strings.TrimSpace(u.LastVisitAt) != "" {
lastVisitAt = u.LastVisitAt
}
return UserPublic{
Account: u.Account,
Username: u.Username,
Email: u.Email,
Level: u.Level,
SproutCoins: u.SproutCoins,
LastCheckInDate: u.LastCheckInDate,
LastCheckInAt: lastCheckInAt,
LastVisitDate: u.LastVisitDate,
CheckInDays: checkInDays,
CheckInStreak: checkInStreak,
LastVisitAt: lastVisitAt,
VisitDays: visitDays,
VisitStreak: visitStreak,
SecondaryEmails: u.SecondaryEmails,
Phone: u.Phone,
AvatarURL: u.ResolvedAvatarURL(),
CustomAvatarURL: strings.TrimSpace(u.AvatarURL),
WebsiteURL: u.WebsiteURL,
Bio: u.Bio,
CreatedAt: u.CreatedAt,
UpdatedAt: u.UpdatedAt,
}
}
// PublicProfile 在 Public 基础上附带最近访问 IP / 展示用地理位置,仅供「用户公开主页」接口使用。
func (u UserRecord) PublicProfile() UserPublic {
p := u.Public()
p.LastVisitIP = strings.TrimSpace(u.LastVisitIP)
p.LastVisitDisplayLocation = strings.TrimSpace(u.LastVisitDisplayLocation)
return p
}
// OwnerPublic 包含仅本人/管理员可见的字段(如最近访问 IP勿用于公开资料接口。
func (u UserRecord) OwnerPublic() UserPublic {
p := u.Public()
p.LastVisitIP = strings.TrimSpace(u.LastVisitIP)
p.LastVisitDisplayLocation = strings.TrimSpace(u.LastVisitDisplayLocation)
p.Banned = u.Banned
p.BanReason = strings.TrimSpace(u.BanReason)
p.BannedAt = strings.TrimSpace(u.BannedAt)
if len(u.AuthClients) > 0 {
p.AuthClients = append([]AuthClientEntry(nil), u.AuthClients...)
}
p.GitHubLinked = strings.TrimSpace(u.GitHubUserID) != ""
p.GiteaLinked = strings.TrimSpace(u.GiteaUserID) != ""
p.LinuxdoLinked = strings.TrimSpace(u.LinuxdoUserID) != ""
p.GoogleLinked = strings.TrimSpace(u.GoogleUserID) != ""
p.MicrosoftLinked = strings.TrimSpace(u.MicrosoftUserID) != ""
return p
}
type UserShowcase struct {
Account string `json:"account"`
Username string `json:"username"`
Level int `json:"level"`
SproutCoins int `json:"sproutCoins"`
AvatarURL string `json:"avatarUrl,omitempty"`
WebsiteURL string `json:"websiteUrl,omitempty"`
Bio string `json:"bio,omitempty"`
}
func (u UserRecord) Showcase() UserShowcase {
return UserShowcase{
Account: u.Account,
Username: u.Username,
Level: u.Level,
SproutCoins: u.SproutCoins,
AvatarURL: u.ResolvedAvatarURL(),
WebsiteURL: u.WebsiteURL,
Bio: u.Bio,
}
}
// PublicUserListEntry 公开用户目录条目(含注册时间供排序与展示)。
type PublicUserListEntry struct {
UserShowcase
CreatedAt string `json:"createdAt"`
}
func (u UserRecord) PublicListEntry() PublicUserListEntry {
return PublicUserListEntry{
UserShowcase: u.Showcase(),
CreatedAt: u.CreatedAt,
}
}
func NowISO() string {
return time.Now().Format(time.RFC3339)
}