chore: remove common error package

This commit is contained in:
Steven 2023-06-20 16:01:13 +08:00
parent df4c09c15b
commit 20884e9370
11 changed files with 68 additions and 140 deletions

View File

@ -2,8 +2,7 @@ package api
import ( import (
"fmt" "fmt"
"net/mail"
"github.com/boojack/shortify/common"
) )
type User struct { type User struct {
@ -15,12 +14,11 @@ type User struct {
RowStatus RowStatus `json:"rowStatus"` RowStatus RowStatus `json:"rowStatus"`
// Domain specific fields // Domain specific fields
Email string `json:"email"` Email string `json:"email"`
DisplayName string `json:"displayName"` DisplayName string `json:"displayName"`
PasswordHash string `json:"-"` PasswordHash string `json:"-"`
OpenID string `json:"openId"` OpenID string `json:"openId"`
Role Role `json:"role"` Role Role `json:"role"`
UserSettingList []*UserSetting `json:"userSettingList"`
} }
type UserCreate struct { type UserCreate struct {
@ -36,7 +34,7 @@ func (create UserCreate) Validate() error {
if len(create.Email) < 3 { if len(create.Email) < 3 {
return fmt.Errorf("email is too short, minimum length is 6") return fmt.Errorf("email is too short, minimum length is 6")
} }
if !common.ValidateEmail(create.Email) { if !validateEmail(create.Email) {
return fmt.Errorf("invalid email format") return fmt.Errorf("invalid email format")
} }
if len(create.Password) < 3 { if len(create.Password) < 3 {
@ -77,3 +75,11 @@ type UserFind struct {
type UserDelete struct { type UserDelete struct {
ID int ID int
} }
// validateEmail validates the email.
func validateEmail(email string) bool {
if _, err := mail.ParseAddress(email); err != nil {
return false
}
return true
}

View File

@ -2,8 +2,8 @@ package v1
import ( import (
"fmt" "fmt"
"net/mail"
"github.com/boojack/shortify/common"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
@ -57,7 +57,7 @@ func (create UserCreate) Validate() error {
if len(create.Email) < 3 { if len(create.Email) < 3 {
return fmt.Errorf("email is too short, minimum length is 6") return fmt.Errorf("email is too short, minimum length is 6")
} }
if !common.ValidateEmail(create.Email) { if !validateEmail(create.Email) {
return fmt.Errorf("invalid email format") return fmt.Errorf("invalid email format")
} }
if len(create.Password) < 3 { if len(create.Password) < 3 {
@ -104,3 +104,11 @@ func (*APIV1Service) RegisterUserRoutes(g *echo.Group) {
return c.String(200, "GET /user") return c.String(200, "GET /user")
}) })
} }
// validateEmail validates the email.
func validateEmail(email string) bool {
if _, err := mail.ParseAddress(email); err != nil {
return false
}
return true
}

View File

@ -1,30 +0,0 @@
package common
import (
"net/mail"
"strings"
"github.com/google/uuid"
)
// HasPrefixes returns true if the string s has any of the given prefixes.
func HasPrefixes(src string, prefixes ...string) bool {
for _, prefix := range prefixes {
if strings.HasPrefix(src, prefix) {
return true
}
}
return false
}
// ValidateEmail validates the email.
func ValidateEmail(email string) bool {
if _, err := mail.ParseAddress(email); err != nil {
return false
}
return true
}
func GenUUID() string {
return uuid.New().String()
}

View File

@ -1,31 +0,0 @@
package common
import (
"testing"
)
func TestValidateEmail(t *testing.T) {
tests := []struct {
email string
want bool
}{
{
email: "t@gmail.com",
want: true,
},
{
email: "@qq.com",
want: false,
},
{
email: "1@gmail",
want: true,
},
}
for _, test := range tests {
result := ValidateEmail(test.email)
if result != test.want {
t.Errorf("Validate Email %s: got result %v, want %v.", test.email, result, test.want)
}
}
}

View File

@ -6,7 +6,6 @@ import (
"strconv" "strconv"
"github.com/boojack/shortify/api" "github.com/boojack/shortify/api"
"github.com/boojack/shortify/common"
"github.com/gorilla/sessions" "github.com/gorilla/sessions"
"github.com/labstack/echo-contrib/session" "github.com/labstack/echo-contrib/session"
@ -69,7 +68,7 @@ func aclMiddleware(s *Server, next echo.HandlerFunc) echo.HandlerFunc {
ID: &userID, ID: &userID,
} }
user, err := s.Store.FindUser(ctx, userFind) user, err := s.Store.FindUser(ctx, userFind)
if err != nil && common.ErrorCode(err) != common.NotFound { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to find user by ID: %d", userID)).SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to find user by ID: %d", userID)).SetInternal(err)
} }
if user != nil { if user != nil {
@ -80,7 +79,7 @@ func aclMiddleware(s *Server, next echo.HandlerFunc) echo.HandlerFunc {
} }
} }
if common.HasPrefixes(path, "/api/ping", "/api/status", "/api/workspace") && c.Request().Method == http.MethodGet { if hasPrefixes(path, "/api/ping", "/api/status", "/api/workspace") && c.Request().Method == http.MethodGet {
return next(c) return next(c)
} }

View File

@ -6,7 +6,7 @@ import (
"net/http" "net/http"
"github.com/boojack/shortify/api" "github.com/boojack/shortify/api"
"github.com/boojack/shortify/common" "github.com/google/uuid"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
@ -24,7 +24,7 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
Email: &signin.Email, Email: &signin.Email,
} }
user, err := s.Store.FindUser(ctx, userFind) user, err := s.Store.FindUser(ctx, userFind)
if err != nil && common.ErrorCode(err) != common.NotFound { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to find user by email %s", signin.Email)).SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to find user by email %s", signin.Email)).SetInternal(err)
} }
if user == nil { if user == nil {
@ -56,7 +56,7 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
Email: signup.Email, Email: signup.Email,
DisplayName: signup.DisplayName, DisplayName: signup.DisplayName,
Password: signup.Password, Password: signup.Password,
OpenID: common.GenUUID(), OpenID: genUUID(),
} }
if err := userCreate.Validate(); err != nil { if err := userCreate.Validate(); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid user create format.").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Invalid user create format.").SetInternal(err)
@ -102,3 +102,7 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
return nil return nil
}) })
} }
func genUUID() string {
return uuid.New().String()
}

