Skip to content

Commit

Permalink
Remove ShareEnabled from TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
pmachapman committed Nov 18, 2024
1 parent 09e94e9 commit 48a6572
Show file tree
Hide file tree
Showing 18 changed files with 152 additions and 152 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export enum CheckingAnswerExport {
export interface CheckingConfig {
checkingEnabled: boolean;
usersSeeEachOthersResponses: boolean;
shareEnabled: boolean;
answerExportMethod: CheckingAnswerExport;
noteTagId?: number;
hideCommunityCheckingText?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export enum SFProjectDomain {
Notes = 'notes',
TextAudio = 'text_audio',
TrainingData = 'training_data',
Drafts = 'drafts'
Drafts = 'drafts',
UserInvites = 'user_invites'
}

// See https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ function testProjectProfile(ordinal: number): SFProjectProfile {
isRightToLeft: false,
translateConfig: {
translationSuggestionsEnabled: false,
shareEnabled: false,
preTranslate: false,
defaultNoteTagId: 1,
draftConfig: {
Expand All @@ -32,7 +31,6 @@ function testProjectProfile(ordinal: number): SFProjectProfile {
checkingConfig: {
checkingEnabled: true,
usersSeeEachOthersResponses: true,
shareEnabled: false,
answerExportMethod: CheckingAnswerExport.MarkedForExport,
hideCommunityCheckingText: false
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export interface DraftConfig {
export interface TranslateConfig {
translationSuggestionsEnabled: boolean;
source?: TranslateSource;
shareEnabled: boolean;
defaultNoteTagId?: number;
preTranslate: boolean;
draftConfig: DraftConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,6 @@ export class SFProjectService extends ProjectService<SFProject> {
},
additionalProperties: false
},
shareEnabled: {
bsonType: 'bool'
},
defaultNoteTagId: {
bsonType: 'int'
},
Expand Down Expand Up @@ -296,9 +293,6 @@ export class SFProjectService extends ProjectService<SFProject> {
usersSeeEachOthersResponses: {
bsonType: 'bool'
},
shareEnabled: {
bsonType: 'bool'
},
answerExportMethod: {
enum: ['', 'all', 'marked_for_export', 'none']
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,15 @@ export class CheckingComponent extends DataLoadingComponent implements OnInit, A
}

get canShare(): boolean {
return this.isProjectAdmin || this.projectDoc?.data?.checkingConfig.shareEnabled === true;
return (
this.projectDoc != null &&
SF_PROJECT_RIGHTS.hasRight(
this.projectDoc.data,
this.userService.currentUserId,
SFProjectDomain.UserInvites,
Operation.Create
)
);
}

get chapterHasAudio(): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -951,8 +951,7 @@ describe('SettingsComponent', () => {
it('should show Translation Suggestions when Based On is set', fakeAsync(() => {
const env = new TestEnvironment();
env.setupProject({
translationSuggestionsEnabled: false,
shareEnabled: false
translationSuggestionsEnabled: false
});
tick();
env.fixture.detectChanges();
Expand Down Expand Up @@ -1045,8 +1044,7 @@ describe('SettingsComponent', () => {
it('Translation Suggestions should remain unchanged when Based On is changed', fakeAsync(() => {
const env = new TestEnvironment();
env.setupProject({
translationSuggestionsEnabled: false,
shareEnabled: false
translationSuggestionsEnabled: false
});
env.wait();
expect(env.translationSuggestionsCheckbox).toBeNull();
Expand Down Expand Up @@ -1077,7 +1075,6 @@ describe('SettingsComponent', () => {
const env = new TestEnvironment();
env.setupProject({
translationSuggestionsEnabled: false,
shareEnabled: false,
source: {
paratextId: 'paratextId01',
projectRef: 'paratext01',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { MatDialogConfig } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router';
import { Operation } from 'realtime-server/lib/esm/common/models/project-rights';
import { SystemRole } from 'realtime-server/lib/esm/common/models/system-role';
import { CheckingAnswerExport } from 'realtime-server/lib/esm/scriptureforge/models/checking-config';
import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights';
import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role';
import { ProjectType, TranslateSource } from 'realtime-server/lib/esm/scriptureforge/models/translate-config';
import { combineLatest, firstValueFrom } from 'rxjs';
import { map, tap } from 'rxjs/operators';
Expand Down Expand Up @@ -489,10 +492,16 @@ export class SettingsComponent extends DataLoadingComponent implements OnInit {
this.projectDoc.data.translateConfig.draftConfig?.additionalTrainingSource?.paratextId,
additionalTrainingData: this.projectDoc.data.translateConfig.draftConfig.additionalTrainingData,
servalConfig: this.projectDoc.data.translateConfig.draftConfig.servalConfig,
translateShareEnabled: !!this.projectDoc.data.translateConfig.shareEnabled,
translateShareEnabled:
this.projectDoc.data.rolePermissions[SFProjectRole.Viewer]?.includes(
SF_PROJECT_RIGHTS.joinRight(SFProjectDomain.UserInvites, Operation.Create)
) === true,
checkingEnabled: this.projectDoc.data.checkingConfig.checkingEnabled,
usersSeeEachOthersResponses: this.projectDoc.data.checkingConfig.usersSeeEachOthersResponses,
checkingShareEnabled: this.projectDoc.data.checkingConfig.shareEnabled,
checkingShareEnabled:
this.projectDoc.data.rolePermissions[SFProjectRole.CommunityChecker]?.includes(
SF_PROJECT_RIGHTS.joinRight(SFProjectDomain.UserInvites, Operation.Create)
) === true,
hideCommunityCheckingText: this.projectDoc.data.checkingConfig.hideCommunityCheckingText,
checkingAnswerExport: this.projectDoc.data.checkingConfig.answerExportMethod ?? CheckingAnswerExport.All
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Operation } from 'realtime-server/lib/esm/common/models/project-rights';
import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights';
import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role';
import { SubscriptionDisposable } from 'xforge-common/subscription-disposable';
import { UserService } from 'xforge-common/user.service';
import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc';
import { SF_PROJECT_ROLES } from '../../core/models/sf-project-role-info';

export abstract class ShareBaseComponent extends SubscriptionDisposable {
protected projectDoc?: SFProjectProfileDoc;

constructor(protected readonly userService: UserService) {
super();
}

get availableRoles(): SFProjectRole[] {
return SF_PROJECT_ROLES.filter(info => info.canBeShared && this.userShareableRoles.includes(info.role)).map(
r => r.role
) as SFProjectRole[];
}

protected get userShareableRoles(): string[] {
const project = this.projectDoc?.data;
if (project == null) {
return [];
}
const userRole = project.userRoles[this.userService.currentUserId];
return [
{
role: SFProjectRole.CommunityChecker,
permission:
project.checkingConfig.checkingEnabled &&
SF_PROJECT_RIGHTS.hasRight(project, this.userService.currentUserId, SFProjectDomain.Questions, Operation.View)
},
{
role: SFProjectRole.Viewer,
permission:
SF_PROJECT_RIGHTS.hasRight(project, this.userService.currentUserId, SFProjectDomain.Texts, Operation.View) &&
userRole !== SFProjectRole.CommunityChecker
},
{
role: SFProjectRole.Commenter,
permission: SF_PROJECT_RIGHTS.hasRight(
project,
this.userService.currentUserId,
SFProjectDomain.Notes,
Operation.Create
)
}
]
.filter(
info =>
info.permission &&
SF_PROJECT_RIGHTS.hasRight(
this.projectDoc.data,
this.userService.currentUserId,
SFProjectDomain.UserInvites,
Operation.Create
)
)
.map(info => info.role as string);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ <h3>{{ t("send_a_link") }}</h3>
<mat-select-trigger>
{{ roleControl.value ? i18n.localizeRole(roleControl.value) : "" }}
</mat-select-trigger>
@for (roleInfo of availableRolesInfo; track roleInfo) {
<mat-option [value]="roleInfo.role">
<div class="role-name">{{ i18n.localizeRole(roleInfo.role) }}</div>
<div class="role-description">{{ i18n.localizeRoleDescription(roleInfo.role) }}</div>
@for (role of availableRoles; track role) {
<mat-option [value]="role">
<div class="role-name">{{ i18n.localizeRole(role) }}</div>
<div class="role-description">{{ i18n.localizeRoleDescription(role) }}</div>
</mat-option>
}
</mat-select>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testi
import { BrowserModule, By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { RouterModule } from '@angular/router';
import { Operation } from 'realtime-server/lib/esm/common/models/project-rights';
import { CheckingConfig } from 'realtime-server/lib/esm/scriptureforge/models/checking-config';
import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights';
import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role';
import { anything, capture, mock, verify, when } from 'ts-mockito';
import { I18nService } from 'xforge-common/i18n.service';
Expand Down Expand Up @@ -189,10 +191,9 @@ describe('ShareControlComponent', () => {
isLinkSharingEnabled: true
});
env.wait();
const roles: string[] = env.component.availableRolesInfo.map(info => info.role);
expect(roles).toContain(SFProjectRole.CommunityChecker);
expect(roles).toContain(SFProjectRole.Viewer);
expect(roles).toContain(SFProjectRole.Commenter);
expect(env.component.availableRoles).toContain(SFProjectRole.CommunityChecker);
expect(env.component.availableRoles).toContain(SFProjectRole.Viewer);
expect(env.component.availableRoles).toContain(SFProjectRole.Commenter);
}));

it('role should be visible for administrators', fakeAsync(() => {
Expand All @@ -211,14 +212,14 @@ describe('ShareControlComponent', () => {
const env = new TestEnvironment({ userId: 'user02', projectId: 'project01' });
env.wait();
expect(env.hostComponent.component.roleControl.value).toEqual(SF_DEFAULT_SHARE_ROLE);
expect(env.hostComponent.component.availableRolesInfo.length).toBe(3);
expect(env.hostComponent.component.availableRoles.length).toBe(3);
}));

it('default share role should be translation observer when checking is disabled', fakeAsync(() => {
const env = new TestEnvironment({ userId: 'user02', projectId: 'project01', checkingEnabled: false });
env.wait();
expect(env.hostComponent.component.roleControl.value).toEqual(SF_DEFAULT_TRANSLATE_SHARE_ROLE);
expect(env.hostComponent.component.availableRolesInfo.length).toBe(2);
expect(env.hostComponent.component.availableRoles.length).toBe(2);
}));

it('should require setting the email before sending an invite', fakeAsync(() => {
Expand Down Expand Up @@ -297,6 +298,7 @@ class TestEnvironment {
checkingEnabled: true
};
args = { ...defaultArgs, ...args };
const permissions = [SF_PROJECT_RIGHTS.joinRight(SFProjectDomain.UserInvites, Operation.Create)];
this.realtimeService.addSnapshot(SFProjectProfileDoc.COLLECTION, {
id: args.projectId,
data: {
Expand All @@ -305,8 +307,11 @@ class TestEnvironment {
user02: SFProjectRole.ParatextAdministrator,
user03: SFProjectRole.Viewer
},
translateConfig: { shareEnabled: true },
checkingConfig: { checkingEnabled: args.checkingEnabled, shareEnabled: true }
checkingConfig: { checkingEnabled: args.checkingEnabled },
rolePermissions: {
sf_community_checker: permissions,
sf_observer: permissions
}
}
});
when(mockedProjectService.getProfile(anything())).thenCall(projectId =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,21 @@ import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scri
import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role';
import { BehaviorSubject, combineLatest } from 'rxjs';
import { I18nService } from 'xforge-common/i18n.service';
import { ProjectRoleInfo } from 'xforge-common/models/project-role-info';
import { NoticeService } from 'xforge-common/notice.service';
import { OnlineStatusService } from 'xforge-common/online-status.service';
import { SubscriptionDisposable } from 'xforge-common/subscription-disposable';
import { UserService } from 'xforge-common/user.service';
import { XFValidators } from 'xforge-common/xfvalidators';
import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc';
import {
SF_DEFAULT_SHARE_ROLE,
SF_DEFAULT_TRANSLATE_SHARE_ROLE,
SF_PROJECT_ROLES
} from '../../core/models/sf-project-role-info';
import { SF_DEFAULT_SHARE_ROLE, SF_DEFAULT_TRANSLATE_SHARE_ROLE } from '../../core/models/sf-project-role-info';
import { SFProjectService } from '../../core/sf-project.service';
import { ShareBaseComponent } from './share-base.component';

/** UI to share project access with new users, such as by sending an invitation email. */
@Component({
selector: 'app-share-control',
templateUrl: './share-control.component.html',
styleUrls: ['./share-control.component.scss']
})
export class ShareControlComponent extends SubscriptionDisposable {
export class ShareControlComponent extends ShareBaseComponent {
/** Fires when an invitation is sent. */
@Output() invited = new EventEmitter<void>();
@Input() defaultRole: SFProjectRole = SF_DEFAULT_SHARE_ROLE;
Expand All @@ -47,17 +41,16 @@ export class ShareControlComponent extends SubscriptionDisposable {

private _projectId?: string;
private projectId$: BehaviorSubject<string> = new BehaviorSubject<string>('');
private projectDoc?: SFProjectProfileDoc;

constructor(
readonly i18n: I18nService,
private readonly noticeService: NoticeService,
private readonly projectService: SFProjectService,
private readonly onlineStatusService: OnlineStatusService,
private readonly changeDetector: ChangeDetectorRef,
private readonly userService: UserService
userService: UserService
) {
super();
super(userService);
this.subscribe(combineLatest([this.projectId$, this.onlineStatusService.onlineStatus$]), async ([projectId]) => {
if (projectId === '') {
return;
Expand All @@ -84,10 +77,6 @@ export class ShareControlComponent extends SubscriptionDisposable {
this.projectId$.next(id);
}

get availableRolesInfo(): ProjectRoleInfo[] {
return SF_PROJECT_ROLES.filter(info => info.canBeShared && this.userShareableRoles.includes(info.role));
}

get shareRole(): SFProjectRole {
return this.roleControl.value;
}
Expand All @@ -107,44 +96,14 @@ export class ShareControlComponent extends SubscriptionDisposable {
return true;
}

const linkSharingSettings = {
[SFProjectRole.CommunityChecker]: project.checkingConfig.shareEnabled,
[SFProjectRole.Viewer]: project.translateConfig.shareEnabled,
[SFProjectRole.Commenter]: project.translateConfig.shareEnabled
};
return linkSharingSettings[this.shareRole] && this.userShareableRoles.includes(this.shareRole);
}

private get userShareableRoles(): string[] {
const project = this.projectDoc?.data;
if (project == null) {
return [];
}
const userRole = project.userRoles[this.userService.currentUserId];
return [
{
role: SFProjectRole.CommunityChecker,
available: project.checkingConfig.checkingEnabled,
permission:
project.checkingConfig.shareEnabled &&
SF_PROJECT_RIGHTS.hasRight(project, this.userService.currentUserId, SFProjectDomain.Questions, Operation.View)
},
{
role: SFProjectRole.Viewer,
available: true,
permission:
project.translateConfig.shareEnabled &&
SF_PROJECT_RIGHTS.hasRight(project, this.userService.currentUserId, SFProjectDomain.Texts, Operation.View) &&
userRole !== SFProjectRole.CommunityChecker
},
{
role: SFProjectRole.Commenter,
available: true,
permission: this.isProjectAdmin
}
]
.filter(info => info.available && (info.permission || this.isProjectAdmin))
.map(info => info.role as string);
return (
SF_PROJECT_RIGHTS.hasRight(
this.projectDoc.data,
this.userService.currentUserId,
SFProjectDomain.UserInvites,
Operation.Create
) && this.userShareableRoles.includes(this.shareRole)
);
}

private get defaultShareRole(): string | undefined {
Expand Down
Loading

0 comments on commit 48a6572

Please sign in to comment.