Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4df81c8
Add image upload functionality for staff management
JoeProgrammer88 Aug 8, 2025
909474f
Merged main
JoeProgrammer88 Nov 5, 2025
4781fd4
Fixed missing field left out from merging
JoeProgrammer88 Nov 5, 2025
bdf8ee2
Merged main
JoeProgrammer88 Jan 29, 2026
cdba1d1
Merge branch 'main' into StaffPhotos
JoeProgrammer88 Feb 19, 2026
2e585ab
Adjust heading margin and remove #pc2Logo padding
JoeProgrammer88 Feb 19, 2026
9377e4b
Merge branch 'main' into StaffPhotos
JoeProgrammer88 Feb 21, 2026
5723921
Refactor People management: new controller & views
JoeProgrammer88 Feb 21, 2026
3085bdf
Merge branch 'StaffPhotos' of https://github.com/SpeakingInBits/PC2 i…
JoeProgrammer88 Feb 21, 2026
956d8d8
Move ImageUrl property from Staff to People base class
JoeProgrammer88 Feb 23, 2026
01b7bd9
Unify People CRUD for Staff, Board, and Committee
JoeProgrammer88 Feb 23, 2026
f3e94f0
Relax staff photo requirement; add image preview support
JoeProgrammer88 Feb 23, 2026
752bab6
Improve member avatar display and layout on About/Index
JoeProgrammer88 Feb 23, 2026
682f286
Update PriorityOrder field logic in Create/Edit views
JoeProgrammer88 Feb 23, 2026
eca6998
Add logging and image resize params to PeopleController
JoeProgrammer88 Feb 23, 2026
b43a640
Increase resized image dimensions to 350x350 in controller
JoeProgrammer88 Feb 23, 2026
f71adfe
Remove staff header images from About page
JoeProgrammer88 Feb 24, 2026
139012c
Remove person photo before deleting record
JoeProgrammer88 Feb 24, 2026
4247833
Update PC2/Views/People/Index.cshtml
JoeProgrammer88 Feb 24, 2026
56c44ec
Apply suggestions from code review
JoeProgrammer88 Feb 24, 2026
63f2fcd
Refactor PeopleController and related view models
JoeProgrammer88 Feb 24, 2026
bb29c1b
Merge branch 'StaffPhotos' of https://github.com/SpeakingInBits/PC2 i…
JoeProgrammer88 Feb 24, 2026
ac9129f
Refactor: let caller manage file stream disposal
JoeProgrammer88 Mar 3, 2026
1111bd5
Add error handling to PeopleController actions
JoeProgrammer88 Mar 3, 2026
f715c1d
Update staff images to use rounded corners, not circles
JoeProgrammer88 Mar 3, 2026
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
266 changes: 13 additions & 253 deletions PC2/Controllers/AboutController.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.EntityFrameworkCore;
using PC2.Data;
using PC2.Models;
Expand All @@ -13,241 +12,10 @@ public class AboutController : Controller
private readonly ApplicationDbContext _context;
private readonly AzureBlobUploader _azureBlobUploader;

// Iwebhost environment is used to get the path to the wwwroot folder
public AboutController(ApplicationDbContext context, AzureBlobUploader azureBlobUploader)
{
_context = context;
_azureBlobUploader = azureBlobUploader;
}

public async Task<IActionResult> IndexStaff()
{
return View(await StaffDB.GetAllStaffForEditing(_context));
}

/// <summary>
/// Creates a staff member
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult CreateStaff()
{
return View();
}

[HttpPost]
public async Task<IActionResult> CreateStaff(Staff staff)
{
if (ModelState.IsValid)
{
await StaffDB.AddStaff(_context, staff);
return RedirectToAction("IndexStaff");
}
return View(staff);
}

/// <summary>
/// Edits a staff member
/// </summary>
/// <param name="id">The id for the staff member</param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> EditStaff(int id)
{
return View(await StaffDB.GetStaffMember(_context, id));
}

