feat: create admin dashboard with user preferences and library settings
- Add admin dashboard at /admin route consolidating all user settings - Move user preferences (username, email, password, theme) from separate page - Add ebook library preferences section with folder management - Add scan settings (frequency and auto-scan toggle) with database persistence - Create database migration for scan_frequency_minutes and auto_scan_enabled columns - Add API endpoints for scan settings management: - PUT /api/library/scan-settings - Update scan preferences - GET /api/library/scan-settings - Get current scan settings - Update dashboard navigation to link to admin dashboard - Remove old preferences.html template (functionality moved to admin) - Create Bruno API testing files for library endpoints - Add real-time folder loading and management in admin interface - Implement scan settings persistence and retrieval from database
This commit is contained in:
@@ -55,11 +55,13 @@ type UserEbookFolders struct {
|
||||
}
|
||||
|
||||
type Users struct {
|
||||
ID pgtype.UUID `db:"id" json:"id"`
|
||||
Email string `db:"email" json:"email"`
|
||||
Username string `db:"username" json:"username"`
|
||||
PasswordHash string `db:"password_hash" json:"password_hash"`
|
||||
Theme pgtype.Text `db:"theme" json:"theme"`
|
||||
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
||||
ID pgtype.UUID `db:"id" json:"id"`
|
||||
Email string `db:"email" json:"email"`
|
||||
Username string `db:"username" json:"username"`
|
||||
PasswordHash string `db:"password_hash" json:"password_hash"`
|
||||
Theme pgtype.Text `db:"theme" json:"theme"`
|
||||
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
||||
ScanFrequencyMinutes pgtype.Int4 `db:"scan_frequency_minutes" json:"scan_frequency_minutes"`
|
||||
AutoScanEnabled pgtype.Bool `db:"auto_scan_enabled" json:"auto_scan_enabled"`
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ type Querier interface {
|
||||
GetEbookRating(ctx context.Context, arg GetEbookRatingParams) (EbookRatings, error)
|
||||
GetEbookRatings(ctx context.Context, ebookID pgtype.UUID) ([]GetEbookRatingsRow, error)
|
||||
GetReadingProgress(ctx context.Context, arg GetReadingProgressParams) (ReadingProgress, error)
|
||||
GetScanSettings(ctx context.Context, id pgtype.UUID) (GetScanSettingsRow, error)
|
||||
GetUser(ctx context.Context, id pgtype.UUID) (GetUserRow, error)
|
||||
GetUserByEmail(ctx context.Context, email string) (Users, error)
|
||||
GetUserByEmailOrUsername(ctx context.Context, email string) (Users, error)
|
||||
@@ -38,6 +39,7 @@ type Querier interface {
|
||||
UpdateEmail(ctx context.Context, arg UpdateEmailParams) error
|
||||
UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error
|
||||
UpdateReadingProgress(ctx context.Context, arg UpdateReadingProgressParams) (ReadingProgress, error)
|
||||
UpdateScanSettings(ctx context.Context, arg UpdateScanSettingsParams) error
|
||||
UpdateUserTheme(ctx context.Context, arg UpdateUserThemeParams) error
|
||||
UpdateUsername(ctx context.Context, arg UpdateUsernameParams) error
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ func (q *Queries) CreateEbookRating(ctx context.Context, arg CreateEbookRatingPa
|
||||
const CreateUser = `-- name: CreateUser :one
|
||||
INSERT INTO users (email, username, password_hash, theme)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING id, email, username, password_hash, theme, created_at, updated_at
|
||||
RETURNING id, email, username, password_hash, theme, created_at, updated_at, scan_frequency_minutes, auto_scan_enabled
|
||||
`
|
||||
|
||||
type CreateUserParams struct {
|
||||
@@ -157,6 +157,8 @@ func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (Users,
|
||||
&i.Theme,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.ScanFrequencyMinutes,
|
||||
&i.AutoScanEnabled,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -373,6 +375,22 @@ func (q *Queries) GetReadingProgress(ctx context.Context, arg GetReadingProgress
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetScanSettings = `-- name: GetScanSettings :one
|
||||
SELECT scan_frequency_minutes, auto_scan_enabled FROM users WHERE id = $1
|
||||
`
|
||||
|
||||
type GetScanSettingsRow struct {
|
||||
ScanFrequencyMinutes pgtype.Int4 `db:"scan_frequency_minutes" json:"scan_frequency_minutes"`
|
||||
AutoScanEnabled pgtype.Bool `db:"auto_scan_enabled" json:"auto_scan_enabled"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetScanSettings(ctx context.Context, id pgtype.UUID) (GetScanSettingsRow, error) {
|
||||
row := q.db.QueryRow(ctx, GetScanSettings, id)
|
||||
var i GetScanSettingsRow
|
||||
err := row.Scan(&i.ScanFrequencyMinutes, &i.AutoScanEnabled)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetUser = `-- name: GetUser :one
|
||||
SELECT id, email, username, theme, created_at, updated_at FROM users WHERE id = $1
|
||||
`
|
||||
@@ -401,7 +419,7 @@ func (q *Queries) GetUser(ctx context.Context, id pgtype.UUID) (GetUserRow, erro
|
||||
}
|
||||
|
||||
const GetUserByEmail = `-- name: GetUserByEmail :one
|
||||
SELECT id, email, username, password_hash, theme, created_at, updated_at FROM users WHERE email = $1
|
||||
SELECT id, email, username, password_hash, theme, created_at, updated_at, scan_frequency_minutes, auto_scan_enabled FROM users WHERE email = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserByEmail(ctx context.Context, email string) (Users, error) {
|
||||
@@ -415,12 +433,14 @@ func (q *Queries) GetUserByEmail(ctx context.Context, email string) (Users, erro
|
||||
&i.Theme,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.ScanFrequencyMinutes,
|
||||
&i.AutoScanEnabled,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetUserByEmailOrUsername = `-- name: GetUserByEmailOrUsername :one
|
||||
SELECT id, email, username, password_hash, theme, created_at, updated_at FROM users WHERE email = $1 OR username = $1
|
||||
SELECT id, email, username, password_hash, theme, created_at, updated_at, scan_frequency_minutes, auto_scan_enabled FROM users WHERE email = $1 OR username = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserByEmailOrUsername(ctx context.Context, email string) (Users, error) {
|
||||
@@ -434,12 +454,14 @@ func (q *Queries) GetUserByEmailOrUsername(ctx context.Context, email string) (U
|
||||
&i.Theme,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.ScanFrequencyMinutes,
|
||||
&i.AutoScanEnabled,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetUserByUsername = `-- name: GetUserByUsername :one
|
||||
SELECT id, email, username, password_hash, theme, created_at, updated_at FROM users WHERE username = $1
|
||||
SELECT id, email, username, password_hash, theme, created_at, updated_at, scan_frequency_minutes, auto_scan_enabled FROM users WHERE username = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserByUsername(ctx context.Context, username string) (Users, error) {
|
||||
@@ -453,6 +475,8 @@ func (q *Queries) GetUserByUsername(ctx context.Context, username string) (Users
|
||||
&i.Theme,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.ScanFrequencyMinutes,
|
||||
&i.AutoScanEnabled,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -753,6 +777,21 @@ func (q *Queries) UpdateReadingProgress(ctx context.Context, arg UpdateReadingPr
|
||||
return i, err
|
||||
}
|
||||
|
||||
const UpdateScanSettings = `-- name: UpdateScanSettings :exec
|
||||
UPDATE users SET scan_frequency_minutes = $2, auto_scan_enabled = $3, updated_at = NOW() WHERE id = $1
|
||||
`
|
||||
|
||||
type UpdateScanSettingsParams struct {
|
||||
ID pgtype.UUID `db:"id" json:"id"`
|
||||
ScanFrequencyMinutes pgtype.Int4 `db:"scan_frequency_minutes" json:"scan_frequency_minutes"`
|
||||
AutoScanEnabled pgtype.Bool `db:"auto_scan_enabled" json:"auto_scan_enabled"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateScanSettings(ctx context.Context, arg UpdateScanSettingsParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateScanSettings, arg.ID, arg.ScanFrequencyMinutes, arg.AutoScanEnabled)
|
||||
return err
|
||||
}
|
||||
|
||||
const UpdateUserTheme = `-- name: UpdateUserTheme :exec
|
||||
UPDATE users SET theme = $2, updated_at = NOW() WHERE id = $1
|
||||
`
|
||||
|
||||
@@ -84,6 +84,12 @@ UPDATE users SET password_hash = $2, updated_at = NOW() WHERE id = $1;
|
||||
-- name: DeleteUser :exec
|
||||
DELETE FROM users WHERE id = $1;
|
||||
|
||||
-- name: UpdateScanSettings :exec
|
||||
UPDATE users SET scan_frequency_minutes = $2, auto_scan_enabled = $3, updated_at = NOW() WHERE id = $1;
|
||||
|
||||
-- name: GetScanSettings :one
|
||||
SELECT scan_frequency_minutes, auto_scan_enabled FROM users WHERE id = $1;
|
||||
|
||||
-- name: CreateEbookRating :one
|
||||
INSERT INTO ebook_ratings (ebook_id, user_id, rating)
|
||||
VALUES ($1, $2, $3)
|
||||
|
||||
Reference in New Issue
Block a user