Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public static void LoadCampaignssHandlerTestData(AllReadyContext context)
// Campaigns
context.Campaigns.Add(new Campaign { Name = "Campaign 1", ManagingOrganizationId = 1 });
context.Campaigns.Add(new Campaign { Name = "Campaign 2", ManagingOrganizationId = 1 });
context.Campaigns.Add(new Campaign { Name = "Locked Campaign", ManagingOrganizationId = 1, Locked = true });
context.Campaigns.Add(new Campaign { Name = "Unlocked Campaign", ManagingOrganizationId = 1, Locked = false });

context.SaveChanges();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public void AddNewCampaign()
var result = handler.Handle(new EditCampaignCommand { Campaign = newCampaign });

// Assert
Assert.Equal(3, Context.Campaigns.Count());
Assert.Equal(5, Context.Campaigns.Count());
Assert.True(result > 0);
}

Expand Down Expand Up @@ -56,7 +56,7 @@ public void UpdatingExistingCampaignUpdatesAllCoreProperties()
var savedCampaign = Context.Campaigns.SingleOrDefault(s => s.Id == 2);

// Assert
Assert.Equal(2, Context.Campaigns.Count());
Assert.Equal(4, Context.Campaigns.Count());
Assert.Equal(2, result);

Assert.Equal(name, savedCampaign.Name);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using AllReady.Areas.Admin.Features.Campaigns;
using System.Linq;
using Xunit;

namespace AllReady.UnitTest.Areas.Admin.Features.Campaigns
{
public class LockUnlockCampaignCommandHandlerTests : InMemoryContextTest
{
[Fact]
public void LockedCampaignIsUnlocked()
{
// Arrange
var handler = new LockUnlockCampaignCommandHandler(Context);

// Act
var campaign = Context.Campaigns.FirstOrDefault(c => c.Name == "Locked Campaign");
handler.Handle(new LockUnlockCampaignCommand { CampaignId = campaign.Id });
var result = Context.Campaigns.FirstOrDefault(c => c.Name == "Locked Campaign");

// Assert
Assert.False(result.Locked); // Campaign should now be unlocked
}

[Fact]
public void UnlockedCampaignIsLocked()
{
// Arrange
var handler = new LockUnlockCampaignCommandHandler(Context);

// Act
var campaign = Context.Campaigns.FirstOrDefault(c => c.Name == "Unlocked Campaign");
handler.Handle(new LockUnlockCampaignCommand { CampaignId = campaign.Id });
var result = Context.Campaigns.FirstOrDefault(c => c.Name == "Unlocked Campaign");

// Assert
Assert.True(result.Locked); // Campaign should now be locked
}

protected override void LoadTestData()
{
CampaignsHandlerTestHelper.LoadCampaignssHandlerTestData(Context);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,22 @@ public IActionResult DeleteConfirmed(int id)
{
return HttpUnauthorized();
}

_bus.Send(new DeleteCampaignCommand { CampaignId = id });
return RedirectToAction("Index", new { area = "Admin" });
}

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult LockUnlock(int id)
{
if (!User.IsUserType(UserType.SiteAdmin))
{
return HttpUnauthorized();
}

_bus.Send(new LockUnlockCampaignCommand { CampaignId = id });
return RedirectToAction("Details", new { area = "Admin", id = id });
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public CampaignDetailModel Handle(CampaignDetailQuery message)
EndDate = campaign.EndDateTime,
CampaignImpact = campaign.CampaignImpact,
Location = campaign.Location.ToModel(),
Locked = campaign.Locked,
Activities = campaign.Activities.Select(a => new ActivitySummaryModel
{
Id = a.Id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public IEnumerable<CampaignSummaryModel> Handle(CampaignListQuery message)
OrganizationName = c.ManagingOrganization.Name,
TimeZoneId = c.TimeZoneId,
StartDate = c.StartDateTime,
EndDate = c.EndDateTime
EndDate = c.EndDateTime,
Locked = c.Locked
});

return campaigns;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using MediatR;

namespace AllReady.Areas.Admin.Features.Campaigns
{
public class LockUnlockCampaignCommand : IRequest
{
public int CampaignId {get; set;}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using AllReady.Models;
using MediatR;
using System.Linq;

namespace AllReady.Areas.Admin.Features.Campaigns
{
public class LockUnlockCampaignCommandHandler : RequestHandler<LockUnlockCampaignCommand>
{
private AllReadyContext _context;

public LockUnlockCampaignCommandHandler(AllReadyContext context)
{
_context = context;

}
protected override void HandleCore(LockUnlockCampaignCommand message)
{
var campaign =
_context.Campaigns.SingleOrDefault(c => c.Id == message.CampaignId);

if (campaign != null)
{
campaign.Locked = !campaign.Locked;

_context.Update(campaign);
_context.SaveChanges();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,7 @@ public class CampaignDetailModel: IPrimaryContactModel
[EmailAddress]
public string PrimaryContactEmail { get; set; }

public bool Locked { get; set; }

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,6 @@ public CampaignSummaryModel()
[EmailAddress]
public string PrimaryContactEmail { get; set; }

public bool Locked { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
@model AllReady.Areas.Admin.Models.CampaignDetailModel
@using AllReady.Security;

@{ ViewBag.Title = Model.Name; }
<div class="row">
<div class="col-12">
Expand All @@ -11,7 +13,31 @@

<div class="row">
<div id="col-main">
<div class="col-md-9"><h2>@Model.Name <a asp-controller="Campaign" asp-action="Edit" asp-route-id="@Model.Id" class="btn btn-default" title="Edit"><i class="fa fa-edit"></i></a> <a asp-controller="Campaign" asp-action="Delete" asp-route-area="Admin" asp-route-id="@Model.Id" class="btn btn-default"><i class="glyphicon glyphicon-trash"></i></a></h2></div>
<div class="col-md-9">
<h2 class="inline-form">
@Model.Name
</h2>
<a asp-controller="Campaign" asp-action="Edit" asp-route-id="@Model.Id" class="btn btn-default inline-form" title="Edit"><i class="fa fa-edit"></i></a>
<a asp-controller="Campaign" asp-action="Delete" asp-route-area="Admin" asp-route-id="@Model.Id" class="btn btn-default inline-form"><i class="glyphicon glyphicon-trash"></i></a>
@if (User.IsUserType(UserType.SiteAdmin))
{
<form asp-controller="Campaign" asp-route-area="Admin" asp-action="LockUnlock" class="inline-form">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this have to be a form? Seems like a lot of extra code. You are already validating that the logged-in user is a SiteAdmin in CampaignController.LockUnlock

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On this one it's not presenting any other page or input via a http get so I felt it best practice to make this require a http post to the action via a form. If we make it just a hyperlink we potentially should add a page to confirm that we want to lock or unlock the campaign which felt unnecessary.

<input asp-for="Id" type="hidden" />
@if (Model.Locked)
{
<button type="submit" class="btn btn-default inline-form" title="This campaign is currently locked">Unlock</button>
}
else
{
<button type="submit" class="btn btn-default inline-form" title="This campaign is currently unlocked">Lock</button>
}
</form>
}
else if (Model.Locked)
{
<span title="This campaign is locked" class="fa fa-exclamation-triangle text-warning"></span><span> This campaign has been locked by a site administrator. Locked campaigns are not visible to the public or to volunteers.</span>
}
</div>
</div>
</div>

Expand All @@ -24,8 +50,9 @@

</div>
</div>

<div class="row">

<div class="col-md-12">
<dl class="dl-horizontal">
<dt>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
</td>
<td>
<a asp-controller="Campaign" asp-action="Details" asp-route-area="Admin" asp-route-id="@item.Id">@item.Name</a>
@if (item.Locked)
{
<span title="This campaign is locked" class="fa fa-exclamation-triangle text-warning"></span>
}
@if (!string.IsNullOrEmpty(item.Description))
{
<br/><span class="text-muted">@item.Description</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ public ActivityApiController(IAllReadyDataAccess allReadyDataAccess, IMediator b
[HttpGet]
public IEnumerable<ActivityViewModel> Get()
{
return _allReadyDataAccess.Activities.Select(a => new ActivityViewModel(a));
return _allReadyDataAccess.Activities
.Where(c => !c.Campaign.Locked)
.Select(a => new ActivityViewModel(a));
}

// GET api/values/5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public ActivityController(IAllReadyDataAccess allReadyDataAccess, IMediator bus)
[Authorize]
public IActionResult GetMyActivities()
{
var myActivities = _allReadyDataAccess.GetActivitySignups(User.GetUserId());
var myActivities = _allReadyDataAccess.GetActivitySignups(User.GetUserId()).Where(a => !a.Activity.Campaign.Locked);
var signedUp = myActivities.Select(a => new ActivityViewModel(a.Activity));
var viewModel = new MyActivitiesResultsScreenViewModel("My Activities", signedUp);
return View("MyActivities", viewModel);
Expand Down Expand Up @@ -85,7 +85,7 @@ public IActionResult ShowActivity(int id)
{
var activity = _allReadyDataAccess.GetActivity(id);

if (activity == null)
if (activity == null || activity.Campaign.Locked)
{
return HttpNotFound();
}
Expand Down
20 changes: 11 additions & 9 deletions AllReadyApp/Web-App/AllReady/Controllers/CampaignController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using Microsoft.AspNet.Mvc;
using AllReady.Models;
using AllReady.ViewModels;
using Microsoft.Data.Entity;

namespace AllReady.Controllers
{
Expand All @@ -21,7 +20,7 @@ public CampaignController(IAllReadyDataAccess dataAccess)
[Route("~/[controller]")]
public IActionResult Index()
{
return View(_dataAccess.Campaigns.ToViewModel().ToList());
return View(_dataAccess.Campaigns.Where(c => !c.Locked).ToViewModel().ToList());
}

[HttpGet]
Expand All @@ -30,8 +29,8 @@ public IActionResult Details(int id)
{
var campaign = _dataAccess.GetCampaign(id);

if (campaign == null)
HttpNotFound();
if (campaign == null || campaign.Locked)
return HttpNotFound();

return View("Details", new CampaignViewModel(campaign));
}
Expand All @@ -43,7 +42,7 @@ public IActionResult LocationMap(int id)
var campaign = _dataAccess.GetCampaign(id);

if (campaign == null)
HttpNotFound();
return HttpNotFound();

return View("Map", new CampaignViewModel(campaign));
}
Expand All @@ -53,19 +52,22 @@ public IActionResult LocationMap(int id)
public IEnumerable<CampaignViewModel> Get()
{
return _dataAccess.Campaigns
.Where(c => !c.Locked)
.Select(x => new CampaignViewModel(x));
}

// GET api/values/5
[HttpGet("{id}")]
public CampaignViewModel Get(int id)
public ActionResult Get(int id)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this used? I can't figure it out.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something I noticed when testing the API. Previously there was a HttpNotFound(); line which seems to do nothing since it wasn't being actually returned. However to return it the controller needs to be an action result rather than just the model. I may have misunderstood something here about how the MVC Core controllers work for API responses though?

If this is truly an issue we may need to check the other API endpoints as well.

{
var campaign = _dataAccess.GetCampaign(id);

if (campaign == null)
HttpNotFound();
if (campaign == null || campaign.Locked)
{
return HttpNotFound();
}

return campaign.ToViewModel();
return Json(campaign.ToViewModel());
}
}
}
2 changes: 1 addition & 1 deletion AllReadyApp/Web-App/AllReady/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public HomeController(IAllReadyDataAccess dataAccess)

public IActionResult Index()
{
return View(_dataAccess.Campaigns.Where(c => c.EndDateTime.UtcDateTime.Date > DateTime.UtcNow.Date).ToViewModel().OrderBy(vm => vm.EndDate).ToList());
return View(_dataAccess.Campaigns.Where(c => c.EndDateTime.UtcDateTime.Date > DateTime.UtcNow.Date && !c.Locked).ToViewModel().OrderBy(vm => vm.EndDate).ToList());
}

public IActionResult About()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ IEnumerable<Activity> IAllReadyDataAccess.Activities
return _dbContext.Activities
.Include(a => a.Location)
.Include(a => a.Location.PostalCode)
.Include(a => a.Campaign)
.Include(a => a.Campaign.ManagingOrganization)
.Include(a => a.Tasks)
.Include(a => a.RequiredSkills)
Expand Down Expand Up @@ -90,10 +91,11 @@ IEnumerable<TaskSignup> IAllReadyDataAccess.GetTasksAssignedToUser(int activityI
var unfilteredTasks = _dbContext.TaskSignups
.Include(ts => ts.Task)
.ThenInclude(t => t.Activity)
.Include(ts => ts.User)
.ThenInclude(t => t.Campaign)
.Include(ts => ts.User)
.ToList();

var finalTasks = unfilteredTasks.Where(ts => ts.Task.Activity.Id == activityId && ts.User.Id == userId).ToList();
var finalTasks = unfilteredTasks.Where(ts => ts.Task.Activity.Id == activityId && ts.User.Id == userId && !ts.Task.Activity.Campaign.Locked).ToList();

return finalTasks;
}
Expand Down
Loading