diff --git a/admin-tools/src/bundle/archive_es.properties b/admin-tools/src/bundle/archive_es.properties index a7d425e87188..7a4c4e6202d2 100644 --- a/admin-tools/src/bundle/archive_es.properties +++ b/admin-tools/src/bundle/archive_es.properties @@ -5,7 +5,8 @@ archive=Guardando herramientas y contenidos del sitio de la asignatura {0} archive.file=Por favor, indique un nombre de fichero y un sitio id para importar. archive.import=la importaci\u00f3n est\u00e1 limitada a administradores.\n archive.import1=importar {0}\: desde fichero {1} al sitio {2} con el id de creador {3} completar. -archive.import2=importar desde fichero {0} al sitio {2} completar. \n +archive.import2=importar desde fichero {0} al sitio {1} finalizado. \n +archive.import3=No se pudo realizar la importaci\u00f3n desde el fichero {0}. La extensi\u00f3n del fichero no es correcta. archive.limited=archivar est\u00e1 limitado a administradores.\n archive.please=Por favor, indique un sitio para archivar. archive.vm.alert=Alerta\: diff --git a/admin-tools/src/java/org/sakaiproject/archive/tool/ArchiveAction.java b/admin-tools/src/java/org/sakaiproject/archive/tool/ArchiveAction.java index 8585707fc678..afa641b6dbab 100644 --- a/admin-tools/src/java/org/sakaiproject/archive/tool/ArchiveAction.java +++ b/admin-tools/src/java/org/sakaiproject/archive/tool/ArchiveAction.java @@ -347,6 +347,9 @@ public void doImport(RunData data, Context context) && (file != null) && (file.trim().length() > 0)) { String msg = archiveService.merge(file.trim(), id.trim(), null); + if (StringUtils.isBlank(msg)) { + msg = rb.getFormattedMessage("archive.import3", new Object[]{file}); + } addAlert(state, rb.getFormattedMessage("archive.import2", new Object[]{file, id}) + msg); } else diff --git a/assignment/api/pom.xml b/assignment/api/pom.xml index 74d504377e85..35da936e446a 100644 --- a/assignment/api/pom.xml +++ b/assignment/api/pom.xml @@ -52,5 +52,9 @@ org.sakaiproject.contentreview content-review-api + + com.fasterxml.jackson.core + jackson-annotations + diff --git a/assignment/api/src/java/org/sakaiproject/assignment/api/AssignmentService.java b/assignment/api/src/java/org/sakaiproject/assignment/api/AssignmentService.java index 78feba6d647e..7fd1a0be12ee 100644 --- a/assignment/api/src/java/org/sakaiproject/assignment/api/AssignmentService.java +++ b/assignment/api/src/java/org/sakaiproject/assignment/api/AssignmentService.java @@ -23,7 +23,11 @@ import java.io.OutputStream; import java.time.Instant; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import org.sakaiproject.assignment.api.model.Assignment; import org.sakaiproject.assignment.api.model.AssignmentSubmission; @@ -38,7 +42,6 @@ import org.sakaiproject.site.api.Group; import org.sakaiproject.site.api.Site; import org.sakaiproject.user.api.User; -import org.w3c.dom.Element; /** *

@@ -274,17 +277,6 @@ public interface AssignmentService extends EntityProducer { */ public Assignment addAssignment(String context) throws PermissionException; - /** - * Add a new assignment to the directory, from a definition in XML. Must commitEdit() to make official, or cancelEdit() when done! - * - * @param el The XML DOM Element defining the assignment. - * @return A locked AssignmentEdit object (reserving the id). - * @throws IdInvalidException if the assignment id is invalid. - * @throws IdUsedException if the assignment id is already used. - * @throws PermissionException if the current user does not have permission to add an assignnment. - */ - public Assignment mergeAssignment(Element el) throws IdInvalidException, IdUsedException, PermissionException; - /** * Creates and adds a new Assignment to the service which is a copy of an existing Assignment. * @@ -331,17 +323,6 @@ public interface AssignmentService extends EntityProducer { */ public AssignmentSubmission addSubmission(String assignmentId, String submitter) throws PermissionException; - /** - * Add a new AssignmentSubmission to the directory, from a definition in XML. Must commitEdit() to make official, or cancelEdit() when done! - * - * @param el The XML DOM Element defining the submission. - * @return A locked AssignmentSubmission object (reserving the id). - * @throws IdInvalidException if the submission id is invalid. - * @throws IdUsedException if the submission id is already used. - * @throws PermissionException if the current user does not have permission to add a submission. - */ - public AssignmentSubmission mergeSubmission(Element el) throws IdInvalidException, IdUsedException, PermissionException; - /** * Removes an AssignmentSubmission and all references to it * diff --git a/assignment/api/src/java/org/sakaiproject/assignment/api/AssignmentServiceConstants.java b/assignment/api/src/java/org/sakaiproject/assignment/api/AssignmentServiceConstants.java index d1a9c648b791..e0cace45927b 100644 --- a/assignment/api/src/java/org/sakaiproject/assignment/api/AssignmentServiceConstants.java +++ b/assignment/api/src/java/org/sakaiproject/assignment/api/AssignmentServiceConstants.java @@ -125,6 +125,9 @@ public final class AssignmentServiceConstants { AssignmentServiceConstants.NEW_ASSIGNMENT_ADD_TO_GRADEBOOK, AssignmentServiceConstants.PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT))); + public static final String LINE_SEPARATOR = System.getProperty("line.separator"); + public static final String SAK_PROP_ASSIGNMENT_IMPORT_SUBMISSIONS = "assignment.merge.import.submissions"; + private AssignmentServiceConstants() { throw new RuntimeException(this.getClass().getCanonicalName() + " is not to be instantiated"); } diff --git a/assignment/api/src/java/org/sakaiproject/assignment/api/model/Assignment.java b/assignment/api/src/java/org/sakaiproject/assignment/api/model/Assignment.java index 0d25f5a6cdfb..75949934147a 100644 --- a/assignment/api/src/java/org/sakaiproject/assignment/api/model/Assignment.java +++ b/assignment/api/src/java/org/sakaiproject/assignment/api/model/Assignment.java @@ -53,6 +53,10 @@ import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Type; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.JsonManagedReference; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; + /** * Assignment represents a specific assignment for a specific section or class. *

@@ -97,6 +101,7 @@ @NoArgsConstructor @ToString(exclude = {"authors", "submissions", "groups", "properties", "attachments"}) @EqualsAndHashCode(of = "id") +@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") public class Assignment { @Id @@ -168,6 +173,7 @@ public class Assignment { private Integer position; @OneToMany(mappedBy = "assignment", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference private Set submissions = new HashSet<>(); @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) diff --git a/assignment/api/src/java/org/sakaiproject/assignment/api/model/AssignmentSubmission.java b/assignment/api/src/java/org/sakaiproject/assignment/api/model/AssignmentSubmission.java index 871b259ad252..1cf2f21a3229 100644 --- a/assignment/api/src/java/org/sakaiproject/assignment/api/model/AssignmentSubmission.java +++ b/assignment/api/src/java/org/sakaiproject/assignment/api/model/AssignmentSubmission.java @@ -56,6 +56,11 @@ import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Type; +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.JsonManagedReference; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; + /** * AssignmentSubmission represents a student submission for an assignment. */ @@ -67,6 +72,7 @@ @NoArgsConstructor @ToString(exclude = {"assignment", "submitters", "attachments", "feedbackAttachments", "properties"}) @EqualsAndHashCode(of = "id") +@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") public class AssignmentSubmission { @Id @@ -77,11 +83,13 @@ public class AssignmentSubmission { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "ASSIGNMENT_ID") + @JsonBackReference private Assignment assignment; @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @OneToMany(mappedBy = "submission", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) @BatchSize(size = 100) + @JsonManagedReference private Set submitters = new HashSet<>(); //private List submissionLog; diff --git a/assignment/api/src/java/org/sakaiproject/assignment/api/model/AssignmentSubmissionSubmitter.java b/assignment/api/src/java/org/sakaiproject/assignment/api/model/AssignmentSubmissionSubmitter.java index 659309d3e975..3c03233a0570 100644 --- a/assignment/api/src/java/org/sakaiproject/assignment/api/model/AssignmentSubmissionSubmitter.java +++ b/assignment/api/src/java/org/sakaiproject/assignment/api/model/AssignmentSubmissionSubmitter.java @@ -28,6 +28,10 @@ import javax.persistence.Table; import javax.persistence.UniqueConstraint; +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; + import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -53,6 +57,7 @@ @NoArgsConstructor @ToString(exclude = {"submission"}) @EqualsAndHashCode(of = {"submission", "submitter"}) +@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") public class AssignmentSubmissionSubmitter { @Id @@ -63,6 +68,7 @@ public class AssignmentSubmissionSubmitter { @ManyToOne @JoinColumn(name = "SUBMISSION_ID", nullable = false) + @JsonBackReference private AssignmentSubmission submission; @Column(name = "SUBMITTER", length = 99, nullable = false) diff --git a/assignment/impl/pom.xml b/assignment/impl/pom.xml index 82ab44b1a1a5..b887d01e90d7 100644 --- a/assignment/impl/pom.xml +++ b/assignment/impl/pom.xml @@ -155,10 +155,18 @@ com.fasterxml.jackson.dataformat jackson-dataformat-xml + + com.fasterxml.jackson.module + jackson-module-parameter-names + com.fasterxml.jackson.datatype jackson-datatype-jdk8 + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + com.fasterxml.woodstox woodstox-core diff --git a/assignment/impl/src/java/org/sakaiproject/assignment/impl/AssignmentServiceImpl.java b/assignment/impl/src/java/org/sakaiproject/assignment/impl/AssignmentServiceImpl.java index a691fa29211d..731130f3bfa2 100644 --- a/assignment/impl/src/java/org/sakaiproject/assignment/impl/AssignmentServiceImpl.java +++ b/assignment/impl/src/java/org/sakaiproject/assignment/impl/AssignmentServiceImpl.java @@ -53,6 +53,8 @@ import java.util.Stack; import java.util.StringTokenizer; import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -179,6 +181,9 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSSerializer; import org.xml.sax.InputSource; import lombok.Setter; @@ -191,7 +196,7 @@ @Transactional(readOnly = true) public class AssignmentServiceImpl implements AssignmentService, EntityTransferrer, ApplicationContextAware { - @Setter private AnnouncementService announcementService; + @Setter private AnnouncementService announcementService; @Setter private ApplicationContext applicationContext; @Setter private AssignmentActivityProducer assignmentActivityProducer; @Setter private AssignmentDueReminderService assignmentDueReminderService; @@ -284,8 +289,8 @@ public boolean willArchiveMerge() { @Override public String archive(String siteId, Document doc, Stack stack, String archivePath, List attachments) { - String message = "archiving " + getLabel() + " context " + Entity.SEPARATOR + siteId + Entity.SEPARATOR + SiteService.MAIN_CONTAINER + ".\n"; - log.debug(message); + final StringBuilder results = new StringBuilder(); + results.append("begin archiving ").append(getLabel()).append(" context ").append(siteId).append(LINE_SEPARATOR); // start with an element with our very own (service) name Element element = doc.createElement(AssignmentService.class.getName()); @@ -293,6 +298,7 @@ public String archive(String siteId, Document doc, Stack stack, String stack.push(element); Collection assignments = getAssignmentsForContext(siteId); + int assignmentsArchived = 0; for (Assignment assignment : assignments) { String xml = assignmentRepository.toXML(assignment); @@ -302,6 +308,7 @@ public String archive(String siteId, Document doc, Stack stack, String Element assignmentElement = assignmentDocument.getDocumentElement(); Node assignmentNode = doc.importNode(assignmentElement, true); element.appendChild(assignmentNode); + assignmentsArchived++; } catch (Exception e) { log.warn("could not append assignment {} to archive, {}", assignment.getId(), e.getMessage()); } @@ -309,12 +316,34 @@ public String archive(String siteId, Document doc, Stack stack, String stack.pop(); - return message; + results.append("completed archiving ").append(getLabel()).append(" context ").append(siteId).append(" count (").append(assignmentsArchived).append(")").append(LINE_SEPARATOR); + return results.toString(); } @Override + @Transactional public String merge(String siteId, Element root, String archivePath, String fromSiteId, Map attachmentNames, Map userIdTrans, Set userListAllowImport) { - return null; + + final StringBuilder results = new StringBuilder(); + results.append("begin merging ").append(getLabel()).append(" context ").append(siteId).append(LINE_SEPARATOR); + final NodeList allChildrenNodeList = root.getChildNodes(); + final Stream allChildrenNodes = IntStream.range(0, allChildrenNodeList.getLength()).mapToObj(allChildrenNodeList::item); + final List assignmentElements = allChildrenNodes.filter(node -> node.getNodeType() == Node.ELEMENT_NODE).map(element -> (Element) element).collect(Collectors.toList()); + + int assignmentsMerged = 0; + + for (Element assignmentElement : assignmentElements) { + try { + mergeAssignment(siteId, assignmentElement, results); + assignmentsMerged++; + } catch (Exception e) { + final String error = "could not merge assignment with id: " + assignmentElement.getFirstChild().getFirstChild().getNodeValue(); + log.warn(error, e); + results.append(error).append(LINE_SEPARATOR); + } + } + results.append("completed merging ").append(getLabel()).append(" context ").append(siteId).append(" count (").append(assignmentsMerged).append(")").append(LINE_SEPARATOR); + return results.toString(); } @Override @@ -768,14 +797,52 @@ public Assignment addAssignment(String context) throws PermissionException { return assignment; } - @Override - @Transactional - public Assignment mergeAssignment(Element el) throws IdInvalidException, IdUsedException, PermissionException { - // TODO need to write a test for this - // this may also need to handle submission serialization? - Assignment assignmentFromXml = assignmentRepository.fromXML(el.toString()); + private Assignment mergeAssignment(final String siteId, final Element element, final StringBuilder results) throws PermissionException { - return addAssignment(assignmentFromXml.getContext()); + if (!allowAddAssignment(siteId)) { + throw new PermissionException(sessionManager.getCurrentSessionUserId(), SECURE_ADD_ASSIGNMENT, AssignmentReferenceReckoner.reckoner().context(siteId).reckon().getReference()); + } + + // Serialize the element to a String + DOMImplementationLS dom = (DOMImplementationLS) element.getOwnerDocument().getImplementation(); + LSSerializer domSerializer = dom.createLSSerializer(); + domSerializer.getDomConfig().setParameter("xml-declaration", false); + final String xml = domSerializer.writeToString(element); + + // Get an assignment object from the xml + final Assignment assignmentFromXml = assignmentRepository.fromXML(xml); + if (assignmentFromXml != null) { + assignmentFromXml.setId(null); + assignmentFromXml.setContext(siteId); + + if (serverConfigurationService.getBoolean(SAK_PROP_ASSIGNMENT_IMPORT_SUBMISSIONS, false) && !assignmentFromXml.getIsGroup()) { + // here it's imported exactly as it was including all submissions + // except for group submissions as group ids will never be the same + Set submissions = assignmentFromXml.getSubmissions(); + List submitters = submissions.stream().flatMap(s -> s.getSubmitters().stream()).map(AssignmentSubmissionSubmitter::getSubmitter).collect(Collectors.toList()); + // only if all submitters can be found do we import submissions + if (submitters.containsAll(userDirectoryService.getUsers(submitters))) { + submissions.forEach(s -> s.setId(null)); + submissions.forEach(s -> s.getSubmitters().forEach(u -> u.setId(null))); + } + } else { + // here it is importing the assignment only + assignmentFromXml.setDraft(true); + assignmentFromXml.setAttachments(new HashSet<>()); + assignmentFromXml.setGroups(new HashSet<>()); + assignmentFromXml.setTypeOfAccess(SITE); + Map properties = assignmentFromXml.getProperties().entrySet().stream() + .filter(e -> !PROPERTIES_EXCLUDED_FROM_DUPLICATE_ASSIGNMENTS.contains(e.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + assignmentFromXml.setProperties(properties); + assignmentFromXml.setSubmissions(new HashSet<>()); + } + assignmentRepository.newAssignment(assignmentFromXml); + String result = "merging assignment " + assignmentFromXml.getId() + " with " + assignmentFromXml.getSubmissions().size() + " submissions."; + results.append(result).append(LINE_SEPARATOR); + log.debug(result); + } + return assignmentFromXml; } @Override @@ -1110,38 +1177,6 @@ public AssignmentSubmission addSubmission(String assignmentId, String submitter) return null; } - @Override - public AssignmentSubmission mergeSubmission(Element el) throws IdInvalidException, IdUsedException, PermissionException { - // TODO this will probably be handled in merge Assignments as submissions are children of assignments -// AssignmentSubmission submissionFromXml = new AssignmentSubmission(); -// -// // check for a valid submission name -// if (!Validator.checkResourceId(submissionFromXml.getId())) throw new IdInvalidException(submissionFromXml.getId()); -// -// // check security (throws if not permitted) -// unlock(SECURE_ADD_ASSIGNMENT_SUBMISSION, submissionFromXml.getReference()); -// -// // reserve a submission with this id from the info store - if it's in use, this will return null -// AssignmentSubmissionEdit submission = m_submissionStorage.put( submissionFromXml.getId(), -// submissionFromXml.getAssignmentId(), -// submissionFromXml.getSubmitterIdString(), -// (submissionFromXml.getTimeSubmitted() != null)?String.valueOf(submissionFromXml.getTimeSubmitted().getTime()):null, -// Boolean.valueOf(submissionFromXml.getSubmitted()).toString(), -// Boolean.valueOf(submissionFromXml.getGraded()).toString()); -// if (submission == null) -// { -// throw new IdUsedException(submissionFromXml.getId()); -// } -// -// // transfer from the XML read submission object to the SubmissionEdit -// ((BaseAssignmentSubmissionEdit) submission).set(submissionFromXml); -// -// ((BaseAssignmentSubmissionEdit) submission).setEvent(AssignmentConstants.EVENT_ADD_ASSIGNMENT_SUBMISSION); -// -// return submission; - return null; - } - @Override @Transactional public void removeSubmission(AssignmentSubmission submission) throws PermissionException { diff --git a/assignment/impl/src/test/org/sakaiproject/assignment/impl/AssignmentServiceTest.java b/assignment/impl/src/test/org/sakaiproject/assignment/impl/AssignmentServiceTest.java index 65023a6ecabc..aeec561f6cc1 100644 --- a/assignment/impl/src/test/org/sakaiproject/assignment/impl/AssignmentServiceTest.java +++ b/assignment/impl/src/test/org/sakaiproject/assignment/impl/AssignmentServiceTest.java @@ -22,9 +22,14 @@ package org.sakaiproject.assignment.impl; import static org.hamcrest.CoreMatchers.is; +import static org.mockito.ArgumentMatchers.anyCollection; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.time.Duration; @@ -81,12 +86,17 @@ import org.sakaiproject.user.api.User; import org.sakaiproject.user.api.UserNotDefinedException; import org.sakaiproject.util.ResourceLoader; +import org.sakaiproject.util.Xml; import org.sakaiproject.util.api.FormattedText; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import com.github.javafaker.Faker; @@ -923,6 +933,52 @@ public void gradeUpdateFromAssignmentEventObeserver() { } } + @Test + public void mergeAssignmentFromXML() { + String context = UUID.randomUUID().toString(); + String xml = readResourceToString("/importAssignment.xml"); + Document doc = Xml.readDocument(xml); + + if (doc != null) { + // Mock everything needed to have permission + Site siteMock = mock(Site.class); + Collection groupCollection = new ArrayList<>(); + Group groupMock = mock(Group.class); + when(groupMock.getReference()).thenReturn("reference"); + groupCollection.add(groupMock); + when(siteMock.getGroups()).thenReturn(groupCollection); + Set references = new HashSet<>(); + references.add("reference"); + when(authzGroupService.getAuthzGroupsIsAllowed(anyString(), anyString(), anyCollection())).thenReturn(references); + try { + when(siteService.getSite(context)).thenReturn(siteMock); + } catch (IdUnusedException e) { + Assert.fail("Site mock failed"); + } + + when(securityService.unlock("asn.new", "/assignment/a/SITE_ID")).thenReturn(true); + when(securityService.unlock("asn.revise", "/assignment/a/SITE_ID")).thenReturn(true); + when(securityService.unlock("asn.read", "/assignment/a/SITE_ID")).thenReturn(true); + + // verify the root element + Element root = doc.getDocumentElement(); + // the children + NodeList children = root.getChildNodes(); + int length = children.getLength(); + + for (int i = 0; i < length; i++) { + Node child = children.item(i); + if (child.getNodeType() != Node.ELEMENT_NODE) continue; + + Element element = (Element) child; + if ("org.sakaiproject.assignment.api.AssignmentService".equals(element.getTagName())) { + assignmentService.merge(context, element, null, null, null, null, null); + Assert.assertEquals(1, assignmentService.getAssignmentsForContext(context).size()); + } + } + } + } + private AssignmentSubmission createNewSubmission(String context, String submitterId) throws UserNotDefinedException, IdUnusedException { Assignment assignment = createNewAssignment(context); String addSubmissionRef = AssignmentReferenceReckoner.reckoner().context(context).subtype("s").reckon().getReference(); @@ -1057,4 +1113,10 @@ private Event createMockEvent(String context, String gradebookId, Long itemId, S when(event.getContext()).thenReturn(context); return event; } + + private String readResourceToString(String resource) { + InputStream is = this.getClass().getResourceAsStream(resource); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + return br.lines().collect(Collectors.joining("\n")); + } } diff --git a/assignment/impl/src/test/resources/importAssignment.xml b/assignment/impl/src/test/resources/importAssignment.xml new file mode 100644 index 000000000000..b0f28cdbda86 --- /dev/null +++ b/assignment/impl/src/test/resources/importAssignment.xml @@ -0,0 +1,112 @@ + + + + + 12345678-abcd-1234-abcd-123456789abc + Title + Instructions + SITE_ID +

+ 1511517810.303000000 + 1315415101.522000000 + + 1530396000.000000000 + 1531259700.000000000 + 1531346100.000000000 + 1531259700.000000000 + 12345678-abcd-1234-abcd-123456789ab1 + 12345678-abcd-1234-abcd-123456789ab2 + false + false + false + false + 0 + + + 12345678-abcd-1234-abcd-123456789ab3 + + + 00001 + 12345678-abcd-1234-abcd-123456789ab4 + true + gen.nograd + + + + 1513276322.014000000 + 1516957649.084000000 + 1513155622.517000000 + 1516957649.084000000 + + + + FeedbackComment + + gen.nograd + 0 + true + true + true + 12345678-abcd-1234-abcd-123456789ab5 + true + false + false + true + + + 12345678-abcd-1234-abcd-123456789ab6 + 20171213090022517 + 12345678-abcd-1234-abcd-123456789ab7 + 20180126090729084 + 23-dic-2017 11:15 + Thu Dec 14 19:32:02 CET 2017 USER submitted + + + + + 0 + false + false + assignment_instructor_notifications_none + 12345678-abcd-1234-abcd-123456789ab8 + false + false + 0 + 20180621100207763 + assignment_releasereturn_notification_none + false + false + 1 + true + 12345678-abcd-1234-abcd-123456789ab9 + false + false + no + false + 20171124100330341 + false + 0 + 12345678-abcd-1234-abcd-123456789a10 + assignment_releasegrade_notification_none + + + + SITE + false + TEXT_AND_ATTACHMENT_ASSIGNMENT_SUBMISSION + UNGRADED_GRADE_TYPE + 0 + 10 + false + false + true + false + 1416611100.000000000 + false + false + 0 + + false + + + \ No newline at end of file diff --git a/config/configuration/bundles/src/bundle/org/sakaiproject/config/bundle/default.sakai.properties b/config/configuration/bundles/src/bundle/org/sakaiproject/config/bundle/default.sakai.properties index c0e358bc3451..3ca28213dc8e 100644 --- a/config/configuration/bundles/src/bundle/org/sakaiproject/config/bundle/default.sakai.properties +++ b/config/configuration/bundles/src/bundle/org/sakaiproject/config/bundle/default.sakai.properties @@ -1984,6 +1984,10 @@ # Default: false # assignment.show.official.photo=true +# Assignment archive should import submissions during merge +# DEFAULT: false (import only the assignment no submissions) +# assignment.merge.import.submissions=true + # ###################################### # SAK-29406 Allow Assignment tool to grade with two decimal points # ###################################### diff --git a/deploy/pom.xml b/deploy/pom.xml index e738a248cc5b..421d1674b690 100644 --- a/deploy/pom.xml +++ b/deploy/pom.xml @@ -253,6 +253,12 @@ jackson-dataformat-xml compile + + com.fasterxml.jackson.module + jackson-module-parameter-names + ${sakai.jackson.version} + compile + com.fasterxml.jackson.datatype jackson-datatype-jdk8 diff --git a/kernel/kernel-private/pom.xml b/kernel/kernel-private/pom.xml index bd61d8c4396d..bd809a522424 100644 --- a/kernel/kernel-private/pom.xml +++ b/kernel/kernel-private/pom.xml @@ -69,7 +69,23 @@ com.fasterxml.jackson.dataformat jackson-dataformat-xml - ${sakai.jackson.version} + + + com.fasterxml.woodstox + woodstox-core + + + com.fasterxml.jackson.module + jackson-module-parameter-names + ${sakai.jackson.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 net.sf.ehcache diff --git a/kernel/kernel-private/src/main/java/org/sakaiproject/hibernate/CrudRepository.java b/kernel/kernel-private/src/main/java/org/sakaiproject/hibernate/CrudRepository.java index 82f86027ceeb..6a508ad7d52e 100644 --- a/kernel/kernel-private/src/main/java/org/sakaiproject/hibernate/CrudRepository.java +++ b/kernel/kernel-private/src/main/java/org/sakaiproject/hibernate/CrudRepository.java @@ -115,5 +115,7 @@ public interface CrudRepository extends Repository${sakai.jackson.version} provided + + com.fasterxml.jackson.module + jackson-module-parameter-names + ${sakai.jackson.version} + provided + com.fasterxml.jackson.datatype jackson-datatype-jdk8 @@ -567,6 +573,11 @@ ${sakai.jackson.version} provided + + com.fasterxml.jackson.module + jackson-modules-java8 + ${sakai.jackson.version} + com.fasterxml.jackson.module jackson-module-jaxb-annotations