|
|
@@ -12,7 +12,7 @@ import (
|
|
|
"miniflux.app/logger"
|
|
|
"miniflux.app/model"
|
|
|
|
|
|
- "github.com/lib/pq/hstore"
|
|
|
+ "github.com/lib/pq"
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
)
|
|
|
|
|
|
@@ -54,32 +54,37 @@ func (s *Storage) AnotherUserExists(userID int64, username string) bool {
|
|
|
|
|
|
// CreateUser creates a new user.
|
|
|
func (s *Storage) CreateUser(user *model.User) (err error) {
|
|
|
- password := ""
|
|
|
- extra := hstore.Hstore{Map: make(map[string]sql.NullString)}
|
|
|
-
|
|
|
+ hashedPassword := ""
|
|
|
if user.Password != "" {
|
|
|
- password, err = hashPassword(user.Password)
|
|
|
+ hashedPassword, err = hashPassword(user.Password)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if len(user.Extra) > 0 {
|
|
|
- for key, value := range user.Extra {
|
|
|
- extra.Map[key] = sql.NullString{String: value, Valid: true}
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
query := `
|
|
|
INSERT INTO users
|
|
|
- (username, password, is_admin, extra)
|
|
|
+ (username, password, is_admin, google_id, openid_connect_id)
|
|
|
VALUES
|
|
|
- (LOWER($1), $2, $3, $4)
|
|
|
+ (LOWER($1), $2, $3, $4, $5)
|
|
|
RETURNING
|
|
|
- id, username, is_admin, language, theme, timezone, entry_direction, entries_per_page, keyboard_shortcuts, show_reading_time, entry_swipe
|
|
|
+ id,
|
|
|
+ username,
|
|
|
+ is_admin,
|
|
|
+ language,
|
|
|
+ theme,
|
|
|
+ timezone,
|
|
|
+ entry_direction,
|
|
|
+ entries_per_page,
|
|
|
+ keyboard_shortcuts,
|
|
|
+ show_reading_time,
|
|
|
+ entry_swipe,
|
|
|
+ stylesheet,
|
|
|
+ google_id,
|
|
|
+ openid_connect_id
|
|
|
`
|
|
|
|
|
|
- err = s.db.QueryRow(query, user.Username, password, user.IsAdmin, extra).Scan(
|
|
|
+ err = s.db.QueryRow(query, user.Username, hashedPassword, user.IsAdmin, user.GoogleID, user.OpenIDConnectID).Scan(
|
|
|
&user.ID,
|
|
|
&user.Username,
|
|
|
&user.IsAdmin,
|
|
|
@@ -91,6 +96,9 @@ func (s *Storage) CreateUser(user *model.User) (err error) {
|
|
|
&user.KeyboardShortcuts,
|
|
|
&user.ShowReadingTime,
|
|
|
&user.EntrySwipe,
|
|
|
+ &user.Stylesheet,
|
|
|
+ &user.GoogleID,
|
|
|
+ &user.OpenIDConnectID,
|
|
|
)
|
|
|
if err != nil {
|
|
|
return fmt.Errorf(`store: unable to create user: %v`, err)
|
|
|
@@ -101,26 +109,6 @@ func (s *Storage) CreateUser(user *model.User) (err error) {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-// UpdateExtraField updates an extra field of the given user.
|
|
|
-func (s *Storage) UpdateExtraField(userID int64, field, value string) error {
|
|
|
- query := fmt.Sprintf(`UPDATE users SET extra = extra || hstore('%s', $1) WHERE id=$2`, field)
|
|
|
- _, err := s.db.Exec(query, value, userID)
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf(`store: unable to update user extra field: %v`, err)
|
|
|
- }
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-// RemoveExtraField deletes an extra field for the given user.
|
|
|
-func (s *Storage) RemoveExtraField(userID int64, field string) error {
|
|
|
- query := `UPDATE users SET extra = delete(extra, $1) WHERE id=$2`
|
|
|
- _, err := s.db.Exec(query, field, userID)
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf(`store: unable to remove user extra field: %v`, err)
|
|
|
- }
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
// UpdateUser updates a user.
|
|
|
func (s *Storage) UpdateUser(user *model.User) error {
|
|
|
if user.Password != "" {
|
|
|
@@ -141,9 +129,12 @@ func (s *Storage) UpdateUser(user *model.User) error {
|
|
|
entries_per_page=$8,
|
|
|
keyboard_shortcuts=$9,
|
|
|
show_reading_time=$10,
|
|
|
- entry_swipe=$11
|
|
|
+ entry_swipe=$11,
|
|
|
+ stylesheet=$12,
|
|
|
+ google_id=$13,
|
|
|
+ openid_connect_id=$14
|
|
|
WHERE
|
|
|
- id=$12
|
|
|
+ id=$15
|
|
|
`
|
|
|
|
|
|
_, err = s.db.Exec(
|
|
|
@@ -159,6 +150,9 @@ func (s *Storage) UpdateUser(user *model.User) error {
|
|
|
user.KeyboardShortcuts,
|
|
|
user.ShowReadingTime,
|
|
|
user.EntrySwipe,
|
|
|
+ user.Stylesheet,
|
|
|
+ user.GoogleID,
|
|
|
+ user.OpenIDConnectID,
|
|
|
user.ID,
|
|
|
)
|
|
|
if err != nil {
|
|
|
@@ -176,9 +170,12 @@ func (s *Storage) UpdateUser(user *model.User) error {
|
|
|
entries_per_page=$7,
|
|
|
keyboard_shortcuts=$8,
|
|
|
show_reading_time=$9,
|
|
|
- entry_swipe=$10
|
|
|
+ entry_swipe=$10,
|
|
|
+ stylesheet=$11,
|
|
|
+ google_id=$12,
|
|
|
+ openid_connect_id=$13
|
|
|
WHERE
|
|
|
- id=$11
|
|
|
+ id=$14
|
|
|
`
|
|
|
|
|
|
_, err := s.db.Exec(
|
|
|
@@ -193,6 +190,9 @@ func (s *Storage) UpdateUser(user *model.User) error {
|
|
|
user.KeyboardShortcuts,
|
|
|
user.ShowReadingTime,
|
|
|
user.EntrySwipe,
|
|
|
+ user.Stylesheet,
|
|
|
+ user.GoogleID,
|
|
|
+ user.OpenIDConnectID,
|
|
|
user.ID,
|
|
|
)
|
|
|
|
|
|
@@ -201,10 +201,6 @@ func (s *Storage) UpdateUser(user *model.User) error {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if err := s.UpdateExtraField(user.ID, "custom_css", user.Extra["custom_css"]); err != nil {
|
|
|
- return fmt.Errorf(`store: unable to update user custom css: %v`, err)
|
|
|
- }
|
|
|
-
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
@@ -234,7 +230,9 @@ func (s *Storage) UserByID(userID int64) (*model.User, error) {
|
|
|
show_reading_time,
|
|
|
entry_swipe,
|
|
|
last_login_at,
|
|
|
- extra
|
|
|
+ stylesheet,
|
|
|
+ google_id,
|
|
|
+ openid_connect_id
|
|
|
FROM
|
|
|
users
|
|
|
WHERE
|
|
|
@@ -259,7 +257,9 @@ func (s *Storage) UserByUsername(username string) (*model.User, error) {
|
|
|
show_reading_time,
|
|
|
entry_swipe,
|
|
|
last_login_at,
|
|
|
- extra
|
|
|
+ stylesheet,
|
|
|
+ google_id,
|
|
|
+ openid_connect_id
|
|
|
FROM
|
|
|
users
|
|
|
WHERE
|
|
|
@@ -268,8 +268,8 @@ func (s *Storage) UserByUsername(username string) (*model.User, error) {
|
|
|
return s.fetchUser(query, username)
|
|
|
}
|
|
|
|
|
|
-// UserByExtraField finds a user by an extra field value.
|
|
|
-func (s *Storage) UserByExtraField(field, value string) (*model.User, error) {
|
|
|
+// UserByField finds a user by a field value.
|
|
|
+func (s *Storage) UserByField(field, value string) (*model.User, error) {
|
|
|
query := `
|
|
|
SELECT
|
|
|
id,
|
|
|
@@ -284,13 +284,22 @@ func (s *Storage) UserByExtraField(field, value string) (*model.User, error) {
|
|
|
show_reading_time,
|
|
|
entry_swipe,
|
|
|
last_login_at,
|
|
|
- extra
|
|
|
+ stylesheet,
|
|
|
+ google_id,
|
|
|
+ openid_connect_id
|
|
|
FROM
|
|
|
users
|
|
|
WHERE
|
|
|
- extra->$1=$2
|
|
|
+ %s=$1
|
|
|
`
|
|
|
- return s.fetchUser(query, field, value)
|
|
|
+ return s.fetchUser(fmt.Sprintf(query, pq.QuoteIdentifier(field)), value)
|
|
|
+}
|
|
|
+
|
|
|
+// AnotherUserWithFieldExists returns true if a user has the value set for the given field.
|
|
|
+func (s *Storage) AnotherUserWithFieldExists(userID int64, field, value string) bool {
|
|
|
+ var result bool
|
|
|
+ s.db.QueryRow(fmt.Sprintf(`SELECT true FROM users WHERE id <> $1 AND %s=$2`, pq.QuoteIdentifier(field)), userID, value).Scan(&result)
|
|
|
+ return result
|
|
|
}
|
|
|
|
|
|
// UserByAPIKey returns a User from an API Key.
|
|
|
@@ -309,7 +318,9 @@ func (s *Storage) UserByAPIKey(token string) (*model.User, error) {
|
|
|
u.show_reading_time,
|
|
|
u.entry_swipe,
|
|
|
u.last_login_at,
|
|
|
- u.extra
|
|
|
+ u.stylesheet,
|
|
|
+ u.google_id,
|
|
|
+ u.openid_connect_id
|
|
|
FROM
|
|
|
users u
|
|
|
LEFT JOIN
|
|
|
@@ -321,8 +332,6 @@ func (s *Storage) UserByAPIKey(token string) (*model.User, error) {
|
|
|
}
|
|
|
|
|
|
func (s *Storage) fetchUser(query string, args ...interface{}) (*model.User, error) {
|
|
|
- var extra hstore.Hstore
|
|
|
-
|
|
|
user := model.NewUser()
|
|
|
err := s.db.QueryRow(query, args...).Scan(
|
|
|
&user.ID,
|
|
|
@@ -337,7 +346,9 @@ func (s *Storage) fetchUser(query string, args ...interface{}) (*model.User, err
|
|
|
&user.ShowReadingTime,
|
|
|
&user.EntrySwipe,
|
|
|
&user.LastLoginAt,
|
|
|
- &extra,
|
|
|
+ &user.Stylesheet,
|
|
|
+ &user.GoogleID,
|
|
|
+ &user.OpenIDConnectID,
|
|
|
)
|
|
|
|
|
|
if err == sql.ErrNoRows {
|
|
|
@@ -346,12 +357,6 @@ func (s *Storage) fetchUser(query string, args ...interface{}) (*model.User, err
|
|
|
return nil, fmt.Errorf(`store: unable to fetch user: %v`, err)
|
|
|
}
|
|
|
|
|
|
- for key, value := range extra.Map {
|
|
|
- if value.Valid {
|
|
|
- user.Extra[key] = value.String
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
return user, nil
|
|
|
}
|
|
|
|
|
|
@@ -404,7 +409,9 @@ func (s *Storage) Users() (model.Users, error) {
|
|
|
show_reading_time,
|
|
|
entry_swipe,
|
|
|
last_login_at,
|
|
|
- extra
|
|
|
+ stylesheet,
|
|
|
+ google_id,
|
|
|
+ openid_connect_id
|
|
|
FROM
|
|
|
users
|
|
|
ORDER BY username ASC
|
|
|
@@ -417,7 +424,6 @@ func (s *Storage) Users() (model.Users, error) {
|
|
|
|
|
|
var users model.Users
|
|
|
for rows.Next() {
|
|
|
- var extra hstore.Hstore
|
|
|
user := model.NewUser()
|
|
|
err := rows.Scan(
|
|
|
&user.ID,
|
|
|
@@ -432,19 +438,15 @@ func (s *Storage) Users() (model.Users, error) {
|
|
|
&user.ShowReadingTime,
|
|
|
&user.EntrySwipe,
|
|
|
&user.LastLoginAt,
|
|
|
- &extra,
|
|
|
+ &user.Stylesheet,
|
|
|
+ &user.GoogleID,
|
|
|
+ &user.OpenIDConnectID,
|
|
|
)
|
|
|
|
|
|
if err != nil {
|
|
|
return nil, fmt.Errorf(`store: unable to fetch users row: %v`, err)
|
|
|
}
|
|
|
|
|
|
- for key, value := range extra.Map {
|
|
|
- if value.Valid {
|
|
|
- user.Extra[key] = value.String
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
users = append(users, user)
|
|
|
}
|
|
|
|