Skip to content

Commit b62c1e3

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

File tree

2 files changed

+39
-8
lines changed

2 files changed

+39
-8
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: 25 additions & 2 deletions
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();
@@ -58,7 +60,8 @@ describe('DraftHistoryEntryComponent', () => {
5860
{ provide: TrainingDataService, useMock: mockedTrainingDataService },
5961
{ provide: ActivatedProjectService, useMock: mockedActivatedProjectService },
6062
{ provide: FeatureFlagService, useMock: mockedFeatureFlagsService },
61-
{ provide: DraftOptionsService, useMock: mockedDraftOptionsService }
63+
{ provide: DraftOptionsService, useMock: mockedDraftOptionsService },
64+
{ provide: PermissionsService, useMock: mockedPermissionsService }
6265
]
6366
}));
6467

@@ -84,6 +87,7 @@ describe('DraftHistoryEntryComponent', () => {
8487
instance(trainingDataQuery)
8588
);
8689
when(mockedDraftOptionsService.areFormattingOptionsAvailableButUnselected(anything())).thenReturn(true);
90+
when(mockedPermissionsService.isUserOnProject(anything())).thenResolve(true);
8791
fixture = TestBed.createComponent(DraftHistoryEntryComponent);
8892
component = fixture.componentInstance;
8993
fixture.detectChanges();
@@ -149,6 +153,25 @@ describe('DraftHistoryEntryComponent', () => {
149153
expect(fixture.nativeElement.querySelector('.requested-label')).not.toBeNull();
150154
}));
151155

156+
it('should not get source project if user does not have permission', fakeAsync(() => {
157+
when(mockedPermissionsService.isUserOnProject(anything())).thenResolve(false);
158+
const user = 'user-display-name';
159+
const date = dateAfterFormattingSupported;
160+
const trainingBooks = ['GEN'];
161+
const translateBooks = ['EXO'];
162+
const trainingDataFiles = [];
163+
const entry = getStandardBuildDto({ user, date, trainingBooks, translateBooks, trainingDataFiles });
164+
165+
// SUT
166+
component.entry = entry;
167+
tick();
168+
fixture.detectChanges();
169+
170+
verify(mockedPermissionsService.isUserOnProject('project02')).twice();
171+
verify(mockedSFProjectService.getProfile('project02')).never();
172+
expect(component.translationSource).toEqual('');
173+
}));
174+
152175
it('should state that the model did not have training configuration', fakeAsync(() => {
153176
when(mockedI18nService.enumerateList(anything())).thenReturn('src');
154177
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
@@ -13,6 +13,7 @@ import { RealtimeQuery } from 'xforge-common/models/realtime-query';
1313
import { UserService } from 'xforge-common/user.service';
1414
import { SFProjectProfileDoc } from '../../../../core/models/sf-project-profile-doc';
1515
import { TrainingDataDoc } from '../../../../core/models/training-data-doc';
16+
import { PermissionsService } from '../../../../core/permissions.service';
1617
import { SFProjectService } from '../../../../core/sf-project.service';
1718
import { BuildDto } from '../../../../machine-api/build-dto';
1819
import { BuildStates } from '../../../../machine-api/build-states';
@@ -97,8 +98,11 @@ export class DraftHistoryEntryComponent {
9798
// Get the target language, if it is not already set
9899
this._targetLanguage ??= target?.data?.writingSystem.tag;
99100

100-
// Get the source project, if it is configured
101-
const source = r.projectId === '' ? undefined : await this.projectService.getProfile(r.projectId);
101+
let source: SFProjectProfileDoc | undefined;
102+
// Get the source project, if it is configured and the user has access
103+
if (await this.permissionsService.isUserOnProject(r.projectId)) {
104+
source = r.projectId === '' ? undefined : await this.projectService.getProfile(r.projectId);
105+
}
102106

103107
// Get the source language, if it is not already set
104108
this._sourceLanguage ??= source?.data?.writingSystem.tag;
@@ -126,10 +130,13 @@ export class DraftHistoryEntryComponent {
126130
this._translationSources = [];
127131
void Promise.all(
128132
translationScriptureRanges.map(async r => {
129-
const source =
130-
r.projectId === '' || r.projectId === value?.engine?.id
131-
? undefined
132-
: await this.projectService.getProfile(r.projectId);
133+
let source: SFProjectProfileDoc | undefined;
134+
if (await this.permissionsService.isUserOnProject(r.projectId)) {
135+
source =
136+
r.projectId === '' || r.projectId === value?.engine?.id
137+
? undefined
138+
: await this.projectService.getProfile(r.projectId);
139+
}
133140
const sourceShortName = source?.data?.shortName;
134141
if (sourceShortName != null) this._translationSources.push(sourceShortName);
135142
})
@@ -294,6 +301,7 @@ export class DraftHistoryEntryComponent {
294301
private readonly activatedProjectService: ActivatedProjectService,
295302
readonly featureFlags: FeatureFlagService,
296303
private readonly draftOptionsService: DraftOptionsService,
304+
private readonly permissionsService: PermissionsService,
297305
private readonly destroyRef: DestroyRef
298306
) {}
299307

0 commit comments

Comments
 (0)