diff --git a/di/wire_gen.go b/di/wire_gen.go index d09b64f..bc5816a 100644 --- a/di/wire_gen.go +++ b/di/wire_gen.go @@ -50,7 +50,7 @@ func Init() (Container, error) { authService := auth.NewService(authRepository, zapLogger, config) authHandler := auth.NewHandler(authService, zapLogger) evtregRepository := evtreg.NewRepository(db) - evtregService := evtreg.NewService(zapLogger, evtregRepository) + evtregService := evtreg.NewService(zapLogger, evtregRepository, eventCache) evtregHandler := evtreg.NewHandler(evtregService) corsHandler := cfgldr.MakeCorsConfig(config) authMiddleware := middleware.NewAuthMiddleware(authRepository, config) diff --git a/internal/event/event.cache.go b/internal/event/event.cache.go index 2d938d2..02a00c1 100644 --- a/internal/event/event.cache.go +++ b/internal/event/event.cache.go @@ -13,6 +13,7 @@ import ( type Cache interface { Get(ctx context.Context, key string) (bool, string, *apperror.AppError) Set(ctx context.Context, key string, value string, expiration time.Duration) *apperror.AppError + Del(ctx context.Context, keys ...string) *apperror.AppError } type cacheImpl struct { @@ -48,3 +49,11 @@ func (s *cacheImpl) Set(ctx context.Context, key string, value string, expiratio return nil } } + +func (s *cacheImpl) Del(ctx context.Context, keys ...string) *apperror.AppError { + if err := s.redis.Del(ctx, keys...).Err(); err != nil { + s.logger.Error("could not delete keys", zap.Strings("keys", keys), zap.Error(err)) + return apperror.InternalError + } + return nil +} diff --git a/internal/event/event.handler.go b/internal/event/event.handler.go index d1dd594..f34670d 100644 --- a/internal/event/event.handler.go +++ b/internal/event/event.handler.go @@ -133,5 +133,5 @@ func (h *handlerImpl) GetEventById(c *gin.Context) { func setHeader(c *gin.Context) { c.Header("Content-Type", "application/json; charset=utf-8") - c.Header("Cache-Control", "public, max-age=3600") + c.Header("Cache-Control", "public, max-age=30") } diff --git a/internal/evtreg/evtreg.handler.go b/internal/evtreg/evtreg.handler.go index e42e99b..b732c9f 100644 --- a/internal/evtreg/evtreg.handler.go +++ b/internal/evtreg/evtreg.handler.go @@ -48,8 +48,9 @@ func (h *handlerImpl) RegisterEvent(c *gin.Context) { return } - if apperr := h.svc.RegisterEvent(email, scheduleId); apperr != nil { + if apperr := h.svc.RegisterEvent(c, email, scheduleId); apperr != nil { utils.ReturnError(c, apperr) + return } c.AbortWithStatus(http.StatusNoContent) diff --git a/internal/evtreg/evtreg.repository.go b/internal/evtreg/evtreg.repository.go index 7611be8..76e494b 100644 --- a/internal/evtreg/evtreg.repository.go +++ b/internal/evtreg/evtreg.repository.go @@ -24,11 +24,11 @@ type repositoryImpl struct { } func (r *repositoryImpl) GetUserWithEventRegistrationByEmail(user *model.User, email string) error { - return r.db.Preload("RegisteredEvents").Preload("RegisteredEvents.Schedule").Where("email = ?", email).First(&user).Error + return r.db.Model(user).Preload("RegisteredEvents").Preload("RegisteredEvents.Schedule").Where("email = ?", email).First(&user).Error } func (r *repositoryImpl) GetScheduleById(schedule *model.Schedule, scheduleId int) error { - return r.db.Where("id = ?", scheduleId).First(schedule).Error + return r.db.Model(schedule).Where("id = ?", scheduleId).First(schedule).Error } func (r *repositoryImpl) RegisterEvent(userId int, scheduleId int) error { diff --git a/internal/evtreg/evtreg.service.go b/internal/evtreg/evtreg.service.go index 09d4a11..83913a5 100644 --- a/internal/evtreg/evtreg.service.go +++ b/internal/evtreg/evtreg.service.go @@ -1,22 +1,26 @@ package evtreg import ( + "context" "errors" + "fmt" "github.com/isd-sgcu/oph66-backend/apperror" + "github.com/isd-sgcu/oph66-backend/internal/event" "github.com/isd-sgcu/oph66-backend/internal/model" "go.uber.org/zap" "gorm.io/gorm" ) type Service interface { - RegisterEvent(userEmail string, scheduleId int) *apperror.AppError + RegisterEvent(ctx context.Context, userEmail string, scheduleId int) *apperror.AppError } -func NewService(logger *zap.Logger, repo Repository) Service { +func NewService(logger *zap.Logger, repo Repository, cache event.Cache) Service { return &serviceImpl{ logger, repo, + cache, } } @@ -25,9 +29,10 @@ var _ Service = &serviceImpl{} type serviceImpl struct { logger *zap.Logger repo Repository + cache event.Cache } -func (h *serviceImpl) RegisterEvent(userEmail string, scheduleId int) *apperror.AppError { +func (h *serviceImpl) RegisterEvent(ctx context.Context, userEmail string, scheduleId int) *apperror.AppError { var user model.User if err := h.repo.GetUserWithEventRegistrationByEmail(&user, userEmail); errors.Is(err, gorm.ErrRecordNotFound) { return apperror.UserNotFound @@ -57,5 +62,10 @@ func (h *serviceImpl) RegisterEvent(userEmail string, scheduleId int) *apperror. return apperror.InternalError } + keys := []string{fmt.Sprintf("get_event_by_id-%v", schedule.EventId), "get_all_events"} + if apperr := h.cache.Del(ctx, keys...); apperr != nil { + return apperr + } + return nil } diff --git a/migrations/00-init.sql b/migrations/00-init.sql index a32b7c7..0d3dd9c 100644 --- a/migrations/00-init.sql +++ b/migrations/00-init.sql @@ -134,3 +134,17 @@ CREATE TABLE event_registrations ( ); INSERT INTO feature_flags(key, enabled, cache_duration, extra_info) VALUES ('livestream', FALSE, 10, '{"url": "https://www.youtube.com/watch?v=0tOXxuLcaog"}'); + +CREATE OR REPLACE FUNCTION update_attandee_count() + RETURNS void + LANGUAGE plpgsql +AS $function$ +declare + sid INTEGER; + cnt INTEGER; +BEGIN +for sid, cnt in select id, count(user_id) from schedules s left join event_registrations er on s.id = er.schedule_id group by s.id loop + update schedules set current_attendee = cnt where id = sid; +end loop; +end; +$function$;