package controller import ( "netidhub-saas-be/app/module/article_approval_flows/request" "netidhub-saas-be/app/module/article_approval_flows/service" usersRepository "netidhub-saas-be/app/module/users/repository" "netidhub-saas-be/utils/paginator" utilSvc "netidhub-saas-be/utils/service" "strconv" "github.com/gofiber/fiber/v2" "github.com/rs/zerolog" utilRes "netidhub-saas-be/utils/response" utilVal "netidhub-saas-be/utils/validator" ) type articleApprovalFlowsController struct { articleApprovalFlowsService service.ArticleApprovalFlowsService UsersRepo usersRepository.UsersRepository Log zerolog.Logger } type ArticleApprovalFlowsController interface { All(c *fiber.Ctx) error Show(c *fiber.Ctx) error SubmitForApproval(c *fiber.Ctx) error Approve(c *fiber.Ctx) error Reject(c *fiber.Ctx) error RequestRevision(c *fiber.Ctx) error Resubmit(c *fiber.Ctx) error GetMyApprovalQueue(c *fiber.Ctx) error GetPendingApprovals(c *fiber.Ctx) error GetApprovalHistory(c *fiber.Ctx) error GetDashboardStats(c *fiber.Ctx) error GetWorkloadStats(c *fiber.Ctx) error GetApprovalAnalytics(c *fiber.Ctx) error } func NewArticleApprovalFlowsController(articleApprovalFlowsService service.ArticleApprovalFlowsService, usersRepo usersRepository.UsersRepository, log zerolog.Logger) ArticleApprovalFlowsController { return &articleApprovalFlowsController{ articleApprovalFlowsService: articleApprovalFlowsService, UsersRepo: usersRepo, Log: log, } } // All ArticleApprovalFlows // @Summary Get all ArticleApprovalFlows // @Description API for getting all ArticleApprovalFlows // @Tags ArticleApprovalFlows // @Security Bearer // @Param Authorization header string true "Insert the Authorization" // @Param req query request.ArticleApprovalFlowsQueryRequest false "query parameters" // @Param req query paginator.Pagination false "pagination parameters" // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError // @Failure 401 {object} response.UnauthorizedError // @Failure 500 {object} response.InternalServerError // @Router /article-approval-flows [get] func (_i *articleApprovalFlowsController) All(c *fiber.Ctx) error { paginate, err := paginator.Paginate(c) if err != nil { return err } reqContext := request.ArticleApprovalFlowsQueryRequestContext{ ArticleId: c.Query("articleId"), WorkflowId: c.Query("workflowId"), StatusId: c.Query("statusId"), SubmittedBy: c.Query("submittedBy"), CurrentStep: c.Query("currentStep"), DateFrom: c.Query("dateFrom"), DateTo: c.Query("dateTo"), } req := reqContext.ToParamRequest() req.Pagination = paginate // Get Authorization token from header authToken := c.Get("Authorization") _i.Log.Info().Interface("authToken", authToken).Msg("") articleApprovalFlowsData, paging, err := _i.articleApprovalFlowsService.GetAll(authToken, req) if err != nil { return err } return utilRes.Resp(c, utilRes.Response{ Success: true, Messages: utilRes.Messages{"ArticleApprovalFlows list successfully retrieved"}, Data: articleApprovalFlowsData, Meta: paging, }) } // Show ArticleApprovalFlows // @Summary Get one ArticleApprovalFlows // @Description API for getting one ArticleApprovalFlows // @Tags ArticleApprovalFlows // @Security Bearer // @Param Authorization header string true "Insert the Authorization" // @Param id path int true "ArticleApprovalFlows ID" // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError // @Failure 401 {object} response.UnauthorizedError // @Failure 500 {object} response.InternalServerError // @Router /article-approval-flows/{id} [get] func (_i *articleApprovalFlowsController) Show(c *fiber.Ctx) error { id, err := strconv.Atoi(c.Params("id")) if err != nil { return utilRes.ErrorBadRequest(c, "Invalid ID format") } // Get Authorization token from header authToken := c.Get("Authorization") articleApprovalFlowsData, err := _i.articleApprovalFlowsService.FindOne(authToken, uint(id)) if err != nil { return err } return utilRes.Resp(c, utilRes.Response{ Success: true, Messages: utilRes.Messages{"ArticleApprovalFlows successfully retrieved"}, Data: articleApprovalFlowsData, }) } // SubmitForApproval ArticleApprovalFlows // @Summary Submit article for approval // @Description API for submitting article for approval // @Tags ArticleApprovalFlows // @Security Bearer // @Param Authorization header string true "Insert the Authorization" // @Param Authorization header string false "Insert your access token" default(Bearer ) // @Param req body request.SubmitForApprovalRequest true "Submit for approval data" // @Success 201 {object} response.Response // @Failure 400 {object} response.BadRequestError // @Failure 401 {object} response.UnauthorizedError // @Failure 500 {object} response.InternalServerError // @Router /article-approval-flows/submit [post] func (_i *articleApprovalFlowsController) SubmitForApproval(c *fiber.Ctx) error { req := new(request.SubmitForApprovalRequest) if err := c.BodyParser(req); err != nil { return utilRes.ErrorBadRequest(c, "Invalid request body") } if err := utilVal.ParseAndValidate(c, req); err != nil { return err } // Get Authorization token from header and extract user ID authToken := c.Get("Authorization") if authToken == "" { return utilRes.ErrorBadRequest(c, "Authorization token required") } user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user == nil { return utilRes.ErrorBadRequest(c, "Invalid authorization token") } var workflowId *uint if req.WorkflowId != nil { workflowIdVal := uint(*req.WorkflowId) workflowId = &workflowIdVal } articleApprovalFlowsData, err := _i.articleApprovalFlowsService.SubmitArticleForApproval(authToken, uint(req.ArticleId), user.ID, workflowId) if err != nil { return err } return utilRes.Resp(c, utilRes.Response{ Success: true, Messages: utilRes.Messages{"Article successfully submitted for approval"}, Data: articleApprovalFlowsData, }) } // Approve ArticleApprovalFlows // @Summary Approve article // @Description API for approving article // @Tags ArticleApprovalFlows // @Security Bearer // @Param Authorization header string true "Insert the Authorization" // @Param Authorization header string false "Insert your access token" default(Bearer ) // @Param id path int true "ArticleApprovalFlows ID" // @Param req body request.ApprovalActionRequest true "Approval action data" // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError // @Failure 401 {object} response.UnauthorizedError // @Failure 500 {object} response.InternalServerError // @Router /article-approval-flows/{id}/approve [put] func (_i *articleApprovalFlowsController) Approve(c *fiber.Ctx) error { id, err := strconv.Atoi(c.Params("id")) if err != nil { return utilRes.ErrorBadRequest(c, "Invalid ID format") } req := new(request.ApprovalActionRequest) if err := c.BodyParser(req); err != nil { return utilRes.ErrorBadRequest(c, "Invalid request body") } if err := utilVal.ParseAndValidate(c, req); err != nil { return err } // Get Authorization token from header authToken := c.Get("Authorization") if authToken == "" { return utilRes.ErrorBadRequest(c, "Authorization token required") } user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user == nil { return utilRes.ErrorBadRequest(c, "Invalid authorization token") } err = _i.articleApprovalFlowsService.ApproveStep(authToken, uint(id), user.ID, req.Message) if err != nil { return err } return utilRes.Resp(c, utilRes.Response{ Success: true, Messages: utilRes.Messages{"Article successfully approved"}, Data: nil, }) } // Reject ArticleApprovalFlows // @Summary Reject article // @Description API for rejecting article // @Tags ArticleApprovalFlows // @Security Bearer // @Param Authorization header string true "Insert the Authorization" // @Param Authorization header string false "Insert your access token" default(Bearer ) // @Param id path int true "ArticleApprovalFlows ID" // @Param req body request.RejectionRequest true "Rejection data" // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError // @Failure 401 {object} response.UnauthorizedError // @Failure 500 {object} response.InternalServerError // @Router /article-approval-flows/{id}/reject [put] func (_i *articleApprovalFlowsController) Reject(c *fiber.Ctx) error { id, err := strconv.Atoi(c.Params("id")) if err != nil { return utilRes.ErrorBadRequest(c, "Invalid ID format") } req := new(request.RejectionRequest) if err := c.BodyParser(req); err != nil { return utilRes.ErrorBadRequest(c, "Invalid request body") } if err := utilVal.ParseAndValidate(c, req); err != nil { return err } // Get Authorization token from header authToken := c.Get("Authorization") if authToken == "" { return utilRes.ErrorBadRequest(c, "Authorization token required") } user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user == nil { return utilRes.ErrorBadRequest(c, "Invalid authorization token") } err = _i.articleApprovalFlowsService.RejectArticle(authToken, uint(id), user.ID, req.Reason) if err != nil { return err } return utilRes.Resp(c, utilRes.Response{ Success: true, Messages: utilRes.Messages{"Article successfully rejected"}, Data: nil, }) } // RequestRevision ArticleApprovalFlows // @Summary Request revision for article // @Description API for requesting revision for article // @Tags ArticleApprovalFlows // @Security Bearer // @Param Authorization header string true "Insert the Authorization" // @Param Authorization header string false "Insert your access token" default(Bearer ) // @Param id path int true "ArticleApprovalFlows ID" // @Param req body request.RevisionRequest true "Revision request data" // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError // @Failure 401 {object} response.UnauthorizedError // @Failure 500 {object} response.InternalServerError // @Router /article-approval-flows/{id}/request-revision [put] func (_i *articleApprovalFlowsController) RequestRevision(c *fiber.Ctx) error { id, err := strconv.Atoi(c.Params("id")) if err != nil { return utilRes.ErrorBadRequest(c, "Invalid ID format") } req := new(request.RevisionRequest) if err := c.BodyParser(req); err != nil { return utilRes.ErrorBadRequest(c, "Invalid request body") } if err := utilVal.ParseAndValidate(c, req); err != nil { return err } // Get Authorization token from header authToken := c.Get("Authorization") if authToken == "" { return utilRes.ErrorBadRequest(c, "Authorization token required") } user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user == nil { return utilRes.ErrorBadRequest(c, "Invalid authorization token") } err = _i.articleApprovalFlowsService.RequestRevision(authToken, uint(id), user.ID, req.Message) if err != nil { return err } return utilRes.Resp(c, utilRes.Response{ Success: true, Messages: utilRes.Messages{"Revision successfully requested"}, Data: nil, }) } // Resubmit ArticleApprovalFlows // @Summary Resubmit article after revision // @Description API for resubmitting article after revision // @Tags ArticleApprovalFlows // @Security Bearer // @Param Authorization header string true "Insert the Authorization" // @Param Authorization header string false "Insert your access token" default(Bearer ) // @Param id path int true "ArticleApprovalFlows ID" // @Param req body request.ResubmitRequest true "Resubmit data" // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError // @Failure 401 {object} response.UnauthorizedError // @Failure 500 {object} response.InternalServerError // @Router /article-approval-flows/{id}/resubmit [put] func (_i *articleApprovalFlowsController) Resubmit(c *fiber.Ctx) error { id, err := strconv.Atoi(c.Params("id")) if err != nil { return utilRes.ErrorBadRequest(c, "Invalid ID format") } req := new(request.ResubmitRequest) if err := c.BodyParser(req); err != nil { return utilRes.ErrorBadRequest(c, "Invalid request body") } if err := utilVal.ParseAndValidate(c, req); err != nil { return err } // Get Authorization token from header authToken := c.Get("Authorization") if authToken == "" { return utilRes.ErrorBadRequest(c, "Authorization token required") } user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user == nil { return utilRes.ErrorBadRequest(c, "Invalid authorization token") } err = _i.articleApprovalFlowsService.ResubmitAfterRevision(authToken, uint(id), user.ID) if err != nil { return err } return utilRes.Resp(c, utilRes.Response{ Success: true, Messages: utilRes.Messages{"Article successfully resubmitted"}, Data: nil, }) } // GetMyApprovalQueue ArticleApprovalFlows // @Summary Get my approval queue // @Description API for getting my approval queue // @Tags ArticleApprovalFlows // @Security Bearer // @Param Authorization header string true "Insert the Authorization" // @Param Authorization header string false "Insert your access token" default(Bearer ) // @Param includePreview query bool false "Include article preview" // @Param urgentOnly query bool false "Show only urgent articles" // @Param req query paginator.Pagination false "pagination parameters" // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError // @Failure 401 {object} response.UnauthorizedError // @Failure 500 {object} response.InternalServerError // @Router /article-approval-flows/my-queue [get] func (_i *articleApprovalFlowsController) GetMyApprovalQueue(c *fiber.Ctx) error { paginate, err := paginator.Paginate(c) if err != nil { return err } // Get Authorization token from header authToken := c.Get("Authorization") if authToken == "" { return utilRes.ErrorBadRequest(c, "Authorization token required") } user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user == nil { return utilRes.ErrorBadRequest(c, "Invalid authorization token") } // Optional parameters includePreview := c.QueryBool("includePreview", false) urgentOnly := c.QueryBool("urgentOnly", false) approvalQueueData, paging, err := _i.articleApprovalFlowsService.GetMyApprovalQueue(authToken, user.UserLevelId, paginate.Page, paginate.Limit, includePreview, urgentOnly) if err != nil { return err } return utilRes.Resp(c, utilRes.Response{ Success: true, Messages: utilRes.Messages{"My approval queue successfully retrieved"}, Data: approvalQueueData, Meta: paging, }) } // GetPendingApprovals ArticleApprovalFlows // @Summary Get pending approvals // @Description API for getting pending approvals // @Tags ArticleApprovalFlows // @Security Bearer // @Param Authorization header string true "Insert the Authorization" // @Param Authorization header string false "Insert your access token" default(Bearer ) // @Param req query paginator.Pagination false "pagination parameters" // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError // @Failure 401 {object} response.UnauthorizedError // @Failure 500 {object} response.InternalServerError // @Router /article-approval-flows/pending [get] func (_i *articleApprovalFlowsController) GetPendingApprovals(c *fiber.Ctx) error { paginate, err := paginator.Paginate(c) if err != nil { return err } // Get Authorization token from header authToken := c.Get("Authorization") if authToken == "" { return utilRes.ErrorBadRequest(c, "Authorization token required") } user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user == nil { return utilRes.ErrorBadRequest(c, "Invalid authorization token") } filters := make(map[string]interface{}) pendingApprovalsData, paging, err := _i.articleApprovalFlowsService.GetPendingApprovals(authToken, user.UserLevelId, paginate.Page, paginate.Limit, filters) if err != nil { return err } return utilRes.Resp(c, utilRes.Response{ Success: true, Messages: utilRes.Messages{"Pending approvals successfully retrieved"}, Data: pendingApprovalsData, Meta: paging, }) } // GetApprovalHistory ArticleApprovalFlows // @Summary Get approval history // @Description API for getting approval history // @Tags ArticleApprovalFlows // @Security Bearer // @Param Authorization header string true "Insert the Authorization" // @Param articleId query int false "Article ID filter" // @Param userId query int false "User ID filter" // @Param req query paginator.Pagination false "pagination parameters" // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError // @Failure 401 {object} response.UnauthorizedError // @Failure 500 {object} response.InternalServerError // @Router /article-approval-flows/history [get] func (_i *articleApprovalFlowsController) GetApprovalHistory(c *fiber.Ctx) error { paginate, err := paginator.Paginate(c) if err != nil { return err } articleId := 0 if articleIdStr := c.Query("articleId"); articleIdStr != "" { articleId, err = strconv.Atoi(articleIdStr) if err != nil { return utilRes.ErrorBadRequest(c, "Invalid articleId format") } } // userId parameter is not used in the current implementation // userId := 0 // if userIdStr := c.Query("userId"); userIdStr != "" { // userId, err := strconv.Atoi(userIdStr) // if err != nil { // return utilRes.ErrorBadRequest(c, "Invalid userId format") // } // } // Get Authorization token from header authToken := c.Get("Authorization") approvalHistoryData, paging, err := _i.articleApprovalFlowsService.GetApprovalHistory(authToken, uint(articleId), paginate.Page, paginate.Limit) if err != nil { return err } return utilRes.Resp(c, utilRes.Response{ Success: true, Messages: utilRes.Messages{"Approval history successfully retrieved"}, Data: approvalHistoryData, Meta: paging, }) } // GetDashboardStats ArticleApprovalFlows // @Summary Get dashboard statistics // @Description API for getting dashboard statistics // @Tags ArticleApprovalFlows // @Security Bearer // @Param Authorization header string true "Insert the Authorization" // @Param Authorization header string false "Insert your access token" default(Bearer ) // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError // @Failure 401 {object} response.UnauthorizedError // @Failure 500 {object} response.InternalServerError // @Router /article-approval-flows/dashboard-stats [get] func (_i *articleApprovalFlowsController) GetDashboardStats(c *fiber.Ctx) error { // Get Authorization token from header authToken := c.Get("Authorization") if authToken == "" { return utilRes.ErrorBadRequest(c, "Authorization token required") } user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) if user == nil { return utilRes.ErrorBadRequest(c, "Invalid authorization token") } // TODO: Implement GetDashboardStats method in service _ = user.UserLevelId // suppress unused variable warning // dashboardStatsData, err := _i.articleApprovalFlowsService.GetDashboardStats(authToken, user.UserLevelId) // if err != nil { // return err // } return utilRes.Resp(c, utilRes.Response{ Success: true, Messages: utilRes.Messages{"Dashboard statistics successfully retrieved"}, Data: nil, }) } // GetWorkloadStats ArticleApprovalFlows // @Summary Get workload statistics // @Description API for getting workload statistics // @Tags ArticleApprovalFlows // @Security Bearer // @Param Authorization header string true "Insert the Authorization" // @Param Authorization header string false "Insert your access token" default(Bearer ) // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError // @Failure 401 {object} response.UnauthorizedError // @Failure 500 {object} response.InternalServerError // @Router /article-approval-flows/workload-stats [get] func (_i *articleApprovalFlowsController) GetWorkloadStats(c *fiber.Ctx) error { // Get Authorization token from header // authToken := c.Get("Authorization") // TODO: Implement GetWorkloadStats method in service // workloadStatsData, err := _i.articleApprovalFlowsService.GetWorkloadStats(authToken) // if err != nil { // return err // } return utilRes.Resp(c, utilRes.Response{ Success: true, Messages: utilRes.Messages{"Workload statistics successfully retrieved"}, Data: nil, }) } // GetApprovalAnalytics ArticleApprovalFlows // @Summary Get approval analytics // @Description API for getting approval analytics // @Tags ArticleApprovalFlows // @Security Bearer // @Param Authorization header string true "Insert the Authorization" // @Param Authorization header string false "Insert your access token" default(Bearer ) // @Param period query string false "Period filter (daily, weekly, monthly)" // @Param startDate query string false "Start date filter (YYYY-MM-DD)" // @Param endDate query string false "End date filter (YYYY-MM-DD)" // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError // @Failure 401 {object} response.UnauthorizedError // @Failure 500 {object} response.InternalServerError // @Router /article-approval-flows/analytics [get] func (_i *articleApprovalFlowsController) GetApprovalAnalytics(c *fiber.Ctx) error { // period := c.Query("period", "monthly") // startDate := c.Query("startDate") // endDate := c.Query("endDate") // Get Authorization token from header // authToken := c.Get("Authorization") // TODO: Implement GetApprovalAnalytics method in service // analyticsData, err := _i.articleApprovalFlowsService.GetApprovalAnalytics(authToken, period, startDate, endDate) // if err != nil { // return err // } return utilRes.Resp(c, utilRes.Response{ Success: true, Messages: utilRes.Messages{"Approval analytics successfully retrieved"}, Data: nil, }) }