Skip to content

Commit f70c267

Browse files
committed
RE1-T114 PR#332 fixes
1 parent 76fcd11 commit f70c267

36 files changed

Lines changed: 424 additions & 75 deletions

Core/Resgrid.Config/MappingConfig.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public static ResolvedMapConfig GetMapConfig(string key)
8282

8383
if (mapProvider == MapboxMapProvider)
8484
{
85-
var mapboxAccessToken = GetSystemMapboxAccessToken(surfaceKey);
85+
var mapboxAccessToken = NormalizePublicMapboxAccessToken(GetSystemMapboxAccessToken(surfaceKey));
8686

8787
if (TryCreateMapboxConfig(MapBoxStyleUrl, mapboxAccessToken, false, out var mapboxConfig))
8888
return mapboxConfig;
@@ -115,8 +115,9 @@ public static ResolvedMapConfig GetMapConfig(string key)
115115
public static bool TryCreateMapboxConfig(string styleUrl, string accessToken, bool isDepartmentOverride, out ResolvedMapConfig mapConfig)
116116
{
117117
mapConfig = null;
118+
var publicAccessToken = NormalizePublicMapboxAccessToken(accessToken);
118119

119-
if (string.IsNullOrWhiteSpace(styleUrl) || string.IsNullOrWhiteSpace(accessToken))
120+
if (string.IsNullOrWhiteSpace(styleUrl) || string.IsNullOrWhiteSpace(publicAccessToken))
120121
return false;
121122

122123
var styleId = GetMapboxStyleId(styleUrl);
@@ -127,9 +128,9 @@ public static bool TryCreateMapboxConfig(string styleUrl, string accessToken, bo
127128
mapConfig = new ResolvedMapConfig
128129
{
129130
MapProvider = MapboxMapProvider,
130-
TileUrl = $"https://api.mapbox.com/styles/v1/{styleId}/tiles/256/{{z}}/{{x}}/{{y}}@2x?access_token={accessToken}",
131+
TileUrl = $"https://api.mapbox.com/styles/v1/{styleId}/tiles/256/{{z}}/{{x}}/{{y}}@2x?access_token={publicAccessToken}",
131132
StyleUrl = NormalizeMapboxStyleUrl(styleUrl, styleId),
132-
AccessToken = accessToken,
133+
AccessToken = publicAccessToken,
133134
Attribution = MapBoxAttribution,
134135
IsDepartmentOverride = isDepartmentOverride
135136
};
@@ -294,6 +295,18 @@ private static string NormalizeMapboxStyleUrl(string styleUrl, string styleId)
294295
return $"mapbox://styles/{styleId}";
295296
}
296297

298+
private static string NormalizePublicMapboxAccessToken(string accessToken)
299+
{
300+
if (string.IsNullOrWhiteSpace(accessToken))
301+
return string.Empty;
302+
303+
var trimmedAccessToken = accessToken.Trim();
304+
305+
return trimmedAccessToken.StartsWith("pk.", StringComparison.Ordinal)
306+
? trimmedAccessToken
307+
: string.Empty;
308+
}
309+
297310
private static string GetMapboxStyleId(string styleUrl)
298311
{
299312
if (string.IsNullOrWhiteSpace(styleUrl))

Core/Resgrid.Model/UserProfile.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ public class UserProfile: IEntity
178178
[ProtoMember(48)]
179179
public string CalendarSyncToken { get; set; }
180180

181+
[ProtoMember(49)]
182+
public bool MobileVerificationVoiceCodeConsumed { get; set; }
183+
184+
[ProtoMember(50)]
185+
public bool HomeVerificationVoiceCodeConsumed { get; set; }
186+
181187
[NotMapped]
182188
[JsonIgnore]
183189
public object IdValue

Core/Resgrid.Services/ContactVerificationService.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public async Task<bool> SendMobileVerificationCodeAsync(string userId, int depar
8686
string code = GenerateCode();
8787
profile.MobileVerificationCode = _encryptionService.Encrypt(code);
8888
profile.MobileVerificationCodeExpiry = DateTime.UtcNow.AddMinutes(Config.VerificationConfig.VerificationCodeExpiryMinutes);
89+
profile.MobileVerificationVoiceCodeConsumed = false;
8990

9091
await _userProfileService.SaveProfileAsync(departmentId, profile, cancellationToken);
9192

@@ -108,6 +109,7 @@ public async Task<bool> SendHomeVerificationCodeAsync(string userId, int departm
108109
string code = GenerateCode();
109110
profile.HomeVerificationCode = _encryptionService.Encrypt(code);
110111
profile.HomeVerificationCodeExpiry = DateTime.UtcNow.AddMinutes(Config.VerificationConfig.VerificationCodeExpiryMinutes);
112+
profile.HomeVerificationVoiceCodeConsumed = false;
111113

112114
await _userProfileService.SaveProfileAsync(departmentId, profile, cancellationToken);
113115

@@ -270,6 +272,7 @@ public Task ResetVerificationForChangedContactAsync(UserProfile existingProfile,
270272
updatedProfile.MobileNumberVerified = false;
271273
updatedProfile.MobileVerificationCode = null;
272274
updatedProfile.MobileVerificationCodeExpiry = null;
275+
updatedProfile.MobileVerificationVoiceCodeConsumed = false;
273276
updatedProfile.MobileVerificationAttempts = 0;
274277
updatedProfile.MobileVerificationAttemptsResetDate = null;
275278
}
@@ -279,6 +282,7 @@ public Task ResetVerificationForChangedContactAsync(UserProfile existingProfile,
279282
updatedProfile.HomeNumberVerified = false;
280283
updatedProfile.HomeVerificationCode = null;
281284
updatedProfile.HomeVerificationCodeExpiry = null;
285+
updatedProfile.HomeVerificationVoiceCodeConsumed = false;
282286
updatedProfile.HomeVerificationAttempts = 0;
283287
updatedProfile.HomeVerificationAttemptsResetDate = null;
284288
}

Core/Resgrid.Services/UserProfileService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public async Task<Dictionary<string, UserProfile>> GetAllProfilesForDepartmentIn
9393
profile.MobileNumberVerified = false;
9494
profile.MobileVerificationCode = null;
9595
profile.MobileVerificationCodeExpiry = null;
96+
profile.MobileVerificationVoiceCodeConsumed = false;
9697
profile.MobileVerificationAttempts = 0;
9798
profile.MobileVerificationAttemptsResetDate = null;
9899
}
@@ -101,6 +102,7 @@ public async Task<Dictionary<string, UserProfile>> GetAllProfilesForDepartmentIn
101102
profile.HomeNumberVerified = false;
102103
profile.HomeVerificationCode = null;
103104
profile.HomeVerificationCodeExpiry = null;
105+
profile.HomeVerificationVoiceCodeConsumed = false;
104106
profile.HomeVerificationAttempts = 0;
105107
profile.HomeVerificationAttemptsResetDate = null;
106108
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using FluentMigrator;
2+
3+
namespace Resgrid.Providers.Migrations.Migrations
4+
{
5+
[Migration(48)]
6+
public class M0048_AddingVoiceVerificationConsumptionFlags : Migration
7+
{
8+
public override void Up()
9+
{
10+
Alter.Table("UserProfiles")
11+
.AddColumn("MobileVerificationVoiceCodeConsumed").AsBoolean().NotNullable().WithDefaultValue(false)
12+
.AddColumn("HomeVerificationVoiceCodeConsumed").AsBoolean().NotNullable().WithDefaultValue(false);
13+
}
14+
15+
public override void Down()
16+
{
17+
Delete.Column("MobileVerificationVoiceCodeConsumed").FromTable("UserProfiles");
18+
Delete.Column("HomeVerificationVoiceCodeConsumed").FromTable("UserProfiles");
19+
}
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using FluentMigrator;
2+
3+
namespace Resgrid.Providers.MigrationsPg.Migrations
4+
{
5+
[Migration(48)]
6+
public class M0048_AddingVoiceVerificationConsumptionFlagsPg : Migration
7+
{
8+
public override void Up()
9+
{
10+
Alter.Table("UserProfiles".ToLower())
11+
.AddColumn("MobileVerificationVoiceCodeConsumed".ToLower()).AsBoolean().NotNullable().WithDefaultValue(false)
12+
.AddColumn("HomeVerificationVoiceCodeConsumed".ToLower()).AsBoolean().NotNullable().WithDefaultValue(false);
13+
}
14+
15+
public override void Down()
16+
{
17+
Delete.Column("MobileVerificationVoiceCodeConsumed".ToLower()).FromTable("UserProfiles".ToLower());
18+
Delete.Column("HomeVerificationVoiceCodeConsumed".ToLower()).FromTable("UserProfiles".ToLower());
19+
}
20+
}
21+
}

Tests/Resgrid.Tests/Resgrid.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
<ProjectReference Include="..\..\Providers\Resgrid.Providers.Messaging\Resgrid.Providers.Messaging.csproj" />
5555
<ProjectReference Include="..\..\Repositories\Resgrid.Repositories.DataRepository\Resgrid.Repositories.DataRepository.csproj" />
5656
<ProjectReference Include="..\..\Repositories\Resgrid.Repositories.NoSqlRepository\Resgrid.Repositories.NoSqlRepository.csproj" />
57+
<ProjectReference Include="..\..\Web\Resgrid.Web.Services\Resgrid.Web.Services.csproj" />
5758
<ProjectReference Include="..\..\Web\Resgrid.Web.Mcp\Resgrid.Web.Mcp.csproj" />
5859
<ProjectReference Include="..\..\Workers\Resgrid.Workers.Framework\Resgrid.Workers.Framework.csproj" />
5960
<ProjectReference Include="..\..\Providers\Resgrid.Providers.Workflow\Resgrid.Providers.Workflow.csproj" />

Tests/Resgrid.Tests/Services/ContactVerificationServiceTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,32 @@ public async Task should_generate_code_and_send_email()
112112
}
113113
}
114114

115+
[TestFixture]
116+
public class when_sending_phone_verification : with_the_contact_verification_service
117+
{
118+
[Test]
119+
public async Task should_reset_home_voice_consumption_when_sending_a_new_home_code()
120+
{
121+
var profile = BuildProfile();
122+
profile.HomeVerificationVoiceCodeConsumed = true;
123+
UserProfile savedProfile = null;
124+
125+
_userProfileServiceMock
126+
.Setup(s => s.GetProfileByUserIdAsync("user1", true))
127+
.ReturnsAsync(profile);
128+
_userProfileServiceMock
129+
.Setup(s => s.SaveProfileAsync(It.IsAny<int>(), It.IsAny<UserProfile>(), It.IsAny<CancellationToken>()))
130+
.Callback<int, UserProfile, CancellationToken>((_, p, _) => savedProfile = p)
131+
.ReturnsAsync(profile);
132+
133+
var result = await _contactVerificationService.SendHomeVerificationCodeAsync("user1", 1, "15555550123");
134+
135+
result.Should().BeTrue();
136+
savedProfile.Should().NotBeNull();
137+
savedProfile!.HomeVerificationVoiceCodeConsumed.Should().BeFalse();
138+
}
139+
}
140+
115141
[TestFixture]
116142
public class when_confirming_verification_code : with_the_contact_verification_service
117143
{
@@ -238,6 +264,7 @@ public async Task should_reset_mobile_verification_when_number_changes()
238264

239265
updated.MobileNumberVerified.Should().BeFalse();
240266
updated.MobileVerificationCode.Should().BeNull();
267+
updated.MobileVerificationVoiceCodeConsumed.Should().BeFalse();
241268
updated.MobileVerificationAttempts.Should().Be(0);
242269
}
243270

@@ -273,6 +300,23 @@ public async Task should_reset_email_verification_when_email_changes()
273300
updated.EmailVerified.Should().BeFalse();
274301
updated.EmailVerificationCode.Should().BeNull();
275302
}
303+
304+
[Test]
305+
public async Task should_reset_home_voice_consumption_when_number_changes()
306+
{
307+
var existing = BuildProfile();
308+
existing.HomeNumber = "5551112222";
309+
existing.HomeVerificationVoiceCodeConsumed = true;
310+
311+
var updated = BuildProfile();
312+
updated.HomeNumber = "5553334444";
313+
updated.HomeVerificationVoiceCodeConsumed = true;
314+
315+
await _contactVerificationService.ResetVerificationForChangedContactAsync(existing, updated);
316+
317+
updated.HomeVerificationVoiceCodeConsumed.Should().BeFalse();
318+
updated.HomeVerificationCode.Should().BeNull();
319+
}
276320
}
277321

278322
[TestFixture]

Tests/Resgrid.Tests/Services/DepartmentSettingsServiceMapConfigTests.cs

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ public async Task should_fall_back_to_leaflet_system_config_when_override_disabl
131131
public async Task should_fall_back_to_mapbox_system_config_when_website_mode_is_mapbox()
132132
{
133133
MappingConfig.WebsiteMapMode = MappingConfig.MapboxMapProvider;
134+
MappingConfig.WebsiteOSMKey = "pk.system-token";
134135

135136
_departmentSettingsRepository
136137
.Setup(x => x.GetDepartmentSettingByIdTypeAsync(7, DepartmentSettingTypes.MappingUseMapboxOverride))
@@ -140,7 +141,7 @@ public async Task should_fall_back_to_mapbox_system_config_when_website_mode_is_
140141

141142
result.IsDepartmentOverride.Should().BeFalse();
142143
result.MapProvider.Should().Be(MappingConfig.MapboxMapProvider);
143-
result.AccessToken.Should().Be("system-token");
144+
result.AccessToken.Should().Be("pk.system-token");
144145
result.StyleUrl.Should().Be("mapbox://styles/resgrid/abc123");
145146
}
146147

@@ -184,6 +185,7 @@ public async Task should_use_configured_mapbox_tile_url_when_style_url_is_missin
184185
{
185186
MappingConfig.WebsiteMapMode = MappingConfig.MapboxMapProvider;
186187
MappingConfig.MapBoxStyleUrl = string.Empty;
188+
MappingConfig.WebsiteOSMKey = "pk.system-token";
187189

188190
_departmentSettingsRepository
189191
.Setup(x => x.GetDepartmentSettingByIdTypeAsync(7, DepartmentSettingTypes.MappingUseMapboxOverride))
@@ -192,15 +194,16 @@ public async Task should_use_configured_mapbox_tile_url_when_style_url_is_missin
192194
var result = await _service.GetMapConfigForDepartmentAsync(7, InfoConfig.WebsiteKey);
193195

194196
result.MapProvider.Should().Be(MappingConfig.MapboxMapProvider);
195-
result.TileUrl.Should().Be("https://api.mapbox.com/styles/v1/resgrid/abc123/tiles/256/{z}/{x}/{y}?access_token=system-token");
197+
result.TileUrl.Should().Be("https://api.mapbox.com/styles/v1/resgrid/abc123/tiles/256/{z}/{x}/{y}?access_token=pk.system-token");
196198
result.StyleUrl.Should().BeEmpty();
197-
result.AccessToken.Should().Be("system-token");
199+
result.AccessToken.Should().Be("pk.system-token");
198200
}
199201

200202
[Test]
201203
public async Task should_fall_back_to_system_config_when_override_is_incomplete()
202204
{
203205
MappingConfig.WebsiteMapMode = MappingConfig.MapboxMapProvider;
206+
MappingConfig.WebsiteOSMKey = "pk.system-token";
204207

205208
_departmentSettingsRepository
206209
.Setup(x => x.GetDepartmentSettingByIdTypeAsync(7, DepartmentSettingTypes.MappingUseMapboxOverride))
@@ -215,8 +218,48 @@ public async Task should_fall_back_to_system_config_when_override_is_incomplete(
215218
var result = await _service.GetMapConfigForDepartmentAsync(7, InfoConfig.WebsiteKey);
216219

217220
result.IsDepartmentOverride.Should().BeFalse();
218-
result.AccessToken.Should().Be("system-token");
221+
result.AccessToken.Should().Be("pk.system-token");
219222
result.StyleUrl.Should().Be("mapbox://styles/resgrid/abc123");
220223
}
224+
225+
[Test]
226+
public async Task should_fall_back_to_leaflet_when_website_mapbox_access_token_is_private()
227+
{
228+
MappingConfig.WebsiteMapMode = MappingConfig.MapboxMapProvider;
229+
MappingConfig.WebsiteMapboxAccessToken = "sk.website-secret";
230+
MappingConfig.WebsiteOSMKey = string.Empty;
231+
232+
_departmentSettingsRepository
233+
.Setup(x => x.GetDepartmentSettingByIdTypeAsync(7, DepartmentSettingTypes.MappingUseMapboxOverride))
234+
.ReturnsAsync(new DepartmentSetting { DepartmentId = 7, Setting = "false", SettingType = (int)DepartmentSettingTypes.MappingUseMapboxOverride });
235+
236+
var result = await _service.GetMapConfigForDepartmentAsync(7, InfoConfig.WebsiteKey);
237+
238+
result.MapProvider.Should().Be(MappingConfig.LeafletMapProvider);
239+
result.AccessToken.Should().BeEmpty();
240+
result.StyleUrl.Should().BeEmpty();
241+
result.TileUrl.Should().NotContain("sk.website-secret");
242+
}
243+
244+
[Test]
245+
public async Task should_ignore_department_override_when_mapbox_access_token_is_private()
246+
{
247+
_departmentSettingsRepository
248+
.Setup(x => x.GetDepartmentSettingByIdTypeAsync(7, DepartmentSettingTypes.MappingUseMapboxOverride))
249+
.ReturnsAsync(new DepartmentSetting { DepartmentId = 7, Setting = "true", SettingType = (int)DepartmentSettingTypes.MappingUseMapboxOverride });
250+
_departmentSettingsRepository
251+
.Setup(x => x.GetDepartmentSettingByIdTypeAsync(7, DepartmentSettingTypes.MappingMapboxStyleUrl))
252+
.ReturnsAsync(new DepartmentSetting { DepartmentId = 7, Setting = "mapbox://styles/department/customstyle", SettingType = (int)DepartmentSettingTypes.MappingMapboxStyleUrl });
253+
_departmentSettingsRepository
254+
.Setup(x => x.GetDepartmentSettingByIdTypeAsync(7, DepartmentSettingTypes.MappingMapboxAccessToken))
255+
.ReturnsAsync(new DepartmentSetting { DepartmentId = 7, Setting = "sk.department-secret", SettingType = (int)DepartmentSettingTypes.MappingMapboxAccessToken });
256+
257+
var result = await _service.GetMapConfigForDepartmentAsync(7, InfoConfig.WebsiteKey);
258+
259+
result.IsDepartmentOverride.Should().BeFalse();
260+
result.MapProvider.Should().Be(MappingConfig.LeafletMapProvider);
261+
result.AccessToken.Should().BeEmpty();
262+
result.TileUrl.Should().NotContain("sk.department-secret");
263+
}
221264
}
222265
}

0 commit comments

Comments
 (0)