diff --git a/common/archive-impl/impl2/src/java/org/sakaiproject/archive/impl/SiteArchiver.java b/common/archive-impl/impl2/src/java/org/sakaiproject/archive/impl/SiteArchiver.java
index 7fd154ccd889..372be1cf6df8 100644
--- a/common/archive-impl/impl2/src/java/org/sakaiproject/archive/impl/SiteArchiver.java
+++ b/common/archive-impl/impl2/src/java/org/sakaiproject/archive/impl/SiteArchiver.java
@@ -312,7 +312,7 @@ protected String archiveSite(Site site, Document doc, Stack stack, String fromSy
if ( pattern != null ) {
NodeList nl = siteNode.getElementsByTagName("property");
- List toRemove = new ArrayList();
+ List toRemove = new ArrayList<>();
for(int i = 0; i < nl.getLength(); i++) {
Element proptag = (Element)nl.item(i);
diff --git a/common/archive-impl/impl2/src/webapp/WEB-INF/components.xml b/common/archive-impl/impl2/src/webapp/WEB-INF/components.xml
index b3d1df40d644..a697d2bce781 100644
--- a/common/archive-impl/impl2/src/webapp/WEB-INF/components.xml
+++ b/common/archive-impl/impl2/src/webapp/WEB-INF/components.xml
@@ -32,6 +32,7 @@
DiscussionForumService
WebService
LessonBuilderEntityProducer
+ rubrics
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 a4d10cd2fc77..66ae3a7a00ae 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
@@ -533,7 +533,7 @@
# archive.merge.filter.services=false
# List of data service types that can merge in data from an archive
-# DEFAULT: AnnouncementService,AssignmentService,ContentHostingService,CalendarService,ChatEntityProducer,DiscussionService,MailArchiveService,SyllabusService,RWikiObjectService,DiscussionForumService,WebService,LessonBuilderEntityProducer
+# DEFAULT: AnnouncementService,AssignmentService,ContentHostingService,CalendarService,ChatEntityProducer,DiscussionService,MailArchiveService,SyllabusService,RWikiObjectService,DiscussionForumService,WebService,LessonBuilderEntityProducer,RubricsService
# archive.merge.filtered.services={list of service names}
# Controls if user role filtering is enabled. If enabled, any user roles not in the list cannot archive or merge data
diff --git a/rubrics/api/src/main/java/org/sakaiproject/rubrics/api/RubricsConstants.java b/rubrics/api/src/main/java/org/sakaiproject/rubrics/api/RubricsConstants.java
index 3d80f5a34e40..c2afba871743 100644
--- a/rubrics/api/src/main/java/org/sakaiproject/rubrics/api/RubricsConstants.java
+++ b/rubrics/api/src/main/java/org/sakaiproject/rubrics/api/RubricsConstants.java
@@ -24,27 +24,27 @@
public interface RubricsConstants {
- public static final String RBCS_TOOL = "sakai.rubrics";
- public static final String RBCS_TOOL_ASSIGNMENT_GRADES = "sakai.assignment.grades";
- public static final String RBCS_TOOL_FORUMS = "sakai.forums";
- public static final String RBCS_TOOL_GRADEBOOKNG = "sakai.gradebookng";
- public static final String RBCS_TOOL_SAMIGO = "sakai.samigo";
- public static final String RBCS_TOOL_LESSONBUILDERTOOL = "sakai.lessonbuildertool";
+ public static final String RBCS_TOOL = "sakai.rubrics";
+ public static final String RBCS_TOOL_ASSIGNMENT_GRADES = "sakai.assignment.grades";
+ public static final String RBCS_TOOL_FORUMS = "sakai.forums";
+ public static final String RBCS_TOOL_GRADEBOOKNG = "sakai.gradebookng";
+ public static final String RBCS_TOOL_SAMIGO = "sakai.samigo";
+ public static final String RBCS_TOOL_LESSONBUILDERTOOL = "sakai.lessonbuildertool";
- public static final String RBCS_PREFIX = "rbcs-";
- public static final String RBCS_CONFIG_PREFIX = "config-";
- public static final String RBCS_CONFIG = RBCS_PREFIX + RBCS_CONFIG_PREFIX;
- public static final String RBCS_MULTIPLE_OPTIONS_CONFIG = RBCS_PREFIX + "multiple-options-config-";
- public static final String RBCS_ASSOCIATION_STATE_DETAILS = RBCS_PREFIX + "state-details";
- public static final String RBCS_ASSOCIATE_SUFFIX = "associate";
- public static final String RBCS_ASSOCIATE = RBCS_PREFIX + RBCS_ASSOCIATE_SUFFIX;// values: 0 or empty no association, 1 regular association, 2 dynamic rubric in Samigo
- public static final String RBCS_LIST_SUFFIX = "rubricslist";
- public static final String RBCS_LIST = RBCS_PREFIX + RBCS_LIST_SUFFIX;
- public static final String RBCS_SOFT_DELETED = RBCS_PREFIX + "soft-deleted";
- public static final String RBCS_ASSESSOR_ID = "assessorId";
- public static final String RBCS_HAS_ASSOCIATED_RUBRIC = "hasAssociatedRubric";
- public static final String RBCS_STUDENT_SELF_REPORT = "studentSelfReport";
- public static final String RBCS_STUDENT_SELF_REPORT_MODE = "studentSelfReportMode";
+ public static final String RBCS_PREFIX = "rbcs-";
+ public static final String RBCS_CONFIG_PREFIX = "config-";
+ public static final String RBCS_CONFIG = RBCS_PREFIX + RBCS_CONFIG_PREFIX;
+ public static final String RBCS_MULTIPLE_OPTIONS_CONFIG = RBCS_PREFIX + "multiple-options-config-";
+ public static final String RBCS_ASSOCIATION_STATE_DETAILS = RBCS_PREFIX + "state-details";
+ public static final String RBCS_ASSOCIATE_SUFFIX = "associate";
+ public static final String RBCS_ASSOCIATE = RBCS_PREFIX + RBCS_ASSOCIATE_SUFFIX;// values: 0 or empty no association, 1 regular association, 2 dynamic rubric in Samigo
+ public static final String RBCS_LIST_SUFFIX = "rubricslist";
+ public static final String RBCS_LIST = RBCS_PREFIX + RBCS_LIST_SUFFIX;
+ public static final String RBCS_SOFT_DELETED = RBCS_PREFIX + "soft-deleted";
+ public static final String RBCS_ASSESSOR_ID = "assessorId";
+ public static final String RBCS_HAS_ASSOCIATED_RUBRIC = "hasAssociatedRubric";
+ public static final String RBCS_STUDENT_SELF_REPORT = "studentSelfReport";
+ public static final String RBCS_STUDENT_SELF_REPORT_MODE = "studentSelfReportMode";
public static final String RBCS_PERMISSIONS_EVALUATOR = "rubrics.evaluator";
public static final String RBCS_PERMISSIONS_EDITOR = "rubrics.editor";
@@ -53,12 +53,13 @@ public interface RubricsConstants {
public static final String RBCS_EXPORT_PDF = "rubrics.export.pdf";
- //samigo custom props
- public static final String RBCS_PUBLISHED_ASSESSMENT_ENTITY_PREFIX = "pub.";
+ //samigo custom props
+ public static final String RBCS_PUBLISHED_ASSESSMENT_ENTITY_PREFIX = "pub.";
- //forums custom props
- public static final String RBCS_FORUM_ENTITY_PREFIX = "for.";
- public static final String RBCS_TOPIC_ENTITY_PREFIX = "top.";
- public static final String RBCS_MSG_ENTITY_PREFIX = "msg.";
-
+ //forums custom props
+ public static final String RBCS_FORUM_ENTITY_PREFIX = "for.";
+ public static final String RBCS_TOPIC_ENTITY_PREFIX = "top.";
+ public static final String RBCS_MSG_ENTITY_PREFIX = "msg.";
+
+ public static final String LINE_SEPARATOR = System.getProperty("line.separator");
}
diff --git a/rubrics/api/src/main/java/org/sakaiproject/rubrics/api/RubricsService.java b/rubrics/api/src/main/java/org/sakaiproject/rubrics/api/RubricsService.java
index 547033ffe5b7..16f634b65536 100644
--- a/rubrics/api/src/main/java/org/sakaiproject/rubrics/api/RubricsService.java
+++ b/rubrics/api/src/main/java/org/sakaiproject/rubrics/api/RubricsService.java
@@ -29,6 +29,7 @@
import java.util.Optional;
import org.sakaiproject.entity.api.Entity;
+import org.sakaiproject.entity.api.EntityProducer;
import org.sakaiproject.rubrics.api.beans.AssociationTransferBean;
import org.sakaiproject.rubrics.api.beans.CriterionTransferBean;
import org.sakaiproject.rubrics.api.beans.EvaluationTransferBean;
@@ -37,7 +38,7 @@
import org.sakaiproject.rubrics.api.model.Rubric;
import org.sakaiproject.rubrics.api.model.ToolItemRubricAssociation;
-public interface RubricsService {
+public interface RubricsService extends EntityProducer {
public static final String REFERENCE_ROOT = Entity.SEPARATOR + "rubrics";
diff --git a/rubrics/api/src/main/java/org/sakaiproject/rubrics/api/model/Rubric.java b/rubrics/api/src/main/java/org/sakaiproject/rubrics/api/model/Rubric.java
index 7ba8d49f9a10..7adb886621e6 100644
--- a/rubrics/api/src/main/java/org/sakaiproject/rubrics/api/model/Rubric.java
+++ b/rubrics/api/src/main/java/org/sakaiproject/rubrics/api/model/Rubric.java
@@ -65,6 +65,7 @@ public class Rubric implements PersistableEntity, Serializable, Cloneable
@GeneratedValue(strategy = GenerationType.AUTO, generator ="rbc_seq" )
private Long id;
+ @Column(nullable = false)
private String title;
private Boolean weighted = Boolean.FALSE;
@@ -81,14 +82,15 @@ public class Rubric implements PersistableEntity, Serializable, Cloneable
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "rubric")
private List associations = new ArrayList<>();
- private Instant created;
+ @Column(nullable = false)
+ private Instant created = Instant.now();
private Instant modified;
- @Column(length = 99)
+ @Column(length = 99, nullable = false)
private String ownerId;
- @Column(length = 99)
+ @Column(length = 99, nullable = false)
private String creatorId;
private Boolean shared = Boolean.FALSE;
diff --git a/rubrics/impl/pom.xml b/rubrics/impl/pom.xml
index 8a920dbf7778..1cc33e80ddac 100644
--- a/rubrics/impl/pom.xml
+++ b/rubrics/impl/pom.xml
@@ -119,6 +119,11 @@
org.sakaiproject.edu-services.sections
sections-api
+
+ org.sakaiproject.common
+ archive-api
+ test
+
diff --git a/rubrics/impl/src/main/java/org/sakaiproject/rubrics/impl/RubricsServiceImpl.java b/rubrics/impl/src/main/java/org/sakaiproject/rubrics/impl/RubricsServiceImpl.java
index 3c81f03cbb90..c47487272029 100644
--- a/rubrics/impl/src/main/java/org/sakaiproject/rubrics/impl/RubricsServiceImpl.java
+++ b/rubrics/impl/src/main/java/org/sakaiproject/rubrics/impl/RubricsServiceImpl.java
@@ -25,6 +25,7 @@
import static org.sakaiproject.rubrics.api.RubricsConstants.RBCS_CONFIG;
import static org.sakaiproject.rubrics.api.RubricsConstants.RBCS_MULTIPLE_OPTIONS_CONFIG;
import static org.sakaiproject.rubrics.api.RubricsConstants.RBCS_PREFIX;
+import static org.sakaiproject.rubrics.api.RubricsConstants.LINE_SEPARATOR;
import java.awt.Color;
import java.io.ByteArrayOutputStream;
@@ -43,10 +44,11 @@
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
+import java.util.Stack;
import java.util.function.Predicate;
import java.util.stream.Collectors;
-import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.jsoup.Jsoup;
@@ -58,7 +60,6 @@
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.entity.api.Entity;
import org.sakaiproject.entity.api.EntityManager;
-import org.sakaiproject.entity.api.EntityProducer;
import org.sakaiproject.entity.api.EntityTransferrer;
import org.sakaiproject.entity.api.Reference;
import org.sakaiproject.event.api.EventTrackingService;
@@ -88,11 +89,8 @@
import org.sakaiproject.rubrics.api.repository.RatingRepository;
import org.sakaiproject.rubrics.api.repository.ReturnedEvaluationRepository;
import org.sakaiproject.rubrics.api.repository.RubricRepository;
-import org.sakaiproject.site.api.Group;
-import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.api.SiteService;
import org.sakaiproject.time.api.UserTimeService;
-import org.sakaiproject.tool.assessment.data.ifc.assessment.PublishedAssessmentIfc;
import org.sakaiproject.tool.assessment.facade.PublishedAssessmentFacadeQueriesAPI;
import org.sakaiproject.tool.api.SessionManager;
import org.sakaiproject.tool.api.ToolManager;
@@ -107,7 +105,6 @@
import com.lowagie.text.Chunk;
import com.lowagie.text.Document;
-import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.FontFactory;
import com.lowagie.text.PageSize;
@@ -119,10 +116,14 @@
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
@Slf4j
@Setter
@Transactional
-public class RubricsServiceImpl implements RubricsService, EntityProducer, EntityTransferrer {
+public class RubricsServiceImpl implements RubricsService, EntityTransferrer {
private static final Font BOLD_FONT = FontFactory.getFont(FontFactory.HELVETICA, 10, Font.BOLD);
private static final Font NORMAL_FONT = FontFactory.getFont(FontFactory.HELVETICA, 7, Font.NORMAL);
@@ -1280,7 +1281,7 @@ public byte[] createPdf(String siteId, Long rubricId, String toolId, String item
PdfPCell header = new PdfPCell();
Paragraph paragraph = new Paragraph(resourceLoader.getFormattedMessage("export_rubric_title", rubric.getTitle() + "\n"), BOLD_FONT);
- paragraph.setAlignment(Element.ALIGN_LEFT);
+ paragraph.setAlignment(com.lowagie.text.Element.ALIGN_LEFT);
try {
String siteTitle = siteService.getSite(rubric.getOwnerId()).getTitle();
paragraph.add(resourceLoader.getFormattedMessage("export_rubric_site", siteTitle));
@@ -1522,6 +1523,181 @@ public Map transferCopyEntities(String fromContext, String toCon
return transferCopyEntities(fromContext, toContext, ids, null);
}
+ @Override
+ public String getLabel() {
+ return "rubrics";
+ }
+
+ @Override
+ public boolean willArchiveMerge() {
+ return true;
+ }
+
+ @Override
+ public String archive(String siteId, org.w3c.dom.Document doc, Stack stack, String archivePath, List attachments) {
+
+ StringBuilder results = new StringBuilder();
+ results.append("begin archiving ").append(getLabel()).append(" for site ").append(siteId).append(LINE_SEPARATOR);
+
+ Element rubrics = doc.createElement(getLabel());
+ stack.peek().appendChild(rubrics);
+ stack.push(rubrics);
+
+ rubricRepository.findByOwnerId(siteId).stream().sorted((r1, r2) -> r1.getTitle().compareTo(r2.getTitle())).forEach(rubric -> {
+
+ Element rubricEl = doc.createElement("rubric");
+ rubrics.appendChild(rubricEl);
+
+ rubricEl.setAttribute("title", rubric.getTitle());
+ rubricEl.setAttribute("created", Long.toString(rubric.getCreated().getEpochSecond()));
+ rubricEl.setAttribute("creator", rubric.getCreatorId());
+ rubricEl.setAttribute("weighted", Boolean.toString(rubric.getWeighted()));
+ rubricEl.setAttribute("adhoc", Boolean.toString(rubric.getAdhoc()));
+ rubricEl.setAttribute("max-points", Double.toString(rubric.getMaxPoints()));
+
+ Element criteriaEl = doc.createElement("criteria");
+ rubricEl.appendChild(criteriaEl);
+
+ rubric.getCriteria().forEach(criterion -> {
+
+ Element criterionEl = doc.createElement("criterion");
+ criteriaEl.appendChild(criterionEl);
+
+ criterionEl.setAttribute("title", criterion.getTitle());
+ Float weight = criterion.getWeight();
+ if (weight != null) {
+ criterionEl.setAttribute("weight", Float.toString(weight));
+ }
+
+ String description = criterion.getDescription();
+ if (StringUtils.isNotBlank(description)) {
+ Element descriptionEl = doc.createElement("description");
+ criterionEl.appendChild(descriptionEl);
+ descriptionEl.appendChild(doc.createCDATASection(description));
+ }
+
+ Element ratingsEl = doc.createElement("ratings");
+ criterionEl.appendChild(ratingsEl);
+
+ criterion.getRatings().forEach(rating -> {
+
+ Element ratingEl = doc.createElement("rating");
+ ratingsEl.appendChild(ratingEl);
+ ratingEl.setAttribute("title", rating.getTitle());
+ ratingEl.setAttribute("points", Double.toString(rating.getPoints()));
+ String ratingDescription = rating.getDescription();
+ if (StringUtils.isNotBlank(ratingDescription)) {
+ Element ratingDescriptionEl = doc.createElement("description");
+ ratingEl.appendChild(ratingDescriptionEl);
+ ratingDescriptionEl.appendChild(doc.createCDATASection(ratingDescription));
+ }
+ });
+ });
+ });
+
+ stack.pop();
+
+ results.append("completed archiving ").append(getLabel()).append(" for site ").append(siteId).append(LINE_SEPARATOR);
+ return results.toString();
+ }
+
+ @Override
+ public String merge(String toSiteId, Element root, String archivePath, String fromSiteId, Map attachmentNames, Map userIdTrans, Set userListAllowImport) {
+
+ StringBuilder results = new StringBuilder();
+ results.append("begin merging ").append(getLabel()).append(" for site ").append(toSiteId).append(LINE_SEPARATOR);
+
+ String currentUserId = sessionManager.getCurrentSessionUserId();
+
+ if (!root.getTagName().equals(getLabel())) {
+ log.warn("Tried to merge a non <{}> xml document", getLabel());
+ return "Invalid xml document";
+ }
+
+ NodeList rubricNodes = root.getElementsByTagName("rubric");
+
+ for (int i = 0; i < rubricNodes.getLength(); i++) {
+ Element rubricEl = (Element) rubricNodes.item(i);
+
+ String creatorId = currentUserId;
+
+ String originalCreatorId = rubricEl.getAttribute("creator");
+ if (StringUtils.isNotBlank(originalCreatorId)) {
+ try {
+ userDirectoryService.getUser(originalCreatorId);
+ creatorId = originalCreatorId;
+ } catch (UserNotDefinedException unde) {
+ }
+ }
+
+ RubricTransferBean rubricBean = new RubricTransferBean();
+ rubricBean.setOwnerId(toSiteId);
+ // TODO: Do we honour the original creator, or the current user?
+ rubricBean.setCreatorId(creatorId);
+ // TODO: Do we honour the original created date, or use now?
+ rubricBean.setCreated(Instant.ofEpochSecond(Long.parseLong(rubricEl.getAttribute("created"))));
+ rubricBean.setTitle(rubricEl.getAttribute("title"));
+ rubricBean.setMaxPoints(Double.parseDouble(rubricEl.getAttribute("max-points")));
+ rubricBean.setWeighted(Boolean.parseBoolean(rubricEl.getAttribute("weighted")));
+ rubricBean.setAdhoc(Boolean.parseBoolean(rubricEl.getAttribute("adhoc")));
+ rubricBean.setDraft(false);
+
+ NodeList criteriaNodes = rubricEl.getElementsByTagName("criteria");
+ if (criteriaNodes.getLength() != 1) {
+ log.warn("No criteria element in rubrics archive XML");
+ continue;
+ }
+
+ NodeList criterionNodes = ((Element) criteriaNodes.item(0)).getElementsByTagName("criterion");
+
+ List criteria = new ArrayList<>();
+ for (int j = 0; j < criterionNodes.getLength(); j++) {
+ Element criterionEl = (Element) criterionNodes.item(j);
+ CriterionTransferBean criterionBean = new CriterionTransferBean();
+ criterionBean.setTitle(criterionEl.getAttribute("title"));
+
+ NodeList descriptionNodes = criterionEl.getElementsByTagName("description");
+ if (descriptionNodes.getLength() == 1) {
+ CDATASection descriptionSection = (CDATASection) descriptionNodes.item(0).getFirstChild();
+ if (descriptionSection != null) {
+ criterionBean.setDescription(descriptionSection.getNodeValue());
+ }
+ }
+
+ NodeList ratingsNodes = criterionEl.getElementsByTagName("ratings");
+ if (ratingsNodes.getLength() == 1) {
+ NodeList ratingNodes = ((Element) ratingsNodes.item(0)).getElementsByTagName("rating");
+ List ratings = new ArrayList<>();
+ for (int k = 0; k < ratingNodes.getLength(); k++) {
+ Element ratingEl = (Element) ratingNodes.item(k);
+ RatingTransferBean ratingBean = new RatingTransferBean();
+ ratingBean.setTitle(ratingEl.getAttribute("title"));
+ ratingBean.setPoints(Double.parseDouble(ratingEl.getAttribute("points")));
+
+ NodeList ratingDescriptionNodes = ratingEl.getElementsByTagName("description");
+ if (ratingDescriptionNodes.getLength() == 1) {
+ CDATASection ratingDescriptionSection = (CDATASection) ratingDescriptionNodes.item(0).getFirstChild();
+ if (ratingDescriptionSection != null) {
+ ratingBean.setDescription(ratingDescriptionSection.getNodeValue());
+ }
+ }
+ ratings.add(ratingBean);
+ }
+ criterionBean.setRatings(ratings);
+ }
+
+ criteria.add(criterionBean);
+ }
+
+ rubricBean.setCriteria(criteria);
+
+ saveRubric(rubricBean);
+ }
+
+ results.append("completed merging ").append(getLabel()).append(" for site ").append(toSiteId).append(LINE_SEPARATOR);
+ return results.toString();
+ }
+
@Override
public String[] myToolIds() {
return new String[] { RubricsConstants.RBCS_TOOL };
@@ -1636,7 +1812,6 @@ private Optional getCriterionPoints(Criterion cri, Evaluation evaluation
}
private boolean isEditor(String siteId) {
-
return securityService.unlock(RubricsConstants.RBCS_PERMISSIONS_EDITOR, siteService.siteReference(siteId));
}
diff --git a/rubrics/impl/src/test/org/sakaiproject/rubrics/impl/test/RubricsServiceTests.java b/rubrics/impl/src/test/org/sakaiproject/rubrics/impl/test/RubricsServiceTests.java
index 9e419037c75b..6d00bfd9ca87 100644
--- a/rubrics/impl/src/test/org/sakaiproject/rubrics/impl/test/RubricsServiceTests.java
+++ b/rubrics/impl/src/test/org/sakaiproject/rubrics/impl/test/RubricsServiceTests.java
@@ -15,6 +15,8 @@
*/
package org.sakaiproject.rubrics.impl.test;
+import org.apache.commons.lang3.StringUtils;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -30,11 +32,14 @@
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
+import java.util.Stack;
import org.hibernate.SessionFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+
+import org.sakaiproject.archive.api.ArchiveService;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.rubrics.api.RubricsConstants;
import org.sakaiproject.rubrics.api.RubricsService;
@@ -47,12 +52,14 @@
import org.sakaiproject.rubrics.api.model.EvaluatedItemOwnerType;
import org.sakaiproject.rubrics.api.model.Evaluation;
import org.sakaiproject.rubrics.api.model.EvaluationStatus;
+import org.sakaiproject.rubrics.api.model.Rating;
import org.sakaiproject.rubrics.api.model.ReturnedEvaluation;
import org.sakaiproject.rubrics.api.model.Rubric;
import org.sakaiproject.rubrics.api.model.ToolItemRubricAssociation;
import org.sakaiproject.rubrics.api.repository.AssociationRepository;
import org.sakaiproject.rubrics.api.repository.CriterionRepository;
import org.sakaiproject.rubrics.api.repository.EvaluationRepository;
+import org.sakaiproject.rubrics.api.repository.RubricRepository;
import org.sakaiproject.rubrics.api.repository.ReturnedEvaluationRepository;
import org.sakaiproject.rubrics.impl.RubricsServiceImpl;
import org.sakaiproject.site.api.Site;
@@ -64,12 +71,24 @@
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.user.api.UserNotDefinedException;
import org.sakaiproject.util.ResourceLoader;
+import org.sakaiproject.util.Xml;
+
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.springframework.test.util.AopTestUtils;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
import lombok.extern.slf4j.Slf4j;
@Slf4j
@@ -81,6 +100,7 @@ public class RubricsServiceTests extends AbstractTransactionalJUnit4SpringContex
@Autowired private CriterionRepository criterionRepository;
@Autowired private EvaluationRepository evaluationRepository;
@Autowired private ReturnedEvaluationRepository returnedEvaluationRepository;
+ @Autowired private RubricRepository rubricRepository;
@Autowired private RubricsService rubricsService;
@Autowired private SecurityService securityService;
@Autowired private SessionManager sessionManager;
@@ -471,8 +491,6 @@ public void deleteRating() {
int initialRatingsSize = criterionBean.getRatings().size();
RatingTransferBean ratingBean = criterionBean.getRatings().get(2);
- System.out.println(ratingBean.getPoints());
-
switchToUser1();
assertThrows(SecurityException.class, () -> rubricsService.deleteRating(ratingBean.getId(), criterionBean.getId(), siteId, rubricBean.getId()));
@@ -767,6 +785,7 @@ public void saveEvaluationAsTeachingAssistant() {
@Test
public void contextualFilenameNoEvaluation() {
+
switchToInstructor();
RubricTransferBean rubric = rubricsService.createDefaultRubric(siteId);
String toolId = "sakai.assignment";
@@ -782,6 +801,7 @@ public void contextualFilenameNoEvaluation() {
@Test
public void contextualFilename() throws UserNotDefinedException {
+
switchToInstructor();
RubricTransferBean rubric = rubricsService.createDefaultRubric(siteId);
String toolId = "sakai.assignment";
@@ -801,6 +821,184 @@ public void contextualFilename() throws UserNotDefinedException {
assertEquals(rubric.getTitle() + '_' + user1SortName, filename);
}
+ @Test
+ public void archive() {
+
+ switchToInstructor();
+
+ RubricTransferBean rubric1 = rubricsService.createDefaultRubric(siteId);
+ String title1 = "Cheese Sandwich";
+ rubric1.setTitle(title1);
+ String rubric1Criteria1Rating1Description = "This is great";
+ rubric1.getCriteria().get(0).getRatings().get(0).setDescription(rubric1Criteria1Rating1Description);
+ rubricsService.saveRubric(rubric1);
+
+ String rubric2CriteriaDescription = "Rate those sandwiches";
+ RubricTransferBean rubric2 = rubricsService.createDefaultRubric(siteId);
+ String title2 = "Egg Sandwich";
+ rubric2.setTitle(title2);
+ rubric2.getCriteria().get(0).setDescription(rubric2CriteriaDescription);
+ rubricsService.saveRubric(rubric2);
+
+ RubricTransferBean rubric3 = rubricsService.createDefaultRubric(siteId);
+ String title3 = "Ham Sandwich";
+ rubric3.setTitle(title3);
+ rubricsService.saveRubric(rubric3);
+
+ RubricTransferBean[] rubrics = new RubricTransferBean[] { rubric1, rubric2, rubric3 };
+
+ Document doc = Xml.createDocument();
+ Stack stack = new Stack<>();
+
+ Element root = doc.createElement("archive");
+ doc.appendChild(root);
+ root.setAttribute("source", siteId);
+ root.setAttribute("xmlns:sakai", ArchiveService.SAKAI_ARCHIVE_NS);
+ root.setAttribute("xmlns:CHEF", ArchiveService.SAKAI_ARCHIVE_NS.concat("CHEF"));
+ root.setAttribute("xmlns:DAV", ArchiveService.SAKAI_ARCHIVE_NS.concat("DAV"));
+ stack.push(root);
+
+ String results = rubricsService.archive(siteId, doc, stack, "", null);
+
+ assertEquals(1, stack.size());
+
+ NodeList rubricsNode = root.getElementsByTagName(rubricsService.getLabel());
+ assertEquals(1, rubricsNode.getLength());
+
+ NodeList rubricNodes = ((Element) rubricsNode.item(0)).getElementsByTagName("rubric");
+ assertEquals(3, rubricNodes.getLength());
+
+ for (int i = 0; i < rubricNodes.getLength(); i++) {
+
+ RubricTransferBean rubricBean = rubrics[i];
+ Element rubricEl = (Element) rubricNodes.item(i);
+
+ assertEquals(rubricBean.getTitle(), rubricEl.getAttribute("title"));
+ assertEquals(Double.toString(rubricBean.getMaxPoints()), rubricEl.getAttribute("max-points"));
+ assertEquals(Long.toString(rubricBean.getCreated().getEpochSecond()), rubricEl.getAttribute("created"));
+ assertEquals(Boolean.toString(rubricBean.getWeighted()), rubricEl.getAttribute("weighted"));
+ assertEquals(Boolean.toString(rubricBean.getAdhoc()), rubricEl.getAttribute("adhoc"));
+
+ NodeList criteriaNodes = rubricEl.getElementsByTagName("criteria");
+ assertEquals(1, criteriaNodes.getLength());
+
+ NodeList criterionNodes = ((Element) criteriaNodes.item(0)).getElementsByTagName("criterion");
+ assertEquals(rubricBean.getCriteria().size(), criterionNodes.getLength());
+
+ for (int j = 0; j < criterionNodes.getLength(); j++) {
+
+ CriterionTransferBean criterionBean = rubrics[i].getCriteria().get(j);
+ Element criterionEl = (Element) criterionNodes.item(j);
+
+ assertEquals(criterionBean.getTitle(), criterionEl.getAttribute("title"));
+ assertEquals(Float.toString(criterionBean.getWeight()), criterionEl.getAttribute("weight"));
+
+ if (i == 1 && j == 0) {
+ // We've only set a description on the first criteria of the second rubric, and
+ // descriptions are optional
+ NodeList descriptionNodes = criterionEl.getElementsByTagName("description");
+ assertEquals(1, descriptionNodes.getLength());
+ CDATASection descriptionNode = (CDATASection) descriptionNodes.item(0).getFirstChild();
+ assertNotNull(descriptionNode);
+ assertEquals(criterionBean.getDescription(), descriptionNode.getNodeValue());
+ }
+
+ NodeList ratingsNodes = criterionEl.getElementsByTagName("ratings");
+ assertEquals(1, ratingsNodes.getLength());
+
+ NodeList ratingNodes = ((Element) ratingsNodes.item(0)).getElementsByTagName("rating");
+ assertEquals(criterionBean.getRatings().size(), ratingNodes.getLength());
+
+ for (int k = 0; k < ratingNodes.getLength(); k++) {
+
+ RatingTransferBean ratingBean = criterionBean.getRatings().get(k);
+ Element ratingEl = (Element) ratingNodes.item(k);
+
+ assertEquals(ratingBean.getTitle(), ratingEl.getAttribute("title"));
+ assertEquals(Double.toString(ratingBean.getPoints()), ratingEl.getAttribute("points"));
+
+ String ratingDescription = ratingBean.getDescription();
+ if (StringUtils.isNotBlank(ratingDescription)) {
+ NodeList ratingDescriptionNodes = ratingEl.getElementsByTagName("description");
+ assertEquals(1, ratingDescriptionNodes.getLength());
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ public void merge() {
+
+ Document doc = Xml.readDocumentFromStream(this.getClass().getResourceAsStream("/archive/rubrics.xml"));
+
+ Element root = doc.getDocumentElement();
+
+ String fromSite = root.getAttribute("source");
+ String toSite = "my-new-site";
+
+ switchToInstructor(toSite);
+
+ Element rubricsElement = doc.createElement("not-rubrics");
+
+ rubricsService.merge(toSite, rubricsElement, "", fromSite, null, null, null);
+
+ assertEquals("Invalid xml document", rubricsService.merge(siteId, rubricsElement, "", fromSite, null, null, null));
+
+ rubricsElement = (Element) root.getElementsByTagName(rubricsService.getLabel()).item(0);
+
+ rubricsService.merge(toSite, rubricsElement, "", fromSite, null, null, null);
+
+ NodeList rubricNodes = rubricsElement.getElementsByTagName("rubric");
+
+ List rubrics = rubricRepository.findByOwnerId(toSite);
+
+ for (int i = 0; i < rubricNodes.getLength(); i++) {
+ Element rubricEl = (Element) rubricNodes.item(i);
+ String rubricTitle = rubricEl.getAttribute("title");
+ Optional optRubric = rubrics.stream().filter(r -> r.getTitle().equals(rubricTitle)).findAny();
+ assertTrue(optRubric.isPresent());
+ Rubric rubric = optRubric.get();
+ //assertEquals(Double.valueOf(rubricEl.getAttribute("max-points")), rubric.getMaxPoints());
+ assertEquals(Boolean.valueOf(rubricEl.getAttribute("adhoc")), rubric.getAdhoc());
+ assertEquals(Boolean.valueOf(rubricEl.getAttribute("weighted")), rubric.getWeighted());
+
+ NodeList criterionNodes = ((Element) rubricEl.getElementsByTagName("criteria").item(0))
+ .getElementsByTagName("criterion");
+ List criteria = rubric.getCriteria();
+ assertEquals(criterionNodes.getLength(), criteria.size());
+
+ for (int j = 0; j < criterionNodes.getLength(); j++) {
+ Element criterionEl = (Element) criterionNodes.item(j);
+ String criterionTitle = criterionEl.getAttribute("title");
+ Optional optCriterion = criteria.stream().filter(c -> c.getTitle().equals(criterionEl.getAttribute("title"))).findAny();
+ assertTrue(optCriterion.isPresent());
+ Criterion criterion = optCriterion.get();
+ NodeList descriptionNodes = criterionEl.getElementsByTagName("description");
+ if (descriptionNodes.getLength() == 1) {
+ assertEquals(descriptionNodes.item(0).getFirstChild().getNodeValue(), criterion.getDescription());
+ }
+
+ NodeList ratingNodes = ((Element) criterionEl.getElementsByTagName("ratings").item(0))
+ .getElementsByTagName("rating");
+ List ratings = criterion.getRatings();
+ for (int k = 0; k < ratingNodes.getLength(); k++) {
+ Element ratingEl = (Element) ratingNodes.item(j);
+ String ratingTitle = ratingEl.getAttribute("title");
+ Optional optRating = ratings.stream().filter(r -> r.getTitle().equals(ratingEl.getAttribute("title"))).findAny();
+ assertTrue(optRating.isPresent());
+ Rating rating = optRating.get();
+ assertEquals(Double.valueOf(ratingEl.getAttribute("points")), rating.getPoints());
+
+ NodeList ratingDescriptionNodes = ratingEl.getElementsByTagName("description");
+ if (ratingDescriptionNodes.getLength() == 1) {
+ assertEquals(ratingDescriptionNodes.item(0).getFirstChild().getNodeValue(), rating.getDescription());
+ }
+ }
+ }
+ }
+ }
+
private EvaluationTransferBean buildEvaluation(Long associationId, RubricTransferBean rubricBean, String toolItemId) {
EvaluationTransferBean etb = new EvaluationTransferBean();
@@ -824,6 +1022,7 @@ private EvaluationTransferBean buildEvaluation(Long associationId, RubricTransfe
}
private void setupStudentPermissions() {
+
when(securityService.unlock(RubricsConstants.RBCS_PERMISSIONS_EDITOR, siteRef)).thenReturn(false);
when(securityService.unlock(RubricsConstants.RBCS_PERMISSIONS_EVALUATOR, siteRef)).thenReturn(false);
when(securityService.unlock(RubricsConstants.RBCS_PERMISSIONS_EVALUEE, siteRef)).thenReturn(true);
@@ -866,10 +1065,20 @@ private void switchToUser3() {
}
private void switchToInstructor() {
+ switchToInstructor(null);
+ }
- when(securityService.unlock(RubricsConstants.RBCS_PERMISSIONS_EDITOR, siteRef)).thenReturn(true);
- when(securityService.unlock(RubricsConstants.RBCS_PERMISSIONS_EVALUATOR, siteRef)).thenReturn(true);
- when(securityService.unlock(RubricsConstants.RBCS_PERMISSIONS_EVALUEE, siteRef)).thenReturn(false);
+ private void switchToInstructor(String siteId) {
+
+ String ref = siteId != null ? "/site/" + siteId : siteRef;
+
+ if (siteId != null) {
+ when(siteService.siteReference(siteId)).thenReturn(ref);
+ }
+
+ when(securityService.unlock(RubricsConstants.RBCS_PERMISSIONS_EDITOR, ref)).thenReturn(true);
+ when(securityService.unlock(RubricsConstants.RBCS_PERMISSIONS_EVALUATOR, ref)).thenReturn(true);
+ when(securityService.unlock(RubricsConstants.RBCS_PERMISSIONS_EVALUEE, ref)).thenReturn(false);
when(sessionManager.getCurrentSessionUserId()).thenReturn(instructor);
when(userDirectoryService.getCurrentUser()).thenReturn(instructorUser);
diff --git a/rubrics/impl/src/test/resources/archive/rubrics.xml b/rubrics/impl/src/test/resources/archive/rubrics.xml
new file mode 100644
index 000000000000..27af7247a308
--- /dev/null
+++ b/rubrics/impl/src/test/resources/archive/rubrics.xml
@@ -0,0 +1,6 @@
+
+spin it around
+]]>some foods
+]]>rackets
+]]>pitch
+]]>
\ No newline at end of file
diff --git a/webapi/src/main/java/org/sakaiproject/webapi/controllers/RubricsRestController.java b/webapi/src/main/java/org/sakaiproject/webapi/controllers/RubricsRestController.java
index 06dfcf9dc47a..12739ec42cbf 100644
--- a/webapi/src/main/java/org/sakaiproject/webapi/controllers/RubricsRestController.java
+++ b/webapi/src/main/java/org/sakaiproject/webapi/controllers/RubricsRestController.java
@@ -85,7 +85,13 @@ List> getRubricsForSite(@PathVariable String sit
checkSakaiSession();
- return rubricsService.getRubricsForSite(siteId).stream().map(b -> entityModelForRubricBean(b)).collect(Collectors.toList());
+ try {
+ return rubricsService.getRubricsForSite(siteId).stream().map(b -> entityModelForRubricBean(b)).collect(Collectors.toList());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return null;
}
@GetMapping(value = "/rubrics/shared", produces = MediaType.APPLICATION_JSON_VALUE)
diff --git a/webcomponents/tool/src/main/frontend/packages/sakai-editor/src/SakaiEditor.js b/webcomponents/tool/src/main/frontend/packages/sakai-editor/src/SakaiEditor.js
index 647459986e95..04f162f91320 100644
--- a/webcomponents/tool/src/main/frontend/packages/sakai-editor/src/SakaiEditor.js
+++ b/webcomponents/tool/src/main/frontend/packages/sakai-editor/src/SakaiEditor.js
@@ -1,7 +1,5 @@
import { SakaiElement } from "@sakai-ui/sakai-element";
import { html } from "lit";
-import { ifDefined } from "lit/directives/if-defined.js";
-import { unsafeHTML } from "lit/directives/unsafe-html.js";
export class SakaiEditor extends SakaiElement {
@@ -133,14 +131,8 @@ export class SakaiEditor extends SakaiElement {
render() {
- if (this.textarea) {
- return html `
-
- `;
- }
-
return html `
- ${unsafeHTML(this.content)}
+
`;
}
}