Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
package userser
import (
"testing"
"time"
"91porn-server/models/v/usermod"
"91porn-server/models/v/walletmod"
)
func TestToUserRecordListIncludesDramaExpire(t *testing.T) {
expire := time.Date(2026, 9, 26, 12, 0, 0, 0, time.UTC)
users := []usermod.User{{UID: 100001, DramaExpire: expire}}
records := toUserRecordList(
users,
map[uint64]int64{},
map[uint64]uint64{},
map[uint64]int64{},
map[uint64]walletmod.Wallet{},
map[uint64]int{},
map[uint64]int{},
)
if len(records) != 1 {
t.Fatalf("record count = %d, want 1", len(records))
}
if !records[0].DramaExpire.Equal(expire) {
t.Fatalf("dramaExpire = %s, want %s", records[0].DramaExpire, expire)
}
}
+19
View File
@@ -0,0 +1,19 @@
package userser
import (
"91porn-server/common/log"
"91porn-server/models/commod"
"91porn-server/models/v/faqmod"
)
// FaqList 常见问题列表
func FaqList(category string, keywords string, s commod.StdQuery) (data faqmod.FaqListRes, err error) {
result, total, err := faqmod.FaqListForSearch(category, keywords, s)
if err != nil {
log.Error("[METHOD]==>FaqList error", log.E(err))
return
}
data.List = result
data.Total = total
return
}
+85
View File
@@ -0,0 +1,85 @@
package userser
import (
"time"
"91porn-server/common/pageopt"
"91porn-server/models/l/visitlogmod"
"91porn-server/models/v/usermod"
"go.mongodb.org/mongo-driver/bson"
)
type UserInfo struct {
ID *ObjectID `json:"id,omitempty"`
UID *uint64 `json:"uid,omitempty"` //uid
CreatedAt *time.Time `json:"createdAt,omitempty"` //用户创建时间
HasLocked *bool `json:"hasLocked,omitempty"` //已禁止登陆
HasBanned *bool `json:"hasBanned,omitempty"` //已禁言
}
type LoginInfoRecord struct {
User UserInfo `json:"user,omitempty"`
DevID *string `json:"devID,omitempty"` //设备id
DevType *string `json:"devType,omitempty"` //设备类型
SysType *string `json:"sysType,omitempty"` //操作系统类型 安卓 IOS
BuildID *string `json:"buildID,omitempty"` //包ID
Ver *string `json:"ver,omitempty"` //APP版本号
IP *string `json:"ip,omitempty"` //最后登陆IP
LoginTime *time.Time `json:"loginTime,omitempty"` //用户登陆时间
}
type LoginInfoPage struct {
Total int64 `json:"total" bson:"total"`
List []LoginInfoRecord `json:"list" bson:"list"`
}
func LoginInfoPages(skip int64, limit int64, createdAtGTEAndLTMatch pageopt.CreatedAtGTEAndLTMatch, uidMatch pageopt.UIDMatch) (page LoginInfoPage, err error) {
//默认排序条件
sort := bson.D{{Key: "createdAt", Value: -1}}
//整理匹配条件
matList := []Matcher{createdAtGTEAndLTMatch.New(), uidMatch.New()}
//分页数据
logs, err := visitlogmod.List(sort, &skip, &limit, matList...)
if err != nil {
return LoginInfoPage{}, err
}
logsLen := len(logs)
uidList := make([]uint64, logsLen)
for i, v := range logs {
uidList[i] = v.UID
}
uInfoMap, err := usermod.UserMap(uidList)
if err != nil {
return LoginInfoPage{}, err
}
recordList := make([]LoginInfoRecord, logsLen)
for i, log := range logs {
_log := log
record := LoginInfoRecord{}
record.BuildID = &_log.BuildID
record.DevID = &_log.DevID
record.DevType = &_log.DevType
record.SysType = &_log.SysType
record.BuildID = &_log.BuildID
record.Ver = &_log.Ver
record.IP = &_log.IP
record.LoginTime = &_log.CreatedAt
if user, ok := uInfoMap[_log.UID]; ok {
record.User.ID = &user.ID
record.User.UID = &user.UID
record.User.CreatedAt = &user.CreatedAt
record.User.HasLocked = &user.HasLocked
record.User.HasBanned = &user.HasBanned
}
recordList[i] = record
}
count, err := visitlogmod.Count(matList...)
if err != nil {
return LoginInfoPage{}, err
}
return LoginInfoPage{
List: recordList,
Total: count,
}, nil
}
+210
View File
@@ -0,0 +1,210 @@
package userser
import (
"time"
"91porn-server/common/pageopt"
"91porn-server/models/v/reptmod"
"91porn-server/models/v/tagmod"
"91porn-server/models/v/usermod"
"91porn-server/models/v/vidmod"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type Matcher = pageopt.Matcher
type UIDMatch = pageopt.UIDMatch
// M M from Map
type M = bson.M
// D D from Doc
type D = bson.D
// A A from Array
type A = []interface{}
type ObjectID = primitive.ObjectID
type Tag struct {
ID *ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
Name *string `json:"name,omitempty" bson:"tagName,omitempty"` //标签名
}
type Video struct {
Title *string `json:"title,omitempty"` //标题
PublisherID *uint64 `json:"publisherID,omitempty"` //发布者ID
HasLocked bool `json:"hasLocked"` //发布者是否被封禁
Cover *string `json:"cover,omitempty"` //封面
SourceURL *string `json:"sourceURL,omitempty"` //资源地址
SourceID *string `json:"sourceID,omitempty"` //资源ID
Tags []Tag `json:"tags,omitempty"` //标签
}
type Comment struct {
ID *ObjectID `json:"id,omitempty"` //_id
UID *uint64 `json:"uid,omitempty"` //发表评论的 用户ID
Content *string `json:"content,omitempty"` //内容
}
type ReportedUser struct {
UID *uint64 `json:"uid,omitempty"` //被举报对用户ID
HasLocked *bool `json:"hasLocked,omitempty"` //已禁止登陆
HasBanned *bool `json:"hasBanned,omitempty"` //已禁言
}
type ReportInfoDoc struct {
ID *ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
UID *uint64 `json:"uid,omitempty" bson:"uid,omitempty"` //举报者ID
ObjType *reptmod.ReportObjType `json:"objType,omitempty" bson:"objType,omitempty"` //举报对象类型
ObjID *ObjectID `json:"objID,omitempty" bson:"objID,omitempty"` //举报对象ID
Types *string `json:"types,omitempty" bson:"types,omitempty"` //举报分类
CreatedAt *time.Time `json:"createdAt,omitempty" bson:"createdAt,omitempty"` //举报时间
Video Video `json:"video,omitempty" bson:"video,omitempty"` //视屏信息
Comment Comment `json:"comment,omitempty" bson:"comment,omitempty"` //评论信息
ReportedUser ReportedUser `json:"reportedUser,omitempty" bson:"reportedUser,omitempty"` //被举报的用户
ReptStatus *bool `json:"reptStatus,omitempty" bson:"reptStatus,omitempty"` //举报状态
}
type ReportInfoPage struct {
Total int64 `json:"total" bson:"total"`
List []ReportInfoDoc `json:"list" bson:"list"`
}
func ReportInfoPages(typesArray []reptmod.ReportObjType, sort D, skip int64, limit int64, uidMatch UIDMatch, typesMatch reptmod.TypesMatch, createdAtMatch reptmod.CreatedAtGTEAndLTMatch) (ReportInfoPage, error) {
inObjTypeMatch := reptmod.InObjTypeMatch{Typs: typesArray}
matList := []Matcher{
inObjTypeMatch.New(),
uidMatch.New(),
typesMatch.New(),
createdAtMatch.New(),
}
list, err := reptmod.List(sort, skip, limit, matList...)
if err != nil {
return ReportInfoPage{}, err
}
reportList, err := toReportInfoDocList(list)
if err != nil {
return ReportInfoPage{}, err
}
count, err := reptmod.Count(matList...)
if err != nil {
return ReportInfoPage{}, err
}
page := ReportInfoPage{
Total: count,
List: reportList,
}
return page, nil
}
func fillUser(doc *ReportInfoDoc, userMap map[uint64]*usermod.BaseInfo) {
if doc.ObjType == nil {
return
}
if *doc.ObjType != reptmod.User {
return
}
ruid := doc.ReportedUser.UID
if ruid == nil {
return
}
user, ok := userMap[*ruid]
if ok {
doc.ReportedUser.HasLocked = &user.HasLocked
doc.ReportedUser.HasBanned = &user.HasBanned
}
}
func fillVideo(doc *ReportInfoDoc, videoMap map[ObjectID]*vidmod.VideoModel, userMap map[uint64]*usermod.BaseInfo) {
if doc.ObjType == nil {
return
}
if *doc.ObjType != reptmod.Video {
return
}
vid := doc.ObjID
if vid == nil {
return
}
video, ok := videoMap[*vid]
if !ok {
return
}
publishID := video.PublisherID
hasLocked := false
user, ok := userMap[publishID]
if ok {
hasLocked = user.HasLocked
}
doc.Video.Title = &video.Title
doc.Video.Cover = &video.Cover
doc.Video.SourceURL = &video.SourceURL
doc.Video.SourceID = &video.SourceID
doc.Video.PublisherID = &publishID
doc.Video.HasLocked = hasLocked
tagMap, err := tagmod.TagMap(video.Tags)
if err != nil {
return
}
tagList := make([]Tag, len(tagMap))
i := 0
for _, tag := range tagMap {
tagList[i] = Tag{ID: &tag.ID, Name: &tag.TagName}
i++
}
doc.Video.Tags = tagList
}
func toReportInfoDocList(reportList []reptmod.Report) ([]ReportInfoDoc, error) {
reportListLen := len(reportList)
uidList := make([]uint64, reportListLen)
vidList := make([]ObjectID, 0, reportListLen)
for i, v := range reportList {
uidList[i] = v.UID
switch v.ObjType {
case reptmod.User:
if v.ObjUID != nil {
uidList = append(uidList, *v.ObjUID)
}
case reptmod.Video:
if v.ObjID != nil {
vidList = append(vidList, *v.ObjID)
}
}
}
videoMap, err := vidmod.VideoMap(vidList)
if err != nil {
return nil, err
}
//同时查询发布视频者的信息
for _, v := range videoMap {
uidList = append(uidList, v.PublisherID)
}
userMap, err := usermod.GetUsersBaseInfoMap(uidList)
if err != nil {
return nil, err
}
docList := make([]ReportInfoDoc, len(reportList))
for i, v := range reportList {
_v := v
doc := ReportInfoDoc{
ID: &_v.ID,
ObjType: &_v.ObjType,
UID: &_v.UID,
ReportedUser: ReportedUser{
UID: _v.ObjUID,
},
ObjID: _v.ObjID,
Types: &_v.Types,
ReptStatus: &_v.Status,
CreatedAt: &_v.CreatedAt,
}
fillUser(&doc, userMap)
fillVideo(&doc, videoMap, userMap)
docList[i] = doc
}
return docList, nil
}
File diff suppressed because it is too large Load Diff