From c9e987e2bab71da70624fdd4b4e0041b982585cb Mon Sep 17 00:00:00 2001 From: Asai Neko Date: Fri, 6 Feb 2026 18:32:46 +0800 Subject: [PATCH] Add agenda service and submit api Signed-off-by: Asai Neko --- api/agenda/handler.go | 18 ++ api/agenda/submit.go | 99 ++++++ api/auth/exchange.go | 11 +- api/auth/magic.go | 11 +- api/auth/refresh.go | 11 +- api/auth/token.go | 11 +- api/event/attendance.go | 11 +- api/event/checkin.go | 9 +- api/event/info.go | 13 +- api/event/join.go | 13 +- api/event/joined.go | 94 ++++++ api/event/list.go | 13 +- api/kyc/query.go | 11 +- api/kyc/session.go | 11 +- api/user/info.go | 9 +- api/user/list.go | 13 +- api/user/other.go | 13 +- api/user/update.go | 11 +- cmd/gen_exception/definitions/endpoint.yaml | 3 + cmd/gen_exception/definitions/service.yaml | 1 + data/agenda.go | 6 + data/attendance.go | 6 +- data/event.go | 30 ++ docs/docs.go | 341 ++++++++++++++------ docs/swagger.json | 341 ++++++++++++++------ docs/swagger.yaml | 208 ++++++++---- service/service_agenda/service.go | 11 + service/service_agenda/submit.go | 131 ++++++++ service/service_event/get_joined_event.go | 132 ++++++++ service/service_event/service.go | 1 + 30 files changed, 1228 insertions(+), 365 deletions(-) create mode 100644 api/agenda/handler.go create mode 100644 api/agenda/submit.go create mode 100644 api/event/joined.go create mode 100644 service/service_agenda/service.go create mode 100644 service/service_agenda/submit.go create mode 100644 service/service_event/get_joined_event.go diff --git a/api/agenda/handler.go b/api/agenda/handler.go new file mode 100644 index 0000000..4d91d88 --- /dev/null +++ b/api/agenda/handler.go @@ -0,0 +1,18 @@ +package agenda + +import ( + "nixcn-cms/service/service_agenda" + + "github.com/gin-gonic/gin" +) + +type AgendaHandler struct { + svc service_agenda.AgendaService +} + +func ApiHandler(r *gin.RouterGroup) { + agendaSvc := service_agenda.NewAgendaService() + agendaHandler := &AgendaHandler{agendaSvc} + + r.POST("/submit", agendaHandler.Submit) +} diff --git a/api/agenda/submit.go b/api/agenda/submit.go new file mode 100644 index 0000000..b9f757c --- /dev/null +++ b/api/agenda/submit.go @@ -0,0 +1,99 @@ +package agenda + +import ( + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_agenda" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// Submit handles the submission of a new agenda item. +// +// @Summary Submit Agenda +// @Description Creates a new agenda item for a specific attendance record. +// @Tags Agenda +// @Accept json +// @Produce json +// @Param body body service_agenda.SubmitData true "Agenda Submission Data" +// @Success 200 {object} utils.RespStatus{data=service_agenda.SubmitResponse} +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Security ApiKeyAuth +// @Router /agenda/submit [post] +func (self *AgendaHandler) Submit(c *gin.Context) { + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := new(exception.Builder). + SetStatus(exception.StatusUser). + SetService(exception.ServiceUser). + SetEndpoint(exception.EndpointUserServiceInfo). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonErrorMissingUserId). + Throw(c). + String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := new(exception.Builder). + SetStatus(exception.StatusServer). + SetService(exception.ServiceUser). + SetEndpoint(exception.EndpointUserServiceInfo). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonErrorUuidParseFailed). + SetError(err). + Throw(c). + String() + utils.HttpResponse(c, 500, errorCode) + return + } + + data := new(service_agenda.SubmitData) + + if err := c.ShouldBindJSON(data); err != nil { + errorCode := new(exception.Builder). + SetStatus(exception.StatusUser). + SetService(exception.ServiceAgenda). + SetEndpoint(exception.EndpointAgendaServiceSubmit). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonErrorInvalidInput). + SetError(err). + Throw(c). + String() + + utils.HttpResponse(c, 400, errorCode) + return + } + + if data.EventId.String() == "" || data.Name == "" { + errorCode := new(exception.Builder). + SetStatus(exception.StatusUser). + SetService(exception.ServiceAgenda). + SetEndpoint(exception.EndpointAgendaServiceSubmit). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonErrorInvalidInput). + SetError(nil). + Throw(c). + String() + + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.Submit(&service_agenda.SubmitPayload{ + Context: c, + UserId: userId, + Data: data, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), &result.Data) +} diff --git a/api/auth/exchange.go b/api/auth/exchange.go index 37983e2..bc6df80 100644 --- a/api/auth/exchange.go +++ b/api/auth/exchange.go @@ -16,12 +16,11 @@ import ( // @Tags Authentication // @Accept json // @Produce json -// @Param payload body service_auth.ExchangeData true "Exchange Request Credentials" -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=service_auth.ExchangeResponse} "Successful exchange" -// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" -// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Param payload body service_auth.ExchangeData true "Exchange Request Credentials" +// @Success 200 {object} utils.RespStatus{data=service_auth.ExchangeResponse} "Successful exchange" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" // @Router /auth/exchange [post] func (self *AuthHandler) Exchange(c *gin.Context) { var exchangeData service_auth.ExchangeData diff --git a/api/auth/magic.go b/api/auth/magic.go index ea0358a..35f7e72 100644 --- a/api/auth/magic.go +++ b/api/auth/magic.go @@ -15,12 +15,11 @@ import ( // @Tags Authentication // @Accept json // @Produce json -// @Param payload body service_auth.MagicData true "Magic Link Request Data" -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=service_auth.MagicResponse} "Successful request" -// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" -// @Failure 403 {object} utils.RespStatus{data=nil} "Turnstile Verification Failed" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Param payload body service_auth.MagicData true "Magic Link Request Data" +// @Success 200 {object} utils.RespStatus{data=service_auth.MagicResponse} "Successful request" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 403 {object} utils.RespStatus{data=nil} "Turnstile Verification Failed" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" // @Router /auth/magic [post] func (self *AuthHandler) Magic(c *gin.Context) { var magicData service_auth.MagicData diff --git a/api/auth/refresh.go b/api/auth/refresh.go index 4ad23c9..a032c9b 100644 --- a/api/auth/refresh.go +++ b/api/auth/refresh.go @@ -15,12 +15,11 @@ import ( // @Tags Authentication // @Accept json // @Produce json -// @Param payload body service_auth.RefreshData true "Refresh Token Body" -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=service_auth.TokenResponse} "Successful rotation" -// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" -// @Failure 401 {object} utils.RespStatus{data=nil} "Invalid Refresh Token" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Param payload body service_auth.RefreshData true "Refresh Token Body" +// @Success 200 {object} utils.RespStatus{data=service_auth.TokenResponse} "Successful rotation" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Invalid Refresh Token" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" // @Router /auth/refresh [post] func (self *AuthHandler) Refresh(c *gin.Context) { var refreshData service_auth.RefreshData diff --git a/api/auth/token.go b/api/auth/token.go index 3a492ed..e6294bd 100644 --- a/api/auth/token.go +++ b/api/auth/token.go @@ -15,12 +15,11 @@ import ( // @Tags Authentication // @Accept json // @Produce json -// @Param payload body service_auth.TokenData true "Token Request Body" -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=service_auth.TokenResponse} "Successful token issuance" -// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" -// @Failure 403 {object} utils.RespStatus{data=nil} "Invalid or Expired Code" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Param payload body service_auth.TokenData true "Token Request Body" +// @Success 200 {object} utils.RespStatus{data=service_auth.TokenResponse} "Successful token issuance" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 403 {object} utils.RespStatus{data=nil} "Invalid or Expired Code" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" // @Router /auth/token [post] func (self *AuthHandler) Token(c *gin.Context) { var tokenData service_auth.TokenData diff --git a/api/event/attendance.go b/api/event/attendance.go index 1a92bc9..552b928 100644 --- a/api/event/attendance.go +++ b/api/event/attendance.go @@ -15,12 +15,11 @@ import ( // @Description Retrieves the list of attendees, including user info and decrypted KYC data for a specified event. // @Tags Event // @Produce json -// @Param event_id query string true "Event UUID" -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=[]service_event.AttendanceListResponse} "Successful retrieval" -// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" -// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Param event_id query string true "Event UUID" +// @Success 200 {object} utils.RespStatus{data=[]service_event.AttendanceListResponse} "Successful retrieval" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" // @Security ApiKeyAuth // @Router /event/attendance [get] func (self *EventHandler) AttendanceList(c *gin.Context) { diff --git a/api/event/checkin.go b/api/event/checkin.go index bb066a0..b6ed5f7 100644 --- a/api/event/checkin.go +++ b/api/event/checkin.go @@ -18,6 +18,7 @@ import ( // @Produce json // @Param event_id query string true "Event UUID" // @Param X-Api-Version header string true "latest" +// @Param Authorization header string true "Bearer token" // @Success 200 {object} utils.RespStatus{data=service_event.CheckinResponse} "Successfully generated code" // @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" // @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" @@ -84,9 +85,11 @@ func (self *EventHandler) Checkin(c *gin.Context) { // @Tags Event // @Accept json // @Produce json -// @Param payload body service_event.CheckinSubmitData true "Checkin Code Data" -// @Success 200 {object} utils.RespStatus{data=nil} "Attendance marked successfully" -// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Code or Input" +// @Param X-Api-Version header string true "latest" +// @Param Authorization header string true "Bearer token" +// @Param payload body service_event.CheckinSubmitData true "Checkin Code Data" +// @Success 200 {object} utils.RespStatus{data=nil} "Attendance marked successfully" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Code or Input" // @Security ApiKeyAuth // @Router /event/checkin/submit [post] func (self *EventHandler) CheckinSubmit(c *gin.Context) { diff --git a/api/event/info.go b/api/event/info.go index ae53ae9..79b0214 100644 --- a/api/event/info.go +++ b/api/event/info.go @@ -16,13 +16,12 @@ import ( // @Tags Event // @Accept json // @Produce json -// @Param event_id query string true "Event UUID" -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=data.EventIndexDoc} "Successful retrieval" -// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" -// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" -// @Failure 404 {object} utils.RespStatus{data=nil} "Event Not Found" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Param event_id query string true "Event UUID" +// @Success 200 {object} utils.RespStatus{data=data.EventIndexDoc} "Successful retrieval" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 404 {object} utils.RespStatus{data=nil} "Event Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" // @Security ApiKeyAuth // @Router /event/info [get] func (self *EventHandler) Info(c *gin.Context) { diff --git a/api/event/join.go b/api/event/join.go index 7f6a567..53ab0e9 100644 --- a/api/event/join.go +++ b/api/event/join.go @@ -15,13 +15,12 @@ import ( // @Tags Event // @Accept json // @Produce json -// @Param request body service_event.EventJoinData true "Event Join Details (UserId and EventId are required)" -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=service_event.EventJoinResponse} "Successfully joined the event" -// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input or UUID Parse Failed" -// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" -// @Failure 403 {object} utils.RespStatus{data=nil} "Unauthorized / Missing User ID / Event Limit Exceeded" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error / Database Error" +// @Param request body service_event.EventJoinData true "Event Join Details (UserId and EventId are required)" +// @Success 200 {object} utils.RespStatus{data=service_event.EventJoinResponse} "Successfully joined the event" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input or UUID Parse Failed" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 403 {object} utils.RespStatus{data=nil} "Unauthorized / Missing User ID / Event Limit Exceeded" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error / Database Error" // @Security ApiKeyAuth // @Router /event/join [post] func (self *EventHandler) Join(c *gin.Context) { diff --git a/api/event/joined.go b/api/event/joined.go new file mode 100644 index 0000000..e7a5ad0 --- /dev/null +++ b/api/event/joined.go @@ -0,0 +1,94 @@ +package event + +import ( + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_event" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// GetJoined retrieves a paginated list of events that the current user has joined. +// +// @Summary Get Joined Events +// @Description Fetches a list of events where the authenticated user is a participant. Supports pagination. +// @Tags Event +// @Accept json +// @Produce json +// @Param limit query int false "Maximum number of events to return (default 20)" +// @Param offset query int false "Number of events to skip" +// @Success 200 {object} utils.RespStatus{data=[]data.EventIndexDoc} "Successful retrieval of joined events" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Security ApiKeyAuth +// @Router /event/joined [get] +func (self *EventHandler) Joined(c *gin.Context) { + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := new(exception.Builder). + SetStatus(exception.StatusUser). + SetService(exception.ServiceUser). + SetEndpoint(exception.EndpointUserServiceInfo). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonErrorMissingUserId). + Throw(c). + String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := new(exception.Builder). + SetStatus(exception.StatusServer). + SetService(exception.ServiceUser). + SetEndpoint(exception.EndpointUserServiceInfo). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonErrorUuidParseFailed). + SetError(err). + Throw(c). + String() + utils.HttpResponse(c, 500, errorCode) + return + } + + type JoinedQuery struct { + Limit *string `form:"limit"` + Offset *string `form:"offset"` + } + + var query JoinedQuery + if err := c.ShouldBindQuery(&query); err != nil { + exc := new(exception.Builder). + SetStatus(exception.StatusClient). + SetService(exception.ServiceEvent). + SetEndpoint(exception.EndpointEventServiceList). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonErrorInvalidInput). + Throw(c). + String() + + utils.HttpResponse(c, 400, exc) + return + } + + payload := &service_event.JoinedEventListPayload{ + Context: c, + UserId: userId, + Data: &service_event.JoinedEventListData{ + Limit: query.Limit, + Offset: query.Offset, + }, + } + + result := self.svc.GetJoinedEvent(payload) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} diff --git a/api/event/list.go b/api/event/list.go index a9669a7..503c81c 100644 --- a/api/event/list.go +++ b/api/event/list.go @@ -16,13 +16,12 @@ import ( // @Tags Event // @Accept json // @Produce json -// @Param limit query int false "Maximum number of events to return (default 20)" -// @Param offset query int false "Number of events to skip" -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=[]data.EventIndexDoc} "Successful paginated list retrieval" -// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input (Missing offset or malformed parameters)" -// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error (Database query failed)" +// @Param limit query int false "Maximum number of events to return (default 20)" +// @Param offset query int false "Number of events to skip" +// @Success 200 {object} utils.RespStatus{data=[]data.EventIndexDoc} "Successful paginated list retrieval" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input (Missing offset or malformed parameters)" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error (Database query failed)" // @Security ApiKeyAuth // @Router /event/list [get] func (self *EventHandler) List(c *gin.Context) { diff --git a/api/kyc/query.go b/api/kyc/query.go index 5fcca8b..5a8ee9f 100644 --- a/api/kyc/query.go +++ b/api/kyc/query.go @@ -13,12 +13,11 @@ import ( // @Tags KYC // @Accept json // @Produce json -// @Param payload body service_kyc.KycQueryData true "KYC query data (KycId)" -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=service_kyc.KycQueryResponse} "Query processed (success/pending/failed)" -// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid UUID or input" -// @Failure 403 {object} utils.RespStatus{data=nil} "Unauthorized" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Param payload body service_kyc.KycQueryData true "KYC query data (KycId)" +// @Success 200 {object} utils.RespStatus{data=service_kyc.KycQueryResponse} "Query processed (success/pending/failed)" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid UUID or input" +// @Failure 403 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" // @Security ApiKeyAuth // @Router /kyc/query [post] func (self *KycHandler) Query(c *gin.Context) { diff --git a/api/kyc/session.go b/api/kyc/session.go index 41e43a3..8ac0e7f 100644 --- a/api/kyc/session.go +++ b/api/kyc/session.go @@ -13,12 +13,11 @@ import ( // @Tags KYC // @Accept json // @Produce json -// @Param payload body service_kyc.KycSessionData true "KYC session data (Type and Base64 Identity)" -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=service_kyc.KycSessionResponse} "Session created successfully" -// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid input or decode failed" -// @Failure 403 {object} utils.RespStatus{data=nil} "Missing User ID" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error / KYC Service Error" +// @Param payload body service_kyc.KycSessionData true "KYC session data (Type and Base64 Identity)" +// @Success 200 {object} utils.RespStatus{data=service_kyc.KycSessionResponse} "Session created successfully" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid input or decode failed" +// @Failure 403 {object} utils.RespStatus{data=nil} "Missing User ID" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error / KYC Service Error" // @Security ApiKeyAuth // @Router /kyc/session [post] func (self *KycHandler) Session(c *gin.Context) { diff --git a/api/user/info.go b/api/user/info.go index a9c3949..d05e051 100644 --- a/api/user/info.go +++ b/api/user/info.go @@ -16,11 +16,10 @@ import ( // @Tags User // @Accept json // @Produce json -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=service_user.UserInfoData} "Successful profile retrieval" -// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" -// @Failure 404 {object} utils.RespStatus{data=nil} "User Not Found" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error (UUID Parse Failed)" +// @Success 200 {object} utils.RespStatus{data=service_user.UserInfoData} "Successful profile retrieval" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 404 {object} utils.RespStatus{data=nil} "User Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error (UUID Parse Failed)" // @Security ApiKeyAuth // @Router /user/info [get] func (self *UserHandler) Info(c *gin.Context) { diff --git a/api/user/list.go b/api/user/list.go index 0b23204..f2475dd 100644 --- a/api/user/list.go +++ b/api/user/list.go @@ -15,13 +15,12 @@ import ( // @Tags User // @Accept json // @Produce json -// @Param limit query string false "Maximum number of users to return (default 0)" -// @Param offset query string true "Number of users to skip" -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=[]data.UserIndexDoc} "Successful paginated list retrieval" -// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" -// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input (Format Error)" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error (Search Engine or Missing Offset)" +// @Param limit query string false "Maximum number of users to return (default 0)" +// @Param offset query string true "Number of users to skip" +// @Success 200 {object} utils.RespStatus{data=[]data.UserIndexDoc} "Successful paginated list retrieval" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input (Format Error)" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error (Search Engine or Missing Offset)" // @Security ApiKeyAuth // @Router /user/list [get] func (self *UserHandler) List(c *gin.Context) { diff --git a/api/user/other.go b/api/user/other.go index 2974451..39d25d7 100644 --- a/api/user/other.go +++ b/api/user/other.go @@ -16,13 +16,12 @@ import ( // @Tags User // @Accept json // @Produce json -// @Param user_id path string true "Other user id" -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=service_user.UserInfoData} "Successful profile retrieval" -// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" -// @Failure 404 {object} utils.RespStatus{data=nil} "User Not Found" -// @Failure 403 {object} utils.RespStatus{data=nil} "User Not Public" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error (UUID Parse Failed)" +// @Param user_id path string true "Other user id" +// @Success 200 {object} utils.RespStatus{data=service_user.UserInfoData} "Successful profile retrieval" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 404 {object} utils.RespStatus{data=nil} "User Not Found" +// @Failure 403 {object} utils.RespStatus{data=nil} "User Not Public" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error (UUID Parse Failed)" // @Security ApiKeyAuth // @Router /user/info/{user_id} [get] func (self *UserHandler) Other(c *gin.Context) { diff --git a/api/user/update.go b/api/user/update.go index 7ca7428..63977c5 100644 --- a/api/user/update.go +++ b/api/user/update.go @@ -17,12 +17,11 @@ import ( // @Tags User // @Accept json // @Produce json -// @Param payload body service_user.UserInfoData true "Updated User Profile Data" -// @Param X-Api-Version header string true "latest" -// @Success 200 {object} utils.RespStatus{data=nil} "Successful profile update" -// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input (Validation Failed)" -// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" -// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error (Database Error / UUID Parse Failed)" +// @Param payload body service_user.UserInfoData true "Updated User Profile Data" +// @Success 200 {object} utils.RespStatus{data=nil} "Successful profile update" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input (Validation Failed)" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error (Database Error / UUID Parse Failed)" // @Security ApiKeyAuth // @Router /user/update [patch] func (self *UserHandler) Update(c *gin.Context) { diff --git a/cmd/gen_exception/definitions/endpoint.yaml b/cmd/gen_exception/definitions/endpoint.yaml index a1138d5..ca8098f 100644 --- a/cmd/gen_exception/definitions/endpoint.yaml +++ b/cmd/gen_exception/definitions/endpoint.yaml @@ -26,5 +26,8 @@ endpoint: service: session: "01" query: "02" + agenda: + service: + submit: "01" middleware: service: "01" diff --git a/cmd/gen_exception/definitions/service.yaml b/cmd/gen_exception/definitions/service.yaml index be3669e..6b4f221 100644 --- a/cmd/gen_exception/definitions/service.yaml +++ b/cmd/gen_exception/definitions/service.yaml @@ -3,3 +3,4 @@ service: user: "002" event: "003" kyc: "004" + agenda: "005" diff --git a/data/agenda.go b/data/agenda.go index cf5250b..cb78918 100644 --- a/data/agenda.go +++ b/data/agenda.go @@ -14,6 +14,7 @@ type Agenda struct { AttendanceId uuid.UUID `json:"attendance_id" gorm:"type:uuid;not null"` Name string `json:"name" gorm:"type:varchar(255);not null"` Description string `json:"description" gorm:"type:text;not null"` + IsApproved bool `json:"is_approved" gorm:"type:boolean;default:false"` } func (self *Agenda) SetAttendanceId(id uuid.UUID) *Agenda { @@ -31,6 +32,11 @@ func (self *Agenda) SetDescription(desc string) *Agenda { return self } +func (self *Agenda) SetIsApproved(approved bool) *Agenda { + self.IsApproved = approved + return self +} + func (self *Agenda) GetByAgendaId(ctx context.Context, agendaId uuid.UUID) (*Agenda, error) { var agenda Agenda diff --git a/data/attendance.go b/data/attendance.go index ad90c07..1712a47 100644 --- a/data/attendance.go +++ b/data/attendance.go @@ -59,11 +59,11 @@ func (self *Attendance) SetState(s string) *Attendance { } func (self *Attendance) GetAttendance(ctx context.Context, userId, eventId uuid.UUID) (*Attendance, error) { - var checkin Attendance + var attendance Attendance err := Database.WithContext(ctx). Where("user_id = ? AND event_id = ?", userId, eventId). - First(&checkin).Error + First(&attendance).Error if err != nil { if err == gorm.ErrRecordNotFound { @@ -72,7 +72,7 @@ func (self *Attendance) GetAttendance(ctx context.Context, userId, eventId uuid. return nil, err } - return &checkin, err + return &attendance, err } type AttendanceUsers struct { diff --git a/data/event.go b/data/event.go index f93cb17..1d760a5 100644 --- a/data/event.go +++ b/data/event.go @@ -110,3 +110,33 @@ func (self *Event) FastListEvents(ctx context.Context, limit, offset int64) (*[] return &results, nil } + +func (self *Event) GetEventsByUserId(ctx context.Context, userId uuid.UUID, limit, offset int64) (*[]EventIndexDoc, error) { + var results []EventIndexDoc + + err := Database.WithContext(ctx). + Table("events"). + Select(` + events.event_id, + events.name, + events.type, + events.description, + events.start_time, + events.end_time, + events.thumbnail, + events.enable_kyc, + (SELECT COUNT(*) FROM attendances WHERE attendances.event_id = events.event_id) as join_count + `). + Joins("JOIN attendances ON attendances.event_id = events.event_id"). + Where("attendances.user_id = ?", userId). + Order("events.start_time DESC"). + Limit(int(limit)). + Offset(int(offset)). + Scan(&results).Error + + if err != nil { + return nil, err + } + + return &results, nil +} diff --git a/docs/docs.go b/docs/docs.go index f88dee2..1aa2e8a 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -24,6 +24,93 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/agenda/submit": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Creates a new agenda item for a specific attendance record.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Agenda" + ], + "summary": "Submit Agenda", + "parameters": [ + { + "description": "Agenda Submission Data", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/service_agenda.SubmitData" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/service_agenda.SubmitResponse" + } + } + } + ] + } + }, + "400": { + "description": "Invalid Input", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object" + } + } + } + ] + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object" + } + } + } + ] + } + } + } + } + }, "/auth/exchange": { "post": { "description": "Exchanges client credentials and user session for a specific redirect authorization code.", @@ -46,13 +133,6 @@ const docTemplate = `{ "schema": { "$ref": "#/definitions/service_auth.ExchangeData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -153,13 +233,6 @@ const docTemplate = `{ "schema": { "$ref": "#/definitions/service_auth.MagicData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -367,13 +440,6 @@ const docTemplate = `{ "schema": { "$ref": "#/definitions/service_auth.RefreshData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -474,13 +540,6 @@ const docTemplate = `{ "schema": { "$ref": "#/definitions/service_auth.TokenData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -581,13 +640,6 @@ const docTemplate = `{ "name": "event_id", "in": "query", "required": true - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -701,6 +753,13 @@ const docTemplate = `{ "name": "X-Api-Version", "in": "header", "required": true + }, + { + "type": "string", + "description": "Bearer token", + "name": "Authorization", + "in": "header", + "required": true } ], "responses": { @@ -883,6 +942,20 @@ const docTemplate = `{ ], "summary": "Submit Check-in Code", "parameters": [ + { + "type": "string", + "description": "latest", + "name": "X-Api-Version", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Bearer token", + "name": "Authorization", + "in": "header", + "required": true + }, { "description": "Checkin Code Data", "name": "payload", @@ -958,13 +1031,6 @@ const docTemplate = `{ "name": "event_id", "in": "query", "required": true - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1088,13 +1154,6 @@ const docTemplate = `{ "schema": { "$ref": "#/definitions/service_event.EventJoinData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1191,6 +1250,117 @@ const docTemplate = `{ } } }, + "/event/joined": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Fetches a list of events where the authenticated user is a participant. Supports pagination.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Event" + ], + "summary": "Get Joined Events", + "parameters": [ + { + "type": "integer", + "description": "Maximum number of events to return (default 20)", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "Number of events to skip", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful retrieval of joined events", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/data.EventIndexDoc" + } + } + } + } + ] + } + }, + "400": { + "description": "Invalid Input", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object" + } + } + } + ] + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object" + } + } + } + ] + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object" + } + } + } + ] + } + } + } + } + }, "/event/list": { "get": { "security": [ @@ -1221,13 +1391,6 @@ const docTemplate = `{ "description": "Number of events to skip", "name": "offset", "in": "query" - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1336,13 +1499,6 @@ const docTemplate = `{ "schema": { "$ref": "#/definitions/service_kyc.KycQueryData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1448,13 +1604,6 @@ const docTemplate = `{ "schema": { "$ref": "#/definitions/service_kyc.KycSessionData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1551,15 +1700,6 @@ const docTemplate = `{ "User" ], "summary": "Get My User Information", - "parameters": [ - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true - } - ], "responses": { "200": { "description": "Successful profile retrieval", @@ -1661,13 +1801,6 @@ const docTemplate = `{ "name": "user_id", "in": "path", "required": true - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1795,13 +1928,6 @@ const docTemplate = `{ "name": "offset", "in": "query", "required": true - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1910,13 +2036,6 @@ const docTemplate = `{ "schema": { "$ref": "#/definitions/service_user.UserInfoData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -2061,6 +2180,28 @@ const docTemplate = `{ } } }, + "service_agenda.SubmitData": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "event_id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "service_agenda.SubmitResponse": { + "type": "object", + "properties": { + "agenda_id": { + "type": "string" + } + } + }, "service_auth.ExchangeData": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index ef94eb7..83aca91 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -22,6 +22,93 @@ "host": "localhost:8000", "basePath": "/app/api/v1", "paths": { + "/agenda/submit": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Creates a new agenda item for a specific attendance record.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Agenda" + ], + "summary": "Submit Agenda", + "parameters": [ + { + "description": "Agenda Submission Data", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/service_agenda.SubmitData" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/service_agenda.SubmitResponse" + } + } + } + ] + } + }, + "400": { + "description": "Invalid Input", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object" + } + } + } + ] + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object" + } + } + } + ] + } + } + } + } + }, "/auth/exchange": { "post": { "description": "Exchanges client credentials and user session for a specific redirect authorization code.", @@ -44,13 +131,6 @@ "schema": { "$ref": "#/definitions/service_auth.ExchangeData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -151,13 +231,6 @@ "schema": { "$ref": "#/definitions/service_auth.MagicData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -365,13 +438,6 @@ "schema": { "$ref": "#/definitions/service_auth.RefreshData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -472,13 +538,6 @@ "schema": { "$ref": "#/definitions/service_auth.TokenData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -579,13 +638,6 @@ "name": "event_id", "in": "query", "required": true - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -699,6 +751,13 @@ "name": "X-Api-Version", "in": "header", "required": true + }, + { + "type": "string", + "description": "Bearer token", + "name": "Authorization", + "in": "header", + "required": true } ], "responses": { @@ -881,6 +940,20 @@ ], "summary": "Submit Check-in Code", "parameters": [ + { + "type": "string", + "description": "latest", + "name": "X-Api-Version", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Bearer token", + "name": "Authorization", + "in": "header", + "required": true + }, { "description": "Checkin Code Data", "name": "payload", @@ -956,13 +1029,6 @@ "name": "event_id", "in": "query", "required": true - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1086,13 +1152,6 @@ "schema": { "$ref": "#/definitions/service_event.EventJoinData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1189,6 +1248,117 @@ } } }, + "/event/joined": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Fetches a list of events where the authenticated user is a participant. Supports pagination.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Event" + ], + "summary": "Get Joined Events", + "parameters": [ + { + "type": "integer", + "description": "Maximum number of events to return (default 20)", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "Number of events to skip", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful retrieval of joined events", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/data.EventIndexDoc" + } + } + } + } + ] + } + }, + "400": { + "description": "Invalid Input", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object" + } + } + } + ] + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object" + } + } + } + ] + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.RespStatus" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object" + } + } + } + ] + } + } + } + } + }, "/event/list": { "get": { "security": [ @@ -1219,13 +1389,6 @@ "description": "Number of events to skip", "name": "offset", "in": "query" - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1334,13 +1497,6 @@ "schema": { "$ref": "#/definitions/service_kyc.KycQueryData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1446,13 +1602,6 @@ "schema": { "$ref": "#/definitions/service_kyc.KycSessionData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1549,15 +1698,6 @@ "User" ], "summary": "Get My User Information", - "parameters": [ - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true - } - ], "responses": { "200": { "description": "Successful profile retrieval", @@ -1659,13 +1799,6 @@ "name": "user_id", "in": "path", "required": true - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1793,13 +1926,6 @@ "name": "offset", "in": "query", "required": true - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -1908,13 +2034,6 @@ "schema": { "$ref": "#/definitions/service_user.UserInfoData" } - }, - { - "type": "string", - "description": "latest", - "name": "X-Api-Version", - "in": "header", - "required": true } ], "responses": { @@ -2059,6 +2178,28 @@ } } }, + "service_agenda.SubmitData": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "event_id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "service_agenda.SubmitResponse": { + "type": "object", + "properties": { + "agenda_id": { + "type": "string" + } + } + }, "service_auth.ExchangeData": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index c6695e8..425be1b 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -42,6 +42,20 @@ definitions: username: type: string type: object + service_agenda.SubmitData: + properties: + description: + type: string + event_id: + type: string + name: + type: string + type: object + service_agenda.SubmitResponse: + properties: + agenda_id: + type: string + type: object service_auth.ExchangeData: properties: client_id: @@ -205,6 +219,53 @@ info: title: NixCN CMS API version: "1.0" paths: + /agenda/submit: + post: + consumes: + - application/json + description: Creates a new agenda item for a specific attendance record. + parameters: + - description: Agenda Submission Data + in: body + name: body + required: true + schema: + $ref: '#/definitions/service_agenda.SubmitData' + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/utils.RespStatus' + - properties: + data: + $ref: '#/definitions/service_agenda.SubmitResponse' + type: object + "400": + description: Invalid Input + schema: + allOf: + - $ref: '#/definitions/utils.RespStatus' + - properties: + data: + type: object + type: object + "500": + description: Internal Server Error + schema: + allOf: + - $ref: '#/definitions/utils.RespStatus' + - properties: + data: + type: object + type: object + security: + - ApiKeyAuth: [] + summary: Submit Agenda + tags: + - Agenda /auth/exchange: post: consumes: @@ -218,11 +279,6 @@ paths: required: true schema: $ref: '#/definitions/service_auth.ExchangeData' - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: @@ -278,11 +334,6 @@ paths: required: true schema: $ref: '#/definitions/service_auth.MagicData' - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: @@ -403,11 +454,6 @@ paths: required: true schema: $ref: '#/definitions/service_auth.RefreshData' - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: @@ -463,11 +509,6 @@ paths: required: true schema: $ref: '#/definitions/service_auth.TokenData' - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: @@ -520,11 +561,6 @@ paths: name: event_id required: true type: string - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: @@ -588,6 +624,11 @@ paths: name: X-Api-Version required: true type: string + - description: Bearer token + in: header + name: Authorization + required: true + type: string produces: - application/json responses: @@ -685,6 +726,16 @@ paths: - application/json description: Submits the generated code to mark the user as attended. parameters: + - description: latest + in: header + name: X-Api-Version + required: true + type: string + - description: Bearer token + in: header + name: Authorization + required: true + type: string - description: Checkin Code Data in: body name: payload @@ -729,11 +780,6 @@ paths: name: event_id required: true type: string - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: @@ -800,11 +846,6 @@ paths: required: true schema: $ref: '#/definitions/service_event.EventJoinData' - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: @@ -858,6 +899,67 @@ paths: summary: Join an Event tags: - Event + /event/joined: + get: + consumes: + - application/json + description: Fetches a list of events where the authenticated user is a participant. + Supports pagination. + parameters: + - description: Maximum number of events to return (default 20) + in: query + name: limit + type: integer + - description: Number of events to skip + in: query + name: offset + type: integer + produces: + - application/json + responses: + "200": + description: Successful retrieval of joined events + schema: + allOf: + - $ref: '#/definitions/utils.RespStatus' + - properties: + data: + items: + $ref: '#/definitions/data.EventIndexDoc' + type: array + type: object + "400": + description: Invalid Input + schema: + allOf: + - $ref: '#/definitions/utils.RespStatus' + - properties: + data: + type: object + type: object + "401": + description: Unauthorized + schema: + allOf: + - $ref: '#/definitions/utils.RespStatus' + - properties: + data: + type: object + type: object + "500": + description: Internal Server Error + schema: + allOf: + - $ref: '#/definitions/utils.RespStatus' + - properties: + data: + type: object + type: object + security: + - ApiKeyAuth: [] + summary: Get Joined Events + tags: + - Event /event/list: get: consumes: @@ -873,11 +975,6 @@ paths: in: query name: offset type: integer - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: @@ -937,11 +1034,6 @@ paths: required: true schema: $ref: '#/definitions/service_kyc.KycQueryData' - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: @@ -999,11 +1091,6 @@ paths: required: true schema: $ref: '#/definitions/service_kyc.KycSessionData' - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: @@ -1054,12 +1141,6 @@ paths: - application/json description: Fetches the complete profile data for the user associated with the provided session/token. - parameters: - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: @@ -1116,11 +1197,6 @@ paths: name: user_id required: true type: string - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: @@ -1190,11 +1266,6 @@ paths: name: offset required: true type: string - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: @@ -1255,11 +1326,6 @@ paths: required: true schema: $ref: '#/definitions/service_user.UserInfoData' - - description: latest - in: header - name: X-Api-Version - required: true - type: string produces: - application/json responses: diff --git a/service/service_agenda/service.go b/service/service_agenda/service.go new file mode 100644 index 0000000..4ccc3ce --- /dev/null +++ b/service/service_agenda/service.go @@ -0,0 +1,11 @@ +package service_agenda + +type AgendaService interface { + Submit(*SubmitPayload) *SubmitResult +} + +type AgendaServiceImpl struct{} + +func NewAgendaService() AgendaService { + return &AgendaServiceImpl{} +} diff --git a/service/service_agenda/submit.go b/service/service_agenda/submit.go new file mode 100644 index 0000000..93995a7 --- /dev/null +++ b/service/service_agenda/submit.go @@ -0,0 +1,131 @@ +package service_agenda + +import ( + "context" + "nixcn-cms/data" + "nixcn-cms/internal/exception" + "nixcn-cms/service/shared" + + "github.com/google/uuid" + "gorm.io/gorm" +) + +type SubmitData struct { + EventId uuid.UUID `json:"event_id"` + Name string `json:"name"` + Description string `json:"description"` +} + +type SubmitPayload struct { + Context context.Context + UserId uuid.UUID `json:"user_id"` + Data *SubmitData +} + +type SubmitResponse struct { + AgendaId uuid.UUID `json:"agenda_id"` +} + +type SubmitResult struct { + Common shared.CommonResult + Data *SubmitResponse +} + +func (self *AgendaServiceImpl) Submit(payload *SubmitPayload) (result *SubmitResult) { + var err error + + attendanceData, err := new(data.Attendance). + GetAttendance(payload.Context, payload.UserId, payload.Data.EventId) + + if err != nil { + if err == gorm.ErrRecordNotFound { + exception := new(exception.Builder). + SetStatus(exception.StatusUser). + SetService(exception.ServiceAgenda). + SetEndpoint(exception.EndpointAgendaServiceSubmit). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonErrorInvalidInput). + SetError(err). + Throw(payload.Context) + + result = &SubmitResult{ + Common: shared.CommonResult{ + HttpCode: 403, + Exception: exception, + }, + Data: nil, + } + + return + } + exception := new(exception.Builder). + SetStatus(exception.StatusServer). + SetService(exception.ServiceAgenda). + SetEndpoint(exception.EndpointAgendaServiceSubmit). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonErrorDatabase). + SetError(err). + Throw(payload.Context) + + result = &SubmitResult{ + Common: shared.CommonResult{ + HttpCode: 500, + Exception: exception, + }, + Data: nil, + } + + return + } + + agendaModel := new(data.Agenda). + SetAttendanceId(attendanceData.AttendanceId). + SetName(payload.Data.Name). + SetDescription(payload.Data.Description). + SetIsApproved(false) + + err = agendaModel.Create(payload.Context) + if err != nil { + exception := new(exception.Builder). + SetStatus(exception.StatusServer). + SetService(exception.ServiceAgenda). + SetEndpoint(exception.EndpointAgendaServiceSubmit). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonErrorDatabase). + SetError(err). + Throw(payload.Context) + + result = &SubmitResult{ + Common: shared.CommonResult{ + HttpCode: 500, + Exception: exception, + }, + Data: nil, + } + + return + } + + successException := new(exception.Builder). + SetStatus(exception.StatusSuccess). + SetService(exception.ServiceAgenda). + SetEndpoint(exception.EndpointAgendaServiceSubmit). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonSuccess). + SetError(nil). + Throw(payload.Context) + + resultData := &SubmitResponse{ + AgendaId: agendaModel.AgendaId, + } + + result = &SubmitResult{ + Common: shared.CommonResult{ + HttpCode: 200, + Exception: successException, + }, + Data: resultData, + } + + return +} diff --git a/service/service_event/get_joined_event.go b/service/service_event/get_joined_event.go new file mode 100644 index 0000000..482038a --- /dev/null +++ b/service/service_event/get_joined_event.go @@ -0,0 +1,132 @@ +package service_event + +import ( + "context" + "nixcn-cms/data" + "nixcn-cms/internal/exception" + "nixcn-cms/service/shared" + "strconv" + + "github.com/google/uuid" +) + +type JoinedEventListData struct { + Limit *string `json:"limit"` + Offset *string `json:"offset"` +} + +type JoinedEventListPayload struct { + Context context.Context + UserId uuid.UUID + Data *JoinedEventListData +} + +type JoinedEventListResult struct { + Common shared.CommonResult + Data *[]data.EventIndexDoc `json:"event_list"` +} + +func (self *EventServiceImpl) GetJoinedEvent(payload *JoinedEventListPayload) (result *JoinedEventListResult) { + var limit string + if payload.Data.Limit == nil || *payload.Data.Limit == "" { + limit = "20" + } else { + limit = *payload.Data.Limit + } + + var offset string + if payload.Data.Offset == nil || *payload.Data.Offset == "" { + exc := new(exception.Builder). + SetStatus(exception.StatusUser). + SetService(exception.ServiceEvent). + SetEndpoint(exception.EndpointEventServiceList). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonErrorInvalidInput). + SetError(nil). + Throw(payload.Context) + + return &JoinedEventListResult{ + Common: shared.CommonResult{ + HttpCode: 400, + Exception: exc, + }, + } + } else { + offset = *payload.Data.Offset + } + + limitNum, err := strconv.Atoi(limit) + if err != nil { + exc := new(exception.Builder). + SetStatus(exception.StatusUser). + SetService(exception.ServiceEvent). + SetEndpoint(exception.EndpointEventServiceList). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonErrorInvalidInput). + SetError(err). + Throw(payload.Context) + + return &JoinedEventListResult{ + Common: shared.CommonResult{HttpCode: 400, Exception: exc}, + } + } + + offsetNum, err := strconv.Atoi(offset) + if err != nil { + exc := new(exception.Builder). + SetStatus(exception.StatusUser). + SetService(exception.ServiceEvent). + SetEndpoint(exception.EndpointEventServiceList). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonErrorInvalidInput). + SetError(err). + Throw(payload.Context) + + return &JoinedEventListResult{ + Common: shared.CommonResult{HttpCode: 400, Exception: exc}, + } + } + + eventList, err := new(data.Event). + GetEventsByUserId(payload.Context, payload.UserId, int64(limitNum), int64(offsetNum)) + + if err != nil { + exc := new(exception.Builder). + SetStatus(exception.StatusServer). + SetService(exception.ServiceEvent). + SetEndpoint(exception.EndpointEventServiceList). + SetType(exception.TypeSpecific). + SetOriginal(exception.EventListDatabaseFailed). + SetError(err). + Throw(payload.Context) + + return &JoinedEventListResult{ + Common: shared.CommonResult{ + HttpCode: 500, + Exception: exc, + }, + } + } + + if eventList != nil { + for i := range *eventList { + (*eventList)[i].IsJoined = true + } + } + + successExc := new(exception.Builder). + SetStatus(exception.StatusSuccess). + SetService(exception.ServiceEvent). + SetEndpoint(exception.EndpointEventServiceList). + SetType(exception.TypeCommon). + SetOriginal(exception.CommonSuccess). + Throw(payload.Context) + + return &JoinedEventListResult{ + Common: shared.CommonResult{ + HttpCode: 200, + Exception: successExc, + }, + Data: eventList, + } +} diff --git a/service/service_event/service.go b/service/service_event/service.go index 2a8f38c..be631f5 100644 --- a/service/service_event/service.go +++ b/service/service_event/service.go @@ -8,6 +8,7 @@ type EventService interface { ListEvents(*EventListPayload) *EventListResult JoinEvent(*EventJoinPayload) *EventJoinResult AttendanceList(*AttendanceListPayload) *AttendanceListResult + GetJoinedEvent(*JoinedEventListPayload) *JoinedEventListResult } type EventServiceImpl struct{}