Skip to content

Commit

Permalink
SAK-33327 Assignments Bulk Download (sakaiproject#5094)
Browse files Browse the repository at this point in the history
  • Loading branch information
ern authored Dec 8, 2017
1 parent 1a9c450 commit 3c4996f
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 328 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -519,22 +519,6 @@ public interface AssignmentService extends EntityProducer {
*/
public String submissionReference(String context, String id, String assignmentId);

/**
* Get the String to form an assignment grade spreadsheet
*
* @param context The assignment context String
* @param assignmentId The id for the assignment object; when null, indicates all assignment in that context
*/
public String gradesSpreadsheetReference(String context, String assignmentId);

/**
* Get the string to form an assignment submissions zip file
*
* @param context The assignment context String
* @param assignmentId The id for the assignment object;
*/
public String submissionsZipReference(String context, String assignmentId);

/**
* Whether a specific user can submit
* @param context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,6 @@ public final class AssignmentServiceConstants {
* The Reference type for an assignment.
*/
public static final String REF_TYPE_ASSIGNMENT = "a";
/**
* The Reference type for an assignment where site groups are to be considered in security computation.
*/
public static final String REF_TYPE_ASSIGNMENT_GROUPS = "a-groups";
/**
* The Reference type for a submission.
*/
Expand All @@ -105,14 +101,7 @@ public final class AssignmentServiceConstants {
* The Reference type for a content.
*/
public static final String REF_TYPE_CONTENT = "c";
/**
* The Reference type for a grade spreadsheet.
*/
public static final String REF_TYPE_GRADES = "grades";
/**
* The Reference type for a submissions zip.
*/
public static final String REF_TYPE_SUBMISSIONS = "submissions";

// the three choices for Gradebook Integration
public static final String GRADEBOOK_INTEGRATION_NO = "no";
public static final String GRADEBOOK_INTEGRATION_ADD = "add";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -77,7 +75,6 @@
import org.sakaiproject.assignment.api.model.AssignmentSubmissionSubmitter;
import org.sakaiproject.assignment.api.model.AssignmentSupplementItemAttachment;
import org.sakaiproject.assignment.api.model.AssignmentSupplementItemService;
import org.sakaiproject.assignment.impl.sort.AnonymousSubmissionComparator;
import org.sakaiproject.assignment.impl.sort.AssignmentSubmissionComparator;
import org.sakaiproject.assignment.impl.sort.UserComparator;
import org.sakaiproject.assignment.persistence.AssignmentRepository;
Expand All @@ -102,11 +99,7 @@
import org.sakaiproject.email.api.DigestService;
import org.sakaiproject.email.api.EmailService;
import org.sakaiproject.entity.api.Entity;
import org.sakaiproject.entity.api.EntityAccessOverloadException;
import org.sakaiproject.entity.api.EntityCopyrightException;
import org.sakaiproject.entity.api.EntityManager;
import org.sakaiproject.entity.api.EntityNotDefinedException;
import org.sakaiproject.entity.api.EntityPermissionException;
import org.sakaiproject.entity.api.EntityTransferrer;
import org.sakaiproject.entity.api.EntityTransferrerRefMigrator;
import org.sakaiproject.entity.api.HttpAccess;
Expand Down Expand Up @@ -444,37 +437,43 @@ public Collection<String> getEntityAuthzGroups(Reference reference, String userI

@Override
public HttpAccess getHttpAccess() {
return new HttpAccess() {
@Override
public void handleAccess(HttpServletRequest req, HttpServletResponse res, Reference ref, Collection copyrightAcceptedRefs)
throws EntityPermissionException, EntityNotDefinedException, EntityAccessOverloadException, EntityCopyrightException {
if (sessionManager.getCurrentSessionUserId() == null) {
// fail the request, user not logged in yet.
} else {
if (REF_TYPE_SUBMISSIONS.equals(ref.getSubType())) {
String queryString = req.getQueryString();
res.setContentType("application/zip");
res.setHeader("Content-Disposition", "attachment; filename = bulk_download.zip");

try (OutputStream out = res.getOutputStream()) {
// get the submissions zip blob
getSubmissionsZip(out, ref.getReference(), queryString);

} catch (Exception ignore) {
log.error("Could not stream the zip of submissions for ref = {}", ref.getReference());
}
} else if (REF_TYPE_GRADES.equals(ref.getSubType())) {
res.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
res.setHeader("Content-Disposition", "attachment; filename = export_grades_file.xlsx");

try (OutputStream out = res.getOutputStream()) {
gradeSheetExporter.getGradesSpreadsheet(out, ref.getReference());
} catch (Exception ignore) {
log.error("Could not stream the grades for ref = {}", ref.getReference());
}
} else {
log.warn("Unhandled reference = {}", ref.getReference());
throw new EntityNotDefinedException(ref.getReference());
return (req, res, ref, copyrightAcceptedRefs) -> {
if (sessionManager.getCurrentSessionUserId() == null) {
log.warn("Only logged in users can access assignment downloads");
} else {
// determine the type of download to create using the reference that was requested
AssignmentReferenceReckoner.AssignmentReference refReckoner = AssignmentReferenceReckoner.reckoner().reference(ref.getReference()).reckon();
if (REFERENCE_ROOT.equals("/" + refReckoner.getType())) {
// don't process any references that are not of type assignment
switch (refReckoner.getSubtype()) {
case REF_TYPE_CONTENT:
case REF_TYPE_ASSIGNMENT:
String queryString = req.getQueryString();
if (StringUtils.isNotBlank(refReckoner.getId())) {
// if subtype is assignment then were downloading all submissions for an assignment
res.setContentType("application/zip");
res.setHeader("Content-Disposition", "attachment; filename = bulk_download.zip");

try (OutputStream out = res.getOutputStream()) {
getSubmissionsZip(out, ref.getReference(), queryString);
} catch (Exception ignore) {
log.warn("Could not stream the zip of submissions for reference: {}", ref.getReference());
}
} else {
// if subtype is assignment and there is no assignmentId then were downloading grades
res.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
res.setHeader("Content-Disposition", "attachment; filename = export_grades_file.xlsx");

try (OutputStream out = res.getOutputStream()) {
gradeSheetExporter.getGradesSpreadsheet(out, ref.getReference(), queryString);
} catch (Exception ignore) {
log.warn("Could not stream the grades for reference: {}", ref.getReference());
}
}
break;
case REF_TYPE_SUBMISSION:
default:
log.warn("Assignments download unhandled download type for reference: {}", ref.getReference());
}
}
}
Expand Down Expand Up @@ -1583,33 +1582,33 @@ public void getSubmissionsZip(OutputStream out, String reference, String query)
byte[] rv = null;

try {
String aRef = AssignmentReferenceReckoner.reckoner().reference(reference).reckon().getId();
Assignment assignment = getAssignment(aRef);
String id = AssignmentReferenceReckoner.reckoner().reference(reference).reckon().getId();
Assignment assignment = getAssignment(id);

if (assignment.getIsGroup()) {
Collection<Group> submitterGroups = getSubmitterGroupList(searchFilterOnly,
viewString.length() == 0 ? AssignmentConstants.ALL : viewString,
searchString,
aRef,
id,
contextString == null ? assignment.getContext() : contextString);
if (submitterGroups != null && !submitterGroups.isEmpty()) {
List<AssignmentSubmission> submissions = new ArrayList<>();
for (Group g : submitterGroups) {
log.debug("ZIP GROUP " + g.getTitle());
AssignmentSubmission sub = getSubmission(aRef, g.getId());
AssignmentSubmission sub = getSubmission(id, g.getId());
log.debug("ZIP GROUP " + g.getTitle() + " SUB " + (sub == null ? "null" : sub.getId()));
if (sub != null) {
submissions.add(sub);
}
}
StringBuilder exceptionMessage = new StringBuilder();

if (allowGradeSubmission(aRef)) {
zipGroupSubmissions(aRef,
if (allowGradeSubmission(reference)) {
zipGroupSubmissions(reference,
assignment.getTitle(),
assignment.getTypeOfGrade().toString(),
assignment.getTypeOfSubmission(),
new SortedIterator(submissions.iterator(), new AssignmentSubmissionComparator(siteService)),
new SortedIterator(submissions.iterator(), new AssignmentSubmissionComparator(applicationContext.getBean(AssignmentService.class), siteService, userDirectoryService)),
out,
exceptionMessage,
withStudentSubmissionText,
Expand All @@ -1633,26 +1632,20 @@ public void getSubmissionsZip(OutputStream out, String reference, String query)
Map<User, AssignmentSubmission> submitters = getSubmitterMap(searchFilterOnly,
viewString.length() == 0 ? AssignmentConstants.ALL : viewString,
searchString,
aRef,
reference,
contextString == null ? assignment.getContext() : contextString);

if (!submitters.isEmpty()) {
List<AssignmentSubmission> submissions = new ArrayList<AssignmentSubmission>(submitters.values());

StringBuilder exceptionMessage = new StringBuilder();

if (allowGradeSubmission(aRef)) {
SortedIterator sortedIterator;
if (assignmentUsesAnonymousGrading(assignment)) {
sortedIterator = new SortedIterator(submissions.iterator(), new AnonymousSubmissionComparator());
} else {
sortedIterator = new SortedIterator(submissions.iterator(), new AssignmentSubmissionComparator(siteService));
}
zipSubmissions(aRef,
if (allowGradeSubmission(reference)) {
zipSubmissions(reference,
assignment.getTitle(),
assignment.getTypeOfGrade(),
assignment.getTypeOfSubmission(),
sortedIterator,
new SortedIterator(submissions.iterator(), new AssignmentSubmissionComparator(applicationContext.getBean(AssignmentService.class), siteService, userDirectoryService)),
out,
exceptionMessage,
withStudentSubmissionText,
Expand Down Expand Up @@ -1696,25 +1689,6 @@ public String submissionReference(String context, String id, String assignmentId
return AssignmentReferenceReckoner.reckoner().context(context).id(id).container(assignmentId).reckon().getReference();
}

@Override
public String gradesSpreadsheetReference(String context, String assignmentId) {
// TODO does ref get handled by ReferenceReckoner?
// based on all assignment in that context
String s = REFERENCE_ROOT + Entity.SEPARATOR + REF_TYPE_GRADES + Entity.SEPARATOR + context;
if (assignmentId != null) {
// based on the specified assignment only
s = s.concat(Entity.SEPARATOR + assignmentId);
}
return s;
}

@Override
public String submissionsZipReference(String context, String assignmentReference) {
// TODO does ref get handled by ReferenceReckoner?
// based on the specified assignment
return REFERENCE_ROOT + Entity.SEPARATOR + REF_TYPE_SUBMISSIONS + Entity.SEPARATOR + context + Entity.SEPARATOR + assignmentReference;
}

@Override
public boolean canSubmit(String context, Assignment a, String userId) {
// submissions are never allowed to non-electronic assignments
Expand Down
Loading

0 comments on commit 3c4996f

Please sign in to comment.