From 0b126202c83049a9eb9a235ba9d3975897caad9e Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Mon, 26 Jan 2026 16:54:57 -0500 Subject: [PATCH] feat: Add role-based access control to database schema - Add role column to users table with admin/user constraint - Add added_by_admin_id column to ebooks table for tracking - Add constraint to ensure only admins can manage folders - Update all SQL queries to include role field - Regenerate database models with new schema --- database/schema/schema.sql | 17 ++++++- internal/database/models.go | 23 +++++---- internal/database/queries.sql.go | 69 +++++++++++++++++---------- internal/database/queries/queries.sql | 18 +++---- 4 files changed, 82 insertions(+), 45 deletions(-) diff --git a/database/schema/schema.sql b/database/schema/schema.sql index cd26c86..ef7e85f 100644 --- a/database/schema/schema.sql +++ b/database/schema/schema.sql @@ -9,6 +9,7 @@ CREATE TABLE users ( password_hash VARCHAR(255) NOT NULL, first_name VARCHAR(255), last_name VARCHAR(255), + role VARCHAR(20) NOT NULL DEFAULT 'user' CHECK (role IN ('admin', 'user')), theme VARCHAR(50) DEFAULT 'tokyo-night', scan_frequency_minutes INTEGER DEFAULT 60, auto_scan_enabled BOOLEAN DEFAULT true, @@ -34,6 +35,7 @@ CREATE TABLE ebooks ( date_published DATE, publisher VARCHAR(255), contributors TEXT, + added_by_admin_id UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); @@ -66,7 +68,10 @@ CREATE TABLE user_ebook_folders ( user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, folder_path VARCHAR(500) NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - UNIQUE(user_id, folder_path) + UNIQUE(user_id, folder_path), + CONSTRAINT admin_only_folder CHECK (EXISTS ( + SELECT 1 FROM users WHERE id = user_id AND role = 'admin' + )) ); -- Create indexes for better query performance @@ -74,6 +79,7 @@ CREATE INDEX idx_users_email ON users(email); CREATE INDEX idx_users_username ON users(username); CREATE INDEX idx_ebooks_title ON ebooks(title); CREATE INDEX idx_ebooks_author ON ebooks(author); +CREATE INDEX idx_ebooks_added_by_admin_id ON ebooks(added_by_admin_id); CREATE INDEX idx_reading_progress_ebook_id ON reading_progress(ebook_id); CREATE INDEX idx_reading_progress_user_id ON reading_progress(user_id); CREATE INDEX idx_ebook_ratings_ebook_id ON ebook_ratings(ebook_id); @@ -81,4 +87,11 @@ CREATE INDEX idx_ebook_ratings_user_id ON ebook_ratings(user_id); CREATE INDEX idx_user_ebook_folders_user_id ON user_ebook_folders(user_id); -- Add comment explaining the rating system -COMMENT ON COLUMN ebook_ratings.rating IS 'Rating scale 1-10 (odd numbers = half-stars: 1,3,5,7,9 = 0.5,1.5,2.5,3.5,4.5 stars)'; \ No newline at end of file +COMMENT ON COLUMN ebook_ratings.rating IS 'Rating scale 1-10 (odd numbers = half-stars: 1,3,5,7,9 = 0.5,1.5,2.5,3.5,4.5 stars)'; + +-- Role System Notes: +-- - All users default to 'user' role +-- - Admin users can: add/edit/delete folders, scan ebooks, modify ebook metadata, delete ebooks +-- - Regular users can: view all ebooks, rate ebooks, track reading progress, manage their profile +-- - To create first admin: UPDATE users SET role = 'admin' WHERE email = 'your-admin-email'; +-- - Only admins can manage folders and ebook metadata \ No newline at end of file diff --git a/internal/database/models.go b/internal/database/models.go index e6e72e2..9d180dd 100644 --- a/internal/database/models.go +++ b/internal/database/models.go @@ -9,9 +9,10 @@ import ( ) type EbookRatings struct { - ID pgtype.UUID `db:"id" json:"id"` - EbookID pgtype.UUID `db:"ebook_id" json:"ebook_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` + ID pgtype.UUID `db:"id" json:"id"` + EbookID pgtype.UUID `db:"ebook_id" json:"ebook_id"` + UserID pgtype.UUID `db:"user_id" json:"user_id"` + // Rating scale 1-10 (odd numbers = half-stars: 1,3,5,7,9 = 0.5,1.5,2.5,3.5,4.5 stars) Rating int32 `db:"rating" json:"rating"` CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` @@ -27,8 +28,6 @@ type Ebooks struct { FileSize pgtype.Int8 `db:"file_size" json:"file_size"` MimeType pgtype.Text `db:"mime_type" json:"mime_type"` CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` Series pgtype.Text `db:"series" json:"series"` SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"` Tags pgtype.Text `db:"tags" json:"tags"` @@ -36,6 +35,9 @@ type Ebooks struct { DatePublished pgtype.Date `db:"date_published" json:"date_published"` Publisher pgtype.Text `db:"publisher" json:"publisher"` Contributors pgtype.Text `db:"contributors" json:"contributors"` + AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"` + CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` + UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` } type ReadingProgress struct { @@ -59,11 +61,12 @@ type Users struct { 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"` FirstName pgtype.Text `db:"first_name" json:"first_name"` LastName pgtype.Text `db:"last_name" json:"last_name"` + Role string `db:"role" json:"role"` + Theme pgtype.Text `db:"theme" json:"theme"` + ScanFrequencyMinutes pgtype.Int4 `db:"scan_frequency_minutes" json:"scan_frequency_minutes"` + AutoScanEnabled pgtype.Bool `db:"auto_scan_enabled" json:"auto_scan_enabled"` + CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` + UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` } diff --git a/internal/database/queries.sql.go b/internal/database/queries.sql.go index 8ebae8e..0441290 100644 --- a/internal/database/queries.sql.go +++ b/internal/database/queries.sql.go @@ -33,9 +33,9 @@ func (q *Queries) AddUserEbookFolder(ctx context.Context, arg AddUserEbookFolder } const CreateEbook = `-- name: CreateEbook :one -INSERT INTO ebooks (title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) -RETURNING id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, created_at, updated_at, series, series_number, tags, asin, date_published, publisher, contributors +INSERT INTO ebooks (title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) +RETURNING id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at ` type CreateEbookParams struct { @@ -54,6 +54,7 @@ type CreateEbookParams struct { DatePublished pgtype.Date `db:"date_published" json:"date_published"` Publisher pgtype.Text `db:"publisher" json:"publisher"` Contributors pgtype.Text `db:"contributors" json:"contributors"` + AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"` } func (q *Queries) CreateEbook(ctx context.Context, arg CreateEbookParams) (Ebooks, error) { @@ -73,6 +74,7 @@ func (q *Queries) CreateEbook(ctx context.Context, arg CreateEbookParams) (Ebook arg.DatePublished, arg.Publisher, arg.Contributors, + arg.AddedByAdminID, ) var i Ebooks err := row.Scan( @@ -85,8 +87,6 @@ func (q *Queries) CreateEbook(ctx context.Context, arg CreateEbookParams) (Ebook &i.FileSize, &i.MimeType, &i.CoverImagePath, - &i.CreatedAt, - &i.UpdatedAt, &i.Series, &i.SeriesNumber, &i.Tags, @@ -94,6 +94,9 @@ func (q *Queries) CreateEbook(ctx context.Context, arg CreateEbookParams) (Ebook &i.DatePublished, &i.Publisher, &i.Contributors, + &i.AddedByAdminID, + &i.CreatedAt, + &i.UpdatedAt, ) return i, err } @@ -131,7 +134,7 @@ func (q *Queries) CreateEbookRating(ctx context.Context, arg CreateEbookRatingPa const CreateUser = `-- name: CreateUser :one INSERT INTO users (email, username, password_hash, first_name, last_name, theme) VALUES ($1, $2, $3, $4, $5, $6) -RETURNING id, email, username, theme, first_name, last_name, created_at, updated_at +RETURNING id, email, username, theme, first_name, last_name, role, created_at, updated_at ` type CreateUserParams struct { @@ -150,6 +153,7 @@ type CreateUserRow struct { Theme pgtype.Text `db:"theme" json:"theme"` FirstName pgtype.Text `db:"first_name" json:"first_name"` LastName pgtype.Text `db:"last_name" json:"last_name"` + Role string `db:"role" json:"role"` CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` } @@ -171,6 +175,7 @@ func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (CreateU &i.Theme, &i.FirstName, &i.LastName, + &i.Role, &i.CreatedAt, &i.UpdatedAt, ) @@ -245,7 +250,7 @@ func (q *Queries) DeleteUserEbookFolder(ctx context.Context, arg DeleteUserEbook } const GetEbook = `-- name: GetEbook :one -SELECT id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, created_at, updated_at, series, series_number, tags, asin, date_published, publisher, contributors FROM ebooks WHERE id = $1 +SELECT id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at FROM ebooks WHERE id = $1 ` func (q *Queries) GetEbook(ctx context.Context, id pgtype.UUID) (Ebooks, error) { @@ -261,8 +266,6 @@ func (q *Queries) GetEbook(ctx context.Context, id pgtype.UUID) (Ebooks, error) &i.FileSize, &i.MimeType, &i.CoverImagePath, - &i.CreatedAt, - &i.UpdatedAt, &i.Series, &i.SeriesNumber, &i.Tags, @@ -270,12 +273,15 @@ func (q *Queries) GetEbook(ctx context.Context, id pgtype.UUID) (Ebooks, error) &i.DatePublished, &i.Publisher, &i.Contributors, + &i.AddedByAdminID, + &i.CreatedAt, + &i.UpdatedAt, ) return i, err } const GetEbookByFilePath = `-- name: GetEbookByFilePath :one -SELECT id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, created_at, updated_at, series, series_number, tags, asin, date_published, publisher, contributors FROM ebooks WHERE file_path = $1 +SELECT id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at FROM ebooks WHERE file_path = $1 ` func (q *Queries) GetEbookByFilePath(ctx context.Context, filePath string) (Ebooks, error) { @@ -291,8 +297,6 @@ func (q *Queries) GetEbookByFilePath(ctx context.Context, filePath string) (Eboo &i.FileSize, &i.MimeType, &i.CoverImagePath, - &i.CreatedAt, - &i.UpdatedAt, &i.Series, &i.SeriesNumber, &i.Tags, @@ -300,6 +304,9 @@ func (q *Queries) GetEbookByFilePath(ctx context.Context, filePath string) (Eboo &i.DatePublished, &i.Publisher, &i.Contributors, + &i.AddedByAdminID, + &i.CreatedAt, + &i.UpdatedAt, ) return i, err } @@ -413,7 +420,7 @@ func (q *Queries) GetScanSettings(ctx context.Context, id pgtype.UUID) (GetScanS } const GetUser = `-- name: GetUser :one -SELECT id, email, username, theme, first_name, last_name, created_at, updated_at FROM users WHERE id = $1 +SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE id = $1 ` type GetUserRow struct { @@ -423,6 +430,7 @@ type GetUserRow struct { Theme pgtype.Text `db:"theme" json:"theme"` FirstName pgtype.Text `db:"first_name" json:"first_name"` LastName pgtype.Text `db:"last_name" json:"last_name"` + Role string `db:"role" json:"role"` CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` } @@ -437,6 +445,7 @@ func (q *Queries) GetUser(ctx context.Context, id pgtype.UUID) (GetUserRow, erro &i.Theme, &i.FirstName, &i.LastName, + &i.Role, &i.CreatedAt, &i.UpdatedAt, ) @@ -444,7 +453,7 @@ func (q *Queries) GetUser(ctx context.Context, id pgtype.UUID) (GetUserRow, erro } const GetUserByEmail = `-- name: GetUserByEmail :one -SELECT id, email, username, theme, first_name, last_name, created_at, updated_at FROM users WHERE email = $1 +SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1 ` type GetUserByEmailRow struct { @@ -454,6 +463,7 @@ type GetUserByEmailRow struct { Theme pgtype.Text `db:"theme" json:"theme"` FirstName pgtype.Text `db:"first_name" json:"first_name"` LastName pgtype.Text `db:"last_name" json:"last_name"` + Role string `db:"role" json:"role"` CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` } @@ -468,6 +478,7 @@ func (q *Queries) GetUserByEmail(ctx context.Context, email string) (GetUserByEm &i.Theme, &i.FirstName, &i.LastName, + &i.Role, &i.CreatedAt, &i.UpdatedAt, ) @@ -475,7 +486,7 @@ func (q *Queries) GetUserByEmail(ctx context.Context, email string) (GetUserByEm } const GetUserByEmailOrUsername = `-- name: GetUserByEmailOrUsername :one -SELECT id, email, username, theme, first_name, last_name, created_at, updated_at FROM users WHERE email = $1 OR username = $1 +SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1 OR username = $1 ` type GetUserByEmailOrUsernameRow struct { @@ -485,6 +496,7 @@ type GetUserByEmailOrUsernameRow struct { Theme pgtype.Text `db:"theme" json:"theme"` FirstName pgtype.Text `db:"first_name" json:"first_name"` LastName pgtype.Text `db:"last_name" json:"last_name"` + Role string `db:"role" json:"role"` CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` } @@ -499,6 +511,7 @@ func (q *Queries) GetUserByEmailOrUsername(ctx context.Context, email string) (G &i.Theme, &i.FirstName, &i.LastName, + &i.Role, &i.CreatedAt, &i.UpdatedAt, ) @@ -506,7 +519,7 @@ func (q *Queries) GetUserByEmailOrUsername(ctx context.Context, email string) (G } const GetUserByUsername = `-- name: GetUserByUsername :one -SELECT id, email, username, theme, first_name, last_name, created_at, updated_at FROM users WHERE username = $1 +SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE username = $1 ` type GetUserByUsernameRow struct { @@ -516,6 +529,7 @@ type GetUserByUsernameRow struct { Theme pgtype.Text `db:"theme" json:"theme"` FirstName pgtype.Text `db:"first_name" json:"first_name"` LastName pgtype.Text `db:"last_name" json:"last_name"` + Role string `db:"role" json:"role"` CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` } @@ -530,6 +544,7 @@ func (q *Queries) GetUserByUsername(ctx context.Context, username string) (GetUs &i.Theme, &i.FirstName, &i.LastName, + &i.Role, &i.CreatedAt, &i.UpdatedAt, ) @@ -566,7 +581,7 @@ func (q *Queries) GetUserEbookFolders(ctx context.Context, userID pgtype.UUID) ( } const GetUserForLogin = `-- name: GetUserForLogin :one -SELECT id, email, username, password_hash, theme, first_name, last_name, created_at, updated_at FROM users WHERE email = $1 OR username = $1 +SELECT id, email, username, password_hash, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1 OR username = $1 ` type GetUserForLoginRow struct { @@ -577,6 +592,7 @@ type GetUserForLoginRow struct { Theme pgtype.Text `db:"theme" json:"theme"` FirstName pgtype.Text `db:"first_name" json:"first_name"` LastName pgtype.Text `db:"last_name" json:"last_name"` + Role string `db:"role" json:"role"` CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` } @@ -592,6 +608,7 @@ func (q *Queries) GetUserForLogin(ctx context.Context, email string) (GetUserFor &i.Theme, &i.FirstName, &i.LastName, + &i.Role, &i.CreatedAt, &i.UpdatedAt, ) @@ -610,7 +627,7 @@ func (q *Queries) GetUserPasswordHash(ctx context.Context, id pgtype.UUID) (stri } const ListEbooks = `-- name: ListEbooks :many -SELECT id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, created_at, updated_at, series, series_number, tags, asin, date_published, publisher, contributors FROM ebooks ORDER BY created_at DESC LIMIT $1 OFFSET $2 +SELECT id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at FROM ebooks ORDER BY created_at DESC LIMIT $1 OFFSET $2 ` type ListEbooksParams struct { @@ -637,8 +654,6 @@ func (q *Queries) ListEbooks(ctx context.Context, arg ListEbooksParams) ([]Ebook &i.FileSize, &i.MimeType, &i.CoverImagePath, - &i.CreatedAt, - &i.UpdatedAt, &i.Series, &i.SeriesNumber, &i.Tags, @@ -646,6 +661,9 @@ func (q *Queries) ListEbooks(ctx context.Context, arg ListEbooksParams) ([]Ebook &i.DatePublished, &i.Publisher, &i.Contributors, + &i.AddedByAdminID, + &i.CreatedAt, + &i.UpdatedAt, ); err != nil { return nil, err } @@ -658,7 +676,7 @@ func (q *Queries) ListEbooks(ctx context.Context, arg ListEbooksParams) ([]Ebook } const ListUsers = `-- name: ListUsers :many -SELECT id, email, username, theme, first_name, last_name, created_at, updated_at FROM users ORDER BY created_at DESC +SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users ORDER BY created_at DESC ` type ListUsersRow struct { @@ -668,6 +686,7 @@ type ListUsersRow struct { Theme pgtype.Text `db:"theme" json:"theme"` FirstName pgtype.Text `db:"first_name" json:"first_name"` LastName pgtype.Text `db:"last_name" json:"last_name"` + Role string `db:"role" json:"role"` CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` } @@ -688,6 +707,7 @@ func (q *Queries) ListUsers(ctx context.Context) ([]ListUsersRow, error) { &i.Theme, &i.FirstName, &i.LastName, + &i.Role, &i.CreatedAt, &i.UpdatedAt, ); err != nil { @@ -717,7 +737,7 @@ UPDATE ebooks SET contributors = $13, updated_at = NOW() WHERE id = $1 -RETURNING id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, created_at, updated_at, series, series_number, tags, asin, date_published, publisher, contributors +RETURNING id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at ` type UpdateEbookParams struct { @@ -763,8 +783,6 @@ func (q *Queries) UpdateEbook(ctx context.Context, arg UpdateEbookParams) (Ebook &i.FileSize, &i.MimeType, &i.CoverImagePath, - &i.CreatedAt, - &i.UpdatedAt, &i.Series, &i.SeriesNumber, &i.Tags, @@ -772,6 +790,9 @@ func (q *Queries) UpdateEbook(ctx context.Context, arg UpdateEbookParams) (Ebook &i.DatePublished, &i.Publisher, &i.Contributors, + &i.AddedByAdminID, + &i.CreatedAt, + &i.UpdatedAt, ) return i, err } diff --git a/internal/database/queries/queries.sql b/internal/database/queries/queries.sql index ad74472..85d620c 100644 --- a/internal/database/queries/queries.sql +++ b/internal/database/queries/queries.sql @@ -1,28 +1,28 @@ -- name: CreateUser :one INSERT INTO users (email, username, password_hash, first_name, last_name, theme) VALUES ($1, $2, $3, $4, $5, $6) -RETURNING id, email, username, theme, first_name, last_name, created_at, updated_at; +RETURNING id, email, username, theme, first_name, last_name, role, created_at, updated_at; -- name: GetUserByEmail :one -SELECT id, email, username, theme, first_name, last_name, created_at, updated_at FROM users WHERE email = $1; +SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1; -- name: GetUserByUsername :one -SELECT id, email, username, theme, first_name, last_name, created_at, updated_at FROM users WHERE username = $1; +SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE username = $1; -- name: GetUserByEmailOrUsername :one -SELECT id, email, username, theme, first_name, last_name, created_at, updated_at FROM users WHERE email = $1 OR username = $1; +SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1 OR username = $1; -- name: GetUserForLogin :one -SELECT id, email, username, password_hash, theme, first_name, last_name, created_at, updated_at FROM users WHERE email = $1 OR username = $1; +SELECT id, email, username, password_hash, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1 OR username = $1; -- name: GetUser :one -SELECT id, email, username, theme, first_name, last_name, created_at, updated_at FROM users WHERE id = $1; +SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE id = $1; -- name: GetUserPasswordHash :one SELECT password_hash FROM users WHERE id = $1; -- name: ListUsers :many -SELECT id, email, username, theme, first_name, last_name, created_at, updated_at FROM users ORDER BY created_at DESC; +SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users ORDER BY created_at DESC; -- name: GetEbook :one SELECT * FROM ebooks WHERE id = $1; @@ -31,8 +31,8 @@ SELECT * FROM ebooks WHERE id = $1; SELECT * FROM ebooks ORDER BY created_at DESC LIMIT $1 OFFSET $2; -- name: CreateEbook :one -INSERT INTO ebooks (title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) +INSERT INTO ebooks (title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) RETURNING *; -- name: UpdateEbook :one