Skip to content

Commit

Permalink
feat(Get Classmate Work): Create endpoint for classmate Summary work (#…
Browse files Browse the repository at this point in the history
…56)

Project content caching and evicting has also been enabled.

Closes #55
  • Loading branch information
geoffreykwan authored Nov 15, 2021
1 parent 3c29b7e commit 2e1410c
Show file tree
Hide file tree
Showing 20 changed files with 480 additions and 91 deletions.
2 changes: 2 additions & 0 deletions src/main/java/org/wise/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
Expand All @@ -37,6 +38,7 @@

@SpringBootApplication
@EnableScheduling
@EnableCaching
public class Application extends SpringBootServletInitializer {

Environment environment;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,7 @@ List<Annotation> getAnnotationsByParams(Integer id, Run run, Group period,
Workgroup fromWorkgroup, Workgroup toWorkgroup, String nodeId, String componentId,
StudentWork studentWork, String localNotebookItemId, NotebookItem notebookItem, String type);

List<Annotation> getAnnotations(Run run, String nodeId, String componentId);

List<Annotation> getAnnotations(Run run, Group period, String nodeId, String componentId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,19 +92,26 @@ public List<Annotation> getAnnotationsByParams(Integer id, Run run, Group period
return (List<Annotation>) (Object) query.getResultList();
}

public List<Annotation> getAnnotations(Run run, String nodeId, String componentId) {
return getAnnotations(run, null, nodeId, componentId);
}

public List<Annotation> getAnnotations(Run run, Group period, String nodeId, String componentId) {
Session session = this.getHibernateTemplate().getSessionFactory().getCurrentSession();
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Annotation> cq = cb.createQuery(Annotation.class);
Root<Annotation> annotationRoot = cq.from(Annotation.class);
Root<RunImpl> runImplRoot = cq.from(RunImpl.class);
Root<PersistentGroup> periodRoot = cq.from(PersistentGroup.class);
List<Predicate> predicates = new ArrayList<>();
predicates.add(cb.equal(runImplRoot.get("id"), run.getId()));
predicates.add(cb.equal(periodRoot.get("id"), period.getId()));
predicates.add(cb.equal(annotationRoot.get("period"), periodRoot));
predicates.add(cb.equal(annotationRoot.get("run"), runImplRoot));
predicates.add(cb.equal(annotationRoot.get("nodeId"), nodeId));
predicates.add(cb.equal(annotationRoot.get("componentId"), componentId));
if (period != null) {
Root<PersistentGroup> periodRoot = cq.from(PersistentGroup.class);
predicates.add(cb.equal(periodRoot.get("id"), period.getId()));
predicates.add(cb.equal(annotationRoot.get("period"), periodRoot));
}
cq.select(annotationRoot).where(predicates.toArray(new Predicate[predicates.size()]));
TypedQuery<Annotation> query = entityManager.createQuery(cq);
return (List<Annotation>) (Object) query.getResultList();
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/wise/portal/dao/work/StudentWorkDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,7 @@ List<StudentWork> getStudentWorkListByParams(Integer id, Run run, Group period,
Workgroup workgroup, Boolean isAutoSave, Boolean isSubmit, String nodeId, String componentId,
String componentType, List<JSONObject> components);

List<StudentWork> getStudentWork(Run run, String nodeId, String componentId);

List<StudentWork> getStudentWork(Run run, Group period, String nodeId, String componentId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,20 +137,26 @@ private List<Predicate> getStudentWorkListByParamsPredicates(CriteriaBuilder cb,
return predicates;
}

public List<StudentWork> getStudentWork(Run run, String nodeId, String componentId) {
return getStudentWork(run, null, nodeId, componentId);
}

public List<StudentWork> getStudentWork(Run run, Group period, String nodeId,
String componentId) {
CriteriaBuilder cb = getCriteriaBuilder();
CriteriaQuery<StudentWork> cq = cb.createQuery(StudentWork.class);
Root<StudentWork> studentWorkRoot = cq.from(StudentWork.class);
List<Predicate> predicates = new ArrayList<>();
Root<RunImpl> runImplRoot = cq.from(RunImpl.class);
Root<PersistentGroup> periodRoot = cq.from(PersistentGroup.class);
predicates.add(cb.equal(runImplRoot.get("id"), run.getId()));
predicates.add(cb.equal(periodRoot.get("id"), period.getId()));
predicates.add(cb.equal(studentWorkRoot.get("run"), runImplRoot));
predicates.add(cb.equal(studentWorkRoot.get("period"), periodRoot));
predicates.add(cb.equal(studentWorkRoot.get("nodeId"), nodeId));
predicates.add(cb.equal(studentWorkRoot.get("componentId"), componentId));
if (period != null) {
Root<PersistentGroup> periodRoot = cq.from(PersistentGroup.class);
predicates.add(cb.equal(periodRoot.get("id"), period.getId()));
predicates.add(cb.equal(studentWorkRoot.get("period"), periodRoot));
}
cq.select(studentWorkRoot).where(predicates.toArray(new Predicate[predicates.size()]))
.orderBy(cb.asc(studentWorkRoot.get("serverSaveTime")));
TypedQuery<StudentWork> query = entityManager.createQuery(cq);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ protected SimpleResponse saveProject(Authentication auth, @PathVariable Long pro
User user = userService.retrieveUserByUsername(auth.getName());
if (projectService.canAuthorProject(project, user)) {
try {
projectService.evictProjectContentCache(projectId);
projectService.saveProjectContentToDisk(projectJSONString, project);
projectService.updateMetadataAndLicenseIfNecessary(project, projectJSONString);
projectService.saveProjectToDatabase(project, user, projectJSONString);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

public abstract class ClassmateDataController {

final String NOT_PERMITTED = "Not permitted";

@Autowired
protected GroupService groupService;

Expand Down Expand Up @@ -58,11 +60,19 @@ protected ProjectComponent getProjectComponent(Run run, String nodeId, String co
return projectContent.getComponent(nodeId, componentId);
}

protected List<StudentWork> getStudentWork(Run run, String nodeId, String componentId) {
return vleService.getStudentWork(run, nodeId, componentId);
}

protected List<StudentWork> getStudentWork(Run run, Group period, String nodeId,
String componentId) {
return vleService.getStudentWork(run, period, nodeId, componentId);
}

protected List<Annotation> getAnnotations(Run run, String nodeId, String componentId) {
return vleService.getAnnotations(run, nodeId, componentId);
}

protected List<Annotation> getAnnotations(Run run, Group period, String nodeId,
String componentId) {
return vleService.getAnnotations(run, period, nodeId, componentId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
@RequestMapping("/api/classmate/discussion")
public class ClassmateDiscussionDataController extends ClassmateDataController {

String DISCUSSION_TYPE = "Discussion";

@GetMapping("/student-work/{runId}/{periodId}/{nodeId}/{componentId}")
public List<StudentWork> getClassmateDiscussionWork(Authentication auth, @PathVariable Long runId,
@PathVariable Long periodId, @PathVariable String nodeId, @PathVariable String componentId)
Expand All @@ -31,7 +33,7 @@ public List<StudentWork> getClassmateDiscussionWork(Authentication auth, @PathVa
if (isAllowedToGetData(auth, run, period, nodeId, componentId)) {
return getStudentWork(run, period, nodeId, componentId);
} else {
throw new AccessDeniedException("Not permitted");
throw new AccessDeniedException(NOT_PERMITTED);
}
}

Expand All @@ -44,7 +46,7 @@ public List<Annotation> getClassmateDiscussionAnnotations(Authentication auth,
if (isAllowedToGetData(auth, run, period, nodeId, componentId)) {
return getAnnotations(run, period, nodeId, componentId);
} else {
throw new AccessDeniedException("Not permitted");
throw new AccessDeniedException(NOT_PERMITTED);
}
}

Expand All @@ -56,6 +58,6 @@ private boolean isAllowedToGetData(Authentication auth, Run run, Group period, S

private boolean isDiscussionComponent(Run run, String nodeId, String componentId)
throws IOException, JSONException, ObjectNotFoundException {
return isComponentType(run, nodeId, componentId, "Discussion");
return isComponentType(run, nodeId, componentId, DISCUSSION_TYPE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.wise.portal.presentation.web.controllers.student;

import java.io.IOException;
import java.util.List;

import org.json.JSONException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.wise.portal.dao.ObjectNotFoundException;
import org.wise.portal.domain.group.Group;
import org.wise.portal.domain.project.impl.ProjectComponent;
import org.wise.portal.domain.run.Run;
import org.wise.vle.domain.annotation.wise5.Annotation;
import org.wise.vle.domain.work.StudentWork;

@RestController
@Secured("ROLE_STUDENT")
@RequestMapping("/api/classmate/summary")
public class ClassmateSummaryDataController extends ClassmateDataController {

final String ALL_PERIODS_SOURCE = "allPeriods";
final String PERIOD_SOURCE = "period";
final String SUMMARY_TYPE = "Summary";

@GetMapping("/student-work/{runId}/{periodId}/{nodeId}/{componentId}/{otherNodeId}/{otherComponentId}/{source}")
public List<StudentWork> getClassmateSummaryWork(Authentication auth, @PathVariable Long runId,
@PathVariable Long periodId, @PathVariable String nodeId, @PathVariable String componentId,
@PathVariable String otherNodeId, @PathVariable String otherComponentId,
@PathVariable String source) throws IOException, JSONException, ObjectNotFoundException {
Run run = runService.retrieveById(runId);
Group period = groupService.retrieveById(periodId);
if (isAllowedToGetData(auth, run, period, nodeId, componentId, otherNodeId, otherComponentId)) {
if (PERIOD_SOURCE.equals(source)) {
return getStudentWork(run, period, otherNodeId, otherComponentId);
} else if (ALL_PERIODS_SOURCE.equals(source)) {
return getStudentWork(run, otherNodeId, otherComponentId);
}
}
throw new AccessDeniedException(NOT_PERMITTED);
}

@GetMapping("/annotations/{runId}/{periodId}/{nodeId}/{componentId}/{otherNodeId}/{otherComponentId}/{source}")
public List<Annotation> getClassmateSummaryAnnotations(Authentication auth,
@PathVariable Long runId, @PathVariable Long periodId, @PathVariable String nodeId,
@PathVariable String componentId, @PathVariable String otherNodeId,
@PathVariable String otherComponentId, @PathVariable String source)
throws IOException, JSONException, ObjectNotFoundException {
Run run = runService.retrieveById(runId);
Group period = groupService.retrieveById(periodId);
if (isAllowedToGetData(auth, run, period, nodeId, componentId, otherNodeId, otherComponentId)) {
if (PERIOD_SOURCE.equals(source)) {
return getAnnotations(run, period, otherNodeId, otherComponentId);
} else if (ALL_PERIODS_SOURCE.equals(source)) {
return getAnnotations(run, otherNodeId, otherComponentId);
}
}
throw new AccessDeniedException(NOT_PERMITTED);
}

private boolean isAllowedToGetData(Authentication auth, Run run, Group period, String nodeId,
String componentId, String otherNodeId, String otherComponentId)
throws IOException, JSONException, ObjectNotFoundException {
return isUserInRunAndPeriod(auth, run, period)
&& isValidSummaryComponent(run, nodeId, componentId, otherNodeId, otherComponentId);
}

private boolean isValidSummaryComponent(Run run, String nodeId, String componentId,
String otherNodeId, String otherComponentId)
throws IOException, JSONException, ObjectNotFoundException {
ProjectComponent projectComponent = getProjectComponent(run, nodeId, componentId);
return SUMMARY_TYPE.equals(projectComponent.getString("type"))
&& otherNodeId.equals(projectComponent.getString("summaryNodeId"))
&& otherComponentId.equals(projectComponent.getString("summaryComponentId"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -384,4 +384,6 @@ void updateProjectNameIfNecessary(Project project, JSONObject projectMetadataJSO
throws JSONException;

String getProjectContent(Project project) throws IOException;

void evictProjectContentCache(Long projectId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,20 @@
import java.util.Set;
import java.util.TreeSet;

import javax.management.timer.Timer;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.text.WordUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.env.Environment;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.model.AlreadyExistsException;
Expand Down Expand Up @@ -920,9 +925,19 @@ public void updateProjectNameIfNecessary(Project project, JSONObject projectMeta
project.setName(projectMetadataJSON.optString("title", project.getName()));
}

@Cacheable(value = "projectContent", key = "#project.getId()")
public String getProjectContent(Project project) throws IOException {
String projectFilePath = appProperties.getProperty("curriculum_base_dir")
+ project.getModulePath();
return FileUtils.readFileToString(new File(projectFilePath));
}

@CacheEvict(value = "projectContent", key = "#projectId", beforeInvocation = true)
public void evictProjectContentCache(Long projectId) {
}

@Scheduled(fixedRate = Timer.ONE_DAY)
@CacheEvict(value = "projectContent", allEntries = true)
public void evictAllProjectContentCache() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ List<StudentWork> getStudentWorkList(Integer id, Integer runId, Integer periodId
Integer workgroupId, Boolean isAutoSave, Boolean isSubmit, String nodeId, String componentId,
String componentType, List<JSONObject> components, Boolean onlyGetLatest);

List<StudentWork> getStudentWork(Run run, String nodeId, String componentId);

List<StudentWork> getStudentWork(Run run, Group period, String nodeId, String componentId);

List<NotebookItem> getNotebookItemsExport(Run run);
Expand Down Expand Up @@ -117,6 +119,8 @@ List<Annotation> getAnnotations(Integer id, Integer runId, Integer periodId,
Integer fromWorkgroupId, Integer toWorkgroupId, String nodeId, String componentId,
Integer studentWorkId, String localNotebookItemId, Integer notebookItemId, String type);

List<Annotation> getAnnotations(Run run, String nodeId, String componentId);

List<Annotation> getAnnotations(Run run, Group period, String nodeId, String componentId);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ public List<StudentWork> getStudentWorkList(Integer id, Integer runId, Integer p
}
}

public List<StudentWork> getStudentWork(Run run, String nodeId, String componentId) {
return studentWorkDao.getStudentWork(run, nodeId, componentId);
}

public List<StudentWork> getStudentWork(Run run, Group period, String nodeId,
String componentId) {
return studentWorkDao.getStudentWork(run, period, nodeId, componentId);
Expand Down Expand Up @@ -534,6 +538,10 @@ public List<Annotation> getAnnotations(Integer id, Integer runId, Integer period
componentId, studentWork, localNotebookItemId, notebookItem, type);
}

public List<Annotation> getAnnotations(Run run, String nodeId, String componentId) {
return annotationDao.getAnnotations(run, nodeId, componentId);
}

public List<Annotation> getAnnotations(Run run, Group period, String nodeId, String componentId) {
return annotationDao.getAnnotations(run, period, nodeId, componentId);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.wise.portal.dao.annotation.impl;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.sql.Timestamp;
import java.util.Calendar;
Expand Down Expand Up @@ -38,6 +39,21 @@ public void getAnnotations_AnnotationsExist_ShouldReturnAnnotations() {
createAndRetrieveAnnotations(NODE_ID1, COMPONENT_ID1, NODE_ID1, COMPONENT_ID1, 1);
}

@Test
public void getAnnotations_FromAllPeriods_ShouldReturnAnnotations() {
Annotation annotation1 = createAnnotation(run1, run1Period1, teacherWorkgroup1, workgroup1,
COMMENT_TYPE, NODE_ID1, COMPONENT_ID1, DUMMY_ANNOTATION_DATA);
addUserToRun(student4, run1, run1Period2);
Workgroup workgroup4 = addUserToRun(student4, run1, run1Period2);
Annotation annotation2 = createAnnotation(run1, run1Period2, teacherWorkgroup1, workgroup4,
COMMENT_TYPE, NODE_ID1, COMPONENT_ID1, DUMMY_ANNOTATION_DATA);
List<Annotation> annotations = annotationDao.getAnnotations(run1, null, NODE_ID1,
COMPONENT_ID1);
assertEquals(2, annotations.size());
assertTrue(annotations.contains(annotation1));
assertTrue(annotations.contains(annotation2));
}

private void createAndRetrieveAnnotations(String createAnnotationNodeId,
String createAnnotationComponentId, String retrieveAnnotationNodeId,
String retrieveAnnotationComponentId, Integer expectedCount) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
package org.wise.portal.dao.work.impl;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.sql.Timestamp;
import java.util.Calendar;
Expand Down Expand Up @@ -115,6 +116,21 @@ public void getStudentWork_WorkDoesNotExist_ShouldReturnEmptyList() {
assertEquals(studentWorkList.size(), 0);
}

@Test
public void getStudentWork_FromAllPeriods_ShouldReturnWork() {
StudentWork studentWork1 = createStudentWork(workgroup1, NODE_ID1, COMPONENT_ID1,
DUMMY_STUDENT_WORK1);
addUserToRun(student4, run1, run1Period2);
Workgroup workgroup4 = addUserToRun(student4, run1, run1Period2);
StudentWork studentWork2 = createStudentWork(workgroup4, NODE_ID1, COMPONENT_ID1,
DUMMY_STUDENT_WORK1);
List<StudentWork> studentWorkList = studentWorkDao.getStudentWork(run1, null, NODE_ID1,
COMPONENT_ID1);
assertEquals(studentWorkList.size(), 2);
assertTrue(studentWorkList.contains(studentWork1));
assertTrue(studentWorkList.contains(studentWork2));
}

private StudentWork createStudentWork(Workgroup workgroup, String nodeId, String componentId,
String studentData) {
StudentWork studentWork = new StudentWork();
Expand Down
Loading

0 comments on commit 2e1410c

Please sign in to comment.