View File

@ -1,8 +1,9 @@
package server package server
import ( import (
"strings"
"github.com/boojack/shortify/api" "github.com/boojack/shortify/api"
"github.com/boojack/shortify/common"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
@ -16,9 +17,19 @@ func composeResponse(data any) any {
} }
} }
// hasPrefixes returns true if the string s has any of the given prefixes.
func hasPrefixes(src string, prefixes ...string) bool {
for _, prefix := range prefixes {
if strings.HasPrefix(src, prefix) {
return true
}
}
return false
}
func defaultAPIRequestSkipper(c echo.Context) bool { func defaultAPIRequestSkipper(c echo.Context) bool {
path := c.Path() path := c.Path()
return common.HasPrefixes(path, "/api", "/o") return hasPrefixes(path, "/api", "/o")
} }
func (server *Server) defaultAuthSkipper(c echo.Context) bool { func (server *Server) defaultAuthSkipper(c echo.Context) bool {
@ -26,7 +37,7 @@ func (server *Server) defaultAuthSkipper(c echo.Context) bool {
path := c.Path() path := c.Path()
// Skip auth. // Skip auth.
if common.HasPrefixes(path, "/api/auth") { if hasPrefixes(path, "/api/auth") {
return true return true
} }
@ -37,7 +48,7 @@ func (server *Server) defaultAuthSkipper(c echo.Context) bool {
OpenID: &openID, OpenID: &openID,
} }
user, err := server.Store.FindUser(ctx, userFind) user, err := server.Store.FindUser(ctx, userFind)
if err != nil && common.ErrorCode(err) != common.NotFound { if err != nil {
return false return false
} }
if user != nil { if user != nil {

View File

@ -7,7 +7,6 @@ import (
"strconv" "strconv"
"github.com/boojack/shortify/api" "github.com/boojack/shortify/api"
"github.com/boojack/shortify/common"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
@ -30,7 +29,7 @@ func (s *Server) registerShortcutRoutes(g *echo.Group) {
Name: &shortcutCreate.Name, Name: &shortcutCreate.Name,
WorkspaceID: &shortcutCreate.WorkspaceID, WorkspaceID: &shortcutCreate.WorkspaceID,
}) })
if err != nil && common.ErrorCode(err) != common.NotFound { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find shortcut").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find shortcut").SetInternal(err)
} }
if existingShortcut != nil { if existingShortcut != nil {
@ -178,9 +177,6 @@ func (s *Server) registerShortcutRoutes(g *echo.Group) {
ID: &shortcutID, ID: &shortcutID,
} }
if err := s.Store.DeleteShortcut(ctx, shortcutDelete); err != nil { if err := s.Store.DeleteShortcut(ctx, shortcutDelete); err != nil {
if common.ErrorCode(err) == common.NotFound {
return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("Shortcut ID not found: %d", shortcutID))
}
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete shortcut").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete shortcut").SetInternal(err)
} }

View File

@ -4,10 +4,10 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"net/mail"
"strconv" "strconv"
"github.com/boojack/shortify/api" "github.com/boojack/shortify/api"
"github.com/boojack/shortify/common"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
@ -40,14 +40,6 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
} }
userSettingList, err := s.Store.FindUserSettingList(ctx, &api.UserSettingFind{
UserID: userID,
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find userSettingList").SetInternal(err)
}
user.UserSettingList = userSettingList
return c.JSON(http.StatusOK, composeResponse(user)) return c.JSON(http.StatusOK, composeResponse(user))
}) })
@ -97,7 +89,7 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted patch user request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted patch user request").SetInternal(err)
} }
if userPatch.Email != nil && !common.ValidateEmail(*userPatch.Email) { if userPatch.Email != nil && !validateEmail(*userPatch.Email) {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid email format") return echo.NewHTTPError(http.StatusBadRequest, "Invalid email format")
} }
@ -112,7 +104,7 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
} }
if userPatch.ResetOpenID != nil && *userPatch.ResetOpenID { if userPatch.ResetOpenID != nil && *userPatch.ResetOpenID {
uuid := common.GenUUID() uuid := genUUID()
userPatch.OpenID = &uuid userPatch.OpenID = &uuid
} }
@ -124,30 +116,6 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
return c.JSON(http.StatusOK, composeResponse(user)) return c.JSON(http.StatusOK, composeResponse(user))
}) })
g.POST("/user/setting", func(c echo.Context) error {
ctx := c.Request().Context()
userID, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing auth session")
}
userSettingUpsert := &api.UserSettingUpsert{}
if err := json.NewDecoder(c.Request().Body).Decode(userSettingUpsert); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post user setting upsert request").SetInternal(err)
}
if err := userSettingUpsert.Validate(); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid user setting format").SetInternal(err)
}
userSettingUpsert.UserID = userID
userSetting, err := s.Store.UpsertUserSetting(ctx, userSettingUpsert)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert user setting").SetInternal(err)
}
return c.JSON(http.StatusOK, composeResponse(userSetting))
})
g.DELETE("/user/:id", func(c echo.Context) error { g.DELETE("/user/:id", func(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
currentUserID, ok := c.Get(getUserIDContextKey()).(int) currentUserID, ok := c.Get(getUserIDContextKey()).(int)
@ -173,12 +141,17 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
ID: userID, ID: userID,
} }
if err := s.Store.DeleteUser(ctx, userDelete); err != nil { if err := s.Store.DeleteUser(ctx, userDelete); err != nil {
if common.ErrorCode(err) == common.NotFound {
return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("User ID not found: %d", userID))
}
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete user").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete user").SetInternal(err)
} }
return c.JSON(http.StatusOK, true) return c.JSON(http.StatusOK, true)
}) })
} }
// validateEmail validates the email.
func validateEmail(email string) bool {
if _, err := mail.ParseAddress(email); err != nil {
return false
}
return true
}

View File

@ -7,7 +7,7 @@ import (
"strconv" "strconv"
"github.com/boojack/shortify/api" "github.com/boojack/shortify/api"
"github.com/boojack/shortify/common" "github.com/boojack/shortify/internal/errorutil"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
@ -108,7 +108,7 @@ func (s *Server) registerWorkspaceRoutes(g *echo.Group) {
Name: &workspaceName, Name: &workspaceName,
}) })
if err != nil { if err != nil {
if common.ErrorCode(err) == common.NotFound { if errorutil.ErrorCode(err) == errorutil.NotFound {
return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("workspace not found by name %s", workspaceName)) return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("workspace not found by name %s", workspaceName))
} }
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to find workspace with name %s", workspaceName)).SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to find workspace with name %s", workspaceName)).SetInternal(err)
@ -119,9 +119,6 @@ func (s *Server) registerWorkspaceRoutes(g *echo.Group) {
Name: &shortcutName, Name: &shortcutName,
}) })
if err != nil { if err != nil {
if common.ErrorCode(err) == common.NotFound {
return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("shortcut not found by name %s", shortcutName))
}
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to find shortcut with name %s", shortcutName)).SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to find shortcut with name %s", shortcutName)).SetInternal(err)
} }
@ -140,9 +137,6 @@ func (s *Server) registerWorkspaceRoutes(g *echo.Group) {
UserID: &userID, UserID: &userID,
}) })
if err != nil { if err != nil {
if common.ErrorCode(err) == common.NotFound {
return echo.NewHTTPError(http.StatusNotFound, "workspace user not found")
}
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find workspace user").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find workspace user").SetInternal(err)
} }
if workspaceUser == nil { if workspaceUser == nil {
@ -224,8 +218,8 @@ func (s *Server) registerWorkspaceRoutes(g *echo.Group) {
if err := s.Store.DeleteWorkspace(ctx, &api.WorkspaceDelete{ if err := s.Store.DeleteWorkspace(ctx, &api.WorkspaceDelete{
ID: workspaceID, ID: workspaceID,
}); err != nil { }); err != nil {
if common.ErrorCode(err) == common.NotFound { if errorutil.ErrorCode(err) == errorutil.NotFound {
return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("User ID not found: %d", userID)) return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("workspace %d not found", workspaceID))
} }
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete user").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete user").SetInternal(err)
} }

View File

@ -7,7 +7,7 @@ import (
"strconv" "strconv"
"github.com/boojack/shortify/api" "github.com/boojack/shortify/api"
"github.com/boojack/shortify/common" "github.com/boojack/shortify/internal/errorutil"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
@ -136,7 +136,7 @@ func (s *Server) registerWorkspaceUserRoutes(g *echo.Group) {
UserID: userID, UserID: userID,
} }
if err := s.Store.DeleteWorkspaceUser(ctx, workspaceUserDelete); err != nil { if err := s.Store.DeleteWorkspaceUser(ctx, workspaceUserDelete); err != nil {
if common.ErrorCode(err) == common.NotFound { if errorutil.ErrorCode(err) == errorutil.NotFound {
return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("Workspace user not found with workspace id %d and user id %d", workspaceID, userID)) return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("Workspace user not found with workspace id %d and user id %d", workspaceID, userID))
} }
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete workspace user").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete workspace user").SetInternal(err)
@ -147,9 +147,7 @@ func (s *Server) registerWorkspaceUserRoutes(g *echo.Group) {
WorkspaceID: &workspaceID, WorkspaceID: &workspaceID,
} }
if err := s.Store.DeleteShortcut(ctx, shortcutDelete); err != nil { if err := s.Store.DeleteShortcut(ctx, shortcutDelete); err != nil {
if common.ErrorCode(err) != common.NotFound { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete shortcut").SetInternal(err)
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete shortcut").SetInternal(err)
}
} }
return c.JSON(http.StatusOK, true) return c.JSON(http.StatusOK, true)