From 6ad9b0d16dab47729478c466b15aea09a027a4b7 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Tue, 21 May 2024 15:45:15 +1200
Subject: [PATCH 01/10] Change existingEmail to googleId
---
...dmin-reject-with-reason-modal.component.ts | 49 +++++++++++++++++--
1 file changed, 46 insertions(+), 3 deletions(-)
diff --git a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
index 051d145d4d6..90ad09df5b2 100644
--- a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
+++ b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
@@ -2,7 +2,9 @@ import { Component, Input, OnInit } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { RejectWithReasonModalComponentResult } from './admin-reject-with-reason-modal-model';
import { environment } from '../../../../environments/environment';
+import { AdminSearchResult, InstructorAccountSearchResult, SearchService } from '../../../../services/search.service';
import { StatusMessageService } from '../../../../services/status-message.service';
+import { ErrorMessageOutput } from '../../../error-message-output';
/**
* Modal to select reject account requests with reason.
@@ -21,6 +23,24 @@ export class RejectWithReasonModalComponent implements OnInit {
@Input()
accountRequestEmail: string = '';
+ existingAccount: InstructorAccountSearchResult = {
+ name: '',
+ email: '',
+ googleId: '',
+ courseId: '',
+ courseName: '',
+ isCourseDeleted: false,
+ institute: '',
+ courseJoinLink: '',
+ homePageLink: '',
+ manageAccountLink: '',
+ showLinks: false,
+ awaitingSessions: {},
+ openSessions: {},
+ notOpenSessions: {},
+ publishedSessions: {},
+ };
+
rejectionReasonBody: string = '
Hi, {accountRequestName}
\n\n'
+ 'Thanks for your interest in using TEAMMATES. '
+ 'We are unable to create a TEAMMATES instructor account for you.
'
@@ -33,17 +53,40 @@ export class RejectWithReasonModalComponent implements OnInit {
+ 'Remedy: If you are a student but you still need an instructor account, '
+ 'please send your justification to {supportEmail}\n\n'
+ 'Reason: You already have an account for this email address and this institution.
'
- + 'Remedy: You can login to TEAMMATES using your Google account {existingEmail}
\n\n'
+ + 'Remedy: You can login to TEAMMATES using your Google account: {googleId} \n\n'
+ 'If you need further clarification or would like to appeal this decision, please '
+ 'feel free to contact us at {supportEmail}
'
+ 'Regards,
TEAMMATES Team.
';
rejectionReasonTitle: string = 'We are Unable to Create an Account for you';
- constructor(public activeModal: NgbActiveModal, public statusMessageService: StatusMessageService) {}
+ constructor(
+ public activeModal: NgbActiveModal,
+ public statusMessageService: StatusMessageService,
+
+ private searchService: SearchService,
+ ) {}
ngOnInit(): void {
this.rejectionReasonBody = this.rejectionReasonBody.replace('{accountRequestName}', this.accountRequestName);
- this.rejectionReasonBody = this.rejectionReasonBody.replace('{existingEmail}', this.accountRequestEmail);
+
+ this.searchService.searchAdmin(this.accountRequestEmail)
+ .subscribe({
+ next: (resp: AdminSearchResult) => {
+ const hasInstructors: boolean = !!(resp.instructors && resp.instructors.length);
+
+ if (!hasInstructors) {
+ this.rejectionReasonBody = this.rejectionReasonBody.replace('{googleId}', 'GOOGLEID NOT FOUND');
+ return;
+ }
+
+ this.existingAccount = resp.instructors[0];
+ this.rejectionReasonBody = this.rejectionReasonBody.replace('{googleId}', this.existingAccount.googleId);
+ },
+ error: (resp: ErrorMessageOutput) => {
+ this.statusMessageService.showErrorToast(resp.error.message);
+ },
+ });
+
this.rejectionReasonBody = this.rejectionReasonBody.replaceAll('{supportEmail}', environment.supportEmail);
}
From 76285736dbdf74207cbef325f9f117194b276f5f Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Tue, 21 May 2024 16:00:51 +1200
Subject: [PATCH 02/10] Add extra info to instructions
---
.../admin-reject-with-reason-modal.component.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
index 90ad09df5b2..f8dcd278a9a 100644
--- a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
+++ b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
@@ -54,6 +54,8 @@ export class RejectWithReasonModalComponent implements OnInit {
+ 'please send your justification to {supportEmail}\n\n'
+ 'Reason: You already have an account for this email address and this institution.
'
+ 'Remedy: You can login to TEAMMATES using your Google account: {googleId}
\n\n'
+ + 'If you are logged into multiple Google accounts, remember to logout from other Google accounts first, '
+ + 'or use an incognito Browser window. Let us know (with a screenshot) if that doesn\'t work.
'
+ 'If you need further clarification or would like to appeal this decision, please '
+ 'feel free to contact us at {supportEmail}
'
+ 'Regards,
TEAMMATES Team.
';
From 47516aea2b6b93cfdfa492a28c2be0c35d417079 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Tue, 21 May 2024 16:10:07 +1200
Subject: [PATCH 03/10] Fix missing googleId if multiple accounts exist
---
.../admin-reject-with-reason-modal.component.ts | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
index f8dcd278a9a..45717d36444 100644
--- a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
+++ b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
@@ -81,7 +81,12 @@ export class RejectWithReasonModalComponent implements OnInit {
return;
}
- this.existingAccount = resp.instructors[0];
+ for (const instructor of resp.instructors) {
+ if (instructor.googleId !== '') {
+ this.existingAccount = instructor;
+ }
+ }
+
this.rejectionReasonBody = this.rejectionReasonBody.replace('{googleId}', this.existingAccount.googleId);
},
error: (resp: ErrorMessageOutput) => {
From cd32bb3c9325884fa9df7c7bd38603051db33ac3 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Thu, 23 May 2024 05:12:10 +1200
Subject: [PATCH 04/10] Add function name to test name
---
.../admin-reject-with-reason-modal.component.spec.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.spec.ts b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.spec.ts
index 66c831077b0..59391826287 100644
--- a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.spec.ts
+++ b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.spec.ts
@@ -36,7 +36,7 @@ describe('RejectWithReasonModal', () => {
expect(fixture).toMatchSnapshot();
});
- it('should show error message when title is empty upon submitting', () => {
+ it('reject: should show error message when title is empty upon submitting', () => {
component.rejectionReasonTitle = '';
fixture.detectChanges();
@@ -51,7 +51,7 @@ describe('RejectWithReasonModal', () => {
expect(spyStatusMessageService).toHaveBeenCalled();
});
- it('should show error message when body is empty upon submitting', () => {
+ it('reject: should show error message when body is empty upon submitting', () => {
component.rejectionReasonBody = '';
fixture.detectChanges();
@@ -65,7 +65,7 @@ describe('RejectWithReasonModal', () => {
expect(spyStatusMessageService).toHaveBeenCalled();
});
- it('should close modal with data', () => {
+ it('reject: should close modal with data', () => {
const spyActiveModal = jest.spyOn(component.activeModal, 'close');
component.rejectionReasonTitle = 'Rejection Title';
component.rejectionReasonBody = 'Rejection Body';
From 0f48d2208d8047daea9e8d94b998d6279a0c82cc Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Thu, 23 May 2024 16:40:18 +1200
Subject: [PATCH 05/10] Move account search to function
---
.../admin-reject-with-reason-modal.component.ts | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
index 45717d36444..2849a8c2aa8 100644
--- a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
+++ b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
@@ -70,7 +70,16 @@ export class RejectWithReasonModalComponent implements OnInit {
ngOnInit(): void {
this.rejectionReasonBody = this.rejectionReasonBody.replace('{accountRequestName}', this.accountRequestName);
+ this.rejectionReasonBody = this.rejectionReasonBody.replaceAll('{supportEmail}', environment.supportEmail);
+
+ this.replaceGoogleId();
+ }
+
+ onRejectionReasonBodyChange(updatedText: string): void {
+ this.rejectionReasonBody = updatedText;
+ }
+ replaceGoogleId(): void {
this.searchService.searchAdmin(this.accountRequestEmail)
.subscribe({
next: (resp: AdminSearchResult) => {
@@ -93,12 +102,6 @@ export class RejectWithReasonModalComponent implements OnInit {
this.statusMessageService.showErrorToast(resp.error.message);
},
});
-
- this.rejectionReasonBody = this.rejectionReasonBody.replaceAll('{supportEmail}', environment.supportEmail);
- }
-
- onRejectionReasonBodyChange(updatedText: string): void {
- this.rejectionReasonBody = updatedText;
}
/**
From 1f33eff60d5022a8cf383994cbe1f0c5ad2fd229 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Thu, 23 May 2024 22:51:45 +1200
Subject: [PATCH 06/10] Change missing googleId string to be shorter
---
.../admin-reject-with-reason-modal.component.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
index 2849a8c2aa8..154773486ec 100644
--- a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
+++ b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
@@ -86,7 +86,7 @@ export class RejectWithReasonModalComponent implements OnInit {
const hasInstructors: boolean = !!(resp.instructors && resp.instructors.length);
if (!hasInstructors) {
- this.rejectionReasonBody = this.rejectionReasonBody.replace('{googleId}', 'GOOGLEID NOT FOUND');
+ this.rejectionReasonBody = this.rejectionReasonBody.replace('{googleId}', 'NO_GOOGLEID');
return;
}
From 7c247b664f9eab5f214f8c02195eb35757e15db0 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Fri, 24 May 2024 04:24:18 +1200
Subject: [PATCH 07/10] Add check for accounts with no googleId
---
.../admin-reject-with-reason-modal.component.ts | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
index 154773486ec..080b813161d 100644
--- a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
+++ b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.ts
@@ -96,7 +96,12 @@ export class RejectWithReasonModalComponent implements OnInit {
}
}
- this.rejectionReasonBody = this.rejectionReasonBody.replace('{googleId}', this.existingAccount.googleId);
+ if (this.existingAccount.googleId === '') {
+ // When an instructor account exists, but for some reason does not have a googleId
+ this.rejectionReasonBody = this.rejectionReasonBody.replace('{googleId}', 'NO_GOOGLEID');
+ } else {
+ this.rejectionReasonBody = this.rejectionReasonBody.replace('{googleId}', this.existingAccount.googleId);
+ }
},
error: (resp: ErrorMessageOutput) => {
this.statusMessageService.showErrorToast(resp.error.message);
From 563cc9fd1e23fdf3407d89a9938995c53e239690 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Fri, 24 May 2024 04:36:50 +1200
Subject: [PATCH 08/10] Add tests for replaceGoogleId
---
...t-with-reason-modal.component.spec.ts.snap | 2 +
...reject-with-reason-modal.component.spec.ts | 66 ++++++++++++++++++-
2 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/__snapshots__/admin-reject-with-reason-modal.component.spec.ts.snap b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/__snapshots__/admin-reject-with-reason-modal.component.spec.ts.snap
index 6d39aa0d076..f657de589c6 100644
--- a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/__snapshots__/admin-reject-with-reason-modal.component.spec.ts.snap
+++ b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/__snapshots__/admin-reject-with-reason-modal.component.spec.ts.snap
@@ -5,8 +5,10 @@ exports[`RejectWithReasonModal should show empty title and body 1`] = `
accountRequestEmail=""
accountRequestName=""
activeModal={[Function NgbActiveModal]}
+ existingAccount={[Function Object]}
rejectionReasonBody={[Function String]}
rejectionReasonTitle={[Function String]}
+ searchService={[Function SearchService]}
statusMessageService={[Function StatusMessageService]}
>
{
+ let searchService: SearchService;
let statusMessageService: StatusMessageService;
let fixture: ComponentFixture;
let component: RejectWithReasonModalComponent;
@@ -15,14 +48,16 @@ describe('RejectWithReasonModal', () => {
declarations: [],
imports: [
HttpClientTestingModule,
+ RouterTestingModule,
],
- providers: [NgbActiveModal, StatusMessageService],
+ providers: [NgbActiveModal, SearchService, StatusMessageService],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(RejectWithReasonModalComponent);
+ searchService = TestBed.inject(SearchService);
statusMessageService = TestBed.inject(StatusMessageService);
fixture.detectChanges();
component = fixture.componentInstance;
@@ -36,6 +71,35 @@ describe('RejectWithReasonModal', () => {
expect(fixture).toMatchSnapshot();
});
+ it('replaceGoogleId: should set the googleId to an empty string if no instructor accounts are found', () => {
+ jest.spyOn(searchService, 'searchAdmin').mockReturnValue(of({
+ students: [],
+ instructors: [],
+ accountRequests: [],
+ }));
+
+ component.replaceGoogleId();
+
+ expect(component.existingAccount.googleId).toEqual('');
+ });
+
+ it('replaceGoogleId: should set the googleId to the instructor accounts googleId', () => {
+ const testInstructor = {
+ ...DEFAULT_INSTRUCTOR_SEARCH_RESULT,
+ googleId: 'instructorGoogleId',
+ };
+
+ jest.spyOn(searchService, 'searchAdmin').mockReturnValue(of({
+ students: [],
+ instructors: [testInstructor],
+ accountRequests: [],
+ }));
+
+ component.replaceGoogleId();
+
+ expect(component.existingAccount.googleId).toEqual('instructorGoogleId');
+ });
+
it('reject: should show error message when title is empty upon submitting', () => {
component.rejectionReasonTitle = '';
fixture.detectChanges();
From 7046a10cb910eeaaf18566949548335dc49191da Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Mon, 27 May 2024 17:14:15 +1200
Subject: [PATCH 09/10] Change instructor search result to use createBuilder
---
.../admin-reject-with-reason-modal.component.spec.ts | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.spec.ts b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.spec.ts
index 1dff8bd1463..43ba22100f5 100644
--- a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.spec.ts
+++ b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.spec.ts
@@ -10,6 +10,7 @@ import {
SearchService,
} from '../../../../services/search.service';
import { StatusMessageService } from '../../../../services/status-message.service';
+import { createBuilder } from '../../../../test-helpers/generic-builder';
const DEFAULT_FEEDBACK_SESSION_GROUP: FeedbackSessionsGroup = {
sessionName: {
@@ -19,7 +20,7 @@ const DEFAULT_FEEDBACK_SESSION_GROUP: FeedbackSessionsGroup = {
},
};
-const DEFAULT_INSTRUCTOR_SEARCH_RESULT: InstructorAccountSearchResult = {
+const instructorAccountSearchResultBuilder = createBuilder({
name: 'name',
email: 'email',
googleId: 'googleId',
@@ -35,7 +36,7 @@ const DEFAULT_INSTRUCTOR_SEARCH_RESULT: InstructorAccountSearchResult = {
openSessions: DEFAULT_FEEDBACK_SESSION_GROUP,
notOpenSessions: DEFAULT_FEEDBACK_SESSION_GROUP,
publishedSessions: DEFAULT_FEEDBACK_SESSION_GROUP,
-};
+});
describe('RejectWithReasonModal', () => {
let searchService: SearchService;
@@ -84,10 +85,7 @@ describe('RejectWithReasonModal', () => {
});
it('replaceGoogleId: should set the googleId to the instructor accounts googleId', () => {
- const testInstructor = {
- ...DEFAULT_INSTRUCTOR_SEARCH_RESULT,
- googleId: 'instructorGoogleId',
- };
+ const testInstructor = instructorAccountSearchResultBuilder.googleId('instructorGoogleId').build();
jest.spyOn(searchService, 'searchAdmin').mockReturnValue(of({
students: [],
From 88ae2394a02a354f0cb45278013f90b5abb3d53e Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Mon, 27 May 2024 17:16:34 +1200
Subject: [PATCH 10/10] Change a test name to fit convention
---
.../admin-reject-with-reason-modal.component.spec.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.spec.ts b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.spec.ts
index 43ba22100f5..e59fb7814cf 100644
--- a/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.spec.ts
+++ b/src/web/app/components/account-requests-table/admin-reject-with-reason-modal/admin-reject-with-reason-modal.component.spec.ts
@@ -84,7 +84,8 @@ describe('RejectWithReasonModal', () => {
expect(component.existingAccount.googleId).toEqual('');
});
- it('replaceGoogleId: should set the googleId to the instructor accounts googleId', () => {
+ it('replaceGoogleId: should set the googleId to the instructor accounts googleId '
+ + 'if an instructor account is found', () => {
const testInstructor = instructorAccountSearchResultBuilder.googleId('instructorGoogleId').build();
jest.spyOn(searchService, 'searchAdmin').mockReturnValue(of({