Skip to content

Commit 15a2627

Browse files
authored
SF-3333b Reduce calls to the DBL, PT, and RTS when configuring sources (#3187)
1 parent 5a0e932 commit 15a2627

2 files changed

Lines changed: 40 additions & 18 deletions

File tree

src/SIL.XForge.Scripture/Services/SFProjectService.cs

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,14 @@ public async Task<string> CreateProjectAsync(string curUserId, SFProjectCreateSe
157157
resources = await _paratextService.GetResourcesAsync(curUserId);
158158
}
159159

160+
// The project will be synced later, and permissions updated on that subsequent sync
160161
TranslateSource source = await GetTranslateSourceAsync(
162+
conn,
161163
curUserId,
162164
projectDoc.Id,
163165
settings.SourceParatextId,
164166
syncIfCreated: false,
167+
updatePermissions: false,
165168
ptProjects,
166169
resources
167170
);
@@ -222,6 +225,7 @@ public async Task<string> CreateResourceProjectAsync(string curUserId, string pa
222225
}
223226
}
224227

228+
await using IConnection conn = await RealtimeService.ConnectAsync(curUserId);
225229
if (addUser)
226230
{
227231
// See if the project exists to add the user to it
@@ -233,18 +237,18 @@ public async Task<string> CreateResourceProjectAsync(string curUserId, string pa
233237
// Add the user, if they are not already on the project
234238
if (!project.UserRoles.ContainsKey(curUserId))
235239
{
236-
await AddUserAsync(curUserId, project.Id, projectRole: null);
240+
await AddUserAsync(conn, curUserId, project.Id, projectRole: null);
237241
}
238242

239243
return project.Id;
240244
}
241245
}
242246

243247
// Create the project, as it does not already exist, and add the user if we should
244-
string projectId = await CreateResourceProjectInternalAsync(curUserId, ptProject);
248+
string projectId = await CreateResourceProjectInternalAsync(conn, ptProject);
245249
if (addUser)
246250
{
247-
await AddUserAsync(curUserId, projectId, projectRole: null);
251+
await AddUserAsync(conn, curUserId, projectId, projectRole: null);
248252
}
249253

250254
return projectId;
@@ -401,10 +405,12 @@ public async Task UpdateSettingsAsync(string curUserId, string projectId, SFProj
401405
if (settings.SourceParatextId != null && !unsetSourceProject)
402406
{
403407
source = await GetTranslateSourceAsync(
408+
conn,
404409
curUserId,
405410
projectId,
406411
settings.SourceParatextId,
407412
syncIfCreated: false,
413+
updatePermissions: true,
408414
ptProjects,
409415
resources,
410416
projectDoc.Data.UserRoles
@@ -421,10 +427,13 @@ public async Task UpdateSettingsAsync(string curUserId, string projectId, SFProj
421427
if (settings.AlternateSourceParatextId != null && !unsetAlternateSourceProject)
422428
{
423429
alternateSource = await GetTranslateSourceAsync(
430+
conn,
424431
curUserId,
425432
projectId,
426433
settings.AlternateSourceParatextId,
427434
syncIfCreated: true,
435+
// Only update permissions if this project is different to the preceding project
436+
updatePermissions: settings.SourceParatextId != settings.AlternateSourceParatextId,
428437
ptProjects,
429438
resources,
430439
projectDoc.Data.UserRoles
@@ -441,10 +450,14 @@ public async Task UpdateSettingsAsync(string curUserId, string projectId, SFProj
441450
if (settings.AlternateTrainingSourceParatextId != null && !unsetAlternateTrainingSourceProject)
442451
{
443452
alternateTrainingSource = await GetTranslateSourceAsync(
453+
conn,
444454
curUserId,
445455
projectId,
446456
settings.AlternateTrainingSourceParatextId,
447457
syncIfCreated: true,
458+
// Only update permissions if this project is different to the preceding projects
459+
updatePermissions: settings.SourceParatextId != settings.AlternateTrainingSourceParatextId
460+
&& settings.AlternateSourceParatextId != settings.AlternateTrainingSourceParatextId,
448461
ptProjects,
449462
resources,
450463
projectDoc.Data.UserRoles
@@ -461,10 +474,15 @@ public async Task UpdateSettingsAsync(string curUserId, string projectId, SFProj
461474
if (settings.AdditionalTrainingSourceParatextId != null && !unsetAdditionalTrainingSourceProject)
462475
{
463476
additionalTrainingSource = await GetTranslateSourceAsync(
477+
conn,
464478
curUserId,
465479
projectId,
466480
settings.AdditionalTrainingSourceParatextId,
467481
syncIfCreated: true,
482+
// Only update permissions if this project is different to the preceding projects
483+
updatePermissions: settings.SourceParatextId != settings.AdditionalTrainingSourceParatextId
484+
&& settings.AlternateSourceParatextId != settings.AdditionalTrainingSourceParatextId
485+
&& settings.AlternateTrainingSourceParatextId != settings.AdditionalTrainingSourceParatextId,
468486
ptProjects,
469487
resources,
470488
projectDoc.Data.UserRoles
@@ -1839,14 +1857,14 @@ private static void UpdateSetting<T>(
18391857
/// <summary>
18401858
/// Asynchronously creates a Scripture Forge project from Paratext resource/project.
18411859
/// </summary>
1842-
/// <param name="curUserId">The current user identifier.</param>
1860+
/// <param name="conn">The connection to the realtime server.</param>
18431861
/// <param name="ptProject">The paratext project.</param>
18441862
/// <returns>SF project id of created project</returns>
18451863
/// <remarks>
18461864
/// This method will also work for a source project that has been deleted for some reason.
18471865
/// </remarks>
18481866
/// <exception cref="InvalidOperationException"></exception>
1849-
private async Task<string> CreateResourceProjectInternalAsync(string curUserId, ParatextProject ptProject)
1867+
private async Task<string> CreateResourceProjectInternalAsync(IConnection conn, ParatextProject ptProject)
18501868
{
18511869
var project = new SFProject
18521870
{
@@ -1866,7 +1884,6 @@ private async Task<string> CreateResourceProjectInternalAsync(string curUserId,
18661884

18671885
// Create the new project using the realtime service
18681886
string projectId = ObjectId.GenerateNewId().ToString();
1869-
await using IConnection conn = await RealtimeService.ConnectAsync(curUserId);
18701887
if (RealtimeService.QuerySnapshots<SFProject>().Any(sfProject => sfProject.ParatextId == project.ParatextId))
18711888
{
18721889
throw new InvalidOperationException(ErrorAlreadyConnectedKey);
@@ -1882,20 +1899,24 @@ private async Task<string> CreateResourceProjectInternalAsync(string curUserId,
18821899
/// <summary>
18831900
/// Gets the translation source asynchronously.
18841901
/// </summary>
1902+
/// <param name="conn">The connection to the realtime server.</param>
18851903
/// <param name="curUserId">The current user identifier.</param>
18861904
/// <param name="sfProjectId">The Scripture Forge project identifier.</param>
18871905
/// <param name="paratextId">The paratext identifier.</param>
18881906
/// <param name="syncIfCreated">If <c>true</c> sync the project if it is created.</param>
1907+
/// <param name="updatePermissions">If <c>true</c> update the project's permissions.</param>
18891908
/// <param name="ptProjects">The paratext projects.</param>
18901909
/// <param name="resources">The paratext resources.</param>
18911910
/// <param name="userRoles">The ids and roles of the users who will need to access the source.</param>
18921911
/// <returns>The <see cref="TranslateSource"/> object for the specified resource.</returns>
18931912
/// <exception cref="DataNotFoundException">The source paratext project does not exist.</exception>
18941913
private async Task<TranslateSource> GetTranslateSourceAsync(
1914+
IConnection conn,
18951915
string curUserId,
18961916
string sfProjectId,
18971917
string paratextId,
18981918
bool syncIfCreated,
1919+
bool updatePermissions,
18991920
IEnumerable<ParatextProject> ptProjects,
19001921
IEnumerable<ParatextResource> resources,
19011922
IReadOnlyDictionary<string, string>? userRoles = null
@@ -1928,12 +1949,10 @@ private async Task<TranslateSource> GetTranslateSourceAsync(
19281949
}
19291950
else
19301951
{
1931-
sourceProjectRef = await CreateResourceProjectInternalAsync(curUserId, sourcePTProject);
1952+
sourceProjectRef = await CreateResourceProjectInternalAsync(conn, sourcePTProject);
19321953
projectCreated = true;
19331954
}
19341955

1935-
await using IConnection conn = await RealtimeService.ConnectAsync(curUserId);
1936-
IDocument<SFProject> projectDoc = projectCreated ? null : await GetProjectDocAsync(sourceProjectRef, conn);
19371956
// Add each user in the target project to the source project so they can access it
19381957
foreach (string userId in userIds)
19391958
{
@@ -1942,15 +1961,7 @@ private async Task<TranslateSource> GetTranslateSourceAsync(
19421961
// Add the user to the project, if the user does not have a role in it
19431962
if (sourceProject == null || !sourceProject.UserRoles.ContainsKey(userId))
19441963
{
1945-
await AddUserAsync(userId, sourceProjectRef, null);
1946-
}
1947-
else if (projectDoc != null)
1948-
{
1949-
Attempt<string> attempt = await TryGetProjectRoleAsync(projectDoc.Data, userId);
1950-
if (attempt.Success)
1951-
{
1952-
await UpdatePermissionsAsync(userId, projectDoc);
1953-
}
1964+
await AddUserAsync(conn, userId, sourceProjectRef, null);
19541965
}
19551966
}
19561967
catch (ForbiddenException)
@@ -1974,6 +1985,12 @@ private async Task<TranslateSource> GetTranslateSourceAsync(
19741985
r => r.UpdateTranslationSourcesAsync(curUserId, sfProjectId)
19751986
);
19761987
}
1988+
else if (updatePermissions)
1989+
{
1990+
// Update all the permissions for all the users on this project or resource
1991+
IDocument<SFProject> projectDoc = await GetProjectDocAsync(sourceProjectRef, conn);
1992+
await UpdatePermissionsAsync(curUserId, projectDoc);
1993+
}
19771994

19781995
return new TranslateSource
19791996
{

src/SIL.XForge/Services/ProjectService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ IFileSystemService fileSystemService
4646
public async Task AddUserAsync(string curUserId, string projectId, string? projectRole)
4747
{
4848
await using IConnection conn = await RealtimeService.ConnectAsync(curUserId);
49+
await AddUserAsync(conn, curUserId, projectId, projectRole);
50+
}
51+
52+
protected async Task AddUserAsync(IConnection conn, string curUserId, string projectId, string? projectRole)
53+
{
4954
IDocument<TModel> projectDoc = await GetProjectDocAsync(projectId, conn);
5055

5156
IDocument<User> userDoc = await GetUserDocAsync(curUserId, conn);

0 commit comments

Comments
 (0)