package controllers import ( "strconv" "abdanhafidz.com/go-boilerplate/models/dto" "abdanhafidz.com/go-boilerplate/services" "github.com/gin-gonic/gin" ) type EventController interface { GetEvents(ctx *gin.Context) GetEventDetail(ctx *gin.Context) CreateEvent(ctx *gin.Context) GetMyEvents(ctx *gin.Context) UpdateEvent(ctx *gin.Context) DeleteEvent(ctx *gin.Context) AddEventPackage(ctx *gin.Context) UpdateEventPackage(ctx *gin.Context) DeleteEventPackage(ctx *gin.Context) AddEventInstructor(ctx *gin.Context) RemoveEventInstructor(ctx *gin.Context) GetPendingEvents(ctx *gin.Context) ApproveEvent(ctx *gin.Context) RejectEvent(ctx *gin.Context) } type eventController struct { eventService services.EventService } func NewEventController(eventService services.EventService) EventController { return &eventController{eventService: eventService} } // GetEvents godoc // @Summary List approved events // @Description Returns a paginated list of approved events visible to members. // @Tags Events // @Produce json // @Param page query int false "Page (default: 1)" // @Param limit query int false "Limit (default: 10)" // @Param search query string false "Search by title" // @Success 200 {object} dto.EventListResponse // @Security BearerAuth // @Router /api/v1/events [get] func (c *eventController) GetEvents(ctx *gin.Context) { page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1")) limit, _ := strconv.Atoi(ctx.DefaultQuery("limit", "10")) search := ctx.Query("search") res, err := c.eventService.GetEvents(ctx.Request.Context(), page, limit, search) ResponseJSON(ctx, "", res, err) } // GetEventDetail godoc // @Summary Get event detail // @Description Returns full event details for the member-facing detail page. // @Tags Events // @Produce json // @Param event_id path string true "Event ID" // @Success 200 {object} dto.EventDetailResponse // @Failure 404 {object} dto.ErrorResponse // @Security BearerAuth // @Router /api/v1/events/{event_id} [get] func (c *eventController) GetEventDetail(ctx *gin.Context) { eventID := ctx.Param("event_id") userID := ParseUserId(ctx) res, err := c.eventService.GetEventDetail(ctx.Request.Context(), eventID, userID) ResponseJSON(ctx, "", res, err) } // CreateEvent godoc // @Summary Create an event // @Description Allows an instructor (DI) to create a new event. Starts in PENDING_APPROVAL status. // @Tags Events // @Accept json // @Produce json // @Param request body dto.CreateEventRequest true "Event Data" // @Success 201 {object} entities.Event // @Failure 400 {object} dto.ErrorResponse // @Failure 401 {object} dto.ErrorResponse // @Security BearerAuth // @Router /api/v1/events [post] func (c *eventController) CreateEvent(ctx *gin.Context) { userID := ParseUserId(ctx) if userID == "" { return } req, err := RequestJSON[dto.CreateEventRequest](ctx) if err != nil { return } res, err := c.eventService.CreateEvent(ctx.Request.Context(), userID, req) if err != nil { ResponseJSON(ctx, req, res, err) return } ctx.JSON(201, gin.H{"success": true, "message": "Event created successfully. Pending approval.", "data": res}) } // GetMyEvents godoc // @Summary Get my events // @Description Returns a paginated list of events created by the authenticated instructor. // @Tags Events // @Produce json // @Param page query int false "Page (default: 1)" // @Param limit query int false "Limit (default: 10)" // @Success 200 {object} dto.EventListResponse // @Security BearerAuth // @Router /api/v1/events/me [get] func (c *eventController) GetMyEvents(ctx *gin.Context) { userID := ParseUserId(ctx) if userID == "" { return } page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1")) limit, _ := strconv.Atoi(ctx.DefaultQuery("limit", "10")) res, err := c.eventService.GetMyEvents(ctx.Request.Context(), userID, page, limit) ResponseJSON(ctx, "", res, err) } // UpdateEvent godoc // @Summary Update an event // @Description Partially update an event owned by the authenticated instructor. // @Tags Events // @Accept json // @Produce json // @Param event_id path string true "Event ID" // @Param request body dto.UpdateEventRequest true "Fields to update" // @Success 200 {object} entities.Event // @Failure 400 {object} dto.ErrorResponse // @Failure 403 {object} dto.ErrorResponse // @Security BearerAuth // @Router /api/v1/events/{event_id} [put] func (c *eventController) UpdateEvent(ctx *gin.Context) { userID := ParseUserId(ctx) if userID == "" { return } eventID := ctx.Param("event_id") req, err := RequestJSON[dto.UpdateEventRequest](ctx) if err != nil { return } res, err := c.eventService.UpdateEvent(ctx.Request.Context(), userID, eventID, req) if err != nil { ResponseJSON(ctx, req, res, err) return } ctx.JSON(200, gin.H{"success": true, "message": "Event updated successfully", "data": res}) } // DeleteEvent godoc // @Summary Delete an event // @Description Delete an event owned by the authenticated instructor. // @Tags Events // @Produce json // @Param event_id path string true "Event ID" // @Success 200 {object} map[string]interface{} // @Failure 403 {object} dto.ErrorResponse // @Failure 404 {object} dto.ErrorResponse // @Security BearerAuth // @Router /api/v1/events/{event_id} [delete] func (c *eventController) DeleteEvent(ctx *gin.Context) { userID := ParseUserId(ctx) if userID == "" { return } eventID := ctx.Param("event_id") err := c.eventService.DeleteEvent(ctx.Request.Context(), userID, eventID) if err != nil { ctx.JSON(400, gin.H{"success": false, "message": err.Error()}) return } ctx.JSON(200, gin.H{"success": true, "message": "Event deleted successfully"}) } // AddEventPackage godoc // @Summary Add package to event // @Description Add a ticket package to an event. Only the event owner can do this. // @Tags Events // @Accept json // @Produce json // @Param event_id path string true "Event ID" // @Param request body dto.CreateEventPackageRequest true "Package Data" // @Success 201 {object} entities.EventPackage // @Security BearerAuth // @Router /api/v1/events/{event_id}/packages [post] func (c *eventController) AddEventPackage(ctx *gin.Context) { userID := ParseUserId(ctx) if userID == "" { return } eventID := ctx.Param("event_id") req, err := RequestJSON[dto.CreateEventPackageRequest](ctx) if err != nil { return } res, err := c.eventService.AddEventPackage(ctx.Request.Context(), userID, eventID, req) if err != nil { ResponseJSON(ctx, req, res, err) return } ctx.JSON(201, gin.H{"success": true, "message": "Package added successfully", "data": res}) } // UpdateEventPackage godoc // @Summary Update an event package // @Description Partially update a ticket package. Only the event owner can do this. // @Tags Events // @Accept json // @Produce json // @Param package_id path string true "Package ID" // @Param request body dto.UpdateEventPackageRequest true "Fields to update" // @Success 200 {object} entities.EventPackage // @Security BearerAuth // @Router /api/v1/events/packages/{package_id} [put] func (c *eventController) UpdateEventPackage(ctx *gin.Context) { userID := ParseUserId(ctx) if userID == "" { return } packageID := ctx.Param("package_id") req, err := RequestJSON[dto.UpdateEventPackageRequest](ctx) if err != nil { return } res, err := c.eventService.UpdateEventPackage(ctx.Request.Context(), userID, packageID, req) if err != nil { ResponseJSON(ctx, req, res, err) return } ctx.JSON(200, gin.H{"success": true, "message": "Package updated successfully", "data": res}) } // DeleteEventPackage godoc // @Summary Delete an event package // @Description Remove a ticket package from an event. Only the event owner can do this. // @Tags Events // @Produce json // @Param package_id path string true "Package ID" // @Success 200 {object} map[string]interface{} // @Security BearerAuth // @Router /api/v1/events/packages/{package_id} [delete] func (c *eventController) DeleteEventPackage(ctx *gin.Context) { userID := ParseUserId(ctx) if userID == "" { return } packageID := ctx.Param("package_id") err := c.eventService.DeleteEventPackage(ctx.Request.Context(), userID, packageID) if err != nil { ctx.JSON(400, gin.H{"success": false, "message": err.Error()}) return } ctx.JSON(200, gin.H{"success": true, "message": "Package deleted successfully"}) } // AddEventInstructor godoc // @Summary Add instructor to event // @Description Link a partner instructor to an event. Only the event owner can do this. // @Tags Events // @Accept json // @Produce json // @Param event_id path string true "Event ID" // @Param request body dto.AddEventInstructorRequest true "Instructor Data" // @Success 201 {object} entities.EventInstructor // @Security BearerAuth // @Router /api/v1/events/{event_id}/instructors [post] func (c *eventController) AddEventInstructor(ctx *gin.Context) { userID := ParseUserId(ctx) if userID == "" { return } eventID := ctx.Param("event_id") req, err := RequestJSON[dto.AddEventInstructorRequest](ctx) if err != nil { return } res, err := c.eventService.AddEventInstructor(ctx.Request.Context(), userID, eventID, req) if err != nil { ResponseJSON(ctx, req, res, err) return } ctx.JSON(201, gin.H{"success": true, "message": "Instructor added successfully", "data": res}) } // RemoveEventInstructor godoc // @Summary Remove instructor from event // @Description Unlink a partner instructor from an event. Only the event owner can do this. // @Tags Events // @Produce json // @Param event_id path string true "Event ID" // @Param instructor_id path string true "Instructor ID" // @Success 200 {object} map[string]interface{} // @Security BearerAuth // @Router /api/v1/events/{event_id}/instructors/{instructor_id} [delete] func (c *eventController) RemoveEventInstructor(ctx *gin.Context) { userID := ParseUserId(ctx) if userID == "" { return } eventID := ctx.Param("event_id") instructorID := ctx.Param("instructor_id") err := c.eventService.RemoveEventInstructor(ctx.Request.Context(), userID, eventID, instructorID) if err != nil { ctx.JSON(400, gin.H{"success": false, "message": err.Error()}) return } ctx.JSON(200, gin.H{"success": true, "message": "Instructor removed successfully"}) } // GetPendingEvents godoc // @Summary List pending events (approval queue) // @Description Returns events awaiting approval. Accessible by admin/DI approvers. // @Tags Events // @Produce json // @Param page query int false "Page (default: 1)" // @Param limit query int false "Limit (default: 10)" // @Success 200 {object} dto.EventListResponse // @Security BearerAuth // @Router /api/v1/events/pending [get] func (c *eventController) GetPendingEvents(ctx *gin.Context) { page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1")) limit, _ := strconv.Atoi(ctx.DefaultQuery("limit", "10")) res, err := c.eventService.GetPendingEvents(ctx.Request.Context(), page, limit) ResponseJSON(ctx, "", res, err) } // ApproveEvent godoc // @Summary Approve an event // @Description Approve a pending event so it becomes visible to members. // @Tags Events // @Produce json // @Param event_id path string true "Event ID" // @Success 200 {object} map[string]interface{} // @Security BearerAuth // @Router /api/v1/events/{event_id}/approve [put] func (c *eventController) ApproveEvent(ctx *gin.Context) { eventID := ctx.Param("event_id") err := c.eventService.ApproveEvent(ctx.Request.Context(), eventID) if err != nil { ctx.JSON(400, gin.H{"success": false, "message": err.Error()}) return } ctx.JSON(200, gin.H{"success": true, "message": "Event approved successfully"}) } // RejectEvent godoc // @Summary Reject an event // @Description Reject a pending event with an optional reason. // @Tags Events // @Accept json // @Produce json // @Param event_id path string true "Event ID" // @Param request body dto.EventApprovalRequest false "Rejection reason" // @Success 200 {object} map[string]interface{} // @Security BearerAuth // @Router /api/v1/events/{event_id}/reject [put] func (c *eventController) RejectEvent(ctx *gin.Context) { eventID := ctx.Param("event_id") req, _ := RequestJSON[dto.EventApprovalRequest](ctx) err := c.eventService.RejectEvent(ctx.Request.Context(), eventID, req.Reason) if err != nil { ctx.JSON(400, gin.H{"success": false, "message": err.Error()}) return } ctx.JSON(200, gin.H{"success": true, "message": "Event rejected"}) }