From a6a87751535f3476828c4c27b9c529daf48e4cb9 Mon Sep 17 00:00:00 2001 From: Steven Date: Thu, 16 Mar 2023 08:08:36 +0800 Subject: [PATCH] feat: add role field to user --- api/user.go | 9 ++++--- server/user.go | 30 ++++------------------ store/db/migration/dev/LATEST__SCHEMA.sql | 3 ++- store/db/migration/prod/LATEST__SCHEMA.sql | 3 ++- store/store.go | 2 +- store/user.go | 19 +++++++++++--- 6 files changed, 31 insertions(+), 35 deletions(-) diff --git a/api/user.go b/api/user.go index d27c001..445a4f4 100644 --- a/api/user.go +++ b/api/user.go @@ -19,6 +19,7 @@ type User struct { DisplayName string `json:"displayName"` PasswordHash string `json:"-"` OpenID string `json:"openId"` + Role Role `json:"role"` UserSettingList []*UserSetting `json:"userSettingList"` } @@ -28,15 +29,16 @@ type UserCreate struct { Password string `json:"password"` PasswordHash string `json:"-"` OpenID string `json:"-"` + Role Role `json:"-"` } func (create UserCreate) Validate() error { - if !common.ValidateEmail(create.Email) { - return fmt.Errorf("invalid email format") - } if len(create.Email) < 3 { return fmt.Errorf("email is too short, minimum length is 6") } + if !common.ValidateEmail(create.Email) { + return fmt.Errorf("invalid email format") + } if len(create.Password) < 3 { return fmt.Errorf("password is too short, minimum length is 6") } @@ -69,6 +71,7 @@ type UserFind struct { Email *string `json:"email"` DisplayName *string `json:"displayName"` OpenID *string `json:"openId"` + Role *Role `json:"-"` } type UserDelete struct { diff --git a/server/user.go b/server/user.go index e8b1aa3..9152467 100644 --- a/server/user.go +++ b/server/user.go @@ -21,11 +21,7 @@ func (s *Server) registerUserRoutes(g *echo.Group) { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch user list").SetInternal(err) } - c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) - if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(userList)); err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode user list response").SetInternal(err) - } - return nil + return c.JSON(http.StatusOK, composeResponse(userList)) }) // GET /api/user/me is used to check if the user is logged in. @@ -52,11 +48,7 @@ func (s *Server) registerUserRoutes(g *echo.Group) { } user.UserSettingList = userSettingList - c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) - if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(user)); err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode user response").SetInternal(err) - } - return nil + return c.JSON(http.StatusOK, composeResponse(user)) }) g.GET("/user/:id", func(c echo.Context) error { @@ -73,11 +65,7 @@ func (s *Server) registerUserRoutes(g *echo.Group) { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch user").SetInternal(err) } - c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) - if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(user)); err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode user response").SetInternal(err) - } - return nil + return c.JSON(http.StatusOK, composeResponse(user)) }) g.PATCH("/user/:id", func(c echo.Context) error { @@ -133,11 +121,7 @@ func (s *Server) registerUserRoutes(g *echo.Group) { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch user").SetInternal(err) } - c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) - if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(user)); err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode user response").SetInternal(err) - } - return nil + return c.JSON(http.StatusOK, composeResponse(user)) }) g.POST("/user/setting", func(c echo.Context) error { @@ -161,11 +145,7 @@ func (s *Server) registerUserRoutes(g *echo.Group) { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert user setting").SetInternal(err) } - c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) - if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(userSetting)); err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode user setting response").SetInternal(err) - } - return nil + return c.JSON(http.StatusOK, composeResponse(userSetting)) }) g.DELETE("/user/:id", func(c echo.Context) error { diff --git a/store/db/migration/dev/LATEST__SCHEMA.sql b/store/db/migration/dev/LATEST__SCHEMA.sql index 3353a70..56afd95 100644 --- a/store/db/migration/dev/LATEST__SCHEMA.sql +++ b/store/db/migration/dev/LATEST__SCHEMA.sql @@ -13,7 +13,8 @@ CREATE TABLE user ( email TEXT NOT NULL UNIQUE, display_name TEXT NOT NULL, password_hash TEXT NOT NULL, - open_id TEXT NOT NULL UNIQUE + open_id TEXT NOT NULL UNIQUE, + role TEXT NOT NULL CHECK (role IN ('ADMIN', 'USER')) DEFAULT 'USER' ); INSERT INTO diff --git a/store/db/migration/prod/LATEST__SCHEMA.sql b/store/db/migration/prod/LATEST__SCHEMA.sql index 3353a70..56afd95 100644 --- a/store/db/migration/prod/LATEST__SCHEMA.sql +++ b/store/db/migration/prod/LATEST__SCHEMA.sql @@ -13,7 +13,8 @@ CREATE TABLE user ( email TEXT NOT NULL UNIQUE, display_name TEXT NOT NULL, password_hash TEXT NOT NULL, - open_id TEXT NOT NULL UNIQUE + open_id TEXT NOT NULL UNIQUE, + role TEXT NOT NULL CHECK (role IN ('ADMIN', 'USER')) DEFAULT 'USER' ); INSERT INTO diff --git a/store/store.go b/store/store.go index 466a829..a46e22b 100644 --- a/store/store.go +++ b/store/store.go @@ -13,7 +13,7 @@ type Store struct { profile *profile.Profile userCache sync.Map // map[int]*userRaw - workspaceCache sync.Map // map[int]*memoRaw + workspaceCache sync.Map // map[int]*workspaceRaw shortcutCache sync.Map // map[int]*shortcutRaw } diff --git a/store/user.go b/store/user.go index dec1983..c2e6b2c 100644 --- a/store/user.go +++ b/store/user.go @@ -25,6 +25,7 @@ type userRaw struct { DisplayName string PasswordHash string OpenID string + Role api.Role } func (raw *userRaw) toUser() *api.User { @@ -39,6 +40,7 @@ func (raw *userRaw) toUser() *api.User { DisplayName: raw.DisplayName, PasswordHash: raw.PasswordHash, OpenID: raw.OpenID, + Role: raw.Role, } } @@ -161,10 +163,11 @@ func createUser(ctx context.Context, tx *sql.Tx, create *api.UserCreate) (*userR email, display_name, password_hash, - open_id + open_id, + role ) VALUES (?, ?, ?, ?) - RETURNING id, created_ts, updated_ts, row_status, email, display_name, password_hash, open_id + RETURNING id, created_ts, updated_ts, row_status, email, display_name, password_hash, open_id, role ` var userRaw userRaw if err := tx.QueryRowContext(ctx, query, @@ -172,6 +175,7 @@ func createUser(ctx context.Context, tx *sql.Tx, create *api.UserCreate) (*userR create.DisplayName, create.PasswordHash, create.OpenID, + create.Role, ).Scan( &userRaw.ID, &userRaw.CreatedTs, @@ -181,6 +185,7 @@ func createUser(ctx context.Context, tx *sql.Tx, create *api.UserCreate) (*userR &userRaw.DisplayName, &userRaw.PasswordHash, &userRaw.OpenID, + &userRaw.Role, ); err != nil { return nil, err } @@ -213,7 +218,7 @@ func patchUser(ctx context.Context, tx *sql.Tx, patch *api.UserPatch) (*userRaw, UPDATE user SET ` + strings.Join(set, ", ") + ` WHERE id = ? - RETURNING id, created_ts, updated_ts, row_status, email, display_name, password_hash, open_id + RETURNING id, created_ts, updated_ts, row_status, email, display_name, password_hash, open_id, role ` row, err := tx.QueryContext(ctx, query, args...) if err != nil { @@ -232,6 +237,7 @@ func patchUser(ctx context.Context, tx *sql.Tx, patch *api.UserPatch) (*userRaw, &userRaw.DisplayName, &userRaw.PasswordHash, &userRaw.OpenID, + &userRaw.Role, ); err != nil { return nil, err } @@ -258,6 +264,9 @@ func findUserList(ctx context.Context, tx *sql.Tx, find *api.UserFind) ([]*userR if v := find.OpenID; v != nil { where, args = append(where, "open_id = ?"), append(args, *v) } + if v := find.Role; v != nil { + where, args = append(where, "role = ?"), append(args, *v) + } query := ` SELECT @@ -268,7 +277,8 @@ func findUserList(ctx context.Context, tx *sql.Tx, find *api.UserFind) ([]*userR email, display_name, password_hash, - open_id + open_id, + role FROM user WHERE ` + strings.Join(where, " AND ") + ` ORDER BY updated_ts DESC, created_ts DESC @@ -291,6 +301,7 @@ func findUserList(ctx context.Context, tx *sql.Tx, find *api.UserFind) ([]*userR &userRaw.DisplayName, &userRaw.PasswordHash, &userRaw.OpenID, + &userRaw.Role, ); err != nil { return nil, err }