Skip to content

Commit

Permalink
fix(Peer Group): Non admins can not create new peer groupings (#1434)
Browse files Browse the repository at this point in the history
Co-authored-by: Jonathan Lim-Breitbart <breity10@gmail.com>
  • Loading branch information
geoffreykwan and breity authored Sep 28, 2023
1 parent 892483b commit cba91ca
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { PeerGrouping } from '../../../../../app/domain/peerGrouping';
import { ReferenceComponent } from '../../../../../app/domain/referenceComponent';
import { ProjectService } from '../../../services/projectService';
import { AVAILABLE_LOGIC, AVAILABLE_MODES, PeerGroupingLogic } from '../PeerGroupingLogic';
import { MatSnackBar } from '@angular/material/snack-bar';

@Directive()
export abstract class AuthorPeerGroupingDialogComponent implements OnInit {
Expand All @@ -18,7 +19,8 @@ export abstract class AuthorPeerGroupingDialogComponent implements OnInit {

constructor(
protected dialogRef: MatDialogRef<AuthorPeerGroupingDialogComponent>,
protected projectService: ProjectService
protected projectService: ProjectService,
protected snackBar: MatSnackBar
) {
this.availableLogic = AVAILABLE_LOGIC;
}
Expand Down Expand Up @@ -52,4 +54,15 @@ export abstract class AuthorPeerGroupingDialogComponent implements OnInit {
cancel(): void {
this.dialogRef.close();
}

protected handleError(error: any): void {
switch (error.messageCode) {
case 'genericError':
this.snackBar.open($localize`An error occurred. Please try again.`);
break;
case 'notAuthorized':
this.snackBar.open($localize`You are not allowed to perform this action.`);
break;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatDialogRef } from '@angular/material/dialog';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { of } from 'rxjs';
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
import { of, throwError } from 'rxjs';
import { PeerGrouping } from '../../../../../app/domain/peerGrouping';
import { ReferenceComponent } from '../../../../../app/domain/referenceComponent';
import { StudentTeacherCommonServicesModule } from '../../../../../app/student-teacher-common-services.module';
Expand All @@ -13,8 +13,10 @@ const TAG1: string = 'tag1';
const REFERENCE_COMPONENT_NODE_ID1 = 'node1';
const REFERENCE_COMPONENT_COMPONENT_ID1 = 'component1';
let component: CreateNewPeerGroupingDialogComponent;
let createNewPeerGroupingSpy: jasmine.Spy, dialogCloseSpy: jasmine.Spy;
let createNewPeerGroupingSpy: jasmine.Spy;
let dialogCloseSpy: jasmine.Spy;
let fixture: ComponentFixture<CreateNewPeerGroupingDialogComponent>;
let snackBar: MatSnackBar;

describe('CreateNewPeerGroupingDialogComponent', () => {
beforeEach(async () => {
Expand All @@ -30,6 +32,7 @@ describe('CreateNewPeerGroupingDialogComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(CreateNewPeerGroupingDialogComponent);
component = fixture.componentInstance;
snackBar = TestBed.inject(MatSnackBar);
fixture.detectChanges();
});
create();
Expand All @@ -41,6 +44,7 @@ function create() {
create_DifferentIdeasMaximizeLogic_ShouldCreatePeerGroup();
create_DifferentScoresAnyLogic_ShouldCreatePeerGroup();
create_DifferentScoresMaximizeLogic_ShouldCreatePeerGroup();
create_ErrorOccurs_ShowsError();
}

function create_RandomLogic_ShouldCreatePeerGroup() {
Expand Down Expand Up @@ -98,3 +102,41 @@ function expectLogicCreateNewPeerGrouping(logicType: string, mode: string) {
expect(createNewPeerGroupingSpy).toHaveBeenCalledWith(newPeerGrouping);
expect(dialogCloseSpy).toHaveBeenCalled();
}

function create_ErrorOccurs_ShowsError(): void {
describe('create new peer grouping returns error', () => {
create_GenericErrorOccurs_ShowsError();
create_NotAuthorizedErrorOccurs_ShowsError();
});
}

function create_GenericErrorOccurs_ShowsError(): void {
describe('returns generic error', () => {
it('shows generic error message in snackbar', async () => {
returnErrorExpectErrorMessage('genericError', 'An error occurred. Please try again.');
});
});
}

function create_NotAuthorizedErrorOccurs_ShowsError(): void {
describe('returns not authorized error', () => {
it('shows not authorized error in snackbar', async () => {
returnErrorExpectErrorMessage('notAuthorized', 'You are not allowed to perform this action.');
});
});
}

function returnErrorExpectErrorMessage(messageCode: string, errorMessage: string): void {
const snackBarSpy = spyOn(snackBar, 'open');
createNewPeerGroupingSpy.and.returnValue(
throwError(() => {
return {
error: {
messageCode: messageCode
}
};
})
);
component.create();
expect(snackBarSpy).toHaveBeenCalledWith(errorMessage);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ export class CreateNewPeerGroupingDialogComponent extends AuthorPeerGroupingDial
protected dialogRef: MatDialogRef<CreateNewPeerGroupingDialogComponent>,
private peerGroupingAuthoringService: PeerGroupingAuthoringService,
protected projectService: ProjectService,
private snackBar: MatSnackBar
protected snackBar: MatSnackBar
) {
super(dialogRef, projectService);
super(dialogRef, projectService, snackBar);
}

ngOnInit(): void {
Expand All @@ -29,13 +29,13 @@ export class CreateNewPeerGroupingDialogComponent extends AuthorPeerGroupingDial
create(): Subscription {
this.peerGrouping.tag = this.peerGroupingAuthoringService.getUniqueTag();
this.updatePeerGroupingLogic();
return this.peerGroupingAuthoringService.createNewPeerGrouping(this.peerGrouping).subscribe(
() => {
return this.peerGroupingAuthoringService.createNewPeerGrouping(this.peerGrouping).subscribe({
next: () => {
this.dialogRef.close();
},
() => {
this.snackBar.open($localize`Please try again (Error: duplicate tag).`);
error: ({ error }) => {
this.handleError(error);
}
);
});
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
import { of, throwError } from 'rxjs';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { PeerGroupingAuthoringService } from '../../../services/peerGroupingAuthoringService';
import { PeerGroupingTestingModule } from '../peer-grouping-testing.module';
import { EditPeerGroupingDialogComponent } from './edit-peer-grouping-dialog.component';
import { PeerGrouping } from '../../../../../app/domain/peerGrouping';
import { StudentTeacherCommonServicesModule } from '../../../../../app/student-teacher-common-services.module';
import { DIFFERENT_IDEAS_VALUE, DIFFERENT_SCORES_VALUE } from '../PeerGroupingLogic';
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';

let component: EditPeerGroupingDialogComponent;
const componentId1 = 'component1';
let dialogCloseSpy: jasmine.Spy;
let fixture: ComponentFixture<EditPeerGroupingDialogComponent>;
const modeAny: string = 'any';
const modeMaximize: string = 'maximize';
const nodeId1 = 'node1';
const modeMaximize: string = 'maximize';
let snackBar: MatSnackBar;
let peerGroupingAuthoringService;
let updatePeerGroupingSpy: jasmine.Spy;

describe('EditPeerGroupingDialogComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [PeerGroupingTestingModule, StudentTeacherCommonServicesModule],
imports: [MatSnackBarModule, PeerGroupingTestingModule, StudentTeacherCommonServicesModule],
declarations: [EditPeerGroupingDialogComponent],
providers: [
{
Expand All @@ -36,7 +40,10 @@ describe('EditPeerGroupingDialogComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(EditPeerGroupingDialogComponent);
component = fixture.componentInstance;
peerGroupingAuthoringService = TestBed.inject(PeerGroupingAuthoringService);
updatePeerGroupingSpy = spyOn(peerGroupingAuthoringService, 'updatePeerGrouping');
dialogCloseSpy = spyOn(TestBed.inject(MatDialogRef), 'close');
snackBar = TestBed.inject(MatSnackBar);
fixture.detectChanges();
});

Expand All @@ -46,56 +53,86 @@ describe('EditPeerGroupingDialogComponent', () => {
});

function savePeerGrouping() {
it('should save peer grouping', async () => {
const settings = new PeerGrouping();
component.peerGrouping = settings;
const updatePeerGroupingSpy = spyOn(
TestBed.inject(PeerGroupingAuthoringService),
'updatePeerGrouping'
).and.returnValue(of(settings));
component.save();
expect(updatePeerGroupingSpy).toHaveBeenCalledWith(settings);
expect(dialogCloseSpy).toHaveBeenCalled();
});
describe('save is clicked', () => {
describe('save to backend is successful', () => {
it('closes the dialog', async () => {
const settings = new PeerGrouping();
component.peerGrouping = settings;
updatePeerGroupingSpy.and.returnValue(of(settings));
component.save();
expect(updatePeerGroupingSpy).toHaveBeenCalledWith(settings);
expect(dialogCloseSpy).toHaveBeenCalled();
});
});

it('should save peer grouping with random logic', () => {
savePeerGroupingWithLogic('random', null, 'random');
});
describe('peer grouping logic is random', () => {
it('properly generates the random logic string', () => {
savePeerGroupingWithLogic('random', null, 'random');
});
});

it('should save peer grouping with manual logic', () => {
savePeerGroupingWithLogic('manual', null, 'manual');
});
describe('peer grouping logic is manual', () => {
it('properly generates the manual logic string', () => {
savePeerGroupingWithLogic('manual', null, 'manual');
});
});

it('should save peer grouping with different ideas any logic', () => {
savePeerGroupingWithLogic(
DIFFERENT_IDEAS_VALUE,
modeAny,
`${DIFFERENT_IDEAS_VALUE}("${nodeId1}", "${componentId1}", "${modeAny}")`
);
});
describe('peer grouping logic is different ideas', () => {
it('properly generates the different ideas logic string', () => {
savePeerGroupingWithLogic(
DIFFERENT_IDEAS_VALUE,
modeAny,
`${DIFFERENT_IDEAS_VALUE}("${nodeId1}", "${componentId1}", "${modeAny}")`
);
});
});

it('should save peer grouping with different ideas maximize logic', () => {
savePeerGroupingWithLogic(
DIFFERENT_IDEAS_VALUE,
modeMaximize,
`${DIFFERENT_IDEAS_VALUE}("${nodeId1}", "${componentId1}", "${modeMaximize}")`
);
});
describe('peer grouping logic is different ideas maximize logic', () => {
it('properly generates the different ideas maximize logic string', () => {
savePeerGroupingWithLogic(
DIFFERENT_IDEAS_VALUE,
modeMaximize,
`${DIFFERENT_IDEAS_VALUE}("${nodeId1}", "${componentId1}", "${modeMaximize}")`
);
});
});

it('should save peer grouping with different scores any logic', () => {
savePeerGroupingWithLogic(
DIFFERENT_SCORES_VALUE,
modeAny,
`${DIFFERENT_SCORES_VALUE}("${nodeId1}", "${componentId1}", "${modeAny}")`
);
});
describe('peer grouping logic is different scores', () => {
it('properly generates the different scores logic string', () => {
savePeerGroupingWithLogic(
DIFFERENT_SCORES_VALUE,
modeAny,
`${DIFFERENT_SCORES_VALUE}("${nodeId1}", "${componentId1}", "${modeAny}")`
);
});
});

describe('peer grouping logic is different scores maximize logic', () => {
it('proplery generates the different scores maximize logic string', () => {
savePeerGroupingWithLogic(
DIFFERENT_SCORES_VALUE,
modeMaximize,
`${DIFFERENT_SCORES_VALUE}("${nodeId1}", "${componentId1}", "${modeMaximize}")`
);
});
});

it('should save peer grouping with different scores maximize logic', () => {
savePeerGroupingWithLogic(
DIFFERENT_SCORES_VALUE,
modeMaximize,
`${DIFFERENT_SCORES_VALUE}("${nodeId1}", "${componentId1}", "${modeMaximize}")`
);
describe('save to backend returns not authorized error', () => {
it('shows not authorized error', () => {
const snackBarSpy = spyOn(snackBar, 'open');
updatePeerGroupingSpy.and.returnValue(
throwError(() => {
return {
error: {
messageCode: 'notAuthorized'
}
};
})
);
component.save();
expect(snackBarSpy).toHaveBeenCalledWith('You are not allowed to perform this action.');
});
});
});
}

Expand All @@ -108,24 +145,26 @@ function savePeerGroupingWithLogic(logicType: string, mode: string, expectedLogi
componentId: 'component1'
};
component.mode = mode;
spyOn(TestBed.inject(PeerGroupingAuthoringService), 'updatePeerGrouping').and.returnValue(
of(peerGrouping)
);
updatePeerGroupingSpy.and.returnValue(of(peerGrouping));
component.save();
expect(component.peerGrouping.logic).toEqual(expectedLogic);
}

function deletePeerGrouping() {
it('should delete peer grouping', () => {
spyOn(window, 'confirm').and.returnValue(true);
component.delete();
expect(dialogCloseSpy).toHaveBeenCalled();
describe('delete is clicked', () => {
it('deletes peer grouping', () => {
spyOn(window, 'confirm').and.returnValue(true);
component.delete();
expect(dialogCloseSpy).toHaveBeenCalled();
});
});
}

function cancelPeerGrouping() {
it('should cancel peer grouping', () => {
component.cancel();
expect(dialogCloseSpy).toHaveBeenCalled();
describe('cancel is clicked', () => {
it('cancels peer grouping', () => {
component.cancel();
expect(dialogCloseSpy).toHaveBeenCalled();
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
DIFFERENT_SCORES_REGEX,
DIFFERENT_SCORES_VALUE
} from '../PeerGroupingLogic';
import { MatSnackBar } from '@angular/material/snack-bar';

@Component({
selector: 'edit-peer-grouping-dialog',
Expand All @@ -23,9 +24,10 @@ export class EditPeerGroupingDialogComponent extends AuthorPeerGroupingDialogCom
@Inject(MAT_DIALOG_DATA) public peerGrouping: PeerGrouping,
protected dialogRef: MatDialogRef<EditPeerGroupingDialogComponent>,
private peerGroupingAuthoringService: PeerGroupingAuthoringService,
protected projectService: ProjectService
protected projectService: ProjectService,
protected snackBar: MatSnackBar
) {
super(dialogRef, projectService);
super(dialogRef, projectService, snackBar);
}

ngOnInit(): void {
Expand Down Expand Up @@ -53,8 +55,13 @@ export class EditPeerGroupingDialogComponent extends AuthorPeerGroupingDialogCom

save(): void {
this.updatePeerGroupingLogic();
this.peerGroupingAuthoringService.updatePeerGrouping(this.peerGrouping).subscribe(() => {
this.dialogRef.close();
this.peerGroupingAuthoringService.updatePeerGrouping(this.peerGrouping).subscribe({
next: () => {
this.dialogRef.close();
},
error: ({ error }) => {
this.handleError(error);
}
});
}

Expand Down
Loading

0 comments on commit cba91ca

Please sign in to comment.