Skip to content

Commit

Permalink
Merge branch 'master' into chore/summary/az-func-schedule-messages
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/Fusion.Summary.Functions/Functions/DepartmentResourceOwnerSync.cs
#	src/Fusion.Summary.Functions/Functions/WeeklyDepartmentSummarySender.cs
  • Loading branch information
Jonathanio123 committed Sep 5, 2024
2 parents 58f798f + 2a9d4ce commit 982fe01
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 67 deletions.
8 changes: 5 additions & 3 deletions src/Fusion.Summary.Api/BaseController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ namespace Fusion.Summary.Api;

public class BaseController : ControllerBase
{
// TODO: Transition to ProblemDetails
protected NotFoundObjectResult DepartmentNotFound(string sapDepartmentId) =>
NotFound(new { message = $"Department with id '{sapDepartmentId}' was not found" });
protected ActionResult DepartmentNotFound(string sapDepartmentId) =>
FusionApiError.NotFound(sapDepartmentId, $"Department with sap id '{sapDepartmentId}' was not found");

protected ActionResult SapDepartmentIdRequired() =>
FusionApiError.InvalidOperation("SapDepartmentIdRequired", "SapDepartmentId route parameter is required");


protected Task DispatchAsync(IRequest command)
Expand Down
60 changes: 19 additions & 41 deletions src/Fusion.Summary.Api/Controllers/DepartmentsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,22 @@
using Fusion.Summary.Api.Controllers.Requests;
using Fusion.Summary.Api.Domain.Commands;
using Fusion.Summary.Api.Domain.Queries;
using Microsoft.ApplicationInsights.AspNetCore.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using HttpRequestExtensions = Microsoft.ApplicationInsights.AspNetCore.Extensions.HttpRequestExtensions;

namespace Fusion.Summary.Api.Controllers;

/// <summary>
/// TODO: Add summary
/// </summary>
[ApiVersion("1.0")]
[Authorize]
[ApiController]
public class DepartmentsController : BaseController
{
/// <summary />
/// TODO: Add summary
/// <returns></returns>
[HttpGet("departments")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(ApiDepartment[]), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetDepartmentsV1()
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<ApiDepartment[]>> GetDepartmentsV1()
{
#region Authorization

Expand All @@ -43,31 +36,19 @@ public async Task<IActionResult> GetDepartmentsV1()

#endregion Authorization

var ret = new List<ApiDepartment>();
var departments = await DispatchAsync(new GetAllDepartments());

// Query
var departments = (await DispatchAsync(new GetAllDepartments())).ToArray();

if (departments.Length == 0)
return NotFound();
else
{
foreach (var d in departments) ret.Add(ApiDepartment.FromQueryDepartment(d));
}
var apiDepartments = departments.Select(ApiDepartment.FromQueryDepartment);

return Ok(ret);
return Ok(apiDepartments);
}

/// <summary />
/// TODO: Add summary
/// <returns></returns>
[HttpGet("departments/{sapDepartmentId}")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(ApiDepartment), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetDepartmentV1(string sapDepartmentId)
public async Task<ActionResult<ApiDepartment>> GetDepartmentV1(string sapDepartmentId)
{
#region Authorization

Expand All @@ -83,7 +64,7 @@ public async Task<IActionResult> GetDepartmentV1(string sapDepartmentId)
#endregion Authorization

if (string.IsNullOrWhiteSpace(sapDepartmentId))
return BadRequest("SapDepartmentId route parameter is required");
return SapDepartmentIdRequired();

var department = await DispatchAsync(new GetDepartment(sapDepartmentId));

Expand All @@ -94,15 +75,12 @@ public async Task<IActionResult> GetDepartmentV1(string sapDepartmentId)
return Ok(ApiDepartment.FromQueryDepartment(department));
}

/// <summary />
/// TODO: Add summary
/// <returns></returns>

[HttpPut("departments/{sapDepartmentId}")]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> PutV1(string sapDepartmentId, [FromBody] PutDepartmentRequest request)
{
Expand All @@ -120,7 +98,7 @@ public async Task<IActionResult> PutV1(string sapDepartmentId, [FromBody] PutDep
#endregion Authorization

if (string.IsNullOrWhiteSpace(sapDepartmentId))
return BadRequest("SapDepartmentId route parameter is required");
return SapDepartmentIdRequired();

var personIdentifiers = request.ResourceOwnersAzureUniqueId
.Concat(request.DelegateResourceOwnersAzureUniqueId)
Expand All @@ -131,7 +109,7 @@ public async Task<IActionResult> PutV1(string sapDepartmentId, [FromBody] PutDep
.ToList();

if (unresolvedProfiles.Count != 0)
return BadRequest($"Profiles: {string.Join(',', unresolvedProfiles)} could not be resolved");
return FusionApiError.NotFound(string.Join(',', unresolvedProfiles), "Profiles could not be resolved");


var department = await DispatchAsync(new GetDepartment(sapDepartmentId));
Expand All @@ -146,7 +124,7 @@ await DispatchAsync(
request.ResourceOwnersAzureUniqueId,
request.DelegateResourceOwnersAzureUniqueId));

return Created();
return Created(Request.GetUri(), null);
}

// Check if department owners has changed
Expand All @@ -160,10 +138,10 @@ await DispatchAsync(
request.ResourceOwnersAzureUniqueId,
request.DelegateResourceOwnersAzureUniqueId));

return Ok();
return NoContent();
}

// No change
return Ok();
return NoContent();
}
}
31 changes: 18 additions & 13 deletions src/Fusion.Summary.Api/Controllers/SummaryReportsController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Net.Mime;
using Fusion.AspNetCore.Api;
using Fusion.AspNetCore.FluentAuthorization;
using Fusion.AspNetCore.OData;
using Fusion.Authorization;
Expand All @@ -7,6 +8,7 @@
using Fusion.Summary.Api.Controllers.Requests;
using Fusion.Summary.Api.Domain.Commands;
using Fusion.Summary.Api.Domain.Queries;
using Microsoft.ApplicationInsights.AspNetCore.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

Expand All @@ -18,14 +20,13 @@ namespace Fusion.Summary.Api.Controllers;
public class SummaryReportsController : BaseController
{
[HttpGet("resource-owners-summary-reports/{sapDepartmentId}/weekly")]
[Produces(MediaTypeNames.Application.Json)]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ODataFilter(nameof(ApiWeeklySummaryReport.Period))]
[ODataOrderBy(nameof(ApiWeeklySummaryReport.Period), nameof(ApiWeeklySummaryReport.Id))]
[ODataTop(100), ODataSkip]
[ApiVersion("1.0")]
public async Task<ActionResult<ApiCollection<ApiWeeklySummaryReport>>> GetWeeklySummaryReportsV1(
[FromRoute] string sapDepartmentId, ODataQueryParams query)
{
Expand All @@ -44,7 +45,7 @@ await Request.RequireAuthorizationAsync(r =>
#endregion

if (string.IsNullOrWhiteSpace(sapDepartmentId))
return BadRequest("SapDepartmentId route parameter is required");
return SapDepartmentIdRequired();

if (await DispatchAsync(new GetDepartment(sapDepartmentId)) is null)
return DepartmentNotFound(sapDepartmentId);
Expand All @@ -55,12 +56,16 @@ await Request.RequireAuthorizationAsync(r =>
.FromQueryCollection(queryReports, ApiWeeklySummaryReport.FromQuerySummaryReport));
}

/// <summary>
/// Summary report key is composed of the department sap id and the period date.
/// If a report already exists for the given period, it will be replaced.
/// </summary>
[HttpPut("resource-owners-summary-reports/{sapDepartmentId}/weekly")]
[Produces(MediaTypeNames.Application.Json)]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
[ApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> PutWeeklySummaryReportV1([FromRoute] string sapDepartmentId,
[FromBody] PutWeeklySummaryReportRequest request)
{
Expand All @@ -79,18 +84,18 @@ await Request.RequireAuthorizationAsync(r =>
#endregion

if (string.IsNullOrWhiteSpace(sapDepartmentId))
return BadRequest("SapDepartmentId route parameter is required");
return SapDepartmentIdRequired();

if (await DispatchAsync(new GetDepartment(sapDepartmentId)) is null)
return DepartmentNotFound(sapDepartmentId);

if (request.Period.DayOfWeek != DayOfWeek.Monday)
return BadRequest("Period date must be the first day of the week");
return FusionApiError.InvalidOperation("InvalidPeriod", "Weekly summary report period date must be a monday");

var command = new PutWeeklySummaryReport(sapDepartmentId, request);

await DispatchAsync(command);
var newReportCreated = await DispatchAsync(command);

return NoContent();
return newReportCreated ? Created(Request.GetUri(), null) : NoContent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Fusion.Summary.Api.Domain.Commands;

public class PutWeeklySummaryReport : IRequest
public class PutWeeklySummaryReport : IRequest<bool>
{
public string SapDepartmentId { get; private set; }

Expand All @@ -20,7 +20,7 @@ public PutWeeklySummaryReport(string sapDepartmentId, PutWeeklySummaryReportRequ
}


public class Handler : IRequestHandler<PutWeeklySummaryReport>
public class Handler : IRequestHandler<PutWeeklySummaryReport, bool>
{
private readonly SummaryDbContext _dbContext;

Expand All @@ -29,7 +29,7 @@ public Handler(SummaryDbContext dbContext)
_dbContext = dbContext;
}

public async Task Handle(PutWeeklySummaryReport request, CancellationToken cancellationToken)
public async Task<bool> Handle(PutWeeklySummaryReport request, CancellationToken cancellationToken)
{
if (!await _dbContext.Departments.AnyAsync(d => d.DepartmentSapId == request.SapDepartmentId,
cancellationToken: cancellationToken))
Expand Down Expand Up @@ -83,6 +83,9 @@ public async Task Handle(PutWeeklySummaryReport request, CancellationToken cance
_dbContext.WeeklySummaryReports.Add(dbSummaryReport);

await _dbContext.SaveChangesAsync(cancellationToken);

// return true if a new report was created
return existingReport is null;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
[
{
"environment": "pr",
"disabledFunctions": [
"weekly-department-recipients-sync",
"weekly-department-summary-sender",
"weekly-department-summary-worker"
]
"disabledFunctions": []
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public WeeklyDepartmentSummarySender(ISummaryApiClient summaryApiClient, INotifi
}

[FunctionName("weekly-department-summary-sender")]
public async Task RunAsync([TimerTrigger("0 0 5 * * 1", RunOnStartup = false)] TimerInfo timerInfo)
public async Task RunAsync([TimerTrigger("0 0 5 * * MON", RunOnStartup = false)] TimerInfo timerInfo)
{
var departments = await summaryApiClient.GetDepartmentsAsync();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,44 @@ public async Task PutAndGetWeeklySummaryReport_ShouldReturnReport()


var response = await _client.PutWeeklySummaryReportAsync(department.DepartmentSapId);
response.Should().BeNoContent();
response.Should().BeCreated();

var getResponse = await _client.GetWeeklySummaryReportsAsync(department.DepartmentSapId);
getResponse.Should().BeSuccessfull();
getResponse.Value!.Items.Should().HaveCount(1);
}

[Fact]
public async Task PutAndUpdateWeeklySummaryReport_ShouldReturnNoContent()
{
using var adminScope = _fixture.AdminScope();
var testUser = _fixture.Fusion.CreateUser().AsEmployee().AzureUniqueId!.Value;

var department = await _client.PutDepartmentAsync(testUser);

var response = await _client.PutWeeklySummaryReportAsync(department.DepartmentSapId);
response.Should().BeCreated();

response = await _client.PutWeeklySummaryReportAsync(department.DepartmentSapId);
response.Should().BeNoContent();
}

[Fact]
public async Task PutWeeklySummaryReport_WithInvalidPeriodDate_ShouldReturnBadRequest()
{
using var adminScope = _fixture.AdminScope();
var testUser = _fixture.Fusion.CreateUser().AsEmployee().AzureUniqueId!.Value;

var department = await _client.PutDepartmentAsync(testUser);

var response = await _client.PutWeeklySummaryReportAsync(department.DepartmentSapId, (report) =>
{
var nowDate = DateTime.UtcNow;
if (nowDate.DayOfWeek == DayOfWeek.Monday)
report.Period = nowDate.AddDays(1);
report.Period = nowDate;
});

response.Should().BeBadRequest();
}
}

0 comments on commit 982fe01

Please sign in to comment.