Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add moderator pages with limited CRUD operations #28

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions GameLibrary/Data/DbInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,16 @@ public static void Initialize(this IApplicationBuilder app)
var roleManager = services.GetRequiredService<RoleManager<Role>>();

// Apply any pending migrations
if (context.Database.GetPendingMigrations().Any())
try
{
context.Database.Migrate();
if (context.Database.GetPendingMigrations().Any())
{
context.Database.Migrate();
}
}
catch (Exception ex)
{
Console.WriteLine($"Migration error: {ex.Message}");
}

// Check if we already have games
Expand All @@ -42,7 +49,7 @@ public static void Initialize(this IApplicationBuilder app)
}

// Ensure roles are created
var roles = new[] { "Administrator", "User" };
var roles = new[] { "Administrator", "User", "Moderator" };
foreach (var role in roles)
{
if (!roleManager.RoleExistsAsync(role).Result)
Expand All @@ -68,6 +75,24 @@ public static void Initialize(this IApplicationBuilder app)
}
}

var moderatorUser = new User
{
Id = Guid.Parse("71a23c2d-f82e-4b47-a843-cfcadbd65a77"),
UserName = "[email protected]",
Email = "[email protected]",
EmailConfirmed = true
};

if (userManager.FindByNameAsync(moderatorUser.UserName).Result == null)
{
var result = userManager.CreateAsync(moderatorUser, "Password123!").Result;
if (result.Succeeded)
{
userManager.AddToRoleAsync(moderatorUser, "Moderator").Wait();
}
}


context.SaveChanges();

// Add test games
Expand Down
Binary file modified GameLibrary/Database.db-shm
Binary file not shown.
Binary file modified GameLibrary/Database.db-wal
Binary file not shown.
5 changes: 0 additions & 5 deletions GameLibrary/Pages/Account/Manage/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,5 @@
</div>
<button id="update-profile-button" type="submit" class="w-100 btn btn-lg btn-primary">Save</button>
</form>

@if (Model.IsAdminRole)
{
<a asp-area="" asp-page="/Admin/Index">Admin Dashboard</a>
}
</div>
</div>
3 changes: 0 additions & 3 deletions GameLibrary/Pages/Account/Manage/Index.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ public IndexModel(
_signInManager = signInManager;
}

public bool IsAdminRole { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
Expand Down Expand Up @@ -92,8 +91,6 @@ public async Task<IActionResult> OnGetAsync()
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}

IsAdminRole = _userManager.IsInRoleAsync(user, "Administrator").Result;

await LoadAsync(user);
return Page();
}
Expand Down
10 changes: 10 additions & 0 deletions GameLibrary/Pages/Account/Manage/ManageNavPages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ public static class ManageNavPages
/// </summary>
public static string TwoFactorAuthentication => "TwoFactorAuthentication";

/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// </summary>
public static string RoleTools => "RoleTools";

/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
Expand Down Expand Up @@ -120,6 +125,11 @@ public static class ManageNavPages
/// </summary>
public static string TwoFactorAuthenticationNavClass(ViewContext viewContext) => PageNavClass(viewContext, TwoFactorAuthentication);

/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// </summary>
public static string RoleToolsNavClass(ViewContext viewContext) => PageNavClass(viewContext, RoleTools);

/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
Expand Down
39 changes: 39 additions & 0 deletions GameLibrary/Pages/Account/Manage/RoleTools.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@page
@model RoleToolsModel
@{
ViewData["Title"] = "Role-Based Tools";
ViewData["ActivePage"] = ManageNavPages.RoleTools;
}

<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card shadow-sm">
<div class="card-header bg-primary-subtle">
<h4 class="mb-0">Role-Based Tools</h4>
</div>
<div class="card-body">
<p class="text-muted">Access tools and dashboards based on your roles.</p>
<div class="d-grid gap-3">
@if (Model.IsAdminRole)
{
<a asp-area="" asp-page="/Admin/Index" class="btn btn-outline-primary btn-lg">
<i class="bi bi-gear-fill me-2"></i> Admin Dashboard
</a>
}
@if (Model.IsModeratorRole)
{
<a asp-area="" asp-page="/Moderator/Index" class="btn btn-outline-warning btn-lg">
<i class="bi bi-shield-fill me-2"></i> Moderator Dashboard
</a>
}
@if (!Model.IsAdminRole && !Model.IsModeratorRole)
{
<p class="text-muted">You do not have any role-based tools available.</p>
}
</div>
</div>
</div>
</div>
</div>
</div>
33 changes: 33 additions & 0 deletions GameLibrary/Pages/Account/Manage/RoleTools.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using GameLibrary.Models;

namespace GameLibrary.Pages.Account.Manage;

public class RoleToolsModel : PageModel
{
private readonly UserManager<User> _userManager;

public RoleToolsModel(UserManager<User> userManager)
{
_userManager = userManager;
}

public bool IsAdminRole { get; set; }
public bool IsModeratorRole { get; set; }

public async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}

IsAdminRole = await _userManager.IsInRoleAsync(user, "Administrator");
IsModeratorRole = await _userManager.IsInRoleAsync(user, "Moderator");

return Page();
}
}
1 change: 1 addition & 0 deletions GameLibrary/Pages/Account/Manage/_ManageNav.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
}
<li class="nav-item"><a class="nav-link @ManageNavPages.TwoFactorAuthenticationNavClass(ViewContext)" id="two-factor" asp-page="./TwoFactorAuthentication">Two-factor authentication</a></li>
<li class="nav-item"><a class="nav-link @ManageNavPages.PersonalDataNavClass(ViewContext)" id="personal-data" asp-page="./PersonalData">Personal data</a></li>
<li class="nav-item"><a class="nav-link @ManageNavPages.RoleToolsNavClass(ViewContext)" id="role-tools" asp-page="./RoleTools">Role-Based Tools</a></li>
</ul>
55 changes: 55 additions & 0 deletions GameLibrary/Pages/Moderator/Index.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
@page
@model GameLibrary.Pages.Moderator.IndexModel

@{
ViewData["Title"] = "Moderator Index";
ViewData["ActivePage"] = ManageNavPages.Index;
}

<h1>Moderator Dashboard</h1>

<div class="row">
<div class="col-md-3">
<div class="card text-white bg-primary mb-3">
<div class="card-header">Total Reviews</div>
<div class="card-body">
<h5 class="card-title">@Model.TotalReviews</h5>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-info mb-3">
<div class="card-header">Total Users</div>
<div class="card-body">
<h5 class="card-title">@Model.TotalUsers</h5>
</div>
</div>
</div>
</div>

<div class="row">
<div class="col-md-6">
<h2>Review Ratings</h2>
<canvas id="reviewRatingsChart"></canvas>
</div>
</div>

@section Scripts {
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
var reviewRatingsCtx = document.getElementById('reviewRatingsChart').getContext('2d');
var reviewRatingsChart = new Chart(reviewRatingsCtx, {
type: 'bar',
data: {
labels: @Html.Raw(Json.Serialize(Model.ReviewRatings.Keys)),
datasets: [{
label: 'Review Ratings',
data: @Html.Raw(Json.Serialize(Model.ReviewRatings.Values)),
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 1
}]
}
});
</script>
}
30 changes: 30 additions & 0 deletions GameLibrary/Pages/Moderator/Index.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using GameLibrary.Data;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;

namespace GameLibrary.Pages.Moderator;

public class IndexModel : PageModel
{
private readonly ApplicationDbContext _context;

public IndexModel(ApplicationDbContext context)
{
_context = context;
}

public int TotalReviews { get; set; }
public int TotalUsers { get; set; }

public Dictionary<int, int> ReviewRatings { get; set; } = new();

public async Task OnGetAsync()
{
TotalReviews = await _context.Reviews.CountAsync();
TotalUsers = await _context.Users.CountAsync();

ReviewRatings = await _context.Reviews
.GroupBy(r => r.Rating)
.ToDictionaryAsync(r => r.Key, r => r.Count());
}
}
21 changes: 21 additions & 0 deletions GameLibrary/Pages/Moderator/ManageNavPages.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Mvc.Rendering;

namespace GameLibrary.Pages.Moderator;

public static class ManageNavPages
{
public static string Index => "Index";
public static string Reviews => "Reviews/Index";
public static string Users => "Users/Index";

public static string IndexNavClass(ViewContext viewContext) => PageNavClass(viewContext, Index);
public static string ReviewsNavClass(ViewContext viewContext) => PageNavClass(viewContext, Reviews);
public static string UsersNavClass(ViewContext viewContext) => PageNavClass(viewContext, Users);

public static string PageNavClass(ViewContext viewContext, string page)
{
var activePage = viewContext.ViewData["ActivePage"] as string
?? System.IO.Path.GetFileNameWithoutExtension(viewContext.ActionDescriptor.DisplayName);
return string.Equals(activePage, page, StringComparison.OrdinalIgnoreCase) ? "active" : null;
}
}
72 changes: 72 additions & 0 deletions GameLibrary/Pages/Moderator/Reviews/Edit.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
@page
@model GameLibrary.Pages.Moderator.Reviews.EditModel

@{
ViewData["Title"] = "Edit Review";
}

<body style="color:#FFD43B;">

<header>
<h1>Edit Review</h1>
</header>

<div class="row container">
<div class="col-md-4">
@if (ViewData["Status"] != null)
{
<div class="alert alert-info">
Current Status: @ViewData["Status"]
</div>
}

<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>

<input type="hidden" asp-for="SelectedId" />

<div class="form-group">
<label asp-for="SelectedGameId" class="control-label">Game</label>
<select asp-for="SelectedGameId" class="form-control" asp-items="Model.Games">
<option value="">Select a game</option>
</select>
<span asp-validation-for="SelectedGameId" class="text-danger"></span>
</div>

<div class="form-group">
<label asp-for="SelectedUserId" class="control-label">User</label>
<select asp-for="SelectedUserId" class="form-control" asp-items="Model.Users">
<option value="">Select a user</option>
</select>
<span asp-validation-for="SelectedUserId" class="text-danger"></span>
</div>

<div class="form-group">
<label asp-for="SelectedRating" class="control-label">Rating</label>
<select asp-for="SelectedRating" class="form-select" required>
<option value="">Select rating</option>
<option value="5">5 - Excellent</option>
<option value="4">4 - Very Good</option>
<option value="3">3 - Good</option>
<option value="2">2 - Fair</option>
<option value="1">1 - Poor</option>
</select>
<span asp-validation-for="SelectedRating" class="text-danger"></span>
</div>

<div class="form-group">
<label asp-for="SelectedContent" class="control-label">Content</label>
<textarea asp-for="SelectedContent" class="form-control"></textarea>
<span asp-validation-for="SelectedContent" class="text-danger"></span>
</div>

<div class="form-group">
<input type="submit" name="submitButton" value="Approve" class="btn btn-success" style="background-color: green; color: white;" />
<input type="submit" name="submitButton" value="Deny" class="btn btn-danger" style="background-color: red; color: white;" />
<a asp-page="Index" class="btn btn-secondary" style="background-color: gray; color: white;">Back to List</a>
</div>
</form>
</div>
</div>

</body>
Loading