feat: update filter article and register middleware

This commit is contained in:
hanif salafi 2025-09-23 07:22:08 +07:00
parent e39a8d442a
commit 1c9b288e10
6 changed files with 80 additions and 60 deletions

View File

@ -58,7 +58,7 @@ func (m *Middleware) Register(db *database.Database) {
m.App.Use(cors.New(cors.Config{ m.App.Use(cors.New(cors.Config{
Next: utilsSvc.IsEnabled(m.Cfg.Middleware.Cors.Enable), Next: utilsSvc.IsEnabled(m.Cfg.Middleware.Cors.Enable),
AllowOrigins: "http://localhost:3000, http://localhost:4000, https://dev.mikulnews.com, https://n8n.qudoco.com, https://narasiahli.com", AllowOrigins: "http://localhost:3000, http://localhost:4000, https://dev.mikulnews.com, https://n8n.qudoco.com, https://narasiahli.com, https://dev.asuransiaman.com, https://dev.beritabumn.com, https://dev.kabarharapan.com, https://dev.kebaikanindonesia.com, https://dev.isukini.com",
AllowMethods: "HEAD, GET, POST, PUT, DELETE, OPTION, PATCH", AllowMethods: "HEAD, GET, POST, PUT, DELETE, OPTION, PATCH",
AllowHeaders: "Origin, Content-Type, Accept, Accept-Language, Authorization, X-Requested-With, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Allow-Origin, Access-Control-Allow-Credentials, X-Csrf-Token, Cookie, Set-Cookie, X-Client-Key", AllowHeaders: "Origin, Content-Type, Accept, Accept-Language, Authorization, X-Requested-With, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Allow-Origin, Access-Control-Allow-Credentials, X-Csrf-Token, Cookie, Set-Cookie, X-Client-Key",
ExposeHeaders: "Content-Length, Content-Type", ExposeHeaders: "Content-Length, Content-Type",

View File

@ -199,6 +199,11 @@ func (_i *articleApprovalFlowsRepository) GetPendingApprovals(clientId *uuid.UUI
query = query.Where("articles.category_id = ?", categoryId) query = query.Where("articles.category_id = ?", categoryId)
} }
if typeId, ok := filters["type_id"]; ok {
query = query.Joins("JOIN articles ON article_approval_flows.article_id = articles.id")
query = query.Where("articles.type_id = ?", typeId)
}
if search, ok := filters["search"]; ok { if search, ok := filters["search"]; ok {
query = query.Joins("JOIN articles ON article_approval_flows.article_id = articles.id") query = query.Joins("JOIN articles ON article_approval_flows.article_id = articles.id")
query = query.Where("articles.title ILIKE ? OR articles.description ILIKE ?", fmt.Sprintf("%%%s%%", search), fmt.Sprintf("%%%s%%", search)) query = query.Where("articles.title ILIKE ? OR articles.description ILIKE ?", fmt.Sprintf("%%%s%%", search), fmt.Sprintf("%%%s%%", search))

View File

@ -4,21 +4,21 @@ import "time"
type ArticleFilesResponse struct { type ArticleFilesResponse struct {
ID uint `json:"id"` ID uint `json:"id"`
ArticleId uint `json:"article_id"` ArticleId uint `json:"articleId"`
FilePath *string `json:"file_path"` FilePath *string `json:"filePath"`
FileUrl *string `json:"file_url"` FileUrl *string `json:"fileUrl"`
FileName *string `json:"file_name"` FileName *string `json:"fileName"`
FileThumbnail *string `json:"file_thumbnail"` FileThumbnail *string `json:"fileThumbnail"`
FileAlt *string `json:"file_alt"` FileAlt *string `json:"fileAlt"`
WidthPixel *string `json:"width_pixel"` WidthPixel *string `json:"widthPixel"`
HeightPixel *string `json:"height_pixel"` HeightPixel *string `json:"heightPixel"`
Size *string `json:"size"` Size *string `json:"size"`
DownloadCount *int `json:"download_count"` DownloadCount *int `json:"downloadCount"`
CreatedById int `json:"created_by_id"` CreatedById int `json:"createdById"`
StatusId int `json:"status_id"` StatusId int `json:"statusId"`
IsPublish *bool `json:"is_publish"` IsPublish *bool `json:"isPublish"`
PublishedAt *time.Time `json:"published_at"` PublishedAt *time.Time `json:"publishedAt"`
IsActive bool `json:"is_active"` IsActive bool `json:"isActive"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updatedAt"`
} }

View File

@ -589,6 +589,7 @@ func (_i *articlesController) GetApprovalStatus(c *fiber.Ctx) error {
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>) // @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param page query int false "page number" // @Param page query int false "page number"
// @Param limit query int false "items per page" // @Param limit query int false "items per page"
// @Param typeId query int false "article type id"
// @Success 200 {object} response.Response // @Success 200 {object} response.Response
// @Failure 400 {object} response.BadRequestError // @Failure 400 {object} response.BadRequestError
// @Failure 401 {object} response.UnauthorizedError // @Failure 401 {object} response.UnauthorizedError
@ -605,13 +606,21 @@ func (_i *articlesController) GetPendingApprovals(c *fiber.Ctx) error {
limit = 10 limit = 10
} }
// Parse typeId filter
var typeId *int
if typeIdStr := c.Query("typeId"); typeIdStr != "" {
if parsedTypeId, err := strconv.Atoi(typeIdStr); err == nil {
typeId = &parsedTypeId
}
}
// Get ClientId from context // Get ClientId from context
clientId := middleware.GetClientID(c) clientId := middleware.GetClientID(c)
// Get Authorization token from header // Get Authorization token from header
authToken := c.Get("Authorization") authToken := c.Get("Authorization")
response, paging, err := _i.articlesService.GetPendingApprovals(clientId, authToken, page, limit) response, paging, err := _i.articlesService.GetPendingApprovals(clientId, authToken, page, limit, typeId) // Updated with typeId filter
if err != nil { if err != nil {
return err return err
} }

View File

@ -62,51 +62,51 @@ type ArticleMonthlyStats struct {
// ArticleApprovalStatusResponse represents the approval status of an article // ArticleApprovalStatusResponse represents the approval status of an article
type ArticleApprovalStatusResponse struct { type ArticleApprovalStatusResponse struct {
ArticleId uint `json:"article_id"` ArticleId uint `json:"articleId"`
WorkflowId *uint `json:"workflow_id"` WorkflowId *uint `json:"workflowId"`
WorkflowName *string `json:"workflow_name"` WorkflowName *string `json:"workflowName"`
CurrentStep int `json:"current_step"` CurrentStep int `json:"currentStep"`
TotalSteps int `json:"total_steps"` TotalSteps int `json:"totalSteps"`
Status string `json:"status"` // "pending", "in_progress", "approved", "rejected", "revision_requested" Status string `json:"status"` // "pending", "in_progress", "approved", "rejected", "revision_requested"
CurrentApprover *string `json:"current_approver"` CurrentApprover *string `json:"currentApprover"`
SubmittedAt *time.Time `json:"submitted_at"` SubmittedAt *time.Time `json:"submittedAt"`
LastActionAt *time.Time `json:"last_action_at"` LastActionAt *time.Time `json:"lastActionAt"`
Progress float64 `json:"progress"` // percentage complete Progress float64 `json:"progress"` // percentage complete
CanApprove bool `json:"can_approve"` // whether current user can approve CanApprove bool `json:"canApprove"` // whether current user can approve
NextStep *string `json:"next_step"` NextStep *string `json:"nextStep"`
} }
// ArticleApprovalQueueResponse represents an article in the approval queue // ArticleApprovalQueueResponse represents an article in the approval queue
type ArticleApprovalQueueResponse struct { type ArticleApprovalQueueResponse struct {
ID uint `json:"id"` ID uint `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Slug string `json:"slug"` Slug string `json:"slug"`
Description string `json:"description"` Description string `json:"description"`
CategoryName string `json:"category_name"` CategoryName string `json:"categoryName"`
AuthorName string `json:"author_name"` AuthorName string `json:"authorName"`
SubmittedAt time.Time `json:"submitted_at"` SubmittedAt time.Time `json:"submittedAt"`
CurrentStep int `json:"current_step"` CurrentStep int `json:"currentStep"`
TotalSteps int `json:"total_steps"` TotalSteps int `json:"totalSteps"`
Priority string `json:"priority"` // "low", "medium", "high", "urgent" Priority string `json:"priority"` // "low", "medium", "high", "urgent"
DaysInQueue int `json:"days_in_queue"` DaysInQueue int `json:"daysInQueue"`
WorkflowName string `json:"workflow_name"` WorkflowName string `json:"workflowName"`
CanApprove bool `json:"can_approve"` CanApprove bool `json:"canApprove"`
EstimatedTime string `json:"estimated_time"` // estimated time to complete approval EstimatedTime string `json:"estimatedTime"` // estimated time to complete approval
} }
// ClientApprovalSettingsResponse represents client-level approval settings // ClientApprovalSettingsResponse represents client-level approval settings
type ClientApprovalSettingsResponse struct { type ClientApprovalSettingsResponse struct {
ClientId string `json:"client_id"` ClientId string `json:"clientId"`
RequiresApproval bool `json:"requires_approval"` RequiresApproval bool `json:"requiresApproval"`
DefaultWorkflowId *uint `json:"default_workflow_id"` DefaultWorkflowId *uint `json:"defaultWorkflowId"`
DefaultWorkflowName *string `json:"default_workflow_name"` DefaultWorkflowName *string `json:"defaultWorkflowName"`
AutoPublishArticles bool `json:"auto_publish_articles"` AutoPublishArticles bool `json:"autoPublishArticles"`
ApprovalExemptUsers []uint `json:"approval_exempt_users"` ApprovalExemptUsers []uint `json:"approvalExemptUsers"`
ApprovalExemptRoles []uint `json:"approval_exempt_roles"` ApprovalExemptRoles []uint `json:"approvalExemptRoles"`
ApprovalExemptCategories []uint `json:"approval_exempt_categories"` ApprovalExemptCategories []uint `json:"approvalExemptCategories"`
RequireApprovalFor []string `json:"require_approval_for"` RequireApprovalFor []string `json:"requireApprovalFor"`
SkipApprovalFor []string `json:"skip_approval_for"` SkipApprovalFor []string `json:"skipApprovalFor"`
IsActive bool `json:"is_active"` IsActive bool `json:"isActive"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updatedAt"`
} }

View File

@ -76,7 +76,7 @@ type ArticlesService interface {
SubmitForApproval(clientId *uuid.UUID, articleId uint, authToken string, workflowId *uint) error SubmitForApproval(clientId *uuid.UUID, articleId uint, authToken string, workflowId *uint) error
GetApprovalStatus(clientId *uuid.UUID, articleId uint) (*response.ArticleApprovalStatusResponse, error) GetApprovalStatus(clientId *uuid.UUID, articleId uint) (*response.ArticleApprovalStatusResponse, error)
GetArticlesWaitingForApproval(clientId *uuid.UUID, authToken string, page, limit int) ([]*response.ArticleApprovalQueueResponse, paginator.Pagination, error) GetArticlesWaitingForApproval(clientId *uuid.UUID, authToken string, page, limit int) ([]*response.ArticleApprovalQueueResponse, paginator.Pagination, error)
GetPendingApprovals(clientId *uuid.UUID, authToken string, page, limit int) ([]*response.ArticleApprovalQueueResponse, paginator.Pagination, error) GetPendingApprovals(clientId *uuid.UUID, authToken string, page, limit int, typeId *int) ([]*response.ArticleApprovalQueueResponse, paginator.Pagination, error) // Updated with typeId filter
// No-approval system methods // No-approval system methods
CheckApprovalRequired(clientId *uuid.UUID, articleId uint, userId uint, userLevelId uint) (bool, error) CheckApprovalRequired(clientId *uuid.UUID, articleId uint, userId uint, userLevelId uint) (bool, error)
@ -872,15 +872,21 @@ func (_i *articlesService) GetApprovalStatus(clientId *uuid.UUID, articleId uint
} }
// GetPendingApprovals gets articles pending approval for a specific user level // GetPendingApprovals gets articles pending approval for a specific user level
func (_i *articlesService) GetPendingApprovals(clientId *uuid.UUID, authToken string, page, limit int) ([]*response.ArticleApprovalQueueResponse, paginator.Pagination, error) { func (_i *articlesService) GetPendingApprovals(clientId *uuid.UUID, authToken string, page, limit int, typeId *int) ([]*response.ArticleApprovalQueueResponse, paginator.Pagination, error) {
// Extract user info from auth token // Extract user info from auth token
user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
if user == nil { if user == nil {
return nil, paginator.Pagination{}, errors.New("user not found from auth token") return nil, paginator.Pagination{}, errors.New("user not found from auth token")
} }
// Prepare filters
filters := make(map[string]interface{})
if typeId != nil {
filters["type_id"] = *typeId
}
// Get pending approvals for the user level // Get pending approvals for the user level
approvalFlows, paging, err := _i.ArticleApprovalFlowsRepo.GetPendingApprovalsByUserLevel(clientId, user.UserLevelId, page, limit) approvalFlows, paging, err := _i.ArticleApprovalFlowsRepo.GetPendingApprovals(clientId, user.UserLevelId, page, limit, filters)
if err != nil { if err != nil {
return nil, paging, err return nil, paging, err
} }