Add user roles and admin page
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
-- User roles table for role-based access control
|
||||
CREATE TABLE IF NOT EXISTS app.user_roles (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL REFERENCES app.users(id),
|
||||
role VARCHAR(50) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_user_role UNIQUE (user_id, role)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_roles_user_id ON app.user_roles(user_id);
|
||||
@@ -0,0 +1,24 @@
|
||||
@page
|
||||
@model Media.JoshHeaps.Net.Pages.AdminModel
|
||||
@{
|
||||
ViewData["Title"] = "Admin";
|
||||
Layout = "_Layout";
|
||||
}
|
||||
|
||||
<div class="dashboard-container">
|
||||
<div class="welcome-section">
|
||||
<div class="welcome-left">
|
||||
<a href="/Landing" class="back-button" title="Back to Home">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="19" y1="12" x2="5" y2="12"></line>
|
||||
<polyline points="12 19 5 12 12 5"></polyline>
|
||||
</svg>
|
||||
</a>
|
||||
<h1>Admin</h1>
|
||||
</div>
|
||||
<div class="quick-actions">
|
||||
<a href="/Profile" class="btn btn-secondary">Profile</a>
|
||||
<a href="/Logout" class="btn btn-danger">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Media.JoshHeaps.Net.Pages
|
||||
{
|
||||
public class AdminModel(DbExecutor dbExecutor) : AuthenticatedPageModel
|
||||
{
|
||||
private readonly DbExecutor _dbExecutor = dbExecutor;
|
||||
|
||||
public async Task<IActionResult> OnGetAsync()
|
||||
{
|
||||
RequireAuthentication();
|
||||
LoadUserSession();
|
||||
|
||||
var denied = await RequireRole("admin", _dbExecutor);
|
||||
if (denied != null) return denied;
|
||||
|
||||
return Page();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,15 @@ namespace Media.JoshHeaps.Net.Pages;
|
||||
|
||||
public abstract class AuthenticatedPageModel : PageModel
|
||||
{
|
||||
protected async Task<IActionResult?> RequireRole(string role, DbExecutor dbExecutor)
|
||||
{
|
||||
var hasRole = await dbExecutor.ExecuteAsync<bool>(
|
||||
"SELECT EXISTS(SELECT 1 FROM app.user_roles WHERE user_id = @UserId AND role = @Role)",
|
||||
new { UserId, Role = role });
|
||||
|
||||
return hasRole ? null : NotFound();
|
||||
}
|
||||
|
||||
public long UserId { get; private set; }
|
||||
protected string Username { get; private set; } = string.Empty;
|
||||
protected string Email { get; private set; } = string.Empty;
|
||||
|
||||
Reference in New Issue
Block a user