package api import ( "agent-desk/internal/builders" "agent-desk/internal/models" "agent-desk/internal/pkg/config" "agent-desk/internal/pkg/dto/request" "agent-desk/internal/pkg/dto/response" "agent-desk/internal/pkg/enums" "agent-desk/internal/pkg/errorsx" "agent-desk/internal/pkg/httpx" "agent-desk/internal/pkg/httpx/params" "agent-desk/internal/repositories" "agent-desk/internal/services" "strings" "github.com/gin-gonic/gin" "github.com/mlogclub/simple/sqls" "github.com/mlogclub/simple/web" "github.com/spf13/cast" "gorm.io/gorm" ) func SupportAuthPostRegister(ctx *gin.Context) { cfg := config.Current() if !cfg.Auth.IsPasswordLoginEnabled() { httpx.WriteJSON(ctx, errorsx.ForbiddenI18n("error.auth.passwordLoginDisabled")) return } req := request.SupportCustomerRegisterRequest{} if err := params.ReadJSON(ctx, &req); err != nil { httpx.WriteJSON(ctx, err) return } ret, err := services.SupportService.RegisterUser(req, cfg.Auth, ctx.ClientIP(), ctx.GetHeader("User-Agent")) if err != nil { httpx.WriteJSON(ctx, err) return } httpx.WriteJSON(ctx, ret) } func SupportGetMe(ctx *gin.Context) { principal, err := services.SupportService.RequireSupportUser(ctx) if err != nil { httpx.WriteJSON(ctx, err) return } user := supportUser(principal.UserID) email := "" if user != nil && user.Email != nil { email = *user.Email } httpx.WriteJSON(ctx, response.SupportUserResponse{ID: principal.UserID, Name: supportPrincipalDisplayName(principal.UserID), Email: email, UserType: principal.UserType}) } func DocPageAnyList(ctx *gin.Context) { cnd := params.NewPagedSqlCnd(ctx, params.QueryFilter{ParamName: "parentId"}, params.QueryFilter{ParamName: "title", Op: params.Like}, ).Eq("status", enums.DocPageStatusPublished).Asc("sort_no").Desc("id") if keyword := strings.TrimSpace(ctx.Query("keyword")); keyword != "" { pattern := "%" + keyword + "%" cnd.Where("(title LIKE ? OR summary LIKE ? OR content LIKE ? OR tags_json LIKE ? OR slug LIKE ?)", pattern, pattern, pattern, pattern, pattern) } list, paging := repositories.DocPageRepository.FindPageByCnd(sqls.DB(), cnd) results := buildDocPageList(list, false) httpx.WriteJSON(ctx, &web.PageResult{Results: results, Page: paging}) } func DocPageGetNavigation(ctx *gin.Context) { list := services.SupportService.FindPublicDocNavigation() httpx.WriteJSON(ctx, builders.BuildDocPageNavigationTree(list)) } func DocPageGetBy(ctx *gin.Context) { id, ok := httpx.GetPathInt64(ctx, "id") if !ok { return } item := repositories.DocPageRepository.Get(sqls.DB(), id) if item == nil || item.Status != enums.DocPageStatusPublished { httpx.WriteJSON(ctx, httpx.JsonErrorMsg(ctx, "error.notFound")) return } _ = repositories.DocPageRepository.UpdateColumn(sqls.DB(), item.ID, "view_count", gorm.Expr("view_count + ?", 1)) httpx.WriteJSON(ctx, builders.BuildDocPage(item, true)) } func DocPagePostFeedback(ctx *gin.Context) { req := request.DocPageFeedbackRequest{} if err := params.ReadJSON(ctx, &req); err != nil { httpx.WriteJSON(ctx, err) return } httpx.WriteJSON(ctx, services.SupportService.FeedbackDocPage(req)) } func CategoryAnyList(ctx *gin.Context) { list := repositories.CategoryRepository.Find(sqls.DB(), sqls.NewCnd().Eq("status", enums.StatusOk).Asc("sort_no").Desc("id")) httpx.WriteJSON(ctx, builders.BuildPostCategories(list)) } func PostAnyList(ctx *gin.Context) { cursor, _ := params.GetInt64(ctx, "cursor") limit, _ := params.GetInt(ctx, "limit") if limit <= 0 || limit > 50 { limit = 20 } cnd := params.NewSqlCnd(ctx, params.QueryFilter{ParamName: "categoryId"}, params.QueryFilter{ParamName: "userId"}, params.QueryFilter{ParamName: "status"}, params.QueryFilter{ParamName: "title", Op: params.Like}, ).Where("status NOT IN ?", []enums.PostStatus{enums.PostStatusHidden, enums.PostStatusDeleted}).Desc("id").Limit(limit + 1) if cursor > 0 { cnd.Lt("id", cursor) } list := repositories.PostRepository.Find(sqls.DB(), cnd) hasMore := len(list) > limit if hasMore { list = list[:limit] } nextCursor := "" if hasMore && len(list) > 0 { nextCursor = cast.ToString(list[len(list)-1].ID) } httpx.WriteJSON(ctx, httpx.CursorData(buildPostList(list), nextCursor, hasMore)) } func PostGetBy(ctx *gin.Context) { id, ok := httpx.GetPathInt64(ctx, "id") if !ok { return } post := repositories.PostRepository.Get(sqls.DB(), id) if post == nil || post.Status == enums.PostStatusHidden || post.Status == enums.PostStatusDeleted { httpx.WriteJSON(ctx, httpx.JsonErrorMsg(ctx, "error.notFound")) return } _ = repositories.PostRepository.UpdateColumn(sqls.DB(), post.ID, "view_count", gorm.Expr("view_count + ?", 1)) comments, err := services.SupportService.ListPostComments(id, 0, "default", 1, 20) if err != nil { httpx.WriteJSON(ctx, err) return } httpx.WriteJSON(ctx, response.PostDetailResponse{Post: *builders.BuildPost(post, supportCategoryName(post.CategoryID), supportUser(post.UserID)), Comments: buildCommentListWithReplies(comments.Comments, comments.Replies)}) } func PostPostCreate(ctx *gin.Context) { principal, err := services.SupportService.RequireSupportUser(ctx) if err != nil { httpx.WriteJSON(ctx, err) return } req := request.CreatePostRequest{} if err := params.ReadJSON(ctx, &req); err != nil { httpx.WriteJSON(ctx, err) return } item, err := services.SupportService.CreatePost(req, principal) if err != nil { httpx.WriteJSON(ctx, err) return } httpx.WriteJSON(ctx, builders.BuildPost(item, supportCategoryName(item.CategoryID), supportUser(principal.UserID))) } func PostPostUpdate(ctx *gin.Context) { principal, err := services.SupportService.RequireSupportUser(ctx) if err != nil { httpx.WriteJSON(ctx, err) return } req := request.UpdatePostRequest{} if err := params.ReadJSON(ctx, &req); err != nil { httpx.WriteJSON(ctx, err) return } httpx.WriteJSON(ctx, services.SupportService.UpdatePost(req, principal)) } func PostPostAcceptComment(ctx *gin.Context) { principal, err := services.SupportService.RequireSupportUser(ctx) if err != nil { httpx.WriteJSON(ctx, err) return } req := request.AcceptCommentRequest{} if err := params.ReadJSON(ctx, &req); err != nil { httpx.WriteJSON(ctx, err) return } httpx.WriteJSON(ctx, services.SupportService.AcceptComment(req, principal, nil)) } func CommentPostCreate(ctx *gin.Context) { principal, err := services.SupportService.RequireSupportUser(ctx) if err != nil { httpx.WriteJSON(ctx, err) return } req := request.CreateCommentRequest{} if err := params.ReadJSON(ctx, &req); err != nil { httpx.WriteJSON(ctx, err) return } item, err := services.SupportService.CreateCustomerComment(req, principal) if err != nil { httpx.WriteJSON(ctx, err) return } httpx.WriteJSON(ctx, builders.BuildComment(item, supportPrincipalDisplayName(principal.UserID))) } func CommentAnyList(ctx *gin.Context) { postID, _ := params.GetInt64(ctx, "postId") parentID, _ := params.GetInt64(ctx, "parentId") page, _ := params.GetInt(ctx, "page") limit, _ := params.GetInt(ctx, "limit") sort, _ := params.Get(ctx, "sort") result, err := services.SupportService.ListPostComments(postID, parentID, sort, page, limit) if err != nil { httpx.WriteJSON(ctx, err) return } httpx.WriteJSON(ctx, &web.PageResult{Results: buildCommentListWithReplies(result.Comments, result.Replies), Page: result.Paging}) } func CommentPostUpdate(ctx *gin.Context) { principal, err := services.SupportService.RequireSupportUser(ctx) if err != nil { httpx.WriteJSON(ctx, err) return } req := request.UpdateCommentRequest{} if err := params.ReadJSON(ctx, &req); err != nil { httpx.WriteJSON(ctx, err) return } httpx.WriteJSON(ctx, services.SupportService.UpdateComment(req, principal)) } func CommentPostDelete(ctx *gin.Context) { principal, err := services.SupportService.RequireSupportUser(ctx) if err != nil { httpx.WriteJSON(ctx, err) return } req := request.IDRequest{} if err := params.ReadJSON(ctx, &req); err != nil { httpx.WriteJSON(ctx, err) return } httpx.WriteJSON(ctx, services.SupportService.DeleteComment(req.ID, principal)) } func CommentPostReport(ctx *gin.Context) { principal, err := services.SupportService.RequireSupportUser(ctx) if err != nil { httpx.WriteJSON(ctx, err) return } req := request.ReportCommentRequest{} if err := params.ReadJSON(ctx, &req); err != nil { httpx.WriteJSON(ctx, err) return } httpx.WriteJSON(ctx, services.SupportService.ReportComment(req, principal)) } func ReactionPostToggle(ctx *gin.Context) { principal, err := services.SupportService.RequireSupportUser(ctx) if err != nil { httpx.WriteJSON(ctx, err) return } req := request.ReactionRequest{} if err := params.ReadJSON(ctx, &req); err != nil { httpx.WriteJSON(ctx, err) return } httpx.WriteJSON(ctx, services.SupportService.ToggleReaction(req.TargetType, req.TargetID, req.ReactionType, principal)) } func buildDocPageList(list []models.DocPage, includeContent bool) []response.DocPageResponse { results := make([]response.DocPageResponse, 0, len(list)) for _, item := range list { if resp := builders.BuildDocPage(&item, includeContent); resp != nil { results = append(results, *resp) } } return results } func buildPostList(list []models.Post) []response.PostResponse { results := make([]response.PostResponse, 0, len(list)) for _, item := range list { if resp := builders.BuildPost(&item, supportCategoryName(item.CategoryID), supportUser(item.UserID)); resp != nil { results = append(results, *resp) } } return results } func buildCommentList(list []models.Comment) []response.CommentResponse { return buildCommentListWithReplies(list, nil) } func buildCommentListWithReplies(list []models.Comment, replies map[int64][]models.Comment) []response.CommentResponse { results := make([]response.CommentResponse, 0, len(list)) for _, item := range list { if resp := builders.BuildComment(&item, supportCommentAuthorName(item)); resp != nil { if len(replies[item.ID]) > 0 { resp.Replies = buildCommentListWithReplies(replies[item.ID], nil) } results = append(results, *resp) } } return results } func supportCategoryName(id int64) string { item := repositories.CategoryRepository.Get(sqls.DB(), id) if item == nil { return "" } return item.Name } func supportUser(id int64) *models.User { return repositories.UserRepository.Get(sqls.DB(), id) } func supportPrincipalDisplayName(id int64) string { user := supportUser(id) if user == nil { return "" } if user.Nickname != "" { return user.Nickname } return user.Username } func supportCommentAuthorName(item models.Comment) string { user := repositories.UserRepository.Get(sqls.DB(), item.AuthorID) if user == nil { return "" } if user.Nickname != "" { return user.Nickname } return user.Username }