diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 20d8fd5e..ef0cbb14 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18.16.0-slim as builder-app +FROM node:18.16.0 as builder-app ARG generate_sourcemap=false WORKDIR /app @@ -10,11 +10,9 @@ COPY . . RUN npm run build -- --configuration production --output-hashing=none -FROM nginx:stable-alpine as builder-modules - -# Ensure that the version of nginx of the builder image is compatible with the nginx version of the main image. -ENV NGINX_VERSION 1.24.0 +FROM nginx:1.27.2-alpine as builder-modules +ENV NGINX_VERSION 1.27.2 ENV MORE_HEADERS_VERSION=0.34 ENV MORE_HEADERS_GITREPO=openresty/headers-more-nginx-module @@ -44,7 +42,7 @@ RUN mkdir -p ${DOWNLOADS} && \ ./configure --with-compat $CONFARGS --add-dynamic-module=${HEADERS_MORE_MODULE} && \ make && make install -FROM nginx:stable-alpine3.17-slim +FROM nginx:1.27.2-alpine ENV NGINX_DIR /usr/share/nginx diff --git a/frontend/Dockerfile.local b/frontend/Dockerfile.local index 9d69c8c4..c2243ca5 100644 --- a/frontend/Dockerfile.local +++ b/frontend/Dockerfile.local @@ -10,11 +10,9 @@ COPY . . RUN npm run build -- --configuration production --output-hashing=none -FROM nginx:stable-alpine as builder-modules - -# Ensure that the version of nginx of the builder image is compatible with the nginx version of the main image. -ENV NGINX_VERSION 1.24.0 +FROM nginx:1.27.2-alpine as builder-modules +ENV NGINX_VERSION 1.27.2 ENV MORE_HEADERS_VERSION=0.34 ENV MORE_HEADERS_GITREPO=openresty/headers-more-nginx-module @@ -44,7 +42,7 @@ RUN mkdir -p ${DOWNLOADS} && \ ./configure --with-compat $CONFARGS --add-dynamic-module=${HEADERS_MORE_MODULE} && \ make && make install -FROM nginx:stable-alpine3.17-slim +FROM nginx:1.27.2-alpine ENV NGINX_DIR /usr/share/nginx diff --git a/server/StrDss.Api/Controllers/OrganizationsController.cs b/server/StrDss.Api/Controllers/OrganizationsController.cs index 1a513cec..24708fe8 100644 --- a/server/StrDss.Api/Controllers/OrganizationsController.cs +++ b/server/StrDss.Api/Controllers/OrganizationsController.cs @@ -220,5 +220,19 @@ public async Task UpdateLocalGov(LocalGovUpdateDto dto, long id) return Ok(); } + + [ApiAuthorize(Permissions.JurisdictionRead)] + [HttpGet("localgovs/jurisdictions/{id}")] + public async Task> GetJurisdiction(long id) + { + var jurisdiction = await _orgService.GetJurisdiction(id); + + if (jurisdiction == null) + { + return NotFound(); + } + + return Ok(jurisdiction); + } } } diff --git a/server/StrDss.Common/Constants.cs b/server/StrDss.Common/Constants.cs index 9a38390f..11750742 100644 --- a/server/StrDss.Common/Constants.cs +++ b/server/StrDss.Common/Constants.cs @@ -14,6 +14,7 @@ public static class Entities public const string BizLicenceRowUntyped = "BizLicenceRowUntyped"; public const string Platform = "Platform"; public const string LocalGov = "LocalGov"; + public const string Jurisdiction = "Jurisdiction"; } public static class Fields { @@ -109,7 +110,6 @@ public static class BizLicenceRowFields public static class PlatformFields { - public const string OrganizationId = "OrganizationId"; public const string OrganizationCd = "OrganizationCd"; public const string OrganizationNm = "OrganizationNm"; public const string PrimaryNoticeOfTakedownContactEmail = "PrimaryNoticeOfTakedownContactEmail"; @@ -121,13 +121,21 @@ public static class PlatformFields public static class LocalGovFields { - public const string OrganizationId = "OrganizationId"; public const string OrganizationCd = "OrganizationCd"; public const string OrganizationNm = "OrganizationNm"; public const string LocalGovernmentType = "LocalGovernmentType"; public const string BusinessLicenceFormatTxt = "BusinessLicenceFormatTxt"; } + public static class JurisdictionFields + { + public const string ManagingOrganizationId = "ManagingOrganizationId"; + public const string IsPrincipalResidenceRequired = "IsPrincipalResidenceRequired"; + public const string IsStrProhibited = "IsStrProhibited"; + public const string IsBusinessLicenceRequired = "IsBusinessLicenceRequired"; + public const string EconomicRegionDsc = "EconomicRegionDsc"; + } + public static class CsvCols { public const string MostRecentPlatformReportMonth = "Most Recent Platform Report Month"; @@ -409,13 +417,15 @@ public static class FieldTypes public const string String = "S"; public const string Decimal = "N"; public const string Date = "D"; + public const string Bool = "B"; } public static class CodeSet { public const string LicenceStatus = "Licence Status"; public const string PlatformTypes = "Platform Types"; - public const string LocalGovTypes = "Local Gov Types"; + public const string LocalGovTypes = "Local Government Types"; + public const string EconomicRegions = "Economic Regions"; } public static class StrDssIdProviders diff --git a/server/StrDss.Data/Mappings/ModelToEntityProfile.cs b/server/StrDss.Data/Mappings/ModelToEntityProfile.cs index 0ddffa8f..d19d883a 100644 --- a/server/StrDss.Data/Mappings/ModelToEntityProfile.cs +++ b/server/StrDss.Data/Mappings/ModelToEntityProfile.cs @@ -35,6 +35,7 @@ public ModelToEntityProfile() CreateMap(); CreateMap(); CreateMap(); + CreateMap(); } } } diff --git a/server/StrDss.Data/Repositories/CodeSetRepository.cs b/server/StrDss.Data/Repositories/CodeSetRepository.cs index b249430b..d5fc4bb3 100644 --- a/server/StrDss.Data/Repositories/CodeSetRepository.cs +++ b/server/StrDss.Data/Repositories/CodeSetRepository.cs @@ -57,6 +57,17 @@ public async Task> LoadCodeSetAsync() }).ToListAsync() ); + commonCodes.AddRange(await + _dbContext.DssEconomicRegions + .AsNoTracking() + .Select(x => new CommonCodeDto + { + CodeSet = CodeSet.EconomicRegions, + CodeName = x.EconomicRegionDsc, + CodeValue = x.EconomicRegionNm + }).ToListAsync() + ); + return commonCodes; } } diff --git a/server/StrDss.Data/Repositories/OrganizationRepository.cs b/server/StrDss.Data/Repositories/OrganizationRepository.cs index 6622d76c..6ec4faf3 100644 --- a/server/StrDss.Data/Repositories/OrganizationRepository.cs +++ b/server/StrDss.Data/Repositories/OrganizationRepository.cs @@ -35,6 +35,8 @@ public interface IOrganizationRepository Task> GetLocalGovs(int pageSize, int pageNumber, string orderBy, string direction); Task UpdateLocalGovAsync(LocalGovUpdateDto dto); Task GetLocalGov(long id); + Task GetJurisdiction(long id); + Task UpdateJurisdictionAsync(JurisdictionUpdateDto dto); } public class OrganizationRepository : RepositoryBase, IOrganizationRepository { @@ -343,9 +345,26 @@ public async Task UpdateLocalGovAsync(LocalGovUpdateDto dto) public async Task GetLocalGov(long id) { - var localGov = _mapper.Map(await _dbContext.DssLocalGovVws.AsNoTracking().FirstOrDefaultAsync(x => x.OrganizationId == id)); + var localGov = _mapper.Map + (await _dbContext.DssLocalGovVws.AsNoTracking().FirstOrDefaultAsync(x => x.OrganizationId == id)); return localGov; } + + public async Task GetJurisdiction(long id) + { + var jurisdiction = _mapper.Map + (await _dbSet.AsNoTracking().FirstOrDefaultAsync(x => x.OrganizationType == OrganizationTypes.LGSub && x.OrganizationId == id)); + + return jurisdiction; + } + + public async Task UpdateJurisdictionAsync(JurisdictionUpdateDto dto) + { + var entity = await _dbSet + .FirstAsync(x => x.OrganizationId == dto.OrganizationId); + + _mapper.Map(dto, entity); + } } } diff --git a/server/StrDss.Model/OrganizationDtos/JurisdictionUpdateDto.cs b/server/StrDss.Model/OrganizationDtos/JurisdictionUpdateDto.cs new file mode 100644 index 00000000..afb302f7 --- /dev/null +++ b/server/StrDss.Model/OrganizationDtos/JurisdictionUpdateDto.cs @@ -0,0 +1,13 @@ +namespace StrDss.Model.OrganizationDtos +{ + public class JurisdictionUpdateDto + { + public long OrganizationId { get; set; } + public long? ManagingOrganizationId { get; set; } + public bool? IsPrincipalResidenceRequired { get; set; } + public bool? IsStrProhibited { get; set; } + public bool? IsBusinessLicenceRequired { get; set; } + public string? EconomicRegionDsc { get; set; } + public DateTime UpdDtm { get; set; } + } +} diff --git a/server/StrDss.Model/OrganizationDtos/JurisdictionsViewDto.cs b/server/StrDss.Model/OrganizationDtos/JurisdictionsViewDto.cs index b9bbe5df..17729b3d 100644 --- a/server/StrDss.Model/OrganizationDtos/JurisdictionsViewDto.cs +++ b/server/StrDss.Model/OrganizationDtos/JurisdictionsViewDto.cs @@ -8,10 +8,11 @@ public class JurisdictionsViewDto public string OrganizationNm { get; set; } = null!; [JsonPropertyName("shapeFileId")] public string OrganizationCd { get; set; } = null!; + public long? ManagingOrganizationId { get; set; } public bool? IsPrincipalResidenceRequired { get; set; } public bool? IsStrProhibited { get; set; } public bool? IsBusinessLicenceRequired { get; set; } public string? EconomicRegionDsc { get; set; } - public long? ManagingOrganizationId { get; set; } + public DateTime UpdDtm { get; set; } } } diff --git a/server/StrDss.Service/FieldValidatorService.cs b/server/StrDss.Service/FieldValidatorService.cs index 8fc300b2..3726a345 100644 --- a/server/StrDss.Service/FieldValidatorService.cs +++ b/server/StrDss.Service/FieldValidatorService.cs @@ -65,6 +65,9 @@ public Dictionary> Validate(string entityName, string fi case FieldTypes.Decimal: messages.AddRange(ValidateNumberField(rule, val)); break; + case FieldTypes.Bool: + messages.AddRange(ValidateBoolField(rule, val)); + break; default: throw new NotImplementedException($"Validation for {rule.FieldType} is not implemented."); } @@ -236,5 +239,34 @@ private List ValidateNumberField(FieldValidationRule rule, T val, int return messages; } + private List ValidateBoolField(FieldValidationRule rule, T val, int rowNum = 0) + { + var messages = new List(); + var rowNumPrefix = rowNum == 0 ? "" : $"Row # {rowNum}: "; + var field = rule.FieldName.WordToWords(); + + if (rule.Required && val is null) + { + messages.Add($"{rowNumPrefix}{field} field is required."); + return messages; + } + + if (!rule.Required && (val is null || val!.ToString()!.IsEmpty())) + return messages; + + bool boolVal; + if (val is bool boolValue) + { + boolVal = boolValue; + } + else + { + messages.Add($"{rowNumPrefix}{field} field must be a boolean value (true or false)."); + return messages; + } + + return messages; + } + } } \ No newline at end of file diff --git a/server/StrDss.Service/JurisdictionValidationRules.cs b/server/StrDss.Service/JurisdictionValidationRules.cs new file mode 100644 index 00000000..af6856a0 --- /dev/null +++ b/server/StrDss.Service/JurisdictionValidationRules.cs @@ -0,0 +1,43 @@ +using StrDss.Common; + +namespace StrDss.Service +{ + public class JurisdictionValidationRules + { + public static void LoadJurisdictionValidationRules(List rules) + { + rules.Add(new FieldValidationRule + { + EntityName = Entities.Jurisdiction, + FieldName = JurisdictionFields.IsPrincipalResidenceRequired, + FieldType = FieldTypes.Bool, + Required = true + }); + + rules.Add(new FieldValidationRule + { + EntityName = Entities.Jurisdiction, + FieldName = JurisdictionFields.IsStrProhibited, + FieldType = FieldTypes.Bool, + Required = true + }); + + rules.Add(new FieldValidationRule + { + EntityName = Entities.Jurisdiction, + FieldName = JurisdictionFields.IsBusinessLicenceRequired, + FieldType = FieldTypes.Bool, + Required = true + }); + + rules.Add(new FieldValidationRule + { + EntityName = Entities.Jurisdiction, + FieldName = JurisdictionFields.EconomicRegionDsc, + FieldType = FieldTypes.String, + Required = false, + CodeSet = CodeSet.EconomicRegions, + }); + } + } +} diff --git a/server/StrDss.Service/OrganizationService.cs b/server/StrDss.Service/OrganizationService.cs index 944142e6..03b992cd 100644 --- a/server/StrDss.Service/OrganizationService.cs +++ b/server/StrDss.Service/OrganizationService.cs @@ -30,6 +30,7 @@ public interface IOrganizationService Task> GetLocalGovs(int pageSize, int pageNumber, string orderBy, string direction); Task GetLocalGov(long id); Task>> UpdateLocalGovAsync(LocalGovUpdateDto dto); + Task GetJurisdiction(long id); } public class OrganizationService : ServiceBase, IOrganizationService { @@ -295,5 +296,10 @@ private async Task>> ValidateLocalGovUpdateDto(L return errors; } + + public async Task GetJurisdiction(long id) + { + return await _orgRepo.GetJurisdiction(id); + } } }