Skip to content

Commit

Permalink
Merge branch 'master' into FIX/13160/update-docs-for-docker
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonqiu212 authored Feb 18, 2025
2 parents cc33752 + 7dc4ef9 commit efc7b05
Show file tree
Hide file tree
Showing 10 changed files with 761 additions and 8 deletions.
5 changes: 4 additions & 1 deletion src/main/java/teammates/common/util/StringHelper.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package teammates.common.util;

import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -179,7 +180,9 @@ public static <T> String toString(List<T> list, String delimiter) {
* Converts a double value between 0 and 1 to 3dp-string.
*/
public static String toDecimalFormatString(double doubleVal) {
DecimalFormat df = new DecimalFormat("0.###");
DecimalFormatSymbols syms = new DecimalFormatSymbols();
syms.setDecimalSeparator('.');
DecimalFormat df = new DecimalFormat("0.###", syms);
return df.format(doubleVal);
}

Expand Down
5 changes: 4 additions & 1 deletion src/main/java/teammates/common/util/TimeHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Locale;

/**
* A helper class to hold time-related functions (e.g., converting dates to strings etc.).
Expand Down Expand Up @@ -105,7 +106,9 @@ public static String formatInstant(Instant instant, String timeZone, String patt
if (zonedDateTime.getHour() == 12 && zonedDateTime.getMinute() == 0) {
processedPattern = pattern.replace("a", "'NOON'");
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(processedPattern);
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern(processedPattern)
.withLocale(Locale.US);
return zonedDateTime.format(formatter);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/teammates/ui/webapi/DeleteAccountAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/**
* Action: deletes an existing account (either student or instructor).
*/
class DeleteAccountAction extends AdminOnlyAction {
public class DeleteAccountAction extends AdminOnlyAction {

@Override
public JsonResult execute() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public void testIsInstructorCommentsOnResponsesAllowed_shouldReturnTrue() {
}

@Test
public void tesValidateResponseDetails() {
public void testValidateResponseDetails() {
FeedbackNumericalScaleQuestionDetails numScaleQuestion = new FeedbackNumericalScaleQuestionDetails();
numScaleQuestion.setStep(0.1);

Expand Down
55 changes: 55 additions & 0 deletions src/test/java/teammates/sqlui/webapi/DeleteAccountActionTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package teammates.sqlui.webapi;

import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import org.testng.annotations.Test;

import teammates.common.datatransfer.InstructorPrivileges;
import teammates.common.util.Const;
import teammates.storage.sqlentity.Account;
import teammates.storage.sqlentity.Course;
import teammates.storage.sqlentity.Instructor;
import teammates.ui.output.MessageOutput;
import teammates.ui.webapi.DeleteAccountAction;

/**
* SUT: {@link DeleteAccountAction}.
*/
public class DeleteAccountActionTest extends BaseActionTest<DeleteAccountAction> {
String googleId = "user-googleId";

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

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

@Test
protected void textExecute_nullParams_throwsInvalidHttpParameterException() {
String[] params = {
Const.ParamsNames.INSTRUCTOR_ID, null,
};
verifyHttpParameterFailure(params);
}

@Test
protected void testExecute_nonNullParams_success() {
Course stubCourse = new Course("course-id", "name", Const.DEFAULT_TIME_ZONE, "institute");
Account stubAccount = new Account(googleId, "name", "[email protected]");
Instructor instructor = new Instructor(stubCourse, "name", "[email protected]",
false, "", null, new InstructorPrivileges());
instructor.setAccount(stubAccount);
String[] params = {
Const.ParamsNames.INSTRUCTOR_ID, instructor.getGoogleId(),
};
DeleteAccountAction action = getAction(params);
MessageOutput actionOutput = (MessageOutput) getJsonResult(action).getOutput();
assertEquals("Account is successfully deleted.", actionOutput.getMessage());
verify(mockLogic, times(1)).deleteAccountCascade(googleId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package teammates.sqlui.webapi;

import static org.mockito.Mockito.when;
import static teammates.common.util.Const.InstructorPermissionRoleNames.INSTRUCTOR_PERMISSION_ROLE_OBSERVER;

import java.util.UUID;

import org.testng.annotations.Test;

import teammates.common.datatransfer.InstructorPrivileges;
import teammates.common.util.Const;
import teammates.storage.sqlentity.Course;
import teammates.storage.sqlentity.FeedbackQuestion;
import teammates.storage.sqlentity.FeedbackSession;
import teammates.storage.sqlentity.Instructor;
import teammates.ui.output.MessageOutput;
import teammates.ui.webapi.DeleteFeedbackQuestionAction;

/**
* SUT: {@link DeleteFeedbackQuestionAction}.
*/
public class DeleteFeedbackQuestionActionTest extends BaseActionTest<DeleteFeedbackQuestionAction> {

private final Instructor typicalInstructor = getTypicalInstructor();
private final Course typicalCourse = typicalInstructor.getCourse();
private final FeedbackSession typicalFeedbackSession = getTypicalFeedbackSessionForCourse(typicalCourse);
private final FeedbackQuestion typicalFeedbackQuestion =
getTypicalFeedbackQuestionForSession(typicalFeedbackSession);

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

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

@Test
void testExecute_feedbackQuestionExists_success() {
when(mockLogic.getFeedbackQuestion(typicalFeedbackQuestion.getId())).thenReturn(typicalFeedbackQuestion);

String[] params = {
Const.ParamsNames.FEEDBACK_QUESTION_ID, typicalFeedbackQuestion.getId().toString(),
};

DeleteFeedbackQuestionAction action = getAction(params);
MessageOutput actionOutput = (MessageOutput) getJsonResult(action).getOutput();

assertEquals("Feedback question deleted!", actionOutput.getMessage());
}

@Test
void testExecute_feedbackQuestionDoesNotExist_failSilently() {
UUID nonexistentQuestionId = UUID.fromString("11110000-0000-0000-0000-000000000000");
when(mockLogic.getFeedbackQuestion(nonexistentQuestionId)).thenReturn(null);

String[] params = {
Const.ParamsNames.FEEDBACK_QUESTION_ID, nonexistentQuestionId.toString(),
};

DeleteFeedbackQuestionAction action = getAction(params);
MessageOutput actionOutput = (MessageOutput) getJsonResult(action).getOutput();

assertEquals("Feedback question deleted!", actionOutput.getMessage());
}

@Test
void testExecute_missingFeedbackQuestionId_throwsInvalidHttpParameterException() {
String[] params = {
Const.ParamsNames.FEEDBACK_QUESTION_ID, null,
};

verifyHttpParameterFailure(params);
}

@Test
void testSpecificAccessControl_nonExistentFeedbackQuestion_cannotAccess() {
when(mockLogic.getFeedbackQuestion(typicalFeedbackQuestion.getId())).thenReturn(null);
String[] submissionParams = {
Const.ParamsNames.FEEDBACK_QUESTION_ID, typicalFeedbackQuestion.getId().toString(),
};

verifyCannotAccess(submissionParams);
}

@Test
void testSpecificAccessControl_withModifySessionPrivilege_canAccess() {
when(mockLogic.getFeedbackQuestion(typicalFeedbackQuestion.getId())).thenReturn(typicalFeedbackQuestion);
when(mockLogic.getFeedbackSession(typicalFeedbackQuestion.getFeedbackSession().getName(),
typicalFeedbackQuestion.getCourseId())).thenReturn(typicalFeedbackSession);
when(mockLogic.getInstructorByGoogleId(typicalCourse.getId(), typicalInstructor.getGoogleId()))
.thenReturn(typicalInstructor);

String[] submissionParams = {
Const.ParamsNames.FEEDBACK_QUESTION_ID, typicalFeedbackQuestion.getId().toString(),
};

loginAsInstructor(typicalInstructor.getGoogleId());
verifyCanAccess(submissionParams);
}

@Test
void testSpecificAccessControl_withoutModifySessionPrivilege_cannotAccess() {
// create instructor without modify session privilege
Instructor instructorWithoutAccess = getTypicalInstructor();
instructorWithoutAccess.setPrivileges(new InstructorPrivileges(INSTRUCTOR_PERMISSION_ROLE_OBSERVER));

when(mockLogic.getFeedbackQuestion(typicalFeedbackQuestion.getId())).thenReturn(typicalFeedbackQuestion);
when(mockLogic.getFeedbackSession(typicalFeedbackQuestion.getFeedbackSession().getName(),
typicalFeedbackQuestion.getCourseId())).thenReturn(typicalFeedbackSession);
when(mockLogic.getInstructorByGoogleId(typicalCourse.getId(), instructorWithoutAccess.getGoogleId()))
.thenReturn(instructorWithoutAccess);

String[] submissionParams = {
Const.ParamsNames.FEEDBACK_QUESTION_ID, typicalFeedbackQuestion.getId().toString(),
};

loginAsInstructor(instructorWithoutAccess.getGoogleId());
verifyCannotAccess(submissionParams);
}

}
Loading

0 comments on commit efc7b05

Please sign in to comment.