mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-10-27 11:09:04 +01:00
refactor: standardize API error handling (#1635)
This commit is contained in:
@@ -7,8 +7,9 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/pocket-id/pocket-id/backend/internal/common"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/apperror"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/dto"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/httpserver"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/utils/cookie"
|
||||
)
|
||||
|
||||
@@ -31,12 +32,11 @@ func newHandler(service *Service, appConfig AppConfigResolver) *handler {
|
||||
// @Param body body tokenCreateDto true "Token options"
|
||||
// @Success 201 {object} object "{ \"token\": \"string\" }"
|
||||
// @Router /api/users/{id}/one-time-access-token [post]
|
||||
func (h *handler) createTokenForUser(c *gin.Context) {
|
||||
func (h *handler) createTokenForUser(c *gin.Context) error {
|
||||
var input tokenCreateDto
|
||||
err := c.ShouldBindJSON(&input)
|
||||
err := httpserver.BindJSON(c, &input)
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the target user ID from the URL and apply the default expiration when no TTL is provided
|
||||
@@ -46,17 +46,16 @@ func (h *handler) createTokenForUser(c *gin.Context) {
|
||||
ttl = defaultTokenDuration
|
||||
}
|
||||
if userID == "" {
|
||||
_ = c.Error(&common.UserIdNotProvidedError{})
|
||||
return
|
||||
return apperror.MissingField("userId")
|
||||
}
|
||||
|
||||
token, err := h.service.CreateToken(c.Request.Context(), userID, ttl)
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, gin.H{"token": token})
|
||||
return nil
|
||||
}
|
||||
|
||||
// requestEmailAsUnauthenticatedUser godoc
|
||||
@@ -68,28 +67,26 @@ func (h *handler) createTokenForUser(c *gin.Context) {
|
||||
// @Param body body emailAsUnauthenticatedUserDto true "Email request information"
|
||||
// @Success 204 "No Content"
|
||||
// @Router /api/one-time-access-email [post]
|
||||
func (h *handler) requestEmailAsUnauthenticatedUser(c *gin.Context) {
|
||||
func (h *handler) requestEmailAsUnauthenticatedUser(c *gin.Context) error {
|
||||
dbConfig, err := h.appConfig.GetConfig(c.Request.Context())
|
||||
if err != nil {
|
||||
_ = c.Error(fmt.Errorf("error loading app configuration: %w", err))
|
||||
return
|
||||
return fmt.Errorf("error loading app configuration: %w", err)
|
||||
}
|
||||
|
||||
var input emailAsUnauthenticatedUserDto
|
||||
err = dto.ShouldBindWithNormalizedJSON(c, &input)
|
||||
err = httpserver.BindJSON(c, &input)
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
deviceToken, err := h.service.RequestOneTimeAccessEmailAsUnauthenticatedUser(c.Request.Context(), dbConfig, input.Email, input.RedirectPath)
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
cookie.AddDeviceTokenCookie(c, deviceToken)
|
||||
c.Status(http.StatusNoContent)
|
||||
return nil
|
||||
}
|
||||
|
||||
// requestEmailAsAdmin godoc
|
||||
@@ -102,18 +99,16 @@ func (h *handler) requestEmailAsUnauthenticatedUser(c *gin.Context) {
|
||||
// @Param body body emailAsAdminDto true "Email request options"
|
||||
// @Success 204 "No Content"
|
||||
// @Router /api/users/{id}/one-time-access-email [post]
|
||||
func (h *handler) requestEmailAsAdmin(c *gin.Context) {
|
||||
func (h *handler) requestEmailAsAdmin(c *gin.Context) error {
|
||||
dbConfig, err := h.appConfig.GetConfig(c.Request.Context())
|
||||
if err != nil {
|
||||
_ = c.Error(fmt.Errorf("error loading app configuration: %w", err))
|
||||
return
|
||||
return fmt.Errorf("error loading app configuration: %w", err)
|
||||
}
|
||||
|
||||
var input emailAsAdminDto
|
||||
err = c.ShouldBindJSON(&input)
|
||||
err = httpserver.BindJSON(c, &input)
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
userID := c.Param("id")
|
||||
@@ -124,11 +119,11 @@ func (h *handler) requestEmailAsAdmin(c *gin.Context) {
|
||||
}
|
||||
err = h.service.RequestOneTimeAccessEmailAsAdmin(c.Request.Context(), dbConfig, userID, ttl)
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
c.Status(http.StatusNoContent)
|
||||
return nil
|
||||
}
|
||||
|
||||
// exchangeToken godoc
|
||||
@@ -138,36 +133,33 @@ func (h *handler) requestEmailAsAdmin(c *gin.Context) {
|
||||
// @Param token path string true "One-time access token"
|
||||
// @Success 200 {object} dto.UserDto
|
||||
// @Router /api/one-time-access-token/{token} [post]
|
||||
func (h *handler) exchangeToken(c *gin.Context) {
|
||||
func (h *handler) exchangeToken(c *gin.Context) error {
|
||||
cfg, err := h.appConfig.GetConfig(c.Request.Context())
|
||||
if err != nil {
|
||||
_ = c.Error(fmt.Errorf("error loading app configuration: %w", err))
|
||||
return
|
||||
return fmt.Errorf("error loading app configuration: %w", err)
|
||||
}
|
||||
|
||||
loginCode := c.Param("token")
|
||||
// reject invalid length login codes
|
||||
if len(loginCode) != 6 && len(loginCode) != 16 {
|
||||
_ = c.Error(&common.TokenInvalidOrExpiredError{})
|
||||
return
|
||||
return apperror.TokenInvalidOrExpired()
|
||||
}
|
||||
|
||||
deviceToken, _ := c.Cookie(cookie.DeviceTokenCookieName)
|
||||
user, token, err := h.service.ExchangeToken(c.Request.Context(), cfg, loginCode, deviceToken, c.ClientIP(), c.Request.UserAgent())
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
var userDto dto.UserDto
|
||||
err = dto.MapStruct(user, &userDto)
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
maxAge := int(cfg.SessionDuration.AsDurationMinutes().Seconds())
|
||||
cookie.AddAccessTokenCookie(c, maxAge, token)
|
||||
|
||||
c.JSON(http.StatusOK, userDto)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user