diff options
| author | nsfisis <nsfisis@gmail.com> | 2024-08-01 21:35:25 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2024-08-01 21:35:25 +0900 |
| commit | f6443042fbec1bd394439904f3c69e23709f7e6a (patch) | |
| tree | 46872e86ed7e42962895e0bfe04064387487523f /backend/api/handlers.go | |
| parent | 10b9be2c2a46b204f83be7d152ca62bf69e8843e (diff) | |
| parent | 94d5d89aa59b6d1e53dab280c26e3a8fcb22b7e4 (diff) | |
| download | phperkaigi-2025-albatross-f6443042fbec1bd394439904f3c69e23709f7e6a.tar.gz phperkaigi-2025-albatross-f6443042fbec1bd394439904f3c69e23709f7e6a.tar.zst phperkaigi-2025-albatross-f6443042fbec1bd394439904f3c69e23709f7e6a.zip | |
Merge branch 'refactor/api'
Diffstat (limited to 'backend/api/handlers.go')
| -rw-r--r-- | backend/api/handlers.go | 246 |
1 files changed, 67 insertions, 179 deletions
diff --git a/backend/api/handlers.go b/backend/api/handlers.go index c96cd2a..35fc9f7 100644 --- a/backend/api/handlers.go +++ b/backend/api/handlers.go @@ -4,7 +4,6 @@ import ( "context" "errors" "net/http" - "strings" "time" "github.com/jackc/pgx/v5" @@ -15,8 +14,6 @@ import ( "github.com/nsfisis/iosdc-japan-2024-albatross/backend/db" ) -var _ StrictServerInterface = (*ApiHandler)(nil) - type ApiHandler struct { q *db.Queries hubs GameHubsInterface @@ -26,20 +23,7 @@ type GameHubsInterface interface { StartGame(gameID int) error } -func NewHandler(queries *db.Queries, hubs GameHubsInterface) *ApiHandler { - return &ApiHandler{ - q: queries, - hubs: hubs, - } -} - -func (h *ApiHandler) GetAdminGames(ctx context.Context, request GetAdminGamesRequestObject) (GetAdminGamesResponseObject, error) { - user := ctx.Value("user").(*auth.JWTClaims) - if !user.IsAdmin { - return GetAdminGames403JSONResponse{ - Message: "Forbidden", - }, nil - } +func (h *ApiHandler) AdminGetGames(ctx context.Context, request AdminGetGamesRequestObject, user *auth.JWTClaims) (AdminGetGamesResponseObject, error) { gameRows, err := h.q.ListGames(ctx) if err != nil { return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) @@ -71,24 +55,20 @@ func (h *ApiHandler) GetAdminGames(ctx context.Context, request GetAdminGamesReq Problem: problem, } } - return GetAdminGames200JSONResponse{ + return AdminGetGames200JSONResponse{ Games: games, }, nil } -func (h *ApiHandler) GetAdminGamesGameId(ctx context.Context, request GetAdminGamesGameIdRequestObject) (GetAdminGamesGameIdResponseObject, error) { - user := ctx.Value("user").(*auth.JWTClaims) - if !user.IsAdmin { - return GetAdminGamesGameId403JSONResponse{ - Message: "Forbidden", - }, nil - } - gameId := request.GameId - row, err := h.q.GetGameById(ctx, int32(gameId)) +func (h *ApiHandler) AdminGetGame(ctx context.Context, request AdminGetGameRequestObject, user *auth.JWTClaims) (AdminGetGameResponseObject, error) { + gameID := request.GameId + row, err := h.q.GetGameById(ctx, int32(gameID)) if err != nil { if errors.Is(err, pgx.ErrNoRows) { - return GetAdminGamesGameId404JSONResponse{ - Message: "Game not found", + return AdminGetGame404JSONResponse{ + NotFoundJSONResponse: NotFoundJSONResponse{ + Message: "Game not found", + }, }, nil } else { return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) @@ -118,18 +98,12 @@ func (h *ApiHandler) GetAdminGamesGameId(ctx context.Context, request GetAdminGa StartedAt: startedAt, Problem: problem, } - return GetAdminGamesGameId200JSONResponse{ + return AdminGetGame200JSONResponse{ Game: game, }, nil } -func (h *ApiHandler) PutAdminGamesGameId(ctx context.Context, request PutAdminGamesGameIdRequestObject) (PutAdminGamesGameIdResponseObject, error) { - user := ctx.Value("user").(*auth.JWTClaims) - if !user.IsAdmin { - return PutAdminGamesGameId403JSONResponse{ - Message: "Forbidden", - }, nil - } +func (h *ApiHandler) AdminPutGame(ctx context.Context, request AdminPutGameRequestObject, user *auth.JWTClaims) (AdminPutGameResponseObject, error) { gameID := request.GameId displayName := request.Body.DisplayName durationSeconds := request.Body.DurationSeconds @@ -140,8 +114,10 @@ func (h *ApiHandler) PutAdminGamesGameId(ctx context.Context, request PutAdminGa game, err := h.q.GetGameById(ctx, int32(gameID)) if err != nil { if err == pgx.ErrNoRows { - return PutAdminGamesGameId404JSONResponse{ - Message: "Game not found", + return AdminPutGame404JSONResponse{ + NotFoundJSONResponse: NotFoundJSONResponse{ + Message: "Game not found", + }, }, nil } else { return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) @@ -202,21 +178,17 @@ func (h *ApiHandler) PutAdminGamesGameId(ctx context.Context, request PutAdminGa ProblemID: changedProblemID, }) if err != nil { - return PutAdminGamesGameId400JSONResponse{ - Message: err.Error(), + return AdminPutGame400JSONResponse{ + BadRequestJSONResponse: BadRequestJSONResponse{ + Message: err.Error(), + }, }, nil } - return PutAdminGamesGameId204Response{}, nil + return AdminPutGame204Response{}, nil } -func (h *ApiHandler) GetAdminUsers(ctx context.Context, request GetAdminUsersRequestObject) (GetAdminUsersResponseObject, error) { - user := ctx.Value("user").(*auth.JWTClaims) - if !user.IsAdmin { - return GetAdminUsers403JSONResponse{ - Message: "Forbidden", - }, nil - } +func (h *ApiHandler) AdminGetUsers(ctx context.Context, request AdminGetUsersRequestObject, user *auth.JWTClaims) (AdminGetUsersResponseObject, error) { users, err := h.q.ListUsers(ctx) if err != nil { return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) @@ -231,7 +203,7 @@ func (h *ApiHandler) GetAdminUsers(ctx context.Context, request GetAdminUsersReq IsAdmin: u.IsAdmin, } } - return GetAdminUsers200JSONResponse{ + return AdminGetUsers200JSONResponse{ Users: responseUsers, }, nil } @@ -239,17 +211,21 @@ func (h *ApiHandler) GetAdminUsers(ctx context.Context, request GetAdminUsersReq func (h *ApiHandler) PostLogin(ctx context.Context, request PostLoginRequestObject) (PostLoginResponseObject, error) { username := request.Body.Username password := request.Body.Password - userId, err := auth.Login(ctx, h.q, username, password) + userID, err := auth.Login(ctx, h.q, username, password) if err != nil { return PostLogin401JSONResponse{ - Message: "Invalid username or password", + UnauthorizedJSONResponse: UnauthorizedJSONResponse{ + Message: "Invalid username or password", + }, }, nil } - user, err := h.q.GetUserById(ctx, int32(userId)) + user, err := h.q.GetUserById(ctx, int32(userID)) if err != nil { return PostLogin401JSONResponse{ - Message: "Invalid username or password", + UnauthorizedJSONResponse: UnauthorizedJSONResponse{ + Message: "Invalid username or password", + }, }, nil } @@ -263,8 +239,7 @@ func (h *ApiHandler) PostLogin(ctx context.Context, request PostLoginRequestObje }, nil } -func (h *ApiHandler) GetToken(ctx context.Context, request GetTokenRequestObject) (GetTokenResponseObject, error) { - user := ctx.Value("user").(*auth.JWTClaims) +func (h *ApiHandler) GetToken(ctx context.Context, request GetTokenRequestObject, user *auth.JWTClaims) (GetTokenResponseObject, error) { newToken, err := auth.NewShortLivedJWT(user) if err != nil { return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) @@ -274,98 +249,53 @@ func (h *ApiHandler) GetToken(ctx context.Context, request GetTokenRequestObject }, nil } -func (h *ApiHandler) GetGames(ctx context.Context, request GetGamesRequestObject) (GetGamesResponseObject, error) { - user := ctx.Value("user").(*auth.JWTClaims) - playerId := request.Params.PlayerId - if !user.IsAdmin { - if playerId == nil || *playerId != user.UserID { - return GetGames403JSONResponse{ - Message: "Forbidden", - }, nil - } +func (h *ApiHandler) GetGames(ctx context.Context, request GetGamesRequestObject, user *auth.JWTClaims) (GetGamesResponseObject, error) { + gameRows, err := h.q.ListGamesForPlayer(ctx, int32(user.UserID)) + if err != nil { + return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) } - if playerId == nil { - gameRows, err := h.q.ListGames(ctx) - if err != nil { - return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) + games := make([]Game, len(gameRows)) + for i, row := range gameRows { + var startedAt *int + if row.StartedAt.Valid { + startedAtTimestamp := int(row.StartedAt.Time.Unix()) + startedAt = &startedAtTimestamp } - games := make([]Game, len(gameRows)) - for i, row := range gameRows { - var startedAt *int - if row.StartedAt.Valid { - startedAtTimestamp := int(row.StartedAt.Time.Unix()) - startedAt = &startedAtTimestamp - } - var problem *Problem - if row.ProblemID != nil { - if row.Title == nil || row.Description == nil { - panic("inconsistent data") - } - problem = &Problem{ - ProblemId: int(*row.ProblemID), - Title: *row.Title, - Description: *row.Description, - } + var problem *Problem + if row.ProblemID != nil { + if row.Title == nil || row.Description == nil { + panic("inconsistent data") } - games[i] = Game{ - GameId: int(row.GameID), - State: GameState(row.State), - DisplayName: row.DisplayName, - DurationSeconds: int(row.DurationSeconds), - StartedAt: startedAt, - Problem: problem, + problem = &Problem{ + ProblemId: int(*row.ProblemID), + Title: *row.Title, + Description: *row.Description, } } - return GetGames200JSONResponse{ - Games: games, - }, nil - } else { - gameRows, err := h.q.ListGamesForPlayer(ctx, int32(*playerId)) - if err != nil { - return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) - } - games := make([]Game, len(gameRows)) - for i, row := range gameRows { - var startedAt *int - if row.StartedAt.Valid { - startedAtTimestamp := int(row.StartedAt.Time.Unix()) - startedAt = &startedAtTimestamp - } - var problem *Problem - if row.ProblemID != nil { - if row.Title == nil || row.Description == nil { - panic("inconsistent data") - } - problem = &Problem{ - ProblemId: int(*row.ProblemID), - Title: *row.Title, - Description: *row.Description, - } - } - games[i] = Game{ - GameId: int(row.GameID), - State: GameState(row.State), - DisplayName: row.DisplayName, - DurationSeconds: int(row.DurationSeconds), - StartedAt: startedAt, - Problem: problem, - } + games[i] = Game{ + GameId: int(row.GameID), + State: GameState(row.State), + DisplayName: row.DisplayName, + DurationSeconds: int(row.DurationSeconds), + StartedAt: startedAt, + Problem: problem, } - return GetGames200JSONResponse{ - Games: games, - }, nil } + return GetGames200JSONResponse{ + Games: games, + }, nil } -func (h *ApiHandler) GetGamesGameId(ctx context.Context, request GetGamesGameIdRequestObject) (GetGamesGameIdResponseObject, error) { - user := ctx.Value("user").(*auth.JWTClaims) +func (h *ApiHandler) GetGame(ctx context.Context, request GetGameRequestObject, user *auth.JWTClaims) (GetGameResponseObject, error) { // TODO: check user permission - gameId := request.GameId - row, err := h.q.GetGameById(ctx, int32(gameId)) + gameID := request.GameId + row, err := h.q.GetGameById(ctx, int32(gameID)) if err != nil { if errors.Is(err, pgx.ErrNoRows) { - return GetGamesGameId404JSONResponse{ - Message: "Game not found", + return GetGame404JSONResponse{ + NotFoundJSONResponse: NotFoundJSONResponse{ + Message: "Game not found", + }, }, nil } else { return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) @@ -397,49 +327,7 @@ func (h *ApiHandler) GetGamesGameId(ctx context.Context, request GetGamesGameIdR StartedAt: startedAt, Problem: problem, } - return GetGamesGameId200JSONResponse{ + return GetGame200JSONResponse{ Game: game, }, nil } - -func _assertUserResponseIsCompatibleWithJWTClaims() { - var c auth.JWTClaims - var u User - u.UserId = c.UserID - u.Username = c.Username - u.DisplayName = c.DisplayName - u.IconPath = c.IconPath - u.IsAdmin = c.IsAdmin - _ = u -} - -func setupJWTFromAuthorizationHeader(c echo.Context) error { - authorization := c.Request().Header.Get("Authorization") - const prefix = "Bearer " - if !strings.HasPrefix(authorization, prefix) { - return echo.NewHTTPError(http.StatusUnauthorized) - } - token := authorization[len(prefix):] - claims, err := auth.ParseJWT(token) - if err != nil { - return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) - } - c.SetRequest(c.Request().WithContext(context.WithValue(c.Request().Context(), "user", claims))) - return nil -} - -func NewJWTMiddleware() StrictMiddlewareFunc { - return func(handler StrictHandlerFunc, operationID string) StrictHandlerFunc { - if operationID == "PostLogin" { - return handler - } - - return func(c echo.Context, request interface{}) (interface{}, error) { - err := setupJWTFromAuthorizationHeader(c) - if err != nil { - return nil, echo.NewHTTPError(http.StatusUnauthorized, err.Error()) - } - return handler(c, request) - } - } -} |
