lv8girl!
This commit is contained in:
98
internal/services/admin.go
Normal file
98
internal/services/admin.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"lv8girl/internal/models"
|
||||
"lv8girl/internal/repositories"
|
||||
)
|
||||
|
||||
type AdminService struct {
|
||||
userRepo *repositories.UserRepository
|
||||
discussionRepo *repositories.DiscussionRepository
|
||||
commentRepo *repositories.CommentRepository
|
||||
likeRepo *repositories.LikeRepository
|
||||
}
|
||||
|
||||
func NewAdminService() *AdminService {
|
||||
return &AdminService{
|
||||
userRepo: repositories.NewUserRepository(),
|
||||
discussionRepo: repositories.NewDiscussionRepository(),
|
||||
commentRepo: repositories.NewCommentRepository(),
|
||||
likeRepo: repositories.NewLikeRepository(),
|
||||
}
|
||||
}
|
||||
|
||||
type Stats struct {
|
||||
Posts int64
|
||||
Users int64
|
||||
Comments int64
|
||||
Likes int64
|
||||
Online int64
|
||||
Approved int64
|
||||
Rejected int64
|
||||
Pending int64
|
||||
}
|
||||
|
||||
func (s *AdminService) GetStats() (*Stats, error) {
|
||||
stats := &Stats{}
|
||||
stats.Posts, _ = s.discussionRepo.Count()
|
||||
stats.Users, _ = s.userRepo.Count()
|
||||
stats.Comments, _ = s.commentRepo.Count()
|
||||
stats.Likes, _ = s.likeRepo.Count()
|
||||
stats.Online, _ = s.userRepo.CountOnline()
|
||||
stats.Approved, _ = s.discussionRepo.CountByStatus("approved")
|
||||
stats.Rejected, _ = s.discussionRepo.CountByStatus("rejected")
|
||||
stats.Pending, _ = s.discussionRepo.CountByStatus("pending")
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func (s *AdminService) GetPendingPosts() ([]models.Discussion, error) {
|
||||
return s.discussionRepo.FindPending()
|
||||
}
|
||||
|
||||
func (s *AdminService) GetPendingUsers() ([]models.User, error) {
|
||||
return s.userRepo.FindPending()
|
||||
}
|
||||
|
||||
func (s *AdminService) ApprovePost(id uint) error {
|
||||
return s.discussionRepo.UpdateStatus(id, "approved")
|
||||
}
|
||||
|
||||
func (s *AdminService) RejectPost(id uint) error {
|
||||
return s.discussionRepo.UpdateStatus(id, "rejected")
|
||||
}
|
||||
|
||||
func (s *AdminService) DeletePost(id uint) error {
|
||||
return s.discussionRepo.Delete(id)
|
||||
}
|
||||
|
||||
func (s *AdminService) ApproveUser(id uint) error {
|
||||
return s.userRepo.UpdateField(id, "status", "approved")
|
||||
}
|
||||
|
||||
func (s *AdminService) RejectUser(id uint) error {
|
||||
return s.userRepo.UpdateField(id, "status", "rejected")
|
||||
}
|
||||
|
||||
func (s *AdminService) UpdateUserRole(id uint, role string) error {
|
||||
return s.userRepo.UpdateField(id, "role", role)
|
||||
}
|
||||
|
||||
func (s *AdminService) DeleteUser(id uint) error {
|
||||
return s.userRepo.Delete(id)
|
||||
}
|
||||
|
||||
func (s *AdminService) GetAllPosts() ([]models.Discussion, error) {
|
||||
return s.discussionRepo.FindAll()
|
||||
}
|
||||
|
||||
func (s *AdminService) GetAllUsers() ([]models.User, error) {
|
||||
return s.userRepo.FindAll()
|
||||
}
|
||||
|
||||
func (s *AdminService) GetAllComments() ([]models.Comment, error) {
|
||||
return s.commentRepo.FindAll()
|
||||
}
|
||||
|
||||
func (s *AdminService) DeleteComment(id uint) error {
|
||||
return s.commentRepo.Delete(id)
|
||||
}
|
||||
87
internal/services/auth.go
Normal file
87
internal/services/auth.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"lv8girl/internal/models"
|
||||
"lv8girl/internal/repositories"
|
||||
)
|
||||
|
||||
type AuthService struct {
|
||||
userRepo *repositories.UserRepository
|
||||
}
|
||||
|
||||
func NewAuthService() *AuthService {
|
||||
return &AuthService{
|
||||
userRepo: repositories.NewUserRepository(),
|
||||
}
|
||||
}
|
||||
|
||||
type LoginResult struct {
|
||||
Success bool
|
||||
User *models.User
|
||||
Error string
|
||||
}
|
||||
|
||||
func (s *AuthService) Login(login, password string) LoginResult {
|
||||
user, err := s.userRepo.FindByUsernameOrEmail(login)
|
||||
if err != nil {
|
||||
return LoginResult{Success: false, Error: "用户名/邮箱或密码错误"}
|
||||
}
|
||||
|
||||
if !s.userRepo.CheckPassword(password, user.PasswordHash) {
|
||||
return LoginResult{Success: false, Error: "用户名/邮箱或密码错误"}
|
||||
}
|
||||
|
||||
switch user.Status {
|
||||
case "pending":
|
||||
return LoginResult{Success: false, Error: "您的账号正在等待管理员审核,请耐心等待。"}
|
||||
case "rejected":
|
||||
return LoginResult{Success: false, Error: "您的账号审核未通过,无法登录。如有疑问,请联系管理员。"}
|
||||
case "approved":
|
||||
if user.Role == "banned" {
|
||||
return LoginResult{Success: false, Error: "您的账号已被封禁,请联系管理员"}
|
||||
}
|
||||
default:
|
||||
return LoginResult{Success: false, Error: "账号状态异常,请联系管理员"}
|
||||
}
|
||||
|
||||
s.userRepo.UpdateLastActive(user.ID)
|
||||
return LoginResult{Success: true, User: user}
|
||||
}
|
||||
|
||||
type RegisterResult struct {
|
||||
Success bool
|
||||
Error string
|
||||
}
|
||||
|
||||
func (s *AuthService) Register(username, email, password string) RegisterResult {
|
||||
if len(username) < 3 || len(username) > 20 {
|
||||
return RegisterResult{Success: false, Error: "用户名长度必须在3-20个字符之间"}
|
||||
}
|
||||
|
||||
if s.userRepo.ExistsByUsernameOrEmail(username, email) {
|
||||
return RegisterResult{Success: false, Error: "用户名或邮箱已被注册"}
|
||||
}
|
||||
|
||||
passwordHash, err := s.userRepo.HashPassword(password)
|
||||
if err != nil {
|
||||
return RegisterResult{Success: false, Error: "注册失败,请稍后重试"}
|
||||
}
|
||||
|
||||
user := &models.User{
|
||||
Username: username,
|
||||
Email: email,
|
||||
PasswordHash: passwordHash,
|
||||
Role: "user",
|
||||
Status: "pending",
|
||||
}
|
||||
|
||||
if err := s.userRepo.Create(user); err != nil {
|
||||
return RegisterResult{Success: false, Error: "注册失败,请稍后重试"}
|
||||
}
|
||||
|
||||
return RegisterResult{Success: true}
|
||||
}
|
||||
|
||||
func (s *AuthService) InitAdmin() error {
|
||||
return s.userRepo.CreateAdminIfNotExists()
|
||||
}
|
||||
92
internal/services/discussion.go
Normal file
92
internal/services/discussion.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"lv8girl/internal/models"
|
||||
"lv8girl/internal/repositories"
|
||||
)
|
||||
|
||||
type DiscussionService struct {
|
||||
discussionRepo *repositories.DiscussionRepository
|
||||
likeRepo *repositories.LikeRepository
|
||||
commentRepo *repositories.CommentRepository
|
||||
}
|
||||
|
||||
func NewDiscussionService() *DiscussionService {
|
||||
return &DiscussionService{
|
||||
discussionRepo: repositories.NewDiscussionRepository(),
|
||||
likeRepo: repositories.NewLikeRepository(),
|
||||
commentRepo: repositories.NewCommentRepository(),
|
||||
}
|
||||
}
|
||||
|
||||
type PostDetailView struct {
|
||||
Post *models.Discussion
|
||||
LikeCount int64
|
||||
CommentCount int64
|
||||
UserLiked bool
|
||||
AuthorPostCount int64
|
||||
}
|
||||
|
||||
func (s *DiscussionService) GetPostDetail(postID, userID uint) (*PostDetailView, error) {
|
||||
post, err := s.discussionRepo.FindByID(postID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
likeCount, _ := s.likeRepo.CountByPostID(postID)
|
||||
commentCount, _ := s.commentRepo.CountByPostID(postID)
|
||||
userLiked := s.likeRepo.Exists(postID, userID)
|
||||
authorPostCount, _ := s.discussionRepo.CountByUserID(post.UserID)
|
||||
|
||||
return &PostDetailView{
|
||||
Post: post,
|
||||
LikeCount: likeCount,
|
||||
CommentCount: commentCount,
|
||||
UserLiked: userLiked,
|
||||
AuthorPostCount: authorPostCount,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *DiscussionService) IncrementViews(postID uint) error {
|
||||
return s.discussionRepo.IncrementViews(postID)
|
||||
}
|
||||
|
||||
func (s *DiscussionService) AddLike(postID, userID uint) error {
|
||||
if s.likeRepo.Exists(postID, userID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
like := &models.Like{
|
||||
PostID: postID,
|
||||
UserID: userID,
|
||||
}
|
||||
return s.likeRepo.Create(like)
|
||||
}
|
||||
|
||||
func (s *DiscussionService) AddComment(postID, userID uint, content string) error {
|
||||
comment := &models.Comment{
|
||||
PostID: postID,
|
||||
UserID: userID,
|
||||
Content: content,
|
||||
}
|
||||
return s.commentRepo.Create(comment)
|
||||
}
|
||||
|
||||
func (s *DiscussionService) GetComments(postID uint) ([]models.Comment, error) {
|
||||
return s.commentRepo.FindByPostID(postID)
|
||||
}
|
||||
|
||||
func (s *DiscussionService) CreatePost(userID uint, title, content, imagePath string) error {
|
||||
post := &models.Discussion{
|
||||
UserID: userID,
|
||||
Title: title,
|
||||
Content: content,
|
||||
ImagePath: imagePath,
|
||||
Status: "pending",
|
||||
}
|
||||
return s.discussionRepo.Create(post)
|
||||
}
|
||||
|
||||
func (s *DiscussionService) GetApprovedPosts(limit int) ([]repositories.PostListItem, error) {
|
||||
return s.discussionRepo.GetPostList(limit)
|
||||
}
|
||||
97
internal/services/message.go
Normal file
97
internal/services/message.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"lv8girl/internal/models"
|
||||
"lv8girl/internal/repositories"
|
||||
)
|
||||
|
||||
type MessageService struct {
|
||||
messageRepo *repositories.MessageRepository
|
||||
userRepo *repositories.UserRepository
|
||||
}
|
||||
|
||||
func NewMessageService() *MessageService {
|
||||
return &MessageService{
|
||||
messageRepo: repositories.NewMessageRepository(),
|
||||
userRepo: repositories.NewUserRepository(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *MessageService) SendMessage(fromUserID, toUserID uint, content string) error {
|
||||
message := &models.PrivateMessage{
|
||||
FromUserID: fromUserID,
|
||||
ToUserID: toUserID,
|
||||
Content: content,
|
||||
IsRead: false,
|
||||
}
|
||||
return s.messageRepo.Create(message)
|
||||
}
|
||||
|
||||
func (s *MessageService) GetUnreadCount(userID uint) (int64, error) {
|
||||
return s.messageRepo.CountUnread(userID)
|
||||
}
|
||||
|
||||
type ConversationView struct {
|
||||
UserID uint
|
||||
Username string
|
||||
Avatar string
|
||||
LastMsg string
|
||||
Time string
|
||||
Unread int64
|
||||
}
|
||||
|
||||
func (s *MessageService) GetConversations(userID uint) ([]ConversationView, error) {
|
||||
messages, err := s.messageRepo.FindConversations(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userMap := make(map[uint]bool)
|
||||
for _, msg := range messages {
|
||||
if msg.FromUserID != userID {
|
||||
userMap[msg.FromUserID] = true
|
||||
}
|
||||
if msg.ToUserID != userID {
|
||||
userMap[msg.ToUserID] = true
|
||||
}
|
||||
}
|
||||
|
||||
var conversations []ConversationView
|
||||
for otherID := range userMap {
|
||||
otherUser, err := s.userRepo.FindByID(otherID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
lastMsg, _ := s.messageRepo.FindLastMessage(userID, otherID)
|
||||
unread, _ := s.messageRepo.CountUnreadFromUser(otherID, userID)
|
||||
|
||||
avatar := ""
|
||||
if otherUser.Avatar != "" {
|
||||
avatar = "/" + otherUser.Avatar
|
||||
}
|
||||
|
||||
conversations = append(conversations, ConversationView{
|
||||
UserID: otherUser.ID,
|
||||
Username: otherUser.Username,
|
||||
Avatar: avatar,
|
||||
LastMsg: lastMsg.Content,
|
||||
Time: lastMsg.CreatedAt.Format("2006-01-02 15:04"),
|
||||
Unread: unread,
|
||||
})
|
||||
}
|
||||
|
||||
return conversations, nil
|
||||
}
|
||||
|
||||
func (s *MessageService) NotifyUserApproved(adminID, userID uint) error {
|
||||
return s.SendMessage(adminID, userID, "恭喜!您的账号已通过管理员审核,现在可以正常登录使用了。")
|
||||
}
|
||||
|
||||
func (s *MessageService) NotifyUserRejected(adminID, userID uint) error {
|
||||
return s.SendMessage(adminID, userID, "您的账号审核未通过。如有疑问,请联系管理员。")
|
||||
}
|
||||
|
||||
func (s *MessageService) NotifyUserBanned(adminID, userID uint) error {
|
||||
return s.SendMessage(adminID, userID, "您的账号已被管理员封禁。如有疑问,请联系管理员。")
|
||||
}
|
||||
94
internal/services/user.go
Normal file
94
internal/services/user.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"lv8girl/internal/models"
|
||||
"lv8girl/internal/repositories"
|
||||
)
|
||||
|
||||
type UserService struct {
|
||||
userRepo *repositories.UserRepository
|
||||
discussionRepo *repositories.DiscussionRepository
|
||||
commentRepo *repositories.CommentRepository
|
||||
messageRepo *repositories.MessageRepository
|
||||
}
|
||||
|
||||
func NewUserService() *UserService {
|
||||
return &UserService{
|
||||
userRepo: repositories.NewUserRepository(),
|
||||
discussionRepo: repositories.NewDiscussionRepository(),
|
||||
commentRepo: repositories.NewCommentRepository(),
|
||||
messageRepo: repositories.NewMessageRepository(),
|
||||
}
|
||||
}
|
||||
|
||||
type UserProfileView struct {
|
||||
User *models.User
|
||||
Posts []models.Discussion
|
||||
PostCount int64
|
||||
UnreadCount int64
|
||||
IsOwner bool
|
||||
}
|
||||
|
||||
func (s *UserService) GetUserProfile(viewerID, targetUserID uint) (*UserProfileView, error) {
|
||||
user, err := s.userRepo.FindByID(targetUserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
posts, _ := s.discussionRepo.FindByUserID(targetUserID)
|
||||
postCount, _ := s.discussionRepo.CountByUserID(targetUserID)
|
||||
|
||||
var unreadCount int64
|
||||
if viewerID != 0 {
|
||||
unreadCount, _ = s.messageRepo.CountUnread(viewerID)
|
||||
}
|
||||
|
||||
return &UserProfileView{
|
||||
User: user,
|
||||
Posts: posts,
|
||||
PostCount: postCount,
|
||||
UnreadCount: unreadCount,
|
||||
IsOwner: viewerID == targetUserID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *UserService) UpdateAvatar(userID uint, avatarPath string) error {
|
||||
user, err := s.userRepo.FindByID(userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.userRepo.UpdateField(user.ID, "avatar", avatarPath)
|
||||
}
|
||||
|
||||
func (s *UserService) GetUserByID(id uint) (*models.User, error) {
|
||||
return s.userRepo.FindByID(id)
|
||||
}
|
||||
|
||||
func (s *UserService) UpdateUserStatus(id uint, status string) error {
|
||||
return s.userRepo.UpdateField(id, "status", status)
|
||||
}
|
||||
|
||||
func (s *UserService) UpdateUserRole(id uint, role string) error {
|
||||
return s.userRepo.UpdateField(id, "role", role)
|
||||
}
|
||||
|
||||
func (s *UserService) DeleteUser(id uint) error {
|
||||
return s.userRepo.Delete(id)
|
||||
}
|
||||
|
||||
func (s *UserService) GetPendingUsers() ([]models.User, error) {
|
||||
return s.userRepo.FindPending()
|
||||
}
|
||||
|
||||
func (s *UserService) GetAllUsers() ([]models.User, error) {
|
||||
return s.userRepo.FindAll()
|
||||
}
|
||||
|
||||
func (s *UserService) GetUserStats() (int64, int64, error) {
|
||||
total, err := s.userRepo.Count()
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
online, err := s.userRepo.CountOnline()
|
||||
return total, online, err
|
||||
}
|
||||
Reference in New Issue
Block a user