[HttpPost]
public async Task<IActionResult> EditStaff(Staff staff)
{
if (ModelState.IsValid)
{
await StaffDB.SaveChanges(_context, staff);
return RedirectToAction("IndexStaff");
}

return View(staff);
}

/// <summary>
/// Deletes a staff member
/// </summary>
/// <param name="id">The id of the staff member</param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> DeleteStaff(int id)
{
return View(await StaffDB.GetStaffMember(_context, id));
}

[HttpPost]
[ActionName("DeleteStaff")]
public async Task<IActionResult> ConfirmDeleteStaff(int id)
{
Staff? staff = await StaffDB.GetStaffMember(_context, id);

if (staff == null)
{
// If staff member is not found
return NotFound(); // Return a NotFound result
}

await StaffDB.Delete(_context, staff);
return RedirectToAction("IndexStaff");
}

public async Task<IActionResult> IndexBoard()
{
return View(await BoardDB.GetAllBoardMembersForEditing(_context));
}

/// <summary>
/// Creates a board member
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult CreateBoard()
{
return View();
}

[HttpPost]
public async Task<IActionResult> CreateBoard(Board board)
{
if (ModelState.IsValid)
{
await BoardDB.CreateBoardMember(_context, board);
return RedirectToAction("IndexBoard");
}

return View(board);
}

/// <summary>
/// Edits a board member
/// </summary>
/// <param name="id">The id of the board member</param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> EditBoard(int id)
{
return View(await BoardDB.GetBoardMember(_context, id));
}

[HttpPost]
public async Task<IActionResult> EditBoard(Board board)
{
if (ModelState.IsValid)
{
await BoardDB.EditBoardMember(_context, board);
return RedirectToAction("IndexBoard");
}

return View(board);
}

/// <summary>
/// Deletes a board member
/// </summary>
/// <param name="id">The id of the board member</param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> DeleteBoard(int id)
{
return View(await BoardDB.GetBoardMember(_context, id));
}

[HttpPost]
[ActionName("DeleteBoard")]
public async Task<IActionResult> ConfirmDeleteBoard(int id)
{
Board? board = await BoardDB.GetBoardMember(_context, id);

if (board == null)
{
// If board member is not found
return NotFound(); // Return a NotFound result
}

await BoardDB.Delete(_context, board);
return RedirectToAction("IndexBoard");
}

public async Task<IActionResult> IndexSteeringCommittee()
{
return View(await SteeringCommitteeDB.GetAllSteeringCommittee(_context));
}

/// <summary>
/// Creates a steering committee member
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult CreateSteeringCommittee()
{
return View();
}

[HttpPost]
public async Task<IActionResult> CreateSteeringCommittee(SteeringCommittee steeringCommittee)
{
if (ModelState.IsValid)
{
await SteeringCommitteeDB.Create(_context, steeringCommittee);
return RedirectToAction("IndexSteeringCommittee");
}

return View(steeringCommittee);
}

/// <summary>
/// Gets a steering committee member by id
/// </summary>
/// <param name="id">The id of the steering committee member</param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> EditSteeringCommittee(int id)
{
return View(await SteeringCommitteeDB.GetSteeringCommitteeMember(_context, id));
}

[HttpPost]
public async Task<IActionResult> EditSteeringCommittee(SteeringCommittee steeringCommittee)
{
if (ModelState.IsValid)
{
await SteeringCommitteeDB.EditSteeringCommittee(_context, steeringCommittee);
return RedirectToAction("IndexSteeringCommittee");
}

return View(steeringCommittee);
}

/// <summary>
/// Deletes a steering committee member by id
/// </summary>
/// <param name="id">The id of the member</param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> DeleteSteeringCommittee(int id)
{
return View(await SteeringCommitteeDB.GetSteeringCommitteeMember(_context, id));
}

[HttpPost]
[ActionName("DeleteSteeringCommittee")]
public async Task<IActionResult> ConfirmDeleteSteeringCommittee(int id)
public AboutController(ApplicationDbContext context, AzureBlobUploader azureBlobUploader)
{
SteeringCommittee? steeringCommittee = await SteeringCommitteeDB.GetSteeringCommitteeMember(_context, id);

if (steeringCommittee == null)
{
// If the steering committee member is not found
return NotFound(); // Return a NotFound result
}

await SteeringCommitteeDB.Delete(_context, steeringCommittee);
return RedirectToAction("IndexSteeringCommittee");
_context = context;
_azureBlobUploader = azureBlobUploader;
}

public async Task<IActionResult> HousingProgramData()
Expand All @@ -260,7 +28,7 @@ public async Task<IActionResult> HousingProgramData()
public async Task<IActionResult> HousingProgramData(HousingProgram model)
{
if (ModelState.IsValid)
{ // if all the data is valid, update the database
{
HousingProgram entry = new()
{
HouseHoldSize = model.HouseHoldSize,
Expand All @@ -272,9 +40,8 @@ public async Task<IActionResult> HousingProgramData(HousingProgram model)
TempData["Message"] = $"Entry for Household size {entry.HouseHoldSize} updated Successfully";
return RedirectToAction("HousingProgramData");
}
// If model state is not valid, return the view with the model to show validation errors

List<HousingProgram> data = await _context.HousingProgram.OrderBy(hp => hp.HouseHoldSize).ToListAsync();
// keep the data from user's input
data[data.FindIndex(hp => hp.HouseHoldSize == model.HouseHoldSize)].MaximumIncome = model.MaximumIncome;
TempData["Message"] = $"Maximum income must be a non - negative number at HouseHold size {model.HouseHoldSize}.";
return View(data);
Expand All @@ -294,7 +61,6 @@ public async Task<IActionResult> UploadNewsletter(IFormFile userFile)
{
try
{
// Upload the file to BLOB storage
string filePath = await _azureBlobUploader.UploadFileAsync(userFile, userFile.FileName);
TempData["Message"] = $"{userFile.FileName} uploaded successfully";

Expand All @@ -304,7 +70,6 @@ public async Task<IActionResult> UploadNewsletter(IFormFile userFile)
Location = filePath,
};

// add newsletterFile to the DB
await NewsletterFileDB.AddAsync(_context, newsLetterFile);
}
catch (Exception ex)
Expand All @@ -331,17 +96,14 @@ public async Task<IActionResult> ConfirmDeleteNewsletter(int id)
try
{
NewsletterFile? newsletter = await NewsletterFileDB.GetFileAsync(_context, id);
// delete actual file from wwwroot/PDF/focus-newsletters
if (newsletter != null)
{
// actual file name is never changed and object location is never changed when renaming
string? originalFile = newsletter.Location?.Split('/').LastOrDefault(); // Get the file name from the end of the URL
string? originalFile = newsletter.Location?.Split('/').LastOrDefault();
if (originalFile != null)
{
bool isDeleted = await _azureBlobUploader.DeleteFileAsync(originalFile); // Delete the file from Azure Blob Storage
bool isDeleted = await _azureBlobUploader.DeleteFileAsync(originalFile);
}

// remove from DB
await NewsletterFileDB.DeleteAsync(_context, newsletter.NewsletterId);
TempData["Message"] = $"{newsletter.Name} deleted successfully";
}
Expand All @@ -357,26 +119,24 @@ public async Task<IActionResult> ConfirmDeleteNewsletter(int id)
[HttpGet]
public async Task<IActionResult> RenameNewsletter(int id)
{
{
return View(await NewsletterFileDB.GetFileAsync(_context, id));
}
return View(await NewsletterFileDB.GetFileAsync(_context, id));
}

[HttpPost]
[ActionName("RenameNewsletter")]
public async Task<IActionResult> ConfirmRenameNewsletter(int id)
{
NewsletterFile? newsletter = await NewsletterFileDB.GetFileAsync(_context, id);

if (newsletter != null)
{
string oldName = newsletter.Name;
string oldName = newsletter.Name;
string newName = Request.Form["Name"];

await NewsletterFileDB.RenameFileAsync(_context, id, newName);
TempData["Message"] = $"Newsletter {oldName} renamed to {newName}";
}

return RedirectToAction("UploadNewsletter");
}
}
Loading
Loading