aboutsummaryrefslogtreecommitdiffstats
path: root/api/handlers
diff options
context:
space:
mode:
authorLeonardo Bishop <me@leonardobishop.com>2025-01-17 13:21:24 +0000
committerLeonardo Bishop <me@leonardobishop.com>2025-01-17 13:21:24 +0000
commitc00b690bd6f600554a1404e692bd9e4373325d27 (patch)
tree4488b625e1c24af52fced6f60ac1b3ddff1383bc /api/handlers
Initial commit
Diffstat (limited to 'api/handlers')
-rw-r--r--api/handlers/favourites.go112
-rw-r--r--api/handlers/schedule.go25
-rw-r--r--api/handlers/users.go112
-rw-r--r--api/handlers/util.go28
4 files changed, 277 insertions, 0 deletions
diff --git a/api/handlers/favourites.go b/api/handlers/favourites.go
new file mode 100644
index 0000000..862d366
--- /dev/null
+++ b/api/handlers/favourites.go
@@ -0,0 +1,112 @@
+package handlers
+
+import (
+ "github.com/LMBishop/confplanner/api/dto"
+ "github.com/LMBishop/confplanner/pkg/favourites"
+ "github.com/gofiber/fiber/v2"
+ "github.com/jackc/pgx/v5/pgtype"
+)
+
+func CreateFavourite(service favourites.Service) fiber.Handler {
+ return func(c *fiber.Ctx) error {
+ var request dto.CreateFavouritesRequest
+ if err := readBody(c, &request); err != nil {
+ return err
+ }
+
+ if request.GUID == nil && request.ID == nil {
+ return &dto.ErrorResponse{
+ Code: fiber.StatusBadRequest,
+ Message: "One of event GUID or event ID must be specified",
+ }
+ }
+
+ uid := c.Locals("uid").(int32)
+ var uuid pgtype.UUID
+ if request.GUID != nil {
+ if err := uuid.Scan(*request.GUID); err != nil {
+ return &dto.ErrorResponse{
+ Code: fiber.StatusBadRequest,
+ Message: "Bad event GUID",
+ }
+ }
+ }
+
+ createdFavourite, err := service.CreateFavouriteForUser(uid, uuid, request.ID)
+ if err != nil {
+ return err
+ }
+
+ return &dto.OkResponse{
+ Code: fiber.StatusCreated,
+ Data: &dto.CreateFavouritesResponse{
+ ID: createdFavourite.ID,
+ },
+ }
+ }
+}
+
+func GetFavourites(service favourites.Service) fiber.Handler {
+ return func(c *fiber.Ctx) error {
+ uid := c.Locals("uid").(int32)
+
+ favourites, err := service.GetFavouritesForUser(uid)
+ if err != nil {
+ return err
+ }
+
+ favouritesResponse := make([]dto.GetFavouritesResponse, 0)
+ for _, favourite := range *favourites {
+ var favouriteResponse dto.GetFavouritesResponse
+ favouriteResponse.Scan(favourite)
+
+ favouritesResponse = append(favouritesResponse, favouriteResponse)
+ }
+
+ return &dto.OkResponse{
+ Code: fiber.StatusOK,
+ Data: favouritesResponse,
+ }
+ }
+}
+
+func DeleteFavourite(service favourites.Service) fiber.Handler {
+ return func(c *fiber.Ctx) error {
+ var request dto.DeleteFavouritesRequest
+ if err := readBody(c, &request); err != nil {
+ return err
+ }
+
+ if request.GUID == nil && request.ID == nil {
+ return &dto.ErrorResponse{
+ Code: fiber.StatusBadRequest,
+ Message: "One of event GUID or event ID must be specified",
+ }
+ }
+
+ uid := c.Locals("uid").(int32)
+ var err error
+ var uuid pgtype.UUID
+ if err := uuid.Scan(*request.GUID); err != nil {
+ return &dto.ErrorResponse{
+ Code: fiber.StatusBadRequest,
+ Message: "Bad event GUID",
+ }
+ }
+
+ err = service.DeleteFavouriteForUserByEventDetails(uid, uuid, request.ID)
+ if err != nil {
+ if err == favourites.ErrNotFound {
+ return &dto.ErrorResponse{
+ Code: fiber.StatusNotFound,
+ Message: "Favourite not found",
+ }
+ }
+ return err
+ }
+
+ return &dto.OkResponse{
+ Code: fiber.StatusOK,
+ }
+ }
+}
diff --git a/api/handlers/schedule.go b/api/handlers/schedule.go
new file mode 100644
index 0000000..fd3a183
--- /dev/null
+++ b/api/handlers/schedule.go
@@ -0,0 +1,25 @@
+package handlers
+
+import (
+ "github.com/LMBishop/confplanner/api/dto"
+ "github.com/LMBishop/confplanner/pkg/schedule"
+ "github.com/gofiber/fiber/v2"
+ "github.com/golang-cz/nilslice"
+)
+
+func GetSchedule(service schedule.Service) fiber.Handler {
+ return func(c *fiber.Ctx) error {
+ schedule, lastUpdated, err := service.GetSchedule()
+ if err != nil {
+ return err
+ }
+
+ return &dto.OkResponse{
+ Code: fiber.StatusOK,
+ Data: &dto.GetScheduleResponse{
+ Schedule: nilslice.Initialize(*schedule),
+ LastUpdated: *lastUpdated,
+ },
+ }
+ }
+}
diff --git a/api/handlers/users.go b/api/handlers/users.go
new file mode 100644
index 0000000..deda9ca
--- /dev/null
+++ b/api/handlers/users.go
@@ -0,0 +1,112 @@
+package handlers
+
+import (
+ "errors"
+ "time"
+
+ "github.com/LMBishop/confplanner/api/dto"
+ "github.com/LMBishop/confplanner/pkg/user"
+ "github.com/gofiber/fiber/v2"
+ "github.com/gofiber/fiber/v2/middleware/session"
+)
+
+func Register(service user.Service) fiber.Handler {
+ return func(c *fiber.Ctx) error {
+ var request dto.RegisterRequest
+ if err := readBody(c, &request); err != nil {
+ return err
+ }
+
+ createdUser, err := service.CreateUser(request.Username, request.Password)
+ if err != nil {
+ if errors.Is(err, user.ErrUserExists) {
+ return &dto.ErrorResponse{
+ Code: fiber.StatusConflict,
+ Message: "User with that username already exists",
+ }
+ } else if errors.Is(err, user.ErrNotAcceptingRegistrations) {
+ return &dto.ErrorResponse{
+ Code: fiber.StatusForbidden,
+ Message: "This service is not currently accepting registrations",
+ }
+ }
+
+ return err
+ }
+
+ return &dto.OkResponse{
+ Code: fiber.StatusCreated,
+ Data: &dto.RegisterResponse{
+ ID: createdUser.ID,
+ },
+ }
+ }
+}
+
+func Login(service user.Service, store *session.Store) fiber.Handler {
+ return func(c *fiber.Ctx) error {
+ var request dto.LoginRequest
+ if err := readBody(c, &request); err != nil {
+ return err
+ }
+
+ user, err := service.Authenticate(request.Username, request.Password)
+ if err != nil {
+ return err
+ }
+
+ if user == nil {
+ return &dto.ErrorResponse{
+ Code: fiber.StatusBadRequest,
+ Message: "Username and password combination not found",
+ }
+ }
+
+ s, err := store.Get(c)
+ if err != nil {
+ return err
+ }
+
+ if s.Fresh() {
+ uid := user.ID
+ sid := s.ID()
+
+ s.Set("uid", uid)
+ s.Set("sid", sid)
+ s.Set("ip", c.Context().RemoteIP().String())
+ s.Set("login", time.Unix(time.Now().Unix(), 0).UTC().String())
+ s.Set("ua", string(c.Request().Header.UserAgent()))
+
+ err = s.Save()
+ if err != nil {
+ return err
+ }
+ }
+
+ return &dto.OkResponse{
+ Code: fiber.StatusOK,
+ Data: &dto.LoginResponse{
+ ID: user.ID,
+ Username: user.Username,
+ },
+ }
+ }
+}
+
+func Logout(store *session.Store) fiber.Handler {
+ return func(c *fiber.Ctx) error {
+ s, err := store.Get(c)
+ if err != nil {
+ return err
+ }
+
+ err = s.Destroy()
+ if err != nil {
+ return err
+ }
+
+ return &dto.OkResponse{
+ Code: fiber.StatusNoContent,
+ }
+ }
+}
diff --git a/api/handlers/util.go b/api/handlers/util.go
new file mode 100644
index 0000000..b0cf344
--- /dev/null
+++ b/api/handlers/util.go
@@ -0,0 +1,28 @@
+package handlers
+
+import (
+ "fmt"
+
+ "github.com/go-playground/validator/v10"
+ "github.com/gofiber/fiber/v2"
+)
+
+var validate = validator.New(validator.WithRequiredStructEnabled())
+
+func readBody(c *fiber.Ctx, request interface{}) error {
+ if err := c.BodyParser(request); err != nil {
+ return &fiber.Error{
+ Code: fiber.StatusBadRequest,
+ Message: fmt.Errorf("Invalid request (%w)", err).Error(),
+ }
+ }
+
+ if err := validate.Struct(request); err != nil {
+ return &fiber.Error{
+ Code: fiber.StatusBadRequest,
+ Message: err.Error(),
+ }
+ }
+
+ return nil
+}