Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#11878] Account request form #13048

Merged
merged 51 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
186a97a
Enable CI on account request form branch
ziqing26 Mar 12, 2024
395bdd7
[#11878] Remove AccountRequest unique constraint (#12899)
jayasting98 Mar 18, 2024
fc1342f
[#11878] Add status and comments to AccountRequest (#12898)
jayasting98 Mar 18, 2024
24a914d
[#11878] Add new account request alert email for admins (#12926)
jayasting98 Mar 25, 2024
126d2c4
[#11878] Add GetAllPendingAccountRequests API (#12927)
EuniceSim142 Mar 25, 2024
cb29108
[#11878] Modify CreateAccountRequestAction (#12913)
jayasting98 Mar 25, 2024
f7eaa61
[#11878] Upgrade instructor request form UI (#12929)
xenosf Mar 27, 2024
40613df
[#11878] Update Admin Home Page UI for ARF (#12933)
domoberzin Mar 27, 2024
5618370
[#11878] Admin Search UI Update for ARF (#12945)
domoberzin Mar 27, 2024
0aa7dfb
[#11878] Add methods to get an account request by ID (#12953)
jayasting98 Mar 28, 2024
f6329eb
[#11878] Add snapshot tests for instructor request form UI (#12942)
xenosf Mar 28, 2024
6049c81
[#11878] Foundation for getting by ID in account request endpoints (#…
jayasting98 Mar 29, 2024
9f0ca34
Get account requests by ID in storage update method (#12955)
jayasting98 Mar 29, 2024
9794b8a
Get an account request by ID in SQL injection tests (#12956)
jayasting98 Mar 29, 2024
00b85ce
[#11878] Create instructor request acknowledgement email (#12944)
xenosf Mar 30, 2024
99eeac7
[#11878] Merge master into account-request-form (#12972)
ziqing26 Mar 31, 2024
7ec74c7
[#11878] Change institute length limit (#12974)
xenosf Apr 2, 2024
0b07036
[#11878] Update SearchAccountRequests endpoint (#12950)
EuniceSim142 Apr 2, 2024
de3181a
[#11878] Integrate instructor request form with API (#12943)
xenosf Apr 4, 2024
5779d2f
[#11878] Create Update Account Request Action (#12982)
domoberzin Apr 5, 2024
4a54001
[#11878] Fix Account Request Update Search Indexing (#12984)
domoberzin Apr 6, 2024
62750b0
[#11878] Add Edit and Approve Account Requests functionality (#12975)
domoberzin Apr 7, 2024
96e5abd
[#11878] Add AccountRequest Rejection email generator. (#12987)
EuniceSim142 Apr 8, 2024
fb0ba19
[#11878] Create reject account request endpoint (#12985)
xenosf Apr 9, 2024
cfff21d
Remove unused modal (#12998)
dishenggg Apr 9, 2024
50c87bc
use transactions for reject account request action (#13001)
domoberzin Apr 9, 2024
a36ecf7
[#11878] Create Rejection Modal for Account Requests (#12989)
domoberzin Apr 10, 2024
6de9607
[#11878] Update DeleteAccountRequest to reference by ID (#12997)
dishenggg Apr 11, 2024
e0beb08
[#11878] Update ResetAccountRequest to reference by ID (#13002)
dishenggg Apr 11, 2024
ce75a0a
[#11878] Add Error Message for Approving Existing Account (#13004)
domoberzin Apr 11, 2024
41524a5
[#11878] Get account request by uuid (#13007)
cedricongjh Apr 12, 2024
451a25a
[#11878] Handle Duplicate Approved Account Requests (#13009)
domoberzin Apr 12, 2024
2bd06e2
[#11878] Merge master into feature (#13011)
ziqing26 Apr 13, 2024
4682dff
[#11878] Add tests for Account Request Table (#12977)
domoberzin Apr 14, 2024
c6b8642
[#11878] Reference account requests by ID in tests (#13017)
jayasting98 Apr 14, 2024
f0e2af3
[#11878] Fix Approval Email Bug (#13027)
domoberzin Apr 14, 2024
589ba08
[#11878] Fix reject email content (#13029)
ziqing26 Apr 14, 2024
9431906
Merge branch 'master' into account-request-form
ziqing26 Apr 14, 2024
0f0fd05
[#11878] Add Toasts (#13028)
domoberzin Apr 14, 2024
bb261f4
[#11878] Remove mention of home page URL from confirmation email (#13…
xenosf Apr 14, 2024
20c29e5
fix highlighting and null statuses (#13031)
domoberzin Apr 15, 2024
3dab1dc
[#11878] Fix Overlapping Tooltip (#13026)
domoberzin Apr 15, 2024
665752c
[#11878] Check if account request is not created by admin before send…
xenosf Apr 15, 2024
7b05fec
[#11878] Add sort by created_at for getAllPendingRequests (#13038)
EuniceSim142 Apr 16, 2024
16f7767
[#11878] Request Page E2E (#13015)
dishenggg Apr 16, 2024
3915b8c
Remove method from logic and db (#13044)
dishenggg Apr 17, 2024
ab22022
[#11878] Migrate AccountRequestsLogic unit tests (#13043)
xenosf Apr 17, 2024
68a4fbf
[#11878] Add Admin E2E Tests (#13020)
domoberzin Apr 17, 2024
78e49b7
Merge branch 'master' into account-request-form
ziqing26 Apr 17, 2024
2cc6ef8
[#11878] Add SQLI tests (#13047)
xenosf Apr 17, 2024
5378b66
Revert "Enable CI on account request form branch" (#13049)
ziqing26 Apr 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions solr/solr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ bin/solr create -c accountrequests -s 2 -rf 2
bin/solr config -c accountrequests -p 8983 -action set-user-property -property update.autoCreateFields -value false
curl -X POST -H 'Content-type: application/json' --data-binary '{"add-field": {"name": "email", "type": "string"}}' localhost:8983/solr/accountrequests/schema
curl -X POST -H 'Content-type: application/json' --data-binary '{"add-field": {"name": "institute", "type": "string"}}' localhost:8983/solr/accountrequests/schema
curl -X POST -H 'Content-type: application/json' --data-binary '{"add-field": {"name": "comments", "type": "string"}}' localhost:8983/solr/accountrequests/schema
curl -X POST -H 'Content-type: application/json' --data-binary '{"add-field": {"name": "status", "type": "string"}}' localhost:8983/solr/accountrequests/schema
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// CHECKSTYLE.OFF:ImportOrder
import com.googlecode.objectify.cmd.Query;

import teammates.common.datatransfer.AccountRequestStatus;
import jakarta.persistence.criteria.CriteriaDelete;

import teammates.common.util.HibernateUtil;
Expand Down Expand Up @@ -57,7 +58,9 @@ protected void migrateEntity(teammates.storage.entity.AccountRequest oldEntity)
AccountRequest newEntity = new AccountRequest(
oldEntity.getEmail(),
oldEntity.getName(),
oldEntity.getInstitute());
oldEntity.getInstitute(),
AccountRequestStatus.APPROVED,
null);

// set registration key to the old value if exists
if (oldEntity.getRegistrationKey() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import teammates.client.connector.DatastoreClient;
import teammates.client.util.ClientProperties;
import teammates.common.datatransfer.AccountRequestStatus;
import teammates.common.util.HibernateUtil;
import teammates.storage.entity.UsageStatistics;
import teammates.storage.sqlentity.Notification;
Expand Down Expand Up @@ -43,7 +44,9 @@ protected void verifySqlConnection() {
teammates.storage.sqlentity.AccountRequest newEntity = new teammates.storage.sqlentity.AccountRequest(
"[email protected]",
"dummy-teammates-account-request",
"dummy-teammates-institute");
"dummy-teammates-institute",
AccountRequestStatus.PENDING,
"dummy-comments");
HibernateUtil.beginTransaction();
HibernateUtil.persist(newEntity);
HibernateUtil.commitTransaction();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.Map;
import java.util.UUID;

import teammates.common.datatransfer.AccountRequestStatus;
import teammates.common.datatransfer.InstructorPermissionRole;
import teammates.common.datatransfer.attributes.AccountAttributes;
import teammates.common.datatransfer.attributes.AccountRequestAttributes;
Expand Down Expand Up @@ -128,7 +129,11 @@ protected Account convert(AccountAttributes accAttr) {
protected AccountRequest convert(AccountRequestAttributes accReqAttr) {
AccountRequest sqlAccountRequest = new AccountRequest(accReqAttr.getEmail(),
accReqAttr.getName(),
accReqAttr.getInstitute());
accReqAttr.getInstitute(), AccountRequestStatus.APPROVED, null);

if (accReqAttr.getRegisteredAt() != null) {
sqlAccountRequest.setStatus(AccountRequestStatus.REGISTERED);
}

sqlAccountRequest.setCreatedAt(accReqAttr.getCreatedAt());
sqlAccountRequest.setRegisteredAt(accReqAttr.getRegisteredAt());
Expand Down
26 changes: 0 additions & 26 deletions src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import teammates.common.util.AppUrl;
import teammates.common.util.Const;
import teammates.e2e.pageobjects.AdminHomePage;
import teammates.storage.sqlentity.AccountRequest;

/**
* SUT: {@link Const.WebPageURIs#ADMIN_HOME_PAGE}.
Expand Down Expand Up @@ -47,31 +46,6 @@ public void testAll() {
String failureMessage = homePage.getMessageForInstructor(1);
assertTrue(failureMessage.contains(
"\"invalidemail\" is not acceptable to TEAMMATES as a/an email because it is not in the correct format."));

assertNotNull(BACKDOOR.getAccountRequest(email, institute));
BACKDOOR.deleteAccountRequest(email, institute);

______TS("Failure case: Instructor is already registered");
AccountRequest registeredAccountRequest = sqlTestData.accountRequests.get("AHome.instructor1OfCourse1");
homePage.queueInstructorForAdding(registeredAccountRequest.getName(),
registeredAccountRequest.getEmail(), registeredAccountRequest.getInstitute());

homePage.addAllInstructors();

failureMessage = homePage.getMessageForInstructor(2);
assertTrue(failureMessage.contains("Cannot create account request as instructor has already registered."));

______TS("Success case: Reset account request");

homePage.clickMoreInfoButtonForRegisteredInstructor(2);
homePage.clickResetAccountRequestLink();

successMessage = homePage.getMessageForInstructor(2);
assertTrue(successMessage.contains(
"Instructor \"" + registeredAccountRequest.getName() + "\" has been successfully created"));

assertNull(BACKDOOR.getAccountRequest(
registeredAccountRequest.getEmail(), registeredAccountRequest.getInstitute()).getRegisteredAt());
}

}
6 changes: 3 additions & 3 deletions src/e2e/java/teammates/e2e/cases/AdminSearchPageE2ETest.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public void testAll() {
searchPage.inputSearchContent(searchContent);
searchPage.clickSearchButton();
searchPage.clickResetAccountRequestButton(accountRequest);
assertNull(BACKDOOR.getAccountRequest(accountRequest.getEmail(), accountRequest.getInstitute()).getRegisteredAt());
assertNull(BACKDOOR.getAccountRequest(accountRequest.getId()).getRegisteredAt());

______TS("Typical case: Delete account request successful");
accountRequest = sqlTestData.accountRequests.get("unregisteredInstructor1");
Expand All @@ -141,7 +141,7 @@ public void testAll() {
searchPage.inputSearchContent(searchContent);
searchPage.clickSearchButton();
searchPage.clickDeleteAccountRequestButton(accountRequest);
assertNull(BACKDOOR.getAccountRequest(accountRequest.getEmail(), accountRequest.getInstitute()));
assertNull(BACKDOOR.getAccountRequest(accountRequest.getId()));
}

private String getExpectedStudentDetails(StudentAttributes student) {
Expand Down Expand Up @@ -193,7 +193,7 @@ private String getExpectedInstructorManageAccountLink(InstructorAttributes instr
@AfterClass
public void classTeardown() {
for (AccountRequest request : sqlTestData.accountRequests.values()) {
BACKDOOR.deleteAccountRequest(request.getEmail(), request.getInstitute());
BACKDOOR.deleteAccountRequest(request.getId());
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/e2e/java/teammates/e2e/cases/BaseE2ETestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;

import org.testng.ITestContext;
import org.testng.annotations.AfterClass;
Expand Down Expand Up @@ -329,7 +330,7 @@ protected String getKeyForStudent(StudentAttributes student) {

@Override
protected AccountRequestAttributes getAccountRequest(AccountRequestAttributes accountRequest) {
return BACKDOOR.getAccountRequest(accountRequest.getEmail(), accountRequest.getInstitute());
return BACKDOOR.getAccountRequest(UUID.fromString(accountRequest.getId()));
}

NotificationAttributes getNotification(String notificationId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public void testAll() {
______TS("Click join link: valid account request key");

String regKey = BACKDOOR
.getRegKeyForAccountRequest("ICJoinConf.newinstr@gmail.tmt", "TEAMMATES Test Institute 1");
.getRegKeyForAccountRequest(sqlTestData.accountRequests.get("ICJoinConf.newinstr").getId());

joinLink = createFrontendUrl(Const.WebPageURIs.JOIN_PAGE)
.withIsCreatingAccount("true")
Expand Down
55 changes: 55 additions & 0 deletions src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package teammates.e2e.cases.sql;

import org.testng.annotations.Test;

import teammates.common.util.AppUrl;
import teammates.common.util.Const;
import teammates.e2e.pageobjects.AdminHomePage;

/**
* SUT: {@link Const.WebPageURIs#ADMIN_HOME_PAGE}.
*/
public class AdminHomePageE2ETest extends BaseE2ETestCase {

@Override
protected void prepareTestData() {
// not needed
}

@Test
@Override
public void testAll() {
AppUrl url = createFrontendUrl(Const.WebPageURIs.ADMIN_HOME_PAGE);
AdminHomePage homePage = loginAdminToPage(url, AdminHomePage.class);

______TS("Test adding instructors with both valid and invalid details");

String name = "AHPUiT Instrúctör WithPlusInEmail";
String email = "[email protected]";
String institute = "TEAMMATES Test Institute 1";

homePage.queueInstructorForAdding(name, email, institute);

String singleLineDetails = "Instructor With Invalid Email | invalidemail | TEAMMATES Test Institute 1";

homePage.queueInstructorForAdding(singleLineDetails);

homePage.addAllInstructors();

String successMessage = homePage.getMessageForInstructor(0);
assertTrue(successMessage.contains(
"Instructor \"AHPUiT Instrúctör WithPlusInEmail\" has been successfully created"));

String failureMessage = homePage.getMessageForInstructor(1);
assertTrue(failureMessage.contains(
"\"invalidemail\" is not acceptable to TEAMMATES as a/an email because it is not in the correct format."));

homePage.reloadPage();

______TS("Verify that newly added instructor appears in account request table");

homePage.verifyInstructorInAccountRequestTable(name, email, institute);

}

}
107 changes: 102 additions & 5 deletions src/e2e/java/teammates/e2e/cases/sql/AdminSearchPageE2ETest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;

import teammates.common.datatransfer.AccountRequestStatus;
import teammates.common.util.AppUrl;
import teammates.common.util.Const;
import teammates.common.util.FieldValidator;
import teammates.common.util.StringHelperExtension;
import teammates.e2e.pageobjects.AdminSearchPage;
import teammates.e2e.util.TestProperties;
import teammates.storage.sqlentity.AccountRequest;
Expand Down Expand Up @@ -116,7 +119,7 @@ public void testAll() {
searchPage.inputSearchContent(searchContent);
searchPage.clickSearchButton();
searchPage.clickResetAccountRequestButton(accountRequest);
assertNull(BACKDOOR.getAccountRequest(accountRequest.getEmail(), accountRequest.getInstitute()).getRegisteredAt());
assertNull(BACKDOOR.getAccountRequest(accountRequest.getId()).getRegisteredAt());

______TS("Typical case: Delete account request successful");
accountRequest = testData.accountRequests.get("unregisteredInstructor1");
Expand All @@ -125,14 +128,108 @@ public void testAll() {
searchPage.inputSearchContent(searchContent);
searchPage.clickSearchButton();
searchPage.clickDeleteAccountRequestButton(accountRequest);
assertNull(BACKDOOR.getAccountRequest(accountRequest.getEmail(), accountRequest.getInstitute()));
assertNull(BACKDOOR.getAccountRequest(accountRequest.getId()));

______TS("Typical case: Edit account request successful");
accountRequest = testData.accountRequests.get("unregisteredInstructor2");
searchContent = accountRequest.getEmail();
searchPage.clearSearchBox();
searchPage.inputSearchContent(searchContent);
searchPage.clickSearchButton();
searchPage.clickEditAccountRequestButton(accountRequest);
searchPage.fillInEditModalFields("Different name", accountRequest.getEmail(),
accountRequest.getInstitute(), "New comment");
searchPage.clickSaveEditAccountRequestButton();
accountRequest.setName("Different name");
accountRequest.setComments("New comment");
searchPage.verifyAccountRequestRowContent(accountRequest);

______TS("Typical case: View comment of account request");
accountRequest = testData.accountRequests.get("unregisteredInstructor2");
searchContent = accountRequest.getEmail();
searchPage.clearSearchBox();
searchPage.inputSearchContent(searchContent);
searchPage.clickSearchButton();
searchPage.clickViewAccountRequestAndVerifyCommentsButton(accountRequest, "New comment");

______TS("Edit account request with invalid details");
accountRequest = testData.accountRequests.get("unregisteredInstructor2");
searchContent = accountRequest.getEmail();
searchPage.clearSearchBox();
searchPage.inputSearchContent(searchContent);
searchPage.clickSearchButton();
searchPage.clickEditAccountRequestButton(accountRequest);
searchPage.fillInEditModalFields(accountRequest.getName(), "invalid",
accountRequest.getInstitute(), "New comment");
searchPage.clickSaveEditAccountRequestButton();
String formattedErrorMessage = String.format("\"%s\" is not acceptable to TEAMMATES as a/an %s because it %s. "
+ "An email address contains some text followed by one '@' sign followed by some more text, "
+ "and should end with a top level domain address like .com. It cannot be longer than %d characters, "
+ "cannot be empty and cannot contain spaces.",
"invalid", FieldValidator.EMAIL_FIELD_NAME, FieldValidator.REASON_INCORRECT_FORMAT,
FieldValidator.EMAIL_MAX_LENGTH);
searchPage.verifyStatusMessage(formattedErrorMessage);

String name = StringHelperExtension.generateStringOfLength(FieldValidator.PERSON_NAME_MAX_LENGTH + 1);

searchPage.clickEditAccountRequestButton(accountRequest);
searchPage.fillInEditModalFields(name, accountRequest.getEmail(), accountRequest.getInstitute(), "New comment");
searchPage.clickSaveEditAccountRequestButton();
formattedErrorMessage = String.format("\"%s\" is not acceptable to TEAMMATES as a/an %s because it %s. "
+ "The value of a/an %s should be no longer than %d characters. It should not be empty.",
name, FieldValidator.PERSON_NAME_FIELD_NAME, FieldValidator.REASON_TOO_LONG,
FieldValidator.PERSON_NAME_FIELD_NAME, FieldValidator.PERSON_NAME_MAX_LENGTH);
searchPage.verifyStatusMessage(formattedErrorMessage);

______TS("Typical case: Approve account request successful");
accountRequest = testData.accountRequests.get("unregisteredInstructor2");
searchContent = accountRequest.getEmail();
searchPage.clearSearchBox();
searchPage.inputSearchContent(searchContent);
searchPage.clickSearchButton();
searchPage.clickApproveAccountRequestButton(accountRequest);
accountRequest.setStatus(AccountRequestStatus.APPROVED);
searchPage.verifyAccountRequestRowContent(accountRequest);

______TS("Typical case: Reject account request successfully");
accountRequest = testData.accountRequests.get("unregisteredInstructor3");
searchContent = accountRequest.getEmail();
searchPage.clearSearchBox();
searchPage.inputSearchContent(searchContent);
searchPage.clickSearchButton();
searchPage.clickRejectAccountRequestButton(accountRequest);
accountRequest.setStatus(AccountRequestStatus.REJECTED);
searchPage.verifyAccountRequestRowContent(accountRequest);

______TS("Reject account request with empty body");
accountRequest = testData.accountRequests.get("unregisteredInstructor5");
searchContent = accountRequest.getEmail();
searchPage.clearSearchBox();
searchPage.inputSearchContent(searchContent);
searchPage.clickSearchButton();
searchPage.clickRejectAccountRequestWithReasonButton(accountRequest);
searchPage.fillInRejectionModalBody("");
searchPage.clickConfirmRejectAccountRequest();
searchPage.verifyStatusMessage("Please provide an email body for the rejection email.");
searchPage.closeRejectionModal();

______TS("Typical case: Reject account request with reason successfully");
accountRequest = testData.accountRequests.get("unregisteredInstructor4");
searchContent = accountRequest.getEmail();
searchPage.clearSearchBox();
searchPage.inputSearchContent(searchContent);
searchPage.clickSearchButton();
searchPage.clickRejectAccountRequestWithReasonButton(accountRequest);
accountRequest.setStatus(AccountRequestStatus.REJECTED);
searchPage.verifyAccountRequestRowContent(accountRequest);
}

private String getExpectedStudentDetails(Student student) {
return String.format("%s [%s] (%s)", student.getCourse().getId(),
student.getSection() == null
? Const.DEFAULT_SECTION
: student.getSection().getName(), student.getTeam().getName());
? Const.DEFAULT_SECTION
: student.getSection().getName(),
student.getTeam().getName());
}

private String getExpectedStudentHomePageLink(Student student) {
Expand Down Expand Up @@ -179,7 +276,7 @@ private String getExpectedInstructorManageAccountLink(Instructor instructor) {
@AfterClass
public void classTeardown() {
for (AccountRequest request : testData.accountRequests.values()) {
BACKDOOR.deleteAccountRequest(request.getEmail(), request.getInstitute());
BACKDOOR.deleteAccountRequest(request.getId());
}
}
}
Loading
Loading