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

Adding API to support linking runs to CK projects #14

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions src/main/java/org/wise/portal/domain/run/Run.java
Original file line number Diff line number Diff line change
Expand Up @@ -397,4 +397,8 @@ public interface Run extends Persistable {
boolean isLockedAfterEndDate();

void setLockedAfterEndDate(boolean isLockedAfterEndDate);

String getConnectCode();

void setConnectCode(String connectCode);
}
8 changes: 8 additions & 0 deletions src/main/java/org/wise/portal/domain/run/impl/RunImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ public class RunImpl implements Run {
@Transient
private static final String COLUMN_NAME_IS_LOCKED_AFTER_END_DATE = "isLockedAfterEndDate";

@Transient
private static final String COLUMN_NAME_CK_PROJECT_CODE = "ckProjectCode";

@Id
@Getter
@Setter
Expand Down Expand Up @@ -247,6 +250,11 @@ public class RunImpl implements Run {
@Setter
private boolean isRandomPeriodAssignment = false;

@Column(name = RunImpl.COLUMN_NAME_CK_PROJECT_CODE)
@Getter
@Setter
private String connectCode;

public Group getPeriodByName(String periodName) throws PeriodNotFoundException {
Set<Group> periods = getPeriods();
for (Group period : periods) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,27 @@
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.net.ssl.HttpsURLConnection;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.apache.http.HttpEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
Expand Down Expand Up @@ -216,6 +224,7 @@ public static JSONObject getRunJSON(Run run) throws JSONException {
runJSON.put("runCode", run.getRuncode());
runJSON.put("startTime", run.getStartTimeMilliseconds());
runJSON.put("endTime", run.getEndTimeMilliseconds());
runJSON.put("code", run.getConnectCode());
Set<Group> periods = run.getPeriods();
JSONArray periodsArray = new JSONArray();
for (Group period : periods) {
Expand Down Expand Up @@ -502,4 +511,56 @@ public static JSONObject createErrorResponse(String messageCode) {
}
return response;
}

/**
* Do a POST request to CK Backend for:
* 1. Linking run to CK Board project.
* 2. Unlinking run from CK Board project.
* 3. Adding members of a run to CK Board project.
*/
public static String doCkBoardPost(HttpServletRequest request, Authentication authentication,
String params, String url) {
try {
String ckSessionCookie = getCkSessionCookie(request);
if (ckSessionCookie != null) {
HttpClient client = HttpClientBuilder.create().build();
HttpPost ckBoardLinkReq = new HttpPost(getCkBoardUrl(url));
ckBoardLinkReq.addHeader("content-type", "application/json");
ckBoardLinkReq.setHeader("Authorization", "Bearer " + ckSessionCookie);
ckBoardLinkReq.setEntity(new StringEntity(params, ContentType.APPLICATION_JSON));
HttpEntity response = client.execute(ckBoardLinkReq).getEntity();
return EntityUtils.toString(response);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

public static String getCkBoardUrl(String apiEndpoint) {
String ckBoardUrl = appProperties.getProperty("ck_board_url");

// The CK Board local backend url is only used for local development and should only be set in
// local development environments. When we are running locally, we need the local IP and port of
// the CK Board backend because the SCORE API is served using Docker. If the SCORE API makes a
// request to localhost:8001, it won't be able to access the CK Board backend. This is because
// the SCORE API expects localhost to be within the container but the CK Board backend is not in
// the container.
String ckBoardLocalBackendUrl = appProperties.getProperty("ck_board_local_backend_url");
if (ckBoardLocalBackendUrl != null && !ckBoardLocalBackendUrl.equals("")) {
ckBoardUrl = ckBoardLocalBackendUrl;
}
return ckBoardUrl + apiEndpoint;
}

public static String getCkSessionCookie(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
if (cookie.getName().equals("CK_SESSION")) {
return cookie.getValue();
}
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@

import org.apache.commons.lang3.RandomStringUtils;
import org.hibernate.StaleObjectStateException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.orm.hibernate5.HibernateOptimisticLockingFailureException;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.Authentication;
Expand Down Expand Up @@ -68,11 +68,9 @@
import org.wise.portal.presentation.web.exception.InvalidNameException;
import org.wise.portal.presentation.web.response.ErrorResponse;
import org.wise.portal.presentation.web.response.LaunchRunErrorResponse;
import org.wise.portal.presentation.web.response.ResponseEntityGenerator;
import org.wise.portal.presentation.web.response.SimpleResponse;
import org.wise.portal.service.attendance.StudentAttendanceService;
import org.wise.portal.service.authentication.DuplicateUsernameException;
import org.wise.portal.service.password.PasswordService;
import org.wise.portal.service.student.StudentService;

/**
Expand All @@ -87,9 +85,6 @@
@Secured({ "ROLE_STUDENT" })
public class StudentAPIController extends UserAPIController {

@Autowired
protected PasswordService passwordService;

@Autowired
private StudentService studentService;

Expand Down Expand Up @@ -174,7 +169,6 @@ HashMap<String, Object> launchRun(Authentication auth, @RequestParam("runId") Lo
Group period = run.getPeriodOfStudent(user);
String name = "Workgroup for user: " + user.getUserDetails().getUsername();
workgroup = workgroupService.createWorkgroup(name, presentMembers, run, period);
studentService.sendNewWorkgroupJoinedRunMessage(run, period);
return getLaunchRunMap(runId, workgroupId, presentUserIds, absentUserIds, request, run,
presentMembers, workgroup);
} else {
Expand Down Expand Up @@ -264,7 +258,8 @@ private Set<User> getUsers(String[] userIds) throws ObjectNotFoundException {
*/
@PostMapping("/run/register")
HashMap<String, Object> addStudentToRun(Authentication auth,
@RequestParam("runCode") String runCode, @RequestParam("period") String period) {
@RequestParam("runCode") String runCode, @RequestParam("period") String period,
HttpServletRequest request) {
User user = userService.retrieveUserByUsername(auth.getName());
Run run = getRun(runCode);
if (run == null || run.getProject().getWiseVersion() == 4) {
Expand All @@ -278,6 +273,19 @@ HashMap<String, Object> addStudentToRun(Authentication auth,
while (currentLoopIndex < maxLoop) {
try {
studentService.addStudentToRun(user, projectCode);
String connectCode = run.getConnectCode();
if (connectCode != null && !connectCode.equals("")) {
try {
String url = "/api/projects/score/addMember";
JSONObject params = new JSONObject();
params.put("username", user.getUserDetails().getUsername());
params.put("role", "student");
params.put("code", connectCode);
ControllerUtil.doCkBoardPost(request, auth, params.toString(), url);
} catch (Exception e) {
e.printStackTrace();
}
}
HashMap<String, Object> runMap = getRunMap(user, run);
return runMap;
} catch (ObjectNotFoundException e) {
Expand Down Expand Up @@ -335,15 +343,8 @@ private List<String> getPeriodNames(Run run) {

@PostMapping("/register")
@Secured({ "ROLE_ANONYMOUS" })
ResponseEntity<Map<String, Object>> createStudentAccount(
@RequestBody Map<String, String> studentFields, HttpServletRequest request)
throws DuplicateUsernameException, InvalidNameException {
if (ControllerUtil.isReCaptchaEnabled()) {
String token = studentFields.get("token");
if (!ControllerUtil.isReCaptchaResponseValid(token)) {
return ResponseEntityGenerator.createError("recaptchaResponseInvalid");
}
}
HashMap<String, Object> createStudentAccount(@RequestBody Map<String, String> studentFields,
HttpServletRequest request) throws DuplicateUsernameException, InvalidNameException {
StudentUserDetails sud = new StudentUserDetails();
String firstName = studentFields.get("firstName");
String lastName = studentFields.get("lastName");
Expand All @@ -362,14 +363,7 @@ ResponseEntity<Map<String, Object>> createStudentAccount(
sud.setGoogleUserId(studentFields.get("googleUserId"));
sud.setPassword(RandomStringUtils.random(10, true, true));
} else {
String password = studentFields.get("password");
if (!passwordService.isValidLength(password)) {
return ResponseEntityGenerator.createError("invalidPasswordLength");
} else if (!passwordService.isValidPattern(password)) {
return ResponseEntityGenerator.createError("invalidPasswordPattern");
} else {
sud.setPassword(password);
}
sud.setPassword(studentFields.get("password"));
}
Locale locale = request.getLocale();
sud.setLanguage(locale.getLanguage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.RandomStringUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -62,6 +63,12 @@ public class TeacherAPIController extends UserAPIController {
@Value("${google.clientSecret:}")
private String googleClientSecret;

@Value("${ck_board_url}")
private String ckBoardUrl;

@Value("${ck_board_local_backend_url}")
private String ckBoardBackendUrl;

@GetMapping("/runs")
List<HashMap<String, Object>> getRuns(Authentication auth,
@RequestParam(required = false) Integer max) {
Expand Down Expand Up @@ -469,4 +476,69 @@ HashMap<String, Object> editRunIsLockedAfterEndDate(Authentication authenticatio
}
return response;
}

@PostMapping("/run/score/link")
Map<String, Object> linkRunToCkProject(Authentication authentication,
@RequestParam("runId") Long runId, @RequestParam("code") String code,
HttpServletRequest request) {
Map<String, Object> result = new HashMap<>();
try {
User user = userService.retrieveUserByUsername(authentication.getName());
Run run = runService.retrieveById(runId);
if (run.isTeacherAssociatedToThisRun(user)) {
String url = "/api/projects/score/link";
JSONObject params = new JSONObject();
params.put("runId", runId);
params.put("code", code);
String jsonRes = ControllerUtil.doCkBoardPost(request, authentication, params.toString(),
url);
if (jsonRes != null) {
JSONObject json = new JSONObject(jsonRes);
if (json.has("code") && json.getString("code").equals(code)) {
runService.updateCkProjectConnectCode(runId, code);
result.put("code", code);
}
if (json.has("message")) {
result.put("message", json.getString("message"));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}

@PostMapping("/run/score/unlink")
Map<String, Object> ulinkRunFromCkProject(Authentication authentication,
@RequestParam("runId") Long runId, @RequestParam("code") String code,
HttpServletRequest request) {
Map<String, Object> result = new HashMap<>();
try {
User user = userService.retrieveUserByUsername(authentication.getName());
Run run = runService.retrieveById(runId);
if (run.isTeacherAssociatedToThisRun(user)) {
String url = "/api/projects/score/unlink";
JSONObject params = new JSONObject();
params.put("runId", runId);
params.put("code", code);
String jsonRes = ControllerUtil.doCkBoardPost(request, authentication, params.toString(),
url);
if (jsonRes != null) {
JSONObject json = new JSONObject(jsonRes);
if (json.has("code") && json.getString("code").equals(code)) {
runService.updateCkProjectConnectCode(runId, "");
result.put("code", code);
}
if (json.has("message")) {
result.put("message", json.getString("message"));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}

}
Loading