Skip to content
Open
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
2 changes: 1 addition & 1 deletion test/CTS/AssessmentControllerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ private static bool IsForbidResult<T>(ActionResult<T> a)
var forbidResult = a.Result as ForbidResult;
if (result != null)
{
Assert.Equal((int)HttpStatusCode.Forbidden, result?.StatusCode);
Assert.Equal((int)HttpStatusCode.Forbidden, result.StatusCode);
}
Assert.True(result != null || forbidResult != null);

Expand Down
59 changes: 59 additions & 0 deletions test/RAPS/RoleTemplateSimplifiedTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using Viper.Areas.RAPS.Models;
using Viper.Models.RAPS;

namespace Viper.test.RAPS
{
public class RoleTemplateSimplifiedTests
{
[Fact]
public void Constructor_MapsScalarsAndFlattensRoles()
{
// arrange
var rt = new RoleTemplate
{
RoleTemplateId = 42,
TemplateName = "Test Template",
Description = "Desc",
RoleTemplateRoles = new List<RoleTemplateRole>
{
new() { Role = new TblRole { RoleId = 1, Role = "Alpha", DisplayName = "Alpha" } },
new() { Role = new TblRole { RoleId = 2, Role = "Beta", DisplayName = "Beta" } }
}
};

// act
var dto = new RoleTemplateSimplified(rt);

// assert
Assert.Equal(42, dto.RoleTemplateId);
Assert.Equal("Test Template", dto.TemplateName);
Assert.Equal("Desc", dto.Description);
var roles = dto.Roles.ToList();
Assert.Equal(2, roles.Count);
Assert.Equal(1, roles[0].RoleId);
Assert.Equal("Alpha", roles[0].FriendlyName);
Assert.Equal(2, roles[1].RoleId);
Assert.Equal("Beta", roles[1].FriendlyName);
}

[Fact]
public void Constructor_EmptyRoles_ReturnsEmptyCollection()
{
// arrange
var rt = new RoleTemplate
{
RoleTemplateId = 7,
TemplateName = "No Roles",
Description = "",
RoleTemplateRoles = new List<RoleTemplateRole>()
};

// act
var dto = new RoleTemplateSimplified(rt);

// assert
Assert.Equal(7, dto.RoleTemplateId);
Assert.Empty(dto.Roles);
}
}
}
2 changes: 1 addition & 1 deletion web/Areas/CMS/Models/CMSFile.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Viper.Areas.CMS.Models
{
public partial class CMSFile : Viper.Models.VIPER.File
public sealed class CMSFile : Viper.Models.VIPER.File
{
public string FriendlyURL { get; set; }

Expand Down
2 changes: 1 addition & 1 deletion web/Areas/CTS/Controllers/AssessmentController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
[HttpGet]
[Permission(Allow = "SVMSecure.CTS.Manage,SVMSecure.CTS.StudentAssessments,SVMSecure.CTS.AssessClinical,SVMSecure.CTS.MyAssessments")]
[ApiPagination(DefaultPerPage = 100, MaxPerPage = 100)]
public async Task<ActionResult<List<StudentAssessment>>> GetAssessments(int? type, int? studentUserId, int? enteredById, int? serviceId,

Check warning on line 47 in web/Areas/CTS/Controllers/AssessmentController.cs

View workflow job for this annotation

GitHub Actions / Backend Tests

'GetAssessments' has a cyclomatic complexity of '30'. Rewrite or refactor the code to decrease its complexity below '26'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1502)
int? epaId, DateOnly? dateFrom, DateOnly? dateTo, ApiPagination? pagination,
string? sortBy = null, bool descending = false)
{
Expand Down Expand Up @@ -297,7 +297,7 @@
.Include(p => p.StudentInfo)
.Where(p => p.PersonId == epaData.StudentId)
.FirstOrDefaultAsync();
if (student == null || student?.StudentInfo?.ClassLevel == null)
if (student == null || student.StudentInfo?.ClassLevel == null)
{
return BadRequest("Student not found");
}
Expand Down
4 changes: 0 additions & 4 deletions web/Areas/CTS/Controllers/CompetencyController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,6 @@ public async Task<ActionResult<CompetencyDto>> UpdateComptency(int competencyId,
return NotFound();
}

if (competency.CompetencyId == null || competency.CompetencyId <= 0)
{
return BadRequest("CompetencyId is required.");
}
if (competency.Name.Length < 2 || competency.Number.Length < 1)
{
return BadRequest("Name and Number are required.");
Expand Down
6 changes: 3 additions & 3 deletions web/Areas/CTS/Models/AuditRow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ public AuditRow(CtsAudit dbAudit)
Timestamp = dbAudit.TimeStamp;
ModifiedById = dbAudit.ModifiedBy;
ModifiedByName = dbAudit.Modifier.LastName + ", " + dbAudit.Modifier.FirstName;
if (dbAudit?.Encounter?.Student != null)
if (dbAudit.Encounter?.Student != null)
{
ModifiedPersonId = dbAudit.Encounter?.StudentUserId;
ModifiedPersonName = dbAudit.Encounter?.Student?.LastName + ", " + dbAudit.Encounter?.Student?.FirstName;
ModifiedPersonId = dbAudit.Encounter.StudentUserId;
ModifiedPersonName = dbAudit.Encounter.Student.LastName + ", " + dbAudit.Encounter.Student.FirstName;
}

}
Expand Down
6 changes: 5 additions & 1 deletion web/Areas/Effort/Services/PercentRolloverService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public PercentRolloverService(

public async Task<PercentRolloverPreviewDto> GetRolloverPreviewAsync(int year, CancellationToken ct = default)
{
// Bound year for DateTime constructions below (year and year+1 must be valid years).
ArgumentOutOfRangeException.ThrowIfLessThan(year, 1);
ArgumentOutOfRangeException.ThrowIfGreaterThan(year, 9998);

var result = new PercentRolloverPreviewDto();

result.SourceAcademicYear = year;
Expand All @@ -42,7 +46,7 @@ public async Task<PercentRolloverPreviewDto> GetRolloverPreviewAsync(int year, C
var july1Start = new DateTime(year, 7, 1, 0, 0, 0, DateTimeKind.Local);
result.OldEndDate = june30Start;
result.NewStartDate = july1Start;
result.NewEndDate = new DateTime(year + 1, 6, 30, 0, 0, 0, DateTimeKind.Local);
result.NewEndDate = june30Start.AddYears(1);

// Find assignments ending on June 30 of source year (any time on that day)
var assignments = await _context.Percentages
Expand Down
3 changes: 2 additions & 1 deletion web/Areas/Effort/Services/PercentageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,8 @@ public async Task<PercentageValidationResult> ValidatePercentageAsync(
.Where(p => !string.Equals(p.PercentAssignType.Class, LeaveTypeClass, StringComparison.OrdinalIgnoreCase))
.Sum(p => (decimal)EffortConstants.ToDisplayPercent(p.PercentageValue));

if (isNewActive && type != null && !string.Equals(type.Class, LeaveTypeClass, StringComparison.OrdinalIgnoreCase))
// type is guaranteed non-null here: early-return above when result.IsValid==false (set when type==null).
if (isNewActive && !string.Equals(type!.Class, LeaveTypeClass, StringComparison.OrdinalIgnoreCase))
{
var newTotal = activeNonLeaveTotal + Math.Round(request.PercentageValue, EffortConstants.PercentDisplayDecimals);
if (newTotal > 100)
Expand Down
16 changes: 10 additions & 6 deletions web/Areas/RAPS/Controllers/RAPSController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,18 @@ public override async Task OnActionExecutionAsync(ActionExecutingContext context
List<string>? path = HttpContext?.Request?.Path.ToString().Split("/").ToList();
int? rapsIdx = path?.FindIndex(p => p.Equals("raps", StringComparison.OrdinalIgnoreCase));
string instance = "VIPER";
if (rapsIdx != null && rapsIdx > -1 && path?.Count > rapsIdx + 1)
{
instance = path[(int)rapsIdx + 1];
}
string page = "";
if (rapsIdx != null && rapsIdx > -1 && path?.Count > rapsIdx + 2)
// rapsIdx is non-null iff path is non-null (it's derived from path?.FindIndex).
if (rapsIdx is { } idx && idx > -1)
{
page = path[(int)rapsIdx + 2];
if (path!.Count > idx + 1)
{
instance = path[idx + 1];
}
if (path.Count > idx + 2)
{
page = path[idx + 2];
}
}
ViewData["ViperLeftNav"] = await Nav(roleIdValid ? roleId : null,
permIdValid ? permissionId : null,
Expand Down
13 changes: 5 additions & 8 deletions web/Areas/RAPS/Controllers/RoleTemplatesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,9 @@ public async Task<ActionResult<IEnumerable<RoleTemplateSimplified>>> GetRoleTemp
.OrderBy(rt => rt.TemplateName)
.ToListAsync();

List<RoleTemplateSimplified> roleTemplates = new();
foreach (var rt in dbRoleTemplates)
{
roleTemplates.Add(new RoleTemplateSimplified(rt));
}
return roleTemplates;
return dbRoleTemplates
.Select(rt => new RoleTemplateSimplified(rt))
.ToList();
}

// GET: RoleTemplates/5
Expand Down Expand Up @@ -186,8 +183,8 @@ public async Task<ActionResult<RoleTemplateApplyPreview>> RoleTemplateApply(stri

return new RoleTemplateApplyPreview()
{
DisplayName = user?.DisplayFullName ?? "User not found",
MemberId = user?.MothraId ?? "",
DisplayName = user.DisplayFullName,
MemberId = user.MothraId,
Roles = rolesToApply
};
}
Expand Down
2 changes: 1 addition & 1 deletion web/Areas/RAPS/Models/RoleTemplateSimplified.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class RoleTemplateSimplified

public string Description { get; set; } = null!;

public virtual ICollection<RoleSimplified> Roles { get; set; } = new List<RoleSimplified>();
public ICollection<RoleSimplified> Roles { get; set; } = new List<RoleSimplified>();

public RoleTemplateSimplified() { }
public RoleTemplateSimplified(RoleTemplate rt)
Expand Down
6 changes: 3 additions & 3 deletions web/Areas/RAPS/Services/RAPSAuditService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,11 @@ public async Task<List<AuditLog>> GetMemberRolesAndPermissionHistory(string inst
Dictionary<string, List<string>> actionsPerformedOnObject = new();
foreach (AuditLog auditLog in auditEntries)
{
if (auditLog?.RoleId != null || auditLog?.PermissionId != null)
if (auditLog.RoleId != null || auditLog.PermissionId != null)
{
string key = auditLog?.RoleId != null
string key = auditLog.RoleId != null
? "role-" + auditLog.RoleId
: "permission-" + auditLog!.PermissionId;
: "permission-" + auditLog.PermissionId;
if (actionsPerformedOnObject.ContainsKey(key))
{
List<string> moreRecentActions = actionsPerformedOnObject[key];
Expand Down
4 changes: 2 additions & 2 deletions web/Classes/Utilities/AcademicYearHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ public static List<int> GetTermCodesForAcademicYear(IEnumerable<int> allTermCode
/// </summary>
public static DateTime GetAcademicYearStart(DateTime date)
{
var year = date.Month < 7 ? date.Year - 1 : date.Year;
return new DateTime(year, 7, 1, 0, 0, 0, DateTimeKind.Local);
var julyOfYear = new DateTime(date.Year, 7, 1, 0, 0, 0, DateTimeKind.Local);
return date.Month < 7 ? julyOfYear.AddYears(-1) : julyOfYear;
}

/// <summary>
Expand Down
5 changes: 3 additions & 2 deletions web/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public IActionResult EmulateUser(string loginId)

if (protector != null && emulatedUser.LoginId != null)
{
string? encryptedEmulatedLoginId = protector?.Protect(emulatedUser.LoginId);
string encryptedEmulatedLoginId = protector.Protect(emulatedUser.LoginId);

// set emulating cached item to expire after 30 minutes of inactivity
HttpHelper.Cache?.Set(ClaimsTransformer.EmulationCacheNamePrefix + trueLoginId, encryptedEmulatedLoginId, (new MemoryCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromMinutes(30))));
Expand Down Expand Up @@ -319,7 +319,8 @@ private async Task<IActionResult> AuthenticateCasLogin(string? ticket, string? r
{
var claimsIdentity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, validatedUserName), new Claim(ClaimTypes.NameIdentifier, validatedUserName), new Claim(ClaimTypes.AuthenticationMethod, "CAS") }, CookieAuthenticationDefaults.AuthenticationScheme);

XElement? attributesNode = successNode?.Element(_ns + "attributes");
// successNode is guaranteed non-null here: validatedUserName is derived from successNode?.Element(user)?.Value.
XElement? attributesNode = successNode!.Element(_ns + "attributes");
if (attributesNode != null)
{
foreach (string attributeName in _casAttributesToCapture)
Expand Down
10 changes: 5 additions & 5 deletions web/Models/Students/StudentClassYear.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Viper.Models.Students
{
public class StudentClassYear
public sealed class StudentClassYear
{

public int StudentClassYearId { get; set; }
Expand All @@ -20,10 +20,10 @@ public class StudentClassYear
public int? UpdatedBy { get; set; }
public string? Comment { get; set; }

public virtual Person? Student { get; set; }
public virtual ClassYearLeftReason? ClassYearLeftReason { get; set; }
public virtual Person? AddedByPerson { get; set; }
public virtual Person? UpdatedByPerson { get; set; }
public Person? Student { get; set; }
public ClassYearLeftReason? ClassYearLeftReason { get; set; }
public Person? AddedByPerson { get; set; }
public Person? UpdatedByPerson { get; set; }

[NotMapped]
public string? LeftReasonText
Expand Down
20 changes: 12 additions & 8 deletions web/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Amazon;

Check warning on line 1 in web/Program.cs

View workflow job for this annotation

GitHub Actions / Backend Tests

'<Main>$' has a cyclomatic complexity of '31'. Rewrite or refactor the code to decrease its complexity below '26'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1502)
using Amazon.Extensions.NETCore.Setup;
using Amazon.Runtime.CredentialManagement;
using Joonasw.AspNetCore.SecurityHeaders;
Expand All @@ -11,6 +11,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.FileProviders;
using System.Reflection;
using System.Text.Json.Serialization;
using NLog;
using NLog.Web;
Expand All @@ -30,7 +31,7 @@

// Load .env.local for local development only (multiple-instance support)
// Avoid loading in production - guard by ASPNETCORE_ENVIRONMENT.
var envPath = Path.Combine(Directory.GetCurrentDirectory(), "../.env.local");

Check warning on line 34 in web/Program.cs

View workflow job for this annotation

GitHub Actions / Backend Tests

'Program' has a maintainability index of '5'. Rewrite or refactor the code to increase its maintainability index (MI) above '9'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1505)
var aspNetEnv = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
if (string.Equals(aspNetEnv, "Development", StringComparison.OrdinalIgnoreCase)
&& File.Exists(envPath))
Expand Down Expand Up @@ -542,26 +543,29 @@
{
XElement xAwsCredentials = XElement.Load(awsCredentialsFilePath, LoadOptions.None);

if (!String.IsNullOrWhiteSpace(xAwsCredentials?.Element("AccessKeyId")?.Value) && !String.IsNullOrWhiteSpace(xAwsCredentials?.Element("SecretAccessKey")?.Value))
var accessKey = xAwsCredentials.Element("AccessKeyId")?.Value;
var secretKey = xAwsCredentials.Element("SecretAccessKey")?.Value;
if (!String.IsNullOrWhiteSpace(accessKey) && !String.IsNullOrWhiteSpace(secretKey))
{
// grab the credentials ouf of the xml file to stor in the encrypted json file inthe profile
var options = new CredentialProfileOptions
{
AccessKey = xAwsCredentials?.Element("AccessKeyId")?.Value.Trim(),
SecretKey = xAwsCredentials?.Element("SecretAccessKey")?.Value.Trim()
AccessKey = accessKey.Trim(),
SecretKey = secretKey.Trim()
};

var profile = new CredentialProfile("default", options);
// if a region was specified in the xml then use the specified region else default to USWest1
if (!string.IsNullOrWhiteSpace(xAwsCredentials?.Element("RegionEndpoint")?.Value) && xAwsCredentials?.Element("RegionEndpoint") != null)
var regionValue = xAwsCredentials.Element("RegionEndpoint")?.Value.Trim();
if (!string.IsNullOrWhiteSpace(regionValue))
{
#pragma warning disable CS8604 // Possible null reference argument.
profile.Region = typeof(Amazon.RegionEndpoint).GetField(xAwsCredentials?.Element("RegionEndpoint")?.Value)?.GetValue(null) as Amazon.RegionEndpoint;
#pragma warning restore CS8604 // Possible null reference argument.
const BindingFlags regionFieldFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.IgnoreCase;
profile.Region = typeof(RegionEndpoint).GetField(regionValue, regionFieldFlags)?.GetValue(null) as RegionEndpoint
?? RegionEndpoint.USWest1;
}
else
{
profile.Region = Amazon.RegionEndpoint.USWest1;
profile.Region = RegionEndpoint.USWest1;
}
var netSDKFile = new NetSDKCredentialsFile();
netSDKFile.RegisterProfile(profile);
Expand Down
Loading