chore: add `user.open_id` field

prod
Steven 2 years ago
parent 0ba7a9e519
commit 20651d21e1

@ -18,6 +18,7 @@ type User struct {
Email string `json:"email"` Email string `json:"email"`
Name string `json:"name"` Name string `json:"name"`
PasswordHash string `json:"-"` PasswordHash string `json:"-"`
OpenID string `json:"openId"`
UserSettingList []*UserSetting `json:"userSettingList"` UserSettingList []*UserSetting `json:"userSettingList"`
} }
@ -26,6 +27,7 @@ type UserCreate struct {
Name string `json:"name"` Name string `json:"name"`
Password string `json:"password"` Password string `json:"password"`
PasswordHash string PasswordHash string
OpenID string
} }
func (create UserCreate) Validate() error { func (create UserCreate) Validate() error {
@ -53,6 +55,8 @@ type UserPatch struct {
Name *string `json:"name"` Name *string `json:"name"`
Password *string `json:"password"` Password *string `json:"password"`
PasswordHash *string PasswordHash *string
ResetOpenID *bool `json:"resetOpenId"`
OpenID *string
} }
type UserFind struct { type UserFind struct {
@ -62,8 +66,9 @@ type UserFind struct {
RowStatus *RowStatus `json:"rowStatus"` RowStatus *RowStatus `json:"rowStatus"`
// Domain specific fields // Domain specific fields
Email *string `json:"email"` Email *string `json:"email"`
Name *string `json:"name"` Name *string `json:"name"`
OpenID *string `json:"openId"`
} }
type UserDelete struct { type UserDelete struct {

@ -64,6 +64,25 @@ func aclMiddleware(s *Server, next echo.HandlerFunc) echo.HandlerFunc {
return next(c) return next(c)
} }
{
// If there is openId in query string and related user is found, then skip auth.
openID := c.QueryParam("openId")
if openID != "" {
userFind := &api.UserFind{
OpenID: &openID,
}
user, err := s.Store.FindUser(ctx, userFind)
if err != nil && common.ErrorCode(err) != common.NotFound {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user by open_id").SetInternal(err)
}
if user != nil {
// Stores userID into context.
c.Set(getUserIDContextKey(), user.ID)
return next(c)
}
}
}
{ {
sess, _ := session.Get("session", c) sess, _ := session.Get("session", c)
userIDValue := sess.Values[userIDContextKey] userIDValue := sess.Values[userIDContextKey]

@ -61,6 +61,7 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
Email: signup.Email, Email: signup.Email,
Name: signup.Name, Name: signup.Name,
Password: signup.Password, Password: signup.Password,
OpenID: common.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)

@ -59,34 +59,6 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
return nil return nil
}) })
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)
}
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
})
g.GET("/user/:id", func(c echo.Context) error { g.GET("/user/:id", func(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
id, err := strconv.Atoi(c.Param("id")) id, err := strconv.Atoi(c.Param("id"))
@ -151,6 +123,11 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
userPatch.PasswordHash = &passwordHashStr userPatch.PasswordHash = &passwordHashStr
} }
if userPatch.ResetOpenID != nil && *userPatch.ResetOpenID {
uuid := common.GenUUID()
userPatch.OpenID = &uuid
}
user, err := s.Store.PatchUser(ctx, userPatch) user, err := s.Store.PatchUser(ctx, userPatch)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch user").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch user").SetInternal(err)
@ -163,6 +140,34 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
return nil return nil
}) })
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)
}
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
})
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)

@ -55,7 +55,8 @@ CREATE TABLE user (
row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL', row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL',
email TEXT NOT NULL UNIQUE, email TEXT NOT NULL UNIQUE,
name TEXT NOT NULL, name TEXT NOT NULL,
password_hash TEXT NOT NULL password_hash TEXT NOT NULL,
open_id TEXT NOT NULL UNIQUE
); );
INSERT INTO INSERT INTO
@ -75,6 +76,12 @@ WHERE
rowid = old.rowid; rowid = old.rowid;
END; END;
CREATE INDEX user_id_index ON user(id);
CREATE UNIQUE INDEX user_email_index ON user(email);
CREATE UNIQUE INDEX user_open_id_index ON user(open_id);
-- user_setting -- user_setting
CREATE TABLE user_setting ( CREATE TABLE user_setting (
user_id INTEGER NOT NULL, user_id INTEGER NOT NULL,

@ -3,7 +3,8 @@ INSERT INTO
`id`, `id`,
`email`, `email`,
`name`, `name`,
`password_hash` `password_hash`,
`open_id`
) )
VALUES VALUES
( (
@ -11,39 +12,6 @@ VALUES
'demo@iamcorgi.com', 'demo@iamcorgi.com',
'Demo Host', 'Demo Host',
-- raw password: secret -- raw password: secret
'$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK' '$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK',
'demo_open_id'
); );
INSERT INTO
user (
`id`,
`email`,
`name`,
`password_hash`
)
VALUES
(
102,
'jack@iamcorgi.com',
'Jack',
-- raw password: secret
'$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK'
);
INSERT INTO
user (
`id`,
`row_status`,
`email`,
`name`,
`password_hash`
)
VALUES
(
103,
'ARCHIVED',
'bob@iamcorgi.com',
'Bob',
-- raw password: secret
'$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK'
);

@ -24,6 +24,7 @@ type userRaw struct {
Email string Email string
Name string Name string
PasswordHash string PasswordHash string
OpenID string
} }
func (raw *userRaw) toUser() *api.User { func (raw *userRaw) toUser() *api.User {
@ -37,6 +38,7 @@ func (raw *userRaw) toUser() *api.User {
Email: raw.Email, Email: raw.Email,
Name: raw.Name, Name: raw.Name,
PasswordHash: raw.PasswordHash, PasswordHash: raw.PasswordHash,
OpenID: raw.OpenID,
} }
} }
@ -174,24 +176,27 @@ func createUser(ctx context.Context, tx *sql.Tx, create *api.UserCreate) (*userR
INSERT INTO user ( INSERT INTO user (
email, email,
name, name,
password_hash password_hash,
open_id
) )
VALUES (?, ?, ?) VALUES (?, ?, ?, ?)
RETURNING id, email, name, password_hash, created_ts, updated_ts, row_status RETURNING id, created_ts, updated_ts, row_status, email, name, password_hash, open_id
` `
var userRaw userRaw var userRaw userRaw
if err := tx.QueryRowContext(ctx, query, if err := tx.QueryRowContext(ctx, query,
create.Email, create.Email,
create.Name, create.Name,
create.PasswordHash, create.PasswordHash,
create.OpenID,
).Scan( ).Scan(
&userRaw.ID, &userRaw.ID,
&userRaw.Email,
&userRaw.Name,
&userRaw.PasswordHash,
&userRaw.CreatedTs, &userRaw.CreatedTs,
&userRaw.UpdatedTs, &userRaw.UpdatedTs,
&userRaw.RowStatus, &userRaw.RowStatus,
&userRaw.Email,
&userRaw.Name,
&userRaw.PasswordHash,
&userRaw.OpenID,
); err != nil { ); err != nil {
return nil, FormatError(err) return nil, FormatError(err)
} }
@ -214,6 +219,9 @@ func patchUser(ctx context.Context, tx *sql.Tx, patch *api.UserPatch) (*userRaw,
if v := patch.PasswordHash; v != nil { if v := patch.PasswordHash; v != nil {
set, args = append(set, "password_hash = ?"), append(args, *v) set, args = append(set, "password_hash = ?"), append(args, *v)
} }
if v := patch.OpenID; v != nil {
set, args = append(set, "open_id = ?"), append(args, *v)
}
args = append(args, patch.ID) args = append(args, patch.ID)
@ -221,7 +229,7 @@ func patchUser(ctx context.Context, tx *sql.Tx, patch *api.UserPatch) (*userRaw,
UPDATE user UPDATE user
SET ` + strings.Join(set, ", ") + ` SET ` + strings.Join(set, ", ") + `
WHERE id = ? WHERE id = ?
RETURNING id, created_ts, updated_ts, row_status, email, name, password_hash RETURNING id, created_ts, updated_ts, row_status, email, name, password_hash, open_id
` `
row, err := tx.QueryContext(ctx, query, args...) row, err := tx.QueryContext(ctx, query, args...)
if err != nil { if err != nil {
@ -239,6 +247,7 @@ func patchUser(ctx context.Context, tx *sql.Tx, patch *api.UserPatch) (*userRaw,
&userRaw.Email, &userRaw.Email,
&userRaw.Name, &userRaw.Name,
&userRaw.PasswordHash, &userRaw.PasswordHash,
&userRaw.OpenID,
); err != nil { ); err != nil {
return nil, FormatError(err) return nil, FormatError(err)
} }
@ -265,6 +274,9 @@ func findUserList(ctx context.Context, tx *sql.Tx, find *api.UserFind) ([]*userR
if v := find.Name; v != nil { if v := find.Name; v != nil {
where, args = append(where, "name = ?"), append(args, *v) where, args = append(where, "name = ?"), append(args, *v)
} }
if v := find.OpenID; v != nil {
where, args = append(where, "open_id = ?"), append(args, *v)
}
query := ` query := `
SELECT SELECT
@ -274,7 +286,8 @@ func findUserList(ctx context.Context, tx *sql.Tx, find *api.UserFind) ([]*userR
row_status, row_status,
email, email,
name, name,
password_hash password_hash,
open_id
FROM user FROM user
WHERE ` + strings.Join(where, " AND ") + ` WHERE ` + strings.Join(where, " AND ") + `
ORDER BY updated_ts DESC, created_ts DESC, row_status DESC ORDER BY updated_ts DESC, created_ts DESC, row_status DESC
@ -296,6 +309,7 @@ func findUserList(ctx context.Context, tx *sql.Tx, find *api.UserFind) ([]*userR
&userRaw.Email, &userRaw.Email,
&userRaw.Name, &userRaw.Name,
&userRaw.PasswordHash, &userRaw.PasswordHash,
&userRaw.OpenID,
); err != nil { ); err != nil {
return nil, FormatError(err) return nil, FormatError(err)
} }

Loading…
Cancel
Save