Skip to content

Commit

Permalink
[#11878] Create Update Account Request Action (#12982)
Browse files Browse the repository at this point in the history
* create update action and IT

* update javadocs

* update tests

* add more tests

* simplify logic

* remove unused string

* fix test

* allow null comments

* add more tests

* use EntityNotFoundException

* cleanup after create account requests test

* remove unncessary check
  • Loading branch information
domoberzin committed Apr 5, 2024
1 parent de3181a commit 5779d2f
Show file tree
Hide file tree
Showing 6 changed files with 378 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package teammates.it.ui.webapi;

import java.util.List;

import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

Expand Down Expand Up @@ -221,4 +224,16 @@ protected void testAccessControl() throws Exception {
verifyAccessibleWithoutLogin();
}

@Override
@AfterMethod
protected void tearDown() {
HibernateUtil.beginTransaction();
List<AccountRequest> accountRequests = logic.getPendingAccountRequests();
for (AccountRequest ar : accountRequests) {
logic.deleteAccountRequest(ar.getEmail(), ar.getInstitute());
}
accountRequests = logic.getPendingAccountRequests();
HibernateUtil.commitTransaction();
assert accountRequests.isEmpty();
}
}
223 changes: 223 additions & 0 deletions src/it/java/teammates/it/ui/webapi/UpdateAccountRequestActionIT.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
package teammates.it.ui.webapi;

import java.util.UUID;

import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import teammates.common.datatransfer.AccountRequestStatus;
import teammates.common.exception.EntityAlreadyExistsException;
import teammates.common.exception.InvalidParametersException;
import teammates.common.util.Const;
import teammates.common.util.FieldValidator;
import teammates.common.util.HibernateUtil;
import teammates.common.util.StringHelperExtension;
import teammates.storage.sqlentity.AccountRequest;
import teammates.storage.sqlentity.Course;
import teammates.ui.output.AccountRequestData;
import teammates.ui.request.AccountRequestUpdateRequest;
import teammates.ui.request.InvalidHttpRequestBodyException;
import teammates.ui.webapi.EntityNotFoundException;
import teammates.ui.webapi.InvalidHttpParameterException;
import teammates.ui.webapi.JsonResult;
import teammates.ui.webapi.UpdateAccountRequestAction;

/**
* SUT: {@link UpdateAccountRequestAction}.
*/
public class UpdateAccountRequestActionIT extends BaseActionIT<UpdateAccountRequestAction> {

@Override
@BeforeMethod
protected void setUp() throws Exception {
super.setUp();
persistDataBundle(typicalBundle);
HibernateUtil.flushSession();
}

@Override
protected String getActionUri() {
return Const.ResourceURIs.ACCOUNT_REQUEST;
}

@Override
protected String getRequestMethod() {
return PUT;
}

@Override
@Test
public void testExecute() throws Exception {
______TS("edit fields of an account request");
AccountRequest accountRequest = typicalBundle.accountRequests.get("unregisteredInstructor1");
accountRequest.setStatus(AccountRequestStatus.PENDING);
UUID id = accountRequest.getId();
String name = "newName";
String email = "newEmail@email.com";
String institute = "newInstitute";
String comments = "newComments";
AccountRequestStatus status = accountRequest.getStatus();

AccountRequestUpdateRequest requestBody = new AccountRequestUpdateRequest(name, email, institute, status, comments);
String[] params = new String[] {Const.ParamsNames.ACCOUNT_REQUEST_ID, id.toString()};

UpdateAccountRequestAction action = getAction(requestBody, params);
JsonResult result = action.execute();

assertEquals(result.getStatusCode(), 200);
AccountRequestData data = (AccountRequestData) result.getOutput();

assertEquals(name, data.getName());
assertEquals(email, data.getEmail());
assertEquals(institute, data.getInstitute());
assertEquals(status, data.getStatus());
assertEquals(comments, data.getComments());
verifyNoEmailsSent();

______TS("approve a pending account request");
accountRequest = typicalBundle.accountRequests.get("unregisteredInstructor2");
accountRequest.setStatus(AccountRequestStatus.PENDING);
requestBody = new AccountRequestUpdateRequest(accountRequest.getName(), accountRequest.getEmail(),
accountRequest.getInstitute(), AccountRequestStatus.APPROVED, accountRequest.getComments());
params = new String[] {Const.ParamsNames.ACCOUNT_REQUEST_ID, accountRequest.getId().toString()};
action = getAction(requestBody, params);
result = getJsonResult(action, 200);
data = (AccountRequestData) result.getOutput();

assertEquals(accountRequest.getName(), data.getName());
assertEquals(accountRequest.getEmail(), data.getEmail());
assertEquals(accountRequest.getInstitute(), data.getInstitute());
assertEquals(AccountRequestStatus.APPROVED, data.getStatus());
assertEquals(accountRequest.getComments(), data.getComments());
verifyNumberOfEmailsSent(1);

______TS("already registered account request has no email sent when approved");
accountRequest = typicalBundle.accountRequests.get("instructor2");
requestBody = new AccountRequestUpdateRequest(name, email, institute, AccountRequestStatus.APPROVED, comments);
params = new String[] {Const.ParamsNames.ACCOUNT_REQUEST_ID, accountRequest.getId().toString()};

action = getAction(requestBody, params);
result = getJsonResult(action, 200);
data = (AccountRequestData) result.getOutput();

assertEquals(name, data.getName());
assertEquals(email, data.getEmail());
assertEquals(institute, data.getInstitute());
assertEquals(AccountRequestStatus.REGISTERED, data.getStatus());
assertEquals(comments, data.getComments());
verifyNumberOfEmailsSent(0);

______TS("non-existent but valid uuid");
requestBody = new AccountRequestUpdateRequest("name", "email",
"institute", AccountRequestStatus.PENDING, "comments");
String validUuid = UUID.randomUUID().toString();
params = new String[] {Const.ParamsNames.ACCOUNT_REQUEST_ID, validUuid};

EntityNotFoundException enfe = verifyEntityNotFound(requestBody, params);

assertEquals(String.format("Account request with id = %s not found", validUuid), enfe.getMessage());

______TS("invalid uuid");
requestBody = new AccountRequestUpdateRequest("name", "email",
"institute", AccountRequestStatus.PENDING, "comments");
params = new String[] {Const.ParamsNames.ACCOUNT_REQUEST_ID, "invalid"};

InvalidHttpParameterException ihpe = verifyHttpParameterFailure(requestBody, params);

assertEquals("Invalid UUID string: invalid", ihpe.getMessage());

______TS("invalid email");
accountRequest = typicalBundle.accountRequests.get("unregisteredInstructor1");
id = accountRequest.getId();
email = "newEmail";
status = accountRequest.getStatus();

requestBody = new AccountRequestUpdateRequest(name, email, institute, status, comments);
params = new String[] {Const.ParamsNames.ACCOUNT_REQUEST_ID, id.toString()};

InvalidHttpRequestBodyException ihrbe = verifyHttpRequestBodyFailure(requestBody, params);

assertEquals(getPopulatedErrorMessage(FieldValidator.EMAIL_ERROR_MESSAGE, email,
FieldValidator.EMAIL_FIELD_NAME, FieldValidator.REASON_INCORRECT_FORMAT, FieldValidator.EMAIL_MAX_LENGTH),
ihrbe.getMessage());

______TS("invalid name alphanumeric");
name = "@$@#$#@#@$#@$";
email = "newEmail@email.com";

requestBody = new AccountRequestUpdateRequest(name, email, institute, status, comments);
params = new String[] {Const.ParamsNames.ACCOUNT_REQUEST_ID, id.toString()};

ihrbe = verifyHttpRequestBodyFailure(requestBody, params);

assertEquals(getPopulatedErrorMessage(FieldValidator.INVALID_NAME_ERROR_MESSAGE, name,
FieldValidator.PERSON_NAME_FIELD_NAME, FieldValidator.REASON_START_WITH_NON_ALPHANUMERIC_CHAR),
ihrbe.getMessage());

______TS("invalid name too long");
name = StringHelperExtension.generateStringOfLength(FieldValidator.PERSON_NAME_MAX_LENGTH + 1);

requestBody = new AccountRequestUpdateRequest(name, email, institute, status, comments);
params = new String[] {Const.ParamsNames.ACCOUNT_REQUEST_ID, id.toString()};

ihrbe = verifyHttpRequestBodyFailure(requestBody, params);

assertEquals(getPopulatedErrorMessage(FieldValidator.SIZE_CAPPED_NON_EMPTY_STRING_ERROR_MESSAGE, name,
FieldValidator.PERSON_NAME_FIELD_NAME, FieldValidator.REASON_TOO_LONG,
FieldValidator.PERSON_NAME_MAX_LENGTH), ihrbe.getMessage());

______TS("null email value");
name = "newName";

requestBody = new AccountRequestUpdateRequest(name, null, institute, status, comments);
params = new String[] {Const.ParamsNames.ACCOUNT_REQUEST_ID, id.toString()};

ihrbe = verifyHttpRequestBodyFailure(requestBody, params);

assertEquals("email cannot be null", ihrbe.getMessage());

______TS("null name value");
requestBody = new AccountRequestUpdateRequest(null, email, institute, status, comments);
params = new String[] {Const.ParamsNames.ACCOUNT_REQUEST_ID, id.toString()};

ihrbe = verifyHttpRequestBodyFailure(requestBody, params);

assertEquals("name cannot be null", ihrbe.getMessage());

______TS("null status value");
requestBody = new AccountRequestUpdateRequest(name, email, institute, null, comments);
params = new String[] {Const.ParamsNames.ACCOUNT_REQUEST_ID, id.toString()};

ihrbe = verifyHttpRequestBodyFailure(requestBody, params);

assertEquals("status cannot be null", ihrbe.getMessage());

______TS("null institute value");
requestBody = new AccountRequestUpdateRequest(name, email, null, status, comments);
params = new String[] {Const.ParamsNames.ACCOUNT_REQUEST_ID, id.toString()};

ihrbe = verifyHttpRequestBodyFailure(requestBody, params);

assertEquals("institute cannot be null", ihrbe.getMessage());

______TS("allow null comments in request");
requestBody = new AccountRequestUpdateRequest(name, email, institute, status, null);
params = new String[] {Const.ParamsNames.ACCOUNT_REQUEST_ID, id.toString()};

action = getAction(requestBody, params);
result = getJsonResult(action, 200);
data = (AccountRequestData) result.getOutput();

assertEquals(name, data.getName());
assertEquals(email, data.getEmail());
assertEquals(institute, data.getInstitute());
assertEquals(null, data.getComments());
}

@Override
@Test
protected void testAccessControl() throws InvalidParametersException, EntityAlreadyExistsException {
Course course = typicalBundle.courses.get("course1");
verifyOnlyAdminCanAccess(course);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package teammates.ui.request;

import javax.annotation.Nullable;

import teammates.common.datatransfer.AccountRequestStatus;
import teammates.common.util.SanitizationHelper;

/**
* The create request for an account request update request.
*/
public class AccountRequestUpdateRequest extends BasicRequest {
private String name;
private String email;
private String institute;
private AccountRequestStatus status;

@Nullable
private String comments;

public AccountRequestUpdateRequest(String name, String email, String institute, AccountRequestStatus status,
String comments) {
this.name = SanitizationHelper.sanitizeName(name);
this.email = SanitizationHelper.sanitizeEmail(email);
this.institute = SanitizationHelper.sanitizeName(institute);
this.status = status;
if (comments != null) {
this.comments = SanitizationHelper.sanitizeTextField(comments);
}
}

@Override
public void validate() throws InvalidHttpRequestBodyException {
assertTrue(name != null, "name cannot be null");
assertTrue(email != null, "email cannot be null");
assertTrue(institute != null, "institute cannot be null");
assertTrue(status != null, "status cannot be null");
assertTrue(status == AccountRequestStatus.APPROVED
|| status == AccountRequestStatus.REJECTED
|| status == AccountRequestStatus.PENDING
|| status == AccountRequestStatus.REGISTERED,
"status must be one of the following: APPROVED, REJECTED, PENDING, REGISTERED");
}

public String getName() {
return this.name;
}

public String getEmail() {
return this.email;
}

public String getInstitute() {
return this.institute;
}

public AccountRequestStatus getStatus() {
return this.status;
}

public String getComments() {
return this.comments;
}
}
1 change: 1 addition & 0 deletions src/main/java/teammates/ui/webapi/ActionFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public final class ActionFactory {
map(ResourceURIs.ACCOUNT_REQUEST, GET, GetAccountRequestAction.class);
map(ResourceURIs.ACCOUNT_REQUEST, POST, CreateAccountRequestAction.class);
map(ResourceURIs.ACCOUNT_REQUEST, DELETE, DeleteAccountRequestAction.class);
map(ResourceURIs.ACCOUNT_REQUEST, PUT, UpdateAccountRequestAction.class);
map(ResourceURIs.ACCOUNT_REQUESTS, GET, GetAccountRequestsAction.class);
map(ResourceURIs.ACCOUNT_REQUEST_RESET, PUT, ResetAccountRequestAction.class);
map(ResourceURIs.ACCOUNTS, GET, GetAccountsAction.class);
Expand Down
75 changes: 75 additions & 0 deletions src/main/java/teammates/ui/webapi/UpdateAccountRequestAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package teammates.ui.webapi;

import java.util.UUID;

import teammates.common.datatransfer.AccountRequestStatus;
import teammates.common.exception.EntityDoesNotExistException;
import teammates.common.exception.InvalidParametersException;
import teammates.common.util.Const;
import teammates.common.util.EmailWrapper;
import teammates.storage.sqlentity.AccountRequest;
import teammates.ui.output.AccountRequestData;
import teammates.ui.request.AccountRequestUpdateRequest;
import teammates.ui.request.InvalidHttpRequestBodyException;

/**
* Updates an account request.
*/
public class UpdateAccountRequestAction extends AdminOnlyAction {

static final String ACCOUNT_REQUEST_NOT_FOUND = "Account request with id = %s not found";

@Override
public JsonResult execute() throws InvalidOperationException, InvalidHttpRequestBodyException {
String id = getNonNullRequestParamValue(Const.ParamsNames.ACCOUNT_REQUEST_ID);
UUID accountRequestId;

try {
accountRequestId = UUID.fromString(id);
} catch (IllegalArgumentException e) {
throw new InvalidHttpParameterException(e.getMessage(), e);
}

AccountRequest accountRequest = sqlLogic.getAccountRequest(accountRequestId);

if (accountRequest == null) {
String errorMessage = String.format(ACCOUNT_REQUEST_NOT_FOUND, accountRequestId.toString());
throw new EntityNotFoundException(errorMessage);
}

AccountRequestUpdateRequest accountRequestUpdateRequest =
getAndValidateRequestBody(AccountRequestUpdateRequest.class);

if (accountRequestUpdateRequest.getStatus() == AccountRequestStatus.APPROVED
&& (accountRequest.getStatus() == AccountRequestStatus.PENDING
|| accountRequest.getStatus() == AccountRequestStatus.REJECTED)) {
try {
// should not need to update other fields for an approval
accountRequest.setStatus(accountRequestUpdateRequest.getStatus());
accountRequest = sqlLogic.updateAccountRequest(accountRequest);
EmailWrapper email = sqlEmailGenerator.generateNewInstructorAccountJoinEmail(
accountRequest.getRegistrationUrl(), accountRequest.getEmail(), accountRequest.getName());
emailSender.sendEmail(email);
} catch (InvalidParametersException e) {
throw new InvalidHttpRequestBodyException(e);
} catch (EntityDoesNotExistException e) {
throw new EntityNotFoundException(e);
}
} else {
try {
accountRequest.setName(accountRequestUpdateRequest.getName());
accountRequest.setEmail(accountRequestUpdateRequest.getEmail());
accountRequest.setInstitute(accountRequestUpdateRequest.getInstitute());
accountRequest.setStatus(accountRequest.getStatus());
accountRequest.setComments(accountRequestUpdateRequest.getComments());
sqlLogic.updateAccountRequest(accountRequest);
} catch (InvalidParametersException e) {
throw new InvalidHttpRequestBodyException(e);
} catch (EntityDoesNotExistException e) {
throw new EntityNotFoundException(e);
}
}

return new JsonResult(new AccountRequestData(accountRequest));
}
}
Loading

0 comments on commit 5779d2f

Please sign in to comment.