diff --git a/.env.template b/.env.template index e14d8e3..c7d2edd 100644 --- a/.env.template +++ b/.env.template @@ -6,6 +6,8 @@ IMG_MAX_FILE_SIZE_MB=1 IMG_CROP_WIDTH=500 IMG_CROP_HEIGHT=500 +RPKM_REG_START=2024-07-20T20:00:00Z + SERVICE_AUTH=localhost:3002 SERVICE_BACKEND=localhost:3003 SERVICE_CHECKIN=localhost:3004 diff --git a/cmd/main.go b/cmd/main.go index c157dd6..4dd737d 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -110,11 +110,11 @@ func main() { groupClient := groupProto.NewGroupServiceClient(backendConn) groupSvc := group.NewService(groupClient, logger) - groupHdr := group.NewHandler(groupSvc, validate, logger) + groupHdr := group.NewHandler(groupSvc, &conf.Rpkm, validate, logger) selectionClient := selectionProto.NewSelectionServiceClient(backendConn) selectionSvc := selection.NewService(selectionClient, logger) - selectionHdr := selection.NewHandler(selectionSvc, groupSvc, validate, logger) + selectionHdr := selection.NewHandler(selectionSvc, groupSvc, &conf.Rpkm, validate, logger) pinClient := pinProto.NewPinServiceClient(backendConn) pinSvc := pin.NewService(pinClient, logger) diff --git a/config/config.go b/config/config.go index eab40ed..9729461 100644 --- a/config/config.go +++ b/config/config.go @@ -1,8 +1,10 @@ package config import ( + "fmt" "os" "strconv" + "time" "github.com/joho/godotenv" ) @@ -19,6 +21,10 @@ type ImageConfig struct { CropHeight int } +type RpkmConfig struct { + RegStart time.Time +} + type ServiceConfig struct { Auth string Backend string @@ -41,6 +47,7 @@ type TracerConfig struct { type Config struct { App AppConfig Img ImageConfig + Rpkm RpkmConfig Svc ServiceConfig Cors CorsConfig Db DbConfig @@ -79,6 +86,22 @@ func LoadConfig() (*Config, error) { CropHeight: int(cropHeight), } + parsedTime, err := time.Parse(time.RFC3339, os.Getenv("RPKM_REG_START")) + if err != nil { + return nil, err + } + + const gmtPlus7 = 7 * 60 * 60 + gmtPlus7Location := time.FixedZone("GMT+7", gmtPlus7) + localTime := time.Date( + parsedTime.Year(), parsedTime.Month(), parsedTime.Day(), + parsedTime.Hour(), parsedTime.Minute(), parsedTime.Second(), + parsedTime.Nanosecond(), gmtPlus7Location) + fmt.Println("Local time (GMT+7):", localTime) + rpkmConfig := RpkmConfig{ + RegStart: localTime, + } + serviceConfig := ServiceConfig{ Auth: os.Getenv("SERVICE_AUTH"), Backend: os.Getenv("SERVICE_BACKEND"), @@ -101,6 +124,7 @@ func LoadConfig() (*Config, error) { return &Config{ App: appConfig, Img: imageConfig, + Rpkm: rpkmConfig, Svc: serviceConfig, Cors: corsConfig, Db: DbConfig, diff --git a/docker-compose.qa.template.yml b/docker-compose.qa.template.yml index d35d56e..1a2b267 100644 --- a/docker-compose.qa.template.yml +++ b/docker-compose.qa.template.yml @@ -20,6 +20,10 @@ services: APP_ENV: development APP_MAX_FILE_SIZE_MB: 10 APP_SERVICE_NAME: rpkm67-gateway + IMG_MAX_FILE_SIZE_MB: 1 + IMG_CROP_WIDTH: 500 + IMG_CROP_HEIGHT: 500 + RPKM_REG_START: 2024-07-20T20:00:00Z SERVICE_AUTH: auth:3002 SERVICE_BACKEND: backend:3003 SERVICE_CHECKIN: checkin:3004 diff --git a/internal/group/group.handler.go b/internal/group/group.handler.go index 9b723dc..e48729f 100644 --- a/internal/group/group.handler.go +++ b/internal/group/group.handler.go @@ -3,7 +3,9 @@ package group import ( "net/http" "strings" + "time" + "github.com/isd-sgcu/rpkm67-gateway/config" "github.com/isd-sgcu/rpkm67-gateway/internal/context" "github.com/isd-sgcu/rpkm67-gateway/internal/dto" "github.com/isd-sgcu/rpkm67-gateway/internal/validator" @@ -19,10 +21,11 @@ type Handler interface { DeleteMember(c context.Ctx) } -func NewHandler(svc Service, validate validator.DtoValidator, log *zap.Logger) Handler { +func NewHandler(svc Service, rpkmConf *config.RpkmConfig, validate validator.DtoValidator, log *zap.Logger) Handler { return &handlerImpl{ svc: svc, validate: validate, + rpkmConf: rpkmConf, log: log, } } @@ -30,6 +33,7 @@ func NewHandler(svc Service, validate validator.DtoValidator, log *zap.Logger) H type handlerImpl struct { svc Service validate validator.DtoValidator + rpkmConf *config.RpkmConfig log *zap.Logger } @@ -48,6 +52,11 @@ type handlerImpl struct { // @Failure 500 {object} apperror.AppError // @Router /group/{userId} [get] func (h *handlerImpl) FindByUserId(c context.Ctx) { + if !h.checkRegTime() { + c.ForbiddenError("Registration hasn't started") + return + } + userId := c.Param("userId") if userId == "" { c.BadRequestError("url parameter 'user_id' not found") @@ -90,6 +99,11 @@ func (h *handlerImpl) FindByUserId(c context.Ctx) { // @Failure 500 {object} apperror.AppError // @Router /group/token [get] func (h *handlerImpl) FindByToken(c context.Ctx) { + if !h.checkRegTime() { + c.ForbiddenError("Registration hasn't started") + return + } + token := c.Query("token") if token == "" { c.BadRequestError("url parameter 'token' not found") @@ -129,6 +143,11 @@ func (h *handlerImpl) FindByToken(c context.Ctx) { // @Failure 500 {object} apperror.AppError // @Router /group/{userId} [put] func (h *handlerImpl) UpdateConfirm(c context.Ctx) { + if !h.checkRegTime() { + c.ForbiddenError("Registration hasn't started") + return + } + userId := c.Param("userId") if userId == "" { c.BadRequestError("url parameter 'user_id' not found") @@ -179,6 +198,11 @@ func (h *handlerImpl) UpdateConfirm(c context.Ctx) { // @Failure 500 {object} apperror.AppError // @Router /group/join [post] func (h *handlerImpl) Join(c context.Ctx) { + if !h.checkRegTime() { + c.ForbiddenError("Registration hasn't started") + return + } + body := &dto.JoinGroupRequest{} if err := c.Bind(body); err != nil { h.log.Named("Join").Error("Bind: failed to bind request body", zap.Error(err)) @@ -224,6 +248,11 @@ func (h *handlerImpl) Join(c context.Ctx) { // @Failure 500 {object} apperror.AppError // @Router /group/leave [post] func (h *handlerImpl) Leave(c context.Ctx) { + if !h.checkRegTime() { + c.ForbiddenError("Registration hasn't started") + return + } + body := &dto.LeaveGroupRequest{} if err := c.Bind(body); err != nil { h.log.Named("Leave").Error("Bind: failed to bind request body", zap.Error(err)) @@ -268,6 +297,11 @@ func (h *handlerImpl) Leave(c context.Ctx) { // @Failure 500 {object} apperror.AppError // @Router /group/delete-member [delete] func (h *handlerImpl) DeleteMember(c context.Ctx) { + if !h.checkRegTime() { + c.ForbiddenError("Registration hasn't started") + return + } + body := &dto.DeleteMemberGroupBody{} if err := c.Bind(body); err != nil { h.log.Named("DeleteMember").Error("Bind: failed to bind request body", zap.Error(err)) @@ -297,3 +331,15 @@ func (h *handlerImpl) DeleteMember(c context.Ctx) { Group: res.Group, }) } + +func (h *handlerImpl) checkRegTime() bool { + nowUTC := time.Now().UTC() + gmtPlus7Location := time.FixedZone("GMT+7", 7*60*60) + nowGMTPlus7 := nowUTC.In(gmtPlus7Location) + if nowGMTPlus7.Before(h.rpkmConf.RegStart) { + h.log.Named("checkRegTime").Warn("Forbidden: Registration hasn't started") + return false + } + + return true +} diff --git a/internal/selection/selection.handler.go b/internal/selection/selection.handler.go index 22a21cf..0227903 100644 --- a/internal/selection/selection.handler.go +++ b/internal/selection/selection.handler.go @@ -3,7 +3,9 @@ package selection import ( "net/http" "strings" + "time" + "github.com/isd-sgcu/rpkm67-gateway/config" "github.com/isd-sgcu/rpkm67-gateway/internal/context" "github.com/isd-sgcu/rpkm67-gateway/internal/dto" "github.com/isd-sgcu/rpkm67-gateway/internal/group" @@ -23,14 +25,16 @@ type handlerImpl struct { svc Service groupSvc group.Service validate validator.DtoValidator + rpkmConf *config.RpkmConfig log *zap.Logger } -func NewHandler(svc Service, groupSvc group.Service, validate validator.DtoValidator, log *zap.Logger) Handler { +func NewHandler(svc Service, groupSvc group.Service, rpkmConf *config.RpkmConfig, validate validator.DtoValidator, log *zap.Logger) Handler { return &handlerImpl{ svc: svc, groupSvc: groupSvc, validate: validate, + rpkmConf: rpkmConf, log: log, } } @@ -51,6 +55,10 @@ func NewHandler(svc Service, groupSvc group.Service, validate validator.DtoValid // @Failure 500 {object} apperror.AppError // @Router /selection [post] func (h *handlerImpl) Create(c context.Ctx) { + if !h.checkRegTime() { + c.ForbiddenError("Registration hasn't started") + return + } h.checkGroupLeader(c) body := &dto.CreateSelectionRequest{} @@ -91,6 +99,11 @@ func (h *handlerImpl) Create(c context.Ctx) { // @Failure 500 {object} apperror.AppError // @Router /selection/{groupId} [get] func (h *handlerImpl) FindByGroupId(c context.Ctx) { + if !h.checkRegTime() { + c.ForbiddenError("Registration hasn't started") + return + } + groupId := c.Param("groupId") if groupId == "" { h.log.Named("FindByGroupIdSelection").Error("Param: groupId not found") @@ -134,6 +147,10 @@ func (h *handlerImpl) FindByGroupId(c context.Ctx) { // @Failure 500 {object} apperror.AppError // @Router /selection [patch] func (h *handlerImpl) Update(c context.Ctx) { + if !h.checkRegTime() { + c.ForbiddenError("Registration hasn't started") + return + } h.checkGroupLeader(c) body := &dto.UpdateSelectionRequest{} @@ -177,6 +194,10 @@ func (h *handlerImpl) Update(c context.Ctx) { // @Failure 500 {object} apperror.AppError // @Router /selection [delete] func (h *handlerImpl) Delete(c context.Ctx) { + if !h.checkRegTime() { + c.ForbiddenError("Registration hasn't started") + return + } h.checkGroupLeader(c) body := &dto.DeleteSelectionRequest{} @@ -217,6 +238,11 @@ func (h *handlerImpl) Delete(c context.Ctx) { // @Failure 500 {object} apperror.AppError // @Router /selection/count-by-baan [get] func (h *handlerImpl) CountByBaanId(c context.Ctx) { + if !h.checkRegTime() { + c.ForbiddenError("Registration hasn't started") + return + } + res, appErr := h.svc.CountByBaanId() if appErr != nil { h.log.Named("CountByBaanId").Error("CountByBaanId: ", zap.Error(appErr)) @@ -249,3 +275,15 @@ func (h *handlerImpl) checkGroupLeader(c context.Ctx) { c.Next() } + +func (h *handlerImpl) checkRegTime() bool { + nowUTC := time.Now().UTC() + gmtPlus7Location := time.FixedZone("GMT+7", 7*60*60) + nowGMTPlus7 := nowUTC.In(gmtPlus7Location) + if nowGMTPlus7.Before(h.rpkmConf.RegStart) { + h.log.Named("checkRegTime").Warn("Forbidden: Registration hasn't started") + return false + } + + return true +} diff --git a/internal/selection/test/selection.handler_test.go b/internal/selection/test/selection.handler_test.go index b280b2d..aec8b39 100644 --- a/internal/selection/test/selection.handler_test.go +++ b/internal/selection/test/selection.handler_test.go @@ -3,10 +3,12 @@ package test import ( "net/http" "testing" + "time" "github.com/bxcodec/faker/v4" "github.com/golang/mock/gomock" "github.com/isd-sgcu/rpkm67-gateway/apperror" + "github.com/isd-sgcu/rpkm67-gateway/config" "github.com/isd-sgcu/rpkm67-gateway/internal/dto" "github.com/isd-sgcu/rpkm67-gateway/internal/selection" ctxMock "github.com/isd-sgcu/rpkm67-gateway/mocks/context" @@ -21,6 +23,7 @@ type SelectionHandlerTest struct { suite.Suite controller *gomock.Controller logger *zap.Logger + rpkmConf *config.RpkmConfig userId string Selections []*dto.Selection Selection *dto.Selection @@ -36,6 +39,13 @@ func TestSelectionHandler(t *testing.T) { func (t *SelectionHandlerTest) SetupTest() { t.controller = gomock.NewController(t.T()) t.logger = zap.NewNop() + regStart, err := time.Parse(time.RFC3339, "2021-08-01T00:00:00Z") + if err != nil { + t.T().Fatal(err) + } + t.rpkmConf = &config.RpkmConfig{ + RegStart: regStart, + } t.userId = faker.UUIDHyphenated() @@ -63,7 +73,7 @@ func (t *SelectionHandlerTest) TestCreateSelectionSuccess() { groupSvc := groupMock.NewMockService(t.controller) validator := validatorMock.NewMockDtoValidator(t.controller) context := ctxMock.NewMockCtx(t.controller) - handler := selection.NewHandler(selectionSvc, groupSvc, validator, t.logger) + handler := selection.NewHandler(selectionSvc, groupSvc, t.rpkmConf, validator, t.logger) expectedResp := &dto.CreateSelectionResponse{ Selection: t.Selection, @@ -84,7 +94,7 @@ func (t *SelectionHandlerTest) TestCreateSelectionSuccess() { func (t *SelectionHandlerTest) TestCreateSelectionBindError() { context := ctxMock.NewMockCtx(t.controller) groupSvc := groupMock.NewMockService(t.controller) - handler := selection.NewHandler(nil, groupSvc, nil, t.logger) + handler := selection.NewHandler(nil, groupSvc, t.rpkmConf, nil, t.logger) context.EXPECT().GetString("userId").Return(t.userId) groupSvc.EXPECT().FindByUserId(&dto.FindByUserIdGroupRequest{UserId: t.userId}). @@ -101,7 +111,7 @@ func (t *SelectionHandlerTest) TestCreateSelectionServiceError() { groupSvc := groupMock.NewMockService(t.controller) validator := validatorMock.NewMockDtoValidator(t.controller) context := ctxMock.NewMockCtx(t.controller) - handler := selection.NewHandler(selectionSvc, groupSvc, validator, t.logger) + handler := selection.NewHandler(selectionSvc, groupSvc, t.rpkmConf, validator, t.logger) context.EXPECT().GetString("userId").Return(t.userId) groupSvc.EXPECT().FindByUserId(&dto.FindByUserIdGroupRequest{UserId: t.userId}). @@ -179,7 +189,7 @@ func (t *SelectionHandlerTest) TestDeleteSelectionSuccess() { groupSvc := groupMock.NewMockService(t.controller) validator := validatorMock.NewMockDtoValidator(t.controller) context := ctxMock.NewMockCtx(t.controller) - handler := selection.NewHandler(selectionSvc, groupSvc, validator, t.logger) + handler := selection.NewHandler(selectionSvc, groupSvc, t.rpkmConf, validator, t.logger) expectedResp := &dto.DeleteSelectionResponse{ Success: true, @@ -200,7 +210,7 @@ func (t *SelectionHandlerTest) TestDeleteSelectionSuccess() { func (t *SelectionHandlerTest) TestDeleteSelectionBindError() { context := ctxMock.NewMockCtx(t.controller) groupSvc := groupMock.NewMockService(t.controller) - handler := selection.NewHandler(nil, groupSvc, nil, t.logger) + handler := selection.NewHandler(nil, groupSvc, t.rpkmConf, nil, t.logger) context.EXPECT().GetString("userId").Return(t.userId) groupSvc.EXPECT().FindByUserId(&dto.FindByUserIdGroupRequest{UserId: t.userId}). @@ -217,7 +227,7 @@ func (t *SelectionHandlerTest) TestDeleteSelectionServiceError() { groupSvc := groupMock.NewMockService(t.controller) validator := validatorMock.NewMockDtoValidator(t.controller) context := ctxMock.NewMockCtx(t.controller) - handler := selection.NewHandler(selectionSvc, groupSvc, validator, t.logger) + handler := selection.NewHandler(selectionSvc, groupSvc, t.rpkmConf, validator, t.logger) context.EXPECT().GetString("userId").Return(t.userId) groupSvc.EXPECT().FindByUserId(&dto.FindByUserIdGroupRequest{UserId: t.userId}).