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
This commit is contained in:
2026-01-26 16:54:57 -05:00
parent 86fa337c2c
commit 0b126202c8
4 changed files with 82 additions and 45 deletions
+45 -24
View File
@@ -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
}