Skip to content

Commit c1028ca

Browse files
committed
SF-3615 Fix error on draft generation page if your cannot access source
1 parent e625975 commit c1028ca

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.spec.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/
66
import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data';
77
import { ParagraphBreakFormat, QuoteFormat } from 'realtime-server/lib/esm/scriptureforge/models/translate-config';
88
import { of } from 'rxjs';
9-
import { anything, instance, mock, when } from 'ts-mockito';
9+
import { anything, instance, mock, verify, when } from 'ts-mockito';
1010
import { ActivatedProjectService } from 'xforge-common/activated-project.service';
1111
import { createTestFeatureFlag, FeatureFlagService } from 'xforge-common/feature-flags/feature-flag.service';
1212
import { I18nService } from 'xforge-common/i18n.service';
@@ -18,6 +18,7 @@ import { UserService } from 'xforge-common/user.service';
1818
import { SFProjectProfileDoc } from '../../../../core/models/sf-project-profile-doc';
1919
import { SF_TYPE_REGISTRY } from '../../../../core/models/sf-type-registry';
2020
import { TrainingDataDoc } from '../../../../core/models/training-data-doc';
21+
import { PermissionsService } from '../../../../core/permissions.service';
2122
import { SFProjectService } from '../../../../core/sf-project.service';
2223
import { BuildDto } from '../../../../machine-api/build-dto';
2324
import { BuildStates } from '../../../../machine-api/build-states';
@@ -34,6 +35,7 @@ const mockedTrainingDataService = mock(TrainingDataService);
3435
const mockedActivatedProjectService = mock(ActivatedProjectService);
3536
const mockedFeatureFlagsService = mock(FeatureFlagService);
3637
const mockedDraftOptionsService = mock(DraftOptionsService);
38+
const mockedPermissionsService = mock(PermissionsService);
3739

3840
const oneDay = 1000 * 60 * 60 * 24;
3941
const dateBeforeFormattingSupported = new Date(FORMATTING_OPTIONS_SUPPORTED_DATE.getTime() - oneDay).toISOString();
@@ -56,6 +58,7 @@ describe('DraftHistoryEntryComponent', () => {
5658
{ provide: ActivatedProjectService, useMock: mockedActivatedProjectService },
5759
{ provide: FeatureFlagService, useMock: mockedFeatureFlagsService },
5860
{ provide: DraftOptionsService, useMock: mockedDraftOptionsService },
61+
{ provide: PermissionsService, useMock: mockedPermissionsService },
5962
provideNoopAnimations()
6063
]
6164
}));
@@ -82,6 +85,7 @@ describe('DraftHistoryEntryComponent', () => {
8285
instance(trainingDataQuery)
8386
);
8487
when(mockedDraftOptionsService.areFormattingOptionsAvailableButUnselected(anything())).thenReturn(true);
88+
when(mockedPermissionsService.isUserOnProject(anything())).thenResolve(true);
8589
fixture = TestBed.createComponent(DraftHistoryEntryComponent);
8690
component = fixture.componentInstance;
8791
fixture.detectChanges();
@@ -147,6 +151,25 @@ describe('DraftHistoryEntryComponent', () => {
147151
expect(fixture.nativeElement.querySelector('.requested-label')).not.toBeNull();
148152
}));
149153

154+
it('should not get source project if user does not have permission', fakeAsync(() => {
155+
when(mockedPermissionsService.isUserOnProject(anything())).thenResolve(false);
156+
const user = 'user-display-name';
157+
const date = dateAfterFormattingSupported;
158+
const trainingBooks = ['GEN'];
159+
const translateBooks = ['EXO'];
160+
const trainingDataFiles = [];
161+
const entry = getStandardBuildDto({ user, date, trainingBooks, translateBooks, trainingDataFiles });
162+
163+
// SUT
164+
component.entry = entry;
165+
tick();
166+
fixture.detectChanges();
167+
168+
verify(mockedPermissionsService.isUserOnProject('project02')).twice();
169+
verify(mockedSFProjectService.getProfile('project02')).never();
170+
expect(component.translationSource).toEqual('');
171+
}));
172+
150173
it('should state that the model did not have training configuration', fakeAsync(() => {
151174
when(mockedI18nService.enumerateList(anything())).thenReturn('src');
152175
const user = 'user-display-name';

src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { RealtimeQuery } from 'xforge-common/models/realtime-query';
2929
import { UserService } from 'xforge-common/user.service';
3030
import { SFProjectProfileDoc } from '../../../../core/models/sf-project-profile-doc';
3131
import { TrainingDataDoc } from '../../../../core/models/training-data-doc';
32+
import { PermissionsService } from '../../../../core/permissions.service';
3233
import { SFProjectService } from '../../../../core/sf-project.service';
3334
import { BuildDto } from '../../../../machine-api/build-dto';
3435
import { BuildStates } from '../../../../machine-api/build-states';
@@ -125,8 +126,11 @@ export class DraftHistoryEntryComponent {
125126
// Get the target language, if it is not already set
126127
this._targetLanguage ??= target?.data?.writingSystem.tag;
127128

128-
// Get the source project, if it is configured
129-
const source = r.projectId === '' ? undefined : await this.projectService.getProfile(r.projectId);
129+
let source: SFProjectProfileDoc | undefined;
130+
// Get the source project, if it is configured and the user has access
131+
if (await this.permissionsService.isUserOnProject(r.projectId)) {
132+
source = r.projectId === '' ? undefined : await this.projectService.getProfile(r.projectId);
133+
}
130134

131135
// Get the source language, if it is not already set
132136
this._sourceLanguage ??= source?.data?.writingSystem.tag;
@@ -154,10 +158,13 @@ export class DraftHistoryEntryComponent {
154158
this._translationSources = [];
155159
void Promise.all(
156160
translationScriptureRanges.map(async r => {
157-
const source =
158-
r.projectId === '' || r.projectId === value?.engine?.id
159-
? undefined
160-
: await this.projectService.getProfile(r.projectId);
161+
let source: SFProjectProfileDoc | undefined;
162+
if (await this.permissionsService.isUserOnProject(r.projectId)) {
163+
source =
164+
r.projectId === '' || r.projectId === value?.engine?.id
165+
? undefined
166+
: await this.projectService.getProfile(r.projectId);
167+
}
161168
const sourceShortName = source?.data?.shortName;
162169
if (sourceShortName != null) this._translationSources.push(sourceShortName);
163170
})
@@ -322,6 +329,7 @@ export class DraftHistoryEntryComponent {
322329
private readonly activatedProjectService: ActivatedProjectService,
323330
readonly featureFlags: FeatureFlagService,
324331
private readonly draftOptionsService: DraftOptionsService,
332+
private readonly permissionsService: PermissionsService,
325333
private readonly destroyRef: DestroyRef
326334
) {}
327335

0 commit comments

Comments
 (0)