Skip to content

Commit e960e95

Browse files
authored
Merge pull request #543 from bcgov/yj
feat: business license uplaod
2 parents 226db52 + 1cd4300 commit e960e95

18 files changed

+972
-73
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using Asp.Versioning;
2+
using AutoMapper;
3+
using Microsoft.AspNetCore.Mvc;
4+
using StrDss.Api.Authorization;
5+
using StrDss.Api.Models;
6+
using StrDss.Common;
7+
using StrDss.Model;
8+
using StrDss.Service;
9+
10+
namespace StrDss.Api.Controllers
11+
{
12+
[ApiVersion("1.0")]
13+
[Route("api/[controller]")]
14+
[ApiController]
15+
public class BizLicensesController : BaseApiController
16+
{
17+
private IUploadDeliveryService _uploadService;
18+
private IBizLicenseService _bizLicenseService;
19+
20+
public BizLicensesController(ICurrentUser currentUser, IMapper mapper, IConfiguration config, ILogger<StrDssLogger> logger,
21+
IUploadDeliveryService uploadService, IBizLicenseService bizLicenseService)
22+
: base(currentUser, mapper, config, logger)
23+
{
24+
_uploadService = uploadService;
25+
_bizLicenseService = bizLicenseService;
26+
}
27+
28+
[ApiAuthorize(Permissions.LicenceFileUpload)]
29+
[HttpPost]
30+
public async Task<ActionResult> UploadBizLicenses([FromForm] PlatformDataUploadDto dto)
31+
{
32+
Dictionary<string, List<string>> errors = new Dictionary<string, List<string>>();
33+
34+
if (dto.File == null || dto.File.Length == 0)
35+
{
36+
errors.AddItem("File", $"File is null or empty.");
37+
return ValidationUtils.GetValidationErrorResult(errors, ControllerContext);
38+
}
39+
40+
var maxSizeInMb = _config.GetValue<int>("RENTAL_LISTING_REPORT_MAX_SIZE");
41+
var maxSizeInB = (maxSizeInMb == 0 ? 2 : maxSizeInMb) * 1024 * 1024;
42+
43+
if (dto.File.Length > maxSizeInB)
44+
{
45+
errors.AddItem("File", $"The file size exceeds the maximum size {maxSizeInMb}MB.");
46+
return ValidationUtils.GetValidationErrorResult(errors, ControllerContext);
47+
}
48+
49+
if (!CommonUtils.IsTextFile(dto.File.ContentType))
50+
{
51+
errors.AddItem("File", $"Uploaded file is not a text file.");
52+
return ValidationUtils.GetValidationErrorResult(errors, ControllerContext);
53+
}
54+
55+
using var stream = dto.File.OpenReadStream();
56+
57+
errors = await _uploadService.UploadPlatformData(UploadDeliveryTypes.LicenseData, dto.ReportPeriod, dto.OrganizationId, stream);
58+
59+
if (errors.Count > 0)
60+
{
61+
return ValidationUtils.GetValidationErrorResult(errors, ControllerContext, "One or more validation errors occurred in uploaded file.");
62+
}
63+
64+
return Ok();
65+
}
66+
}
67+
}

server/StrDss.Common/Constants.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public static class Entities
1111
{
1212
public const string RentalListingRowUntyped = "RentalListingRowUntyped";
1313
public const string Role = "Role";
14+
public const string BizLicenseRowUntyped = "BizLicenseRowUntyped";
1415

1516
}
1617
public static class Fields
@@ -83,6 +84,40 @@ public static class RentalListingReportFields
8384
public const string SupplierHost5Id = "SupplierHost5Id";
8485
}
8586

87+
public static class BizLicenseRowFields
88+
{
89+
public const string OrgCd = "OrgCd";
90+
public const string BusinessLicenceNo = "BusinessLicenceNo";
91+
public const string ExpiryDt = "ExpiryDt";
92+
public const string PhysicalRentalAddressTxt = "PhysicalRentalAddressTxt";
93+
public const string LicenceStatusType = "LicenceStatusType";
94+
public const string LicenceTypeTxt = "LicenceTypeTxt";
95+
public const string RestrictionTxt = "RestrictionTxt";
96+
public const string BusinessNm = "BusinessNm";
97+
public const string MailingStreetAddressTxt = "MailingStreetAddressTxt";
98+
public const string MailingCityNm = "MailingCityNm";
99+
public const string MailingProvinceCd = "MailingProvinceCd";
100+
public const string MailingPostalCd = "MailingPostalCd";
101+
public const string BusinessOwnerNm = "BusinessOwnerNm";
102+
public const string BusinessOwnerPhoneNo = "BusinessOwnerPhoneNo";
103+
public const string BusinessOwnerEmailAddressDsc = "BusinessOwnerEmailAddressDsc";
104+
public const string BusinessOperatorNm = "BusinessOperatorNm";
105+
public const string BusinessOperatorPhoneNo = "BusinessOperatorPhoneNo";
106+
public const string BusinessOperatorEmailAddressDsc = "BusinessOperatorEmailAddressDsc";
107+
public const string InfractionTxt = "InfractionTxt";
108+
public const string InfractionDt = "InfractionDt";
109+
public const string PropertyZoneTxt = "PropertyZoneTxt";
110+
public const string AvailableBedroomsQty = "AvailableBedroomsQty";
111+
public const string MaxGuestsAllowedQty = "MaxGuestsAllowedQty";
112+
public const string IsPrincipalResidence = "IsPrincipalResidence";
113+
public const string IsOwnerLivingOnsite = "IsOwnerLivingOnsite";
114+
public const string IsOwnerPropertyTenant = "IsOwnerPropertyTenant";
115+
public const string PropertyFolioNo = "PropertyFolioNo";
116+
public const string PropertyParcelIdentifierNo = "PropertyParcelIdentifierNo";
117+
public const string PropertyLegalDescriptionTxt = "PropertyLegalDescriptionTxt";
118+
}
119+
120+
86121
public static class RentalListingExport
87122
{
88123
public static readonly string[] Headers = new string[]
@@ -316,6 +351,7 @@ public static class UploadDeliveryTypes
316351
{
317352
public const string ListingData = "Listing Data";
318353
public const string TakedownData = "Takedown Data";
354+
public const string LicenseData = "License Data";
319355
}
320356

321357
public static class ListingExportFileNames

server/StrDss.Common/RegexInfo.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public static class RegexDefs
2727
public const string PhoneNumber = "PhoneNumber";
2828
public const string Url = "Url";
2929
public const string YearMonth = "YearMonth";
30+
public const string YearMonthDay = "YearMonthDay";
3031

3132
private static readonly Dictionary<string, RegexInfo> _regexInfos;
3233

@@ -69,6 +70,12 @@ static RegexDefs()
6970
Regex = @"^\d{4}-(0[1-9]|1[0-2])$",
7071
ErrorMessage = "Invalid year-month format. Please use the yyyy-MM format (e.g., 2024-05)."
7172
});
73+
74+
_regexInfos.Add(YearMonthDay, new RegexInfo
75+
{
76+
Regex = @"^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$",
77+
ErrorMessage = "Invalid year-month-day format. Please use the yyyy-MM-dd format (e.g., 2024-05-01)."
78+
});
7279
}
7380

7481
public static RegexInfo GetRegexInfo(string name)
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace StrDss.Data.Entities;
5+
6+
public partial class DssBusinessLicence
7+
{
8+
/// <summary>
9+
/// Unique generated key
10+
/// </summary>
11+
public long BusinessLicenceId { get; set; }
12+
13+
/// <summary>
14+
/// The local government issued licence number that applies to the rental offering
15+
/// </summary>
16+
public string BusinessLicenceNo { get; set; } = null!;
17+
18+
/// <summary>
19+
/// The date on which the business licence expires
20+
/// </summary>
21+
public DateOnly ExpiryDt { get; set; }
22+
23+
/// <summary>
24+
/// The full physical address of the location that is licenced as a short-term rental business
25+
/// </summary>
26+
public string? PhysicalRentalAddressTxt { get; set; }
27+
28+
/// <summary>
29+
/// Free form description of the type of business licence issued (e.g. short-term rental, bed and breakfast, boarding and lodging, tourist accommodation)
30+
/// </summary>
31+
public string? LicenceTypeTxt { get; set; }
32+
33+
/// <summary>
34+
/// Notes related to any restrictions associated with the licence
35+
/// </summary>
36+
public string? RestrictionTxt { get; set; }
37+
38+
/// <summary>
39+
/// Official name of the business
40+
/// </summary>
41+
public string? BusinessNm { get; set; }
42+
43+
/// <summary>
44+
/// Street address component of the business mailing address
45+
/// </summary>
46+
public string? MailingStreetAddressTxt { get; set; }
47+
48+
/// <summary>
49+
/// City component of the business mailing address
50+
/// </summary>
51+
public string? MailingCityNm { get; set; }
52+
53+
/// <summary>
54+
/// Province component of the business mailing address
55+
/// </summary>
56+
public string? MailingProvinceCd { get; set; }
57+
58+
/// <summary>
59+
/// Postal code component of the business mailing address
60+
/// </summary>
61+
public string? MailingPostalCd { get; set; }
62+
63+
/// <summary>
64+
/// Full name of the registered business owner
65+
/// </summary>
66+
public string? BusinessOwnerNm { get; set; }
67+
68+
/// <summary>
69+
/// Phone number of the business owner
70+
/// </summary>
71+
public string? BusinessOwnerPhoneNo { get; set; }
72+
73+
/// <summary>
74+
/// Email address of the business owner
75+
/// </summary>
76+
public string? BusinessOwnerEmailAddressDsc { get; set; }
77+
78+
/// <summary>
79+
/// Full name of the business operator or property manager
80+
/// </summary>
81+
public string? BusinessOperatorNm { get; set; }
82+
83+
/// <summary>
84+
/// Phone number of the business operator
85+
/// </summary>
86+
public string? BusinessOperatorPhoneNo { get; set; }
87+
88+
/// <summary>
89+
/// Email address of the business operator
90+
/// </summary>
91+
public string? BusinessOperatorEmailAddressDsc { get; set; }
92+
93+
/// <summary>
94+
/// Description of an infraction
95+
/// </summary>
96+
public string? InfractionTxt { get; set; }
97+
98+
/// <summary>
99+
/// The date on which the described infraction occurred
100+
/// </summary>
101+
public DateOnly? InfractionDt { get; set; }
102+
103+
/// <summary>
104+
/// Description or name of the property zoning
105+
/// </summary>
106+
public string? PropertyZoneTxt { get; set; }
107+
108+
/// <summary>
109+
/// The number of bedrooms in the dwelling unit that are available for short term rental
110+
/// </summary>
111+
public short? AvailableBedroomsQty { get; set; }
112+
113+
/// <summary>
114+
/// The number of guests that can be accommodated
115+
/// </summary>
116+
public short? MaxGuestsAllowedQty { get; set; }
117+
118+
/// <summary>
119+
/// Indicates whether the short term rental property is a principal residence
120+
/// </summary>
121+
public bool? IsPrincipalResidence { get; set; }
122+
123+
/// <summary>
124+
/// Indicates whether the owner lives on the property
125+
/// </summary>
126+
public bool? IsOwnerLivingOnsite { get; set; }
127+
128+
/// <summary>
129+
/// Indicates whether the business owner rents the property
130+
/// </summary>
131+
public bool? IsOwnerPropertyTenant { get; set; }
132+
133+
/// <summary>
134+
/// The number used to identify the property
135+
/// </summary>
136+
public string? PropertyFolioNo { get; set; }
137+
138+
/// <summary>
139+
/// The PID number assigned by the Land Title and Survey Authority that identifies the piece of land
140+
/// </summary>
141+
public string? PropertyParcelIdentifierNo { get; set; }
142+
143+
/// <summary>
144+
/// The physical description of the property as it is registered with the Land Title and Survey Authority
145+
/// </summary>
146+
public string? PropertyLegalDescriptionTxt { get; set; }
147+
148+
/// <summary>
149+
/// Foreign key
150+
/// </summary>
151+
public string LicenceStatusType { get; set; } = null!;
152+
153+
/// <summary>
154+
/// Foreign key
155+
/// </summary>
156+
public long ProvidingOrganizationId { get; set; }
157+
158+
/// <summary>
159+
/// Foreign key
160+
/// </summary>
161+
public long? AffectedByPhysicalAddressId { get; set; }
162+
163+
/// <summary>
164+
/// Trigger-updated timestamp of last change
165+
/// </summary>
166+
public DateTime UpdDtm { get; set; }
167+
168+
/// <summary>
169+
/// The globally unique identifier (assigned by the identity provider) for the most recent user to record a change
170+
/// </summary>
171+
public Guid? UpdUserGuid { get; set; }
172+
173+
public virtual DssPhysicalAddress? AffectedByPhysicalAddress { get; set; }
174+
175+
public virtual ICollection<DssRentalListing> DssRentalListings { get; set; } = new List<DssRentalListing>();
176+
177+
public virtual DssBusinessLicenceStatusType LicenceStatusTypeNavigation { get; set; } = null!;
178+
179+
public virtual DssOrganization ProvidingOrganization { get; set; } = null!;
180+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace StrDss.Data.Entities;
5+
6+
/// <summary>
7+
/// A potential status for a BUSINESS LICENCE (e.g. Pending, Issued, Suspended, Revoked, Cancelled, Expired)
8+
/// </summary>
9+
public partial class DssBusinessLicenceStatusType
10+
{
11+
/// <summary>
12+
/// System-consistent code for the business licence status (e.g. Pending, Issued, Suspended, Revoked, Cancelled, Expired)
13+
/// </summary>
14+
public string LicenceStatusType { get; set; } = null!;
15+
16+
/// <summary>
17+
/// Business term for the licence status (e.g. Pending, Issued, Suspended, Revoked, Cancelled, Expired)
18+
/// </summary>
19+
public string LicenceStatusTypeNm { get; set; } = null!;
20+
21+
/// <summary>
22+
/// Relative order in which the business prefers to see the status listed
23+
/// </summary>
24+
public short LicenceStatusSortNo { get; set; }
25+
26+
public virtual ICollection<DssBusinessLicence> DssBusinessLicences { get; set; } = new List<DssBusinessLicence>();
27+
}

0 commit comments

Comments
 (0)