|
|
|
@@ -36,7 +36,7 @@ func (q *Queries) CountUsers(ctx context.Context) (int64, error) {
|
|
|
|
|
const createUser = `-- name: CreateUser :one
|
|
|
|
|
INSERT INTO users (username, password_hash, api_token, is_admin, display_name)
|
|
|
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
|
|
|
RETURNING id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name
|
|
|
|
|
RETURNING id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name, auto_approve_requests
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
type CreateUserParams struct {
|
|
|
|
@@ -67,6 +67,49 @@ func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, e
|
|
|
|
|
&i.ListenbrainzToken,
|
|
|
|
|
&i.ListenbrainzEnabled,
|
|
|
|
|
&i.DisplayName,
|
|
|
|
|
&i.AutoApproveRequests,
|
|
|
|
|
)
|
|
|
|
|
return i, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const createUserAdmin = `-- name: CreateUserAdmin :one
|
|
|
|
|
INSERT INTO users (username, password_hash, api_token, is_admin, display_name)
|
|
|
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
|
|
|
RETURNING id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name, auto_approve_requests
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
type CreateUserAdminParams struct {
|
|
|
|
|
Username string
|
|
|
|
|
PasswordHash string
|
|
|
|
|
ApiToken string
|
|
|
|
|
IsAdmin bool
|
|
|
|
|
DisplayName *string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Admin-driven user creation. Distinct from CreateUser/CreateUserFirstAdminRace:
|
|
|
|
|
// the caller (an admin) supplies all five fields explicitly including is_admin,
|
|
|
|
|
// so an admin can promote on creation. Used by POST /api/admin/users.
|
|
|
|
|
func (q *Queries) CreateUserAdmin(ctx context.Context, arg CreateUserAdminParams) (User, error) {
|
|
|
|
|
row := q.db.QueryRow(ctx, createUserAdmin,
|
|
|
|
|
arg.Username,
|
|
|
|
|
arg.PasswordHash,
|
|
|
|
|
arg.ApiToken,
|
|
|
|
|
arg.IsAdmin,
|
|
|
|
|
arg.DisplayName,
|
|
|
|
|
)
|
|
|
|
|
var i User
|
|
|
|
|
err := row.Scan(
|
|
|
|
|
&i.ID,
|
|
|
|
|
&i.Username,
|
|
|
|
|
&i.PasswordHash,
|
|
|
|
|
&i.ApiToken,
|
|
|
|
|
&i.IsAdmin,
|
|
|
|
|
&i.CreatedAt,
|
|
|
|
|
&i.SubsonicPassword,
|
|
|
|
|
&i.ListenbrainzToken,
|
|
|
|
|
&i.ListenbrainzEnabled,
|
|
|
|
|
&i.DisplayName,
|
|
|
|
|
&i.AutoApproveRequests,
|
|
|
|
|
)
|
|
|
|
|
return i, err
|
|
|
|
|
}
|
|
|
|
@@ -78,7 +121,7 @@ VALUES (
|
|
|
|
|
(SELECT NOT EXISTS (SELECT 1 FROM users)),
|
|
|
|
|
$4
|
|
|
|
|
)
|
|
|
|
|
RETURNING id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name
|
|
|
|
|
RETURNING id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name, auto_approve_requests
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
type CreateUserFirstAdminRaceParams struct {
|
|
|
|
@@ -120,10 +163,26 @@ func (q *Queries) CreateUserFirstAdminRace(ctx context.Context, arg CreateUserFi
|
|
|
|
|
&i.ListenbrainzToken,
|
|
|
|
|
&i.ListenbrainzEnabled,
|
|
|
|
|
&i.DisplayName,
|
|
|
|
|
&i.AutoApproveRequests,
|
|
|
|
|
)
|
|
|
|
|
return i, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const deleteUser = `-- name: DeleteUser :exec
|
|
|
|
|
DELETE FROM users WHERE id = $1
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
// Hard delete with cascade. The schema's ON DELETE CASCADE foreign keys
|
|
|
|
|
// handle plays/likes/sessions/etc. Caller must enforce the last-admin
|
|
|
|
|
// guard at the HTTP layer (count admins, refuse if target is the only
|
|
|
|
|
// admin). The lidarr_quarantine, general_likes*, play_events,
|
|
|
|
|
// sessions, and other user-FK tables all have ON DELETE CASCADE so
|
|
|
|
|
// this is a clean drop.
|
|
|
|
|
func (q *Queries) DeleteUser(ctx context.Context, id pgtype.UUID) error {
|
|
|
|
|
_, err := q.db.Exec(ctx, deleteUser, id)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getListenBrainzConfig = `-- name: GetListenBrainzConfig :one
|
|
|
|
|
SELECT
|
|
|
|
|
u.listenbrainz_token,
|
|
|
|
@@ -151,7 +210,7 @@ func (q *Queries) GetListenBrainzConfig(ctx context.Context, id pgtype.UUID) (Ge
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getUserByAPIToken = `-- name: GetUserByAPIToken :one
|
|
|
|
|
SELECT id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name FROM users WHERE api_token = $1
|
|
|
|
|
SELECT id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name, auto_approve_requests FROM users WHERE api_token = $1
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
func (q *Queries) GetUserByAPIToken(ctx context.Context, apiToken string) (User, error) {
|
|
|
|
@@ -168,12 +227,13 @@ func (q *Queries) GetUserByAPIToken(ctx context.Context, apiToken string) (User,
|
|
|
|
|
&i.ListenbrainzToken,
|
|
|
|
|
&i.ListenbrainzEnabled,
|
|
|
|
|
&i.DisplayName,
|
|
|
|
|
&i.AutoApproveRequests,
|
|
|
|
|
)
|
|
|
|
|
return i, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getUserByID = `-- name: GetUserByID :one
|
|
|
|
|
SELECT id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name FROM users WHERE id = $1
|
|
|
|
|
SELECT id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name, auto_approve_requests FROM users WHERE id = $1
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
func (q *Queries) GetUserByID(ctx context.Context, id pgtype.UUID) (User, error) {
|
|
|
|
@@ -190,12 +250,13 @@ func (q *Queries) GetUserByID(ctx context.Context, id pgtype.UUID) (User, error)
|
|
|
|
|
&i.ListenbrainzToken,
|
|
|
|
|
&i.ListenbrainzEnabled,
|
|
|
|
|
&i.DisplayName,
|
|
|
|
|
&i.AutoApproveRequests,
|
|
|
|
|
)
|
|
|
|
|
return i, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getUserByUsername = `-- name: GetUserByUsername :one
|
|
|
|
|
SELECT id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name FROM users WHERE username = $1
|
|
|
|
|
SELECT id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name, auto_approve_requests FROM users WHERE username = $1
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
func (q *Queries) GetUserByUsername(ctx context.Context, username string) (User, error) {
|
|
|
|
@@ -212,6 +273,7 @@ func (q *Queries) GetUserByUsername(ctx context.Context, username string) (User,
|
|
|
|
|
&i.ListenbrainzToken,
|
|
|
|
|
&i.ListenbrainzEnabled,
|
|
|
|
|
&i.DisplayName,
|
|
|
|
|
&i.AutoApproveRequests,
|
|
|
|
|
)
|
|
|
|
|
return i, err
|
|
|
|
|
}
|
|
|
|
@@ -257,6 +319,26 @@ func (q *Queries) ListUsers(ctx context.Context) ([]ListUsersRow, error) {
|
|
|
|
|
return items, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const resetUserPassword = `-- name: ResetUserPassword :exec
|
|
|
|
|
UPDATE users
|
|
|
|
|
SET password_hash = $2
|
|
|
|
|
WHERE id = $1
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
type ResetUserPasswordParams struct {
|
|
|
|
|
ID pgtype.UUID
|
|
|
|
|
PasswordHash string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Admin-driven password reset: caller writes a new hashed password to
|
|
|
|
|
// the target user's row. No knowledge of the old password is required
|
|
|
|
|
// (this is the admin path; self-service "knows current password" is
|
|
|
|
|
// a separate U3 query).
|
|
|
|
|
func (q *Queries) ResetUserPassword(ctx context.Context, arg ResetUserPasswordParams) error {
|
|
|
|
|
_, err := q.db.Exec(ctx, resetUserPassword, arg.ID, arg.PasswordHash)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const setListenBrainzEnabled = `-- name: SetListenBrainzEnabled :exec
|
|
|
|
|
UPDATE users
|
|
|
|
|
SET listenbrainz_enabled = $2
|
|
|
|
@@ -310,7 +392,7 @@ const updateUserAdmin = `-- name: UpdateUserAdmin :one
|
|
|
|
|
UPDATE users
|
|
|
|
|
SET is_admin = $2
|
|
|
|
|
WHERE id = $1
|
|
|
|
|
RETURNING id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name
|
|
|
|
|
RETURNING id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name, auto_approve_requests
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
type UpdateUserAdminParams struct {
|
|
|
|
@@ -334,6 +416,39 @@ func (q *Queries) UpdateUserAdmin(ctx context.Context, arg UpdateUserAdminParams
|
|
|
|
|
&i.ListenbrainzToken,
|
|
|
|
|
&i.ListenbrainzEnabled,
|
|
|
|
|
&i.DisplayName,
|
|
|
|
|
&i.AutoApproveRequests,
|
|
|
|
|
)
|
|
|
|
|
return i, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const updateUserAutoApprove = `-- name: UpdateUserAutoApprove :one
|
|
|
|
|
UPDATE users
|
|
|
|
|
SET auto_approve_requests = $2
|
|
|
|
|
WHERE id = $1
|
|
|
|
|
RETURNING id, username, password_hash, api_token, is_admin, created_at, subsonic_password, listenbrainz_token, listenbrainz_enabled, display_name, auto_approve_requests
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
type UpdateUserAutoApproveParams struct {
|
|
|
|
|
ID pgtype.UUID
|
|
|
|
|
AutoApproveRequests bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Toggle the per-user auto_approve_requests flag.
|
|
|
|
|
func (q *Queries) UpdateUserAutoApprove(ctx context.Context, arg UpdateUserAutoApproveParams) (User, error) {
|
|
|
|
|
row := q.db.QueryRow(ctx, updateUserAutoApprove, arg.ID, arg.AutoApproveRequests)
|
|
|
|
|
var i User
|
|
|
|
|
err := row.Scan(
|
|
|
|
|
&i.ID,
|
|
|
|
|
&i.Username,
|
|
|
|
|
&i.PasswordHash,
|
|
|
|
|
&i.ApiToken,
|
|
|
|
|
&i.IsAdmin,
|
|
|
|
|
&i.CreatedAt,
|
|
|
|
|
&i.SubsonicPassword,
|
|
|
|
|
&i.ListenbrainzToken,
|
|
|
|
|
&i.ListenbrainzEnabled,
|
|
|
|
|
&i.DisplayName,
|
|
|
|
|
&i.AutoApproveRequests,
|
|
|
|
|
)
|
|
|
|
|
return i, err
|
|
|
|
|
}
|
|
|
|
|