File size: 5,808 Bytes
ab82ffd
 
 
c0722d3
40f1c60
ab82ffd
56e28b7
1537c35
ab82ffd
987726a
 
ab82ffd
1b2c396
ab82ffd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c0722d3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ab82ffd
 
987726a
 
 
 
b03de03
 
 
 
 
 
 
1537c35
 
c0722d3
1537c35
 
 
 
 
987726a
 
 
 
 
 
 
 
c0722d3
987726a
1537c35
c0722d3
ab82ffd
c0722d3
ab82ffd
987726a
 
 
 
 
 
 
 
 
 
 
 
ab82ffd
987726a
 
 
ab82ffd
c0722d3
ab82ffd
 
 
c0722d3
 
 
 
 
 
 
 
 
 
ab82ffd
 
 
 
 
 
 
c0722d3
 
 
 
 
 
 
 
 
56e28b7
1800747
c0722d3
ab82ffd
 
c0722d3
1b2c396
c0722d3
1b2c396
 
c0722d3
ab82ffd
 
c0722d3
 
56e28b7
 
 
 
 
 
 
 
 
 
 
 
40f1c60
56e28b7
 
 
40f1c60
c0722d3
 
 
 
ab82ffd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package controllers

import (
	"errors"
	"net/http"
	"strconv"
	"time"

	"abdanhafidz.com/go-boilerplate/models/dto"
	entity "abdanhafidz.com/go-boilerplate/models/entity"
	http_error "abdanhafidz.com/go-boilerplate/models/error"
	"abdanhafidz.com/go-boilerplate/services"
	"abdanhafidz.com/go-boilerplate/utils"
	"github.com/gin-gonic/gin"
)

type EventController interface {
	List(ctx *gin.Context)
	DetailBySlug(ctx *gin.Context)
	Join(ctx *gin.Context)
}

type eventController struct {
	eventService services.EventService
}

func NewEventController(eventService services.EventService) EventController {
	return &eventController{eventService: eventService}
}

// Event List godoc
// @Summary      List Events
// @Description  Retrieve a paginated list of events with optional filters
// @Tags         Event
// @Accept       json
// @Produce      json
// @Param        limit           query     int     false  "Number of items per page"            default(10)
// @Param        page            query     int     false  "Page number"                         default(1)
// @Param        search          query     string  false  "Search term for event titles"
// @Param        sortBy          query     string  false  "Field to sort by (e.g., 'date', 'title')"
// @Param        order           query     string  false  "Sort order ('asc' or 'desc')"
// @Param        registerStatus  query     int     false  "Filter by registration status"
// @Param        status          query     string  false  "Filter by event status (upcoming, ongoing, ended)"
// @Success	  	 200  {object}  dto.SuccessResponse[[]entity.Events]
// @Failure      400  {object}  dto.ErrorResponse
// @Router       /api/v1/events [get]
func (c *eventController) List(ctx *gin.Context) {
	limit, _ := strconv.Atoi(ctx.DefaultQuery("limit", "10"))
	page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
	search := ctx.DefaultQuery("search", "")
	sortBy := ctx.DefaultQuery("sortBy", "")
	order := ctx.DefaultQuery("order", "")

	var registerStatus *int
	if val := ctx.Query("registerStatus"); val != "" {
		if i, err := strconv.Atoi(val); err == nil {
			registerStatus = &i
		}
	}

	var status *string

	if val := ctx.Query("status"); val != "" {
		if val == entity.EventStatusUpcoming || val == entity.EventStatusOngoing || val == entity.EventStatusEnded {
			status = &val
		}
	}
	if limit < 1 {
		limit = 10
	} else if limit > 50 {
		limit = 50
	}
	if page < 1 {
		page = 1
	}

	offset := (page - 1) * limit
	p := entity.Pagination{Limit: limit, Offset: offset, Search: search, SortBy: sortBy, Order: order, RegisterStatus: registerStatus, Status: status}

	accountId := ParseAccountId(ctx)

	list, total, err := c.eventService.List(ctx.Request.Context(), accountId, p)
	var totalPages int
	if total == 0 {
		totalPages = 1
	} else {
		totalPages = int((total + int64(limit) - 1) / int64(limit))
	}
	if page > totalPages {
		page = totalPages
		offset = (page - 1) * limit
		p.Offset = offset
		list, total, err = c.eventService.List(ctx.Request.Context(), accountId, p)
	}
	meta := gin.H{
		"totalItems":  total,
		"totalPages":  totalPages,
		"currentPage": page,
	}

	ResponseJSON(ctx, meta, list, err)
}

// Event Detail By Slug godoc
// @Summary      Get Event Detail by Slug
// @Description  Retrieve detailed information about a specific event using its slug
// @Tags         Event
// @Accept       json
// @Produce      json
// @Param        event_slug  path      string  true  "Event Slug"
// @Success      200         {object}  dto.SuccessResponse[dto.EventDetailResponse]
// @Failure      400         {object}  dto.ErrorResponse
// @Router       /api/v1/events/{event_slug} [get]
func (c *eventController) DetailBySlug(ctx *gin.Context) {
	slug := ctx.Param("event_slug")
	accountId := ParseAccountId(ctx)
	res, err := c.eventService.DetailBySlug(ctx.Request.Context(), slug, accountId)
	ResponseJSON(ctx, gin.H{"event_slug": slug, "id_account": accountId}, res, err)
}

// Join Event godoc
// @Summary      Join Event
// @Description  Register the authenticated user for an event using an event code
// @Tags         Event
// @Accept       json
// @Produce      json
// @Param        request  body      dto.JoinEventRequest  true  "Join Event Request"
// @Success      200      {object}  dto.SuccessResponse[dto.EventDetailResponse]
// @Failure      400      {object}  dto.ErrorResponse
// @Failure      402      {object}  dto.RegisterEventPaymentActionRequiredResponse
// @Security     BearerAuth
// @Router       /api/v1/events/register-event [post]
func (c *eventController) Join(ctx *gin.Context) {
	req := RequestJSON[dto.JoinEventRequest](ctx)

	if err := utils.ValidateCode(req.EventCode); err != nil {
		ResponseJSON(ctx, req, gin.H{}, err)
		return
	}

	accountId := ParseAccountId(ctx)
	res, err := c.eventService.JoinByCode(ctx.Request.Context(), accountId, req.EventCode)

	if errors.Is(err, http_error.PAYMENT_REQUIRED) {
		ctx.JSON(http.StatusPaymentRequired, dto.RegisterEventPaymentActionRequiredResponse{
			Data: dto.RegisterEventPaymentActionRequiredData{
				AccountID:          res.EventPayment.AccountId.String(),
				Amount:             res.EventPayment.Amount,
				EventID:            res.EventPayment.EventId.String(),
				ExpiredAt:          res.EventPayment.ExpiredAt.Format(time.RFC3339),
				ID:                 res.EventPayment.Id.String(),
				InvoiceID:          res.EventPayment.InvoiceId,
				InvoiceURL:         res.EventPayment.InvoiceUrl,
				Status:             res.EventPayment.Status,
				TransactionAt:      res.EventPayment.TransactionAt.Format(time.RFC3339),
				MayarTransactionID: res.EventPayment.ExternalId,
			},
			Message:  http_error.PAYMENT_REQUIRED.Error(),
			MetaData: req.EventCode,
			Status:   "action_required",
		})
		return
	}

	ResponseJSON(ctx, req, res, err)
}