mirror of
https://github.com/miniflux/v2.git
synced 2025-08-31 18:31:01 +00:00
Remove extra column from users table (HSTORE field)
Migrated key/value pairs to specific columns.
This commit is contained in:
parent
ae74f94655
commit
83f3ccab0e
19 changed files with 256 additions and 141 deletions
140
storage/user.go
140
storage/user.go
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue