diff --git a/internal/database/models.go b/internal/database/models.go index ffb0837..445c003 100644 --- a/internal/database/models.go +++ b/internal/database/models.go @@ -349,7 +349,7 @@ type ReadingProgress struct { type RefreshTokens struct { ID pgtype.UUID `db:"id" json:"id"` UserID pgtype.UUID `db:"user_id" json:"user_id"` - Token string `db:"token" json:"token"` + Token pgtype.UUID `db:"token" json:"token"` ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"` CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` RevokedAt pgtype.Timestamptz `db:"revoked_at" json:"revoked_at"` diff --git a/internal/database/querier.go b/internal/database/querier.go index 3bd1a96..b50403f 100644 --- a/internal/database/querier.go +++ b/internal/database/querier.go @@ -103,7 +103,7 @@ type Querier interface { // Get reading history for a user and book GetReadingHistory(ctx context.Context, arg GetReadingHistoryParams) ([]ReadingHistory, error) GetReadingProgress(ctx context.Context, arg GetReadingProgressParams) (ReadingProgress, error) - GetRefreshToken(ctx context.Context, token string) (GetRefreshTokenRow, error) + GetRefreshToken(ctx context.Context, token pgtype.UUID) (GetRefreshTokenRow, error) GetScanSettings(ctx context.Context, id pgtype.UUID) (GetScanSettingsRow, error) GetSyncConflict(ctx context.Context, id pgtype.UUID) (SyncConflicts, error) GetSyncQueueItem(ctx context.Context, id pgtype.UUID) (SyncQueue, error) @@ -119,6 +119,7 @@ type Querier interface { GetUserProgressForBooks(ctx context.Context, arg GetUserProgressForBooksParams) ([]GetUserProgressForBooksRow, error) GetUserVisibleLibraries(ctx context.Context, userID pgtype.UUID) ([]GetUserVisibleLibrariesRow, error) IsBookOnKoboShelf(ctx context.Context, arg IsBookOnKoboShelfParams) (bool, error) + ListAllConflictsByUserAndStatus(ctx context.Context, arg ListAllConflictsByUserAndStatusParams) ([]ListAllConflictsByUserAndStatusRow, error) ListDevicesByType(ctx context.Context, deviceType string) ([]Devices, error) ListDevicesByUser(ctx context.Context, userID pgtype.UUID) ([]Devices, error) ListLibraries(ctx context.Context) ([]ListLibrariesRow, error) @@ -134,7 +135,7 @@ type Querier interface { ResolveSyncConflict(ctx context.Context, arg ResolveSyncConflictParams) (SyncConflicts, error) RevokeAllUserRefreshTokens(ctx context.Context, userID pgtype.UUID) error RevokeDevice(ctx context.Context, id pgtype.UUID) error - RevokeRefreshToken(ctx context.Context, token string) error + RevokeRefreshToken(ctx context.Context, token pgtype.UUID) error // Note: User ebook folders replaced by library folders system // Legacy folder management is now handled through libraries // Search Media Items queries diff --git a/internal/database/queries.sql.go b/internal/database/queries.sql.go index de66c69..aeabb2b 100644 --- a/internal/database/queries.sql.go +++ b/internal/database/queries.sql.go @@ -648,7 +648,7 @@ RETURNING id, user_id, token, expires_at, created_at, revoked_at type CreateRefreshTokenParams struct { UserID pgtype.UUID `db:"user_id" json:"user_id"` - Token string `db:"token" json:"token"` + Token pgtype.UUID `db:"token" json:"token"` ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"` } @@ -2186,7 +2186,7 @@ WHERE rt.token = $1 AND rt.revoked_at IS NULL AND rt.expires_at > NOW() type GetRefreshTokenRow struct { ID pgtype.UUID `db:"id" json:"id"` UserID pgtype.UUID `db:"user_id" json:"user_id"` - Token string `db:"token" json:"token"` + Token pgtype.UUID `db:"token" json:"token"` ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"` CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` RevokedAt pgtype.Timestamptz `db:"revoked_at" json:"revoked_at"` @@ -2195,7 +2195,7 @@ type GetRefreshTokenRow struct { Role string `db:"role" json:"role"` } -func (q *Queries) GetRefreshToken(ctx context.Context, token string) (GetRefreshTokenRow, error) { +func (q *Queries) GetRefreshToken(ctx context.Context, token pgtype.UUID) (GetRefreshTokenRow, error) { row := q.db.QueryRow(ctx, GetRefreshToken, token) var i GetRefreshTokenRow err := row.Scan( @@ -2789,6 +2789,67 @@ func (q *Queries) IsBookOnKoboShelf(ctx context.Context, arg IsBookOnKoboShelfPa return on_shelf, err } +const ListAllConflictsByUserAndStatus = `-- name: ListAllConflictsByUserAndStatus :many +SELECT sc.id, sc.media_item_id, sc.user_id, sc.conflict_type, sc.conflict_data, sc.resolution_status, sc.resolution_data, sc.resolved_by, sc.resolved_at, sc.created_at, mi.title, mi.author +FROM sync_conflicts sc +JOIN media_items mi ON sc.media_item_id = mi.id +WHERE sc.user_id = $1 AND sc.resolution_status = $2 +ORDER BY sc.created_at DESC +` + +type ListAllConflictsByUserAndStatusParams struct { + UserID pgtype.UUID `db:"user_id" json:"user_id"` + ResolutionStatus pgtype.Text `db:"resolution_status" json:"resolution_status"` +} + +type ListAllConflictsByUserAndStatusRow struct { + ID pgtype.UUID `db:"id" json:"id"` + MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` + UserID pgtype.UUID `db:"user_id" json:"user_id"` + ConflictType string `db:"conflict_type" json:"conflict_type"` + ConflictData []byte `db:"conflict_data" json:"conflict_data"` + ResolutionStatus pgtype.Text `db:"resolution_status" json:"resolution_status"` + ResolutionData []byte `db:"resolution_data" json:"resolution_data"` + ResolvedBy pgtype.UUID `db:"resolved_by" json:"resolved_by"` + ResolvedAt pgtype.Timestamptz `db:"resolved_at" json:"resolved_at"` + CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` + Title string `db:"title" json:"title"` + Author pgtype.Text `db:"author" json:"author"` +} + +func (q *Queries) ListAllConflictsByUserAndStatus(ctx context.Context, arg ListAllConflictsByUserAndStatusParams) ([]ListAllConflictsByUserAndStatusRow, error) { + rows, err := q.db.Query(ctx, ListAllConflictsByUserAndStatus, arg.UserID, arg.ResolutionStatus) + if err != nil { + return nil, err + } + defer rows.Close() + items := []ListAllConflictsByUserAndStatusRow{} + for rows.Next() { + var i ListAllConflictsByUserAndStatusRow + if err := rows.Scan( + &i.ID, + &i.MediaItemID, + &i.UserID, + &i.ConflictType, + &i.ConflictData, + &i.ResolutionStatus, + &i.ResolutionData, + &i.ResolvedBy, + &i.ResolvedAt, + &i.CreatedAt, + &i.Title, + &i.Author, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const ListDevicesByType = `-- name: ListDevicesByType :many SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE device_type = $1 ORDER BY created_at DESC ` @@ -3784,7 +3845,7 @@ const RevokeRefreshToken = `-- name: RevokeRefreshToken :exec UPDATE refresh_tokens SET revoked_at = NOW() WHERE token = $1 ` -func (q *Queries) RevokeRefreshToken(ctx context.Context, token string) error { +func (q *Queries) RevokeRefreshToken(ctx context.Context, token pgtype.UUID) error { _, err := q.db.Exec(ctx, RevokeRefreshToken, token) return err }