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
|
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; }
|
public long UserId { get; private set; }
|
||||||
protected string Username { get; private set; } = string.Empty;
|
protected string Username { get; private set; } = string.Empty;
|
||||||
protected string Email { get; private set; } = string.Empty;
|
protected string Email { get; private set; } = string.Empty;
|
||||||
|
|||||||
Reference in New Issue
Block a user