Index: tool/pom.xml
===================================================================
--- tool/pom.xml (revision 129692)
+++ tool/pom.xml (working copy)
@@ -173,6 +173,11 @@
commons-fileupload
commons-fileupload
+
+ org.projectlombok
+ lombok
+ 0.11.6
+
Index: tool/src/java/org/sakaiproject/lessonbuildertool/tool/entityproviders/LessonbuilderEntityProvider.java
===================================================================
--- tool/src/java/org/sakaiproject/lessonbuildertool/tool/entityproviders/LessonbuilderEntityProvider.java (revision 0)
+++ tool/src/java/org/sakaiproject/lessonbuildertool/tool/entityproviders/LessonbuilderEntityProvider.java (working copy)
@@ -0,0 +1,690 @@
+ /**********************************************************************************
+ * $URL: https://source.sakaiproject.org/svn/lessonbuilder/trunk/tool/src/java/org/sakaiproject/lessonbuildertool/tool/entityproviders/LessonbuilderEntityProvider.java $
+ * $Id: LessonbuilderEntityProvider.java $
+ ***********************************************************************************
+ *
+ * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009 The Sakai Foundation
+ *
+ * Licensed under the Educational Community License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.osedu.org/licenses/ECL-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **********************************************************************************/
+
+package org.sakaiproject.lessonbuildertool.tool.entityproviders;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.sakaiproject.entitybroker.EntityReference;
+import org.sakaiproject.entitybroker.EntityView;
+import org.sakaiproject.entitybroker.entityprovider.annotations.EntityCustomAction;
+import org.sakaiproject.entitybroker.entityprovider.EntityProvider;
+import org.sakaiproject.entitybroker.entityprovider.capabilities.ActionsExecutable;
+import org.sakaiproject.entitybroker.entityprovider.capabilities.AutoRegisterEntityProvider;
+import org.sakaiproject.entitybroker.entityprovider.capabilities.Describeable;
+import org.sakaiproject.entitybroker.entityprovider.capabilities.Outputable;
+import org.sakaiproject.entitybroker.entityprovider.capabilities.Resolvable;
+import org.sakaiproject.entitybroker.entityprovider.capabilities.Sampleable;
+import org.sakaiproject.entitybroker.entityprovider.extension.Formats;
+import org.sakaiproject.entitybroker.exception.EntityNotFoundException;
+import org.sakaiproject.entitybroker.util.AbstractEntityProvider;
+
+import org.sakaiproject.exception.IdUnusedException;
+import org.sakaiproject.exception.PermissionException;
+
+import org.sakaiproject.authz.api.SecurityService;
+import org.sakaiproject.site.api.Site;
+import org.sakaiproject.site.api.SiteService;
+import org.sakaiproject.site.api.SiteService.SortType;
+import org.sakaiproject.site.api.ToolConfiguration;
+import org.sakaiproject.tool.api.Session;
+import org.sakaiproject.tool.api.SessionManager;
+import org.sakaiproject.tool.api.ToolManager;
+
+import org.sakaiproject.lessonbuildertool.model.SimplePageToolDao;
+import org.sakaiproject.lessonbuildertool.SimplePage;
+import org.sakaiproject.lessonbuildertool.SimplePageItem;
+import org.sakaiproject.lessonbuildertool.SimplePageQuestionAnswer;
+
+/**
+ * @author fsaez
+ *
+ */
+public class LessonbuilderEntityProvider extends AbstractEntityProvider implements EntityProvider, AutoRegisterEntityProvider, Outputable, Describeable, Sampleable, Resolvable, ActionsExecutable {
+
+ public final static String ENTITY_PREFIX = "lessons";
+ public final static String TOOL_COMMON_ID = "sakai.lessonbuildertool";
+
+ private static final Log log = LogFactory.getLog(LessonbuilderEntityProvider.class);
+
+ @Override
+ public String getEntityPrefix() {
+ return ENTITY_PREFIX;
+ }
+
+ @Override
+ public Object getSampleEntity() {
+ return null;
+ }
+
+ @Override
+ public Object getEntity(EntityReference ref) {
+
+ //get user uuid
+ String id = ref.getId();
+ if(StringUtils.isBlank(id)) {
+ throw new EntityNotFoundException("Invalid lesson.", ref.getId());
+ }
+
+ DecoratedItem ret = null;
+ SimplePageItem item = simplePageToolDao.findItem(Long.valueOf(id));
+
+ if(item == null)
+ throw new EntityNotFoundException("Id not found", id);
+
+ SimplePage page = null;
+ if (item.getType() == SimplePageItem.PAGE)
+ page = simplePageToolDao.getPage(Long.parseLong(item.getSakaiId()));
+ else
+ page = simplePageToolDao.getPage(item.getPageId());
+
+ if(page != null) {
+ String siteId = page.getSiteId();
+
+ Site site = null;
+ try {
+ site = siteService.getSiteVisit(siteId);
+ } catch (IdUnusedException e) {
+ throw new EntityNotFoundException("Invalid siteId: " + siteId, siteId);
+ } catch (PermissionException e) {
+ throw new EntityNotFoundException("No access to site: " + siteId, siteId);
+ }
+
+ //check if given site contains the lessonbuilder tool
+ checkTool(site);
+
+ //check if current user has permission to access to the lessonbuilder tool
+ checkReadPermission(siteId);
+
+ ret = new DecoratedItem(item.getId(), item.getName(), item.getType(), siteId, site.getTitle());
+ }
+ else
+ throw new EntityNotFoundException("Invalid id", id);
+
+ return ret;
+ }
+
+
+ /**
+ * site
+ * example: /direct/lessons/site/SITEID.xml
+ */
+ @EntityCustomAction(action="site",viewKey=EntityView.VIEW_LIST)
+ public List> getLessonsInSite(EntityView view, Map params) {
+
+ String siteId = view.getPathSegment(2);
+
+ if (siteId == null || "".equals(siteId)) {
+ // format of the view should be in a standard message reference
+ throw new IllegalArgumentException("Must include siteId in the path ("+view+"): e.g. /direct/lessons/site/{siteId}");
+ }
+
+ Site site = null;
+ try {
+ site = siteService.getSiteVisit(siteId);
+ } catch (IdUnusedException e) {
+ throw new EntityNotFoundException("Invalid siteId: " + siteId, siteId);
+ } catch (PermissionException e) {
+ throw new EntityNotFoundException("No access to site: " + siteId, siteId);
+ }
+
+ //check if given site contains the lessonbuilder tool
+ checkTool(site);
+
+ //check if current user has permission to access to the lessonbuilder tool
+ checkReadPermission(siteId);
+
+ List ret = new ArrayList();
+
+ List list = simplePageToolDao.findItemsInSite(siteId);
+
+ for(SimplePageItem item : list)
+ {
+ ret.add(new DecoratedSiteItem(item.getId(), item.getName()));
+ }
+
+ return ret;
+ }
+
+ /**
+ * user
+ * example: /direct/lessons/user.xml
+ */
+ @EntityCustomAction(action="user",viewKey=EntityView.VIEW_LIST)
+ public List> getLessonsForUser(EntityView view, Map params) {
+
+ List ret = new ArrayList();
+
+ //first of all, we get a list with all sites that the user can access
+ List siteList = getUserSites();
+ for(Site s : siteList) {
+ try {
+ //check if given site contains the lessonbuilder tool
+ checkTool(s);
+
+ //check if current user has permission to access to the lessonbuilder tool
+ checkReadPermission(s.getId());
+
+ List list = simplePageToolDao.findItemsInSite(s.getId());
+
+ for(SimplePageItem item : list)
+ {
+ ret.add(new DecoratedUserItem(item.getId(), item.getName(), s.getId(), s.getTitle()));
+ }
+
+ }catch(EntityNotFoundException e) { //if there is no lessonbuilder tool in that site, just skip it
+ }catch(SecurityException e) { //if current user can not access to the lessonbuilder tool on that site, just skip it
+ }
+ }
+
+ return ret;
+ }
+
+ /**
+ * lesson
+ * example: /direct/lessons/lesson/LESSONID.xml
+ */
+ @EntityCustomAction(action="lesson",viewKey=EntityView.VIEW_LIST)
+ public List> getLesson(EntityView view, Map params) {
+
+ String id = view.getPathSegment(2);
+
+ if (id == null || "".equals(id)) {
+ // format of the view should be in a standard message reference
+ throw new IllegalArgumentException("Must include lessonId in the path ("+view+"): e.g. /direct/lessons/lesson/{lessonId}");
+ }
+
+ boolean simpleType = false;
+ boolean fullTree = true;
+ if(params != null)
+ {
+ try
+ {
+ if(params.get("type") != null)
+ simpleType = "simple".equals(params.get("type"));
+ }
+ catch(Exception e){}
+ try
+ {
+ if(params.get("fullTree") != null)
+ fullTree = Boolean.valueOf((String)params.get("fullTree"));
+ }
+ catch(Exception e){}
+ }
+
+ List ret = new ArrayList();
+
+ //get item by id
+ SimplePageItem item = simplePageToolDao.findItem(Long.parseLong(id));
+
+ if(item == null)
+ throw new EntityNotFoundException("Id not found", id);
+
+ SimplePage page = null;
+ if (item.getType() == SimplePageItem.PAGE)
+ page = simplePageToolDao.getPage(Long.parseLong(item.getSakaiId()));
+ else
+ page = simplePageToolDao.getPage(item.getPageId());
+
+ if(page != null)
+ {
+ String siteId = page.getSiteId();
+
+ Site site = null;
+ try {
+ site = siteService.getSiteVisit(siteId);
+ } catch (IdUnusedException e) {
+ throw new EntityNotFoundException("Invalid siteId: " + siteId, siteId);
+ } catch (PermissionException e) {
+ throw new EntityNotFoundException("No access to site: " + siteId, siteId);
+ }
+
+ //check if given site contains the lessonbuilder tool
+ checkTool(site);
+
+ //check if current user has permission to access to the lessonbuilder tool
+ checkReadPermission(siteId);
+
+ boolean hasUpdatePermission = checkUpdatePermission(siteId);
+
+ //if required item is not a page or we just want a single item
+ if (item.getType() != SimplePageItem.PAGE || !fullTree)
+ {
+ if(simpleType)
+ ret.add(new DecoratedItem(item.getId(), item.getName(), item.getType(), site.getId(), site.getTitle()));
+ else
+ addItem(item, ret, hasUpdatePermission);
+ return ret;
+ }
+
+ // build map of all pages, so we can check if any is repeated
+ Map pageMap = new HashMap();
+
+ // all pages
+ List pages = simplePageToolDao.getSitePages(siteId);
+ for (SimplePage p: pages)
+ pageMap.put(p.getPageId(), p);
+
+ if(simpleType)
+ findAllSimplePages(item, ret, pageMap, site);
+ else
+ findAllPages(item, ret, pageMap, hasUpdatePermission);
+ }
+ else
+ {
+ throw new EntityNotFoundException("Given id does not pertain to any page", id);
+ }
+
+ return ret;
+ }
+
+
+ @Override
+ public String[] getHandledOutputFormats() {
+ return new String[] {Formats.XML, Formats.JSON};
+ }
+
+ // --------------------------------------------------------------------------------
+ // OUTPUT OBJECTS
+ // --------------------------------------------------------------------------------
+
+ //for getEntity and action=lesson & type=simple
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Data
+ public class DecoratedItem {
+ private long id;
+ private String lessonTitle;
+ private int type;
+ private String siteId;
+ private String siteTitle;
+ }
+
+ // for action=site
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Data
+ public class DecoratedSiteItem {
+ private long id;
+ private String lessonTitle;
+ }
+
+ //for action=user
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Data
+ public class DecoratedUserItem {
+ private long id;
+ private String lessonTitle;
+ private String siteId;
+ private String siteTitle;
+ }
+
+ // simplified version of SimplePageItem (base object) for action=lesson & type!=simple(default)
+ /**
+ * LessonBase: is a wrapper of SimplePageItem, so we can show only the attributes we want. This class is the base from which all other classes extend.
+ * Any attribute shared by all kinds of "items", should be placed here. Attributes are called as SimplePageItem to avoid misunderstandings
+ */
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Data
+ public class LessonBase {
+ private long id;
+ private String name;
+ private int type;
+ private long pageId;
+ private boolean prerequisite;
+ private boolean required;
+
+ public LessonBase(SimplePageItem item)
+ {
+ if(item != null)
+ {
+ this.id = item.getId();
+ this.name = item.getName();
+ this.type = item.getType();
+ this.pageId = item.getPageId();
+ this.prerequisite = item.isPrerequisite();
+ this.required = item.isRequired();
+ }
+ }
+ }
+
+ //(based on LessonBase) for most cases
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Data
+ public class DecoratedLesson extends LessonBase{
+ private String sakaiId;
+ private String html;
+ private String url;
+
+ public DecoratedLesson(SimplePageItem item)
+ {
+ super(item);
+ if(item != null)
+ {
+ this.sakaiId = item.getSakaiId();
+ this.html = item.getHtml();
+ this.url = item.getURL();
+ }
+ }
+ }
+
+ //for question items (base)
+ @NoArgsConstructor
+ @Data
+ public class DecoratedQuiz extends LessonBase {
+ private String questionText;
+ private String questionCorrectText;
+ private String questionIncorrectText;
+ private String questionType;
+ private String questionGraded;
+
+ public DecoratedQuiz(SimplePageItem item)
+ {
+ super(item);
+ }
+
+ public DecoratedQuiz(SimplePageItem item, String questionText, String questionCorrectText, String questionIncorrectText, String questionType, String questionGraded)
+ {
+ super(item);
+ this.questionText = questionText;
+ this.questionCorrectText = questionCorrectText;
+ this.questionIncorrectText = questionIncorrectText;
+ this.questionType = questionType;
+ this.questionGraded = questionGraded;
+ }
+ }
+
+ //for multiple choice questions
+ @NoArgsConstructor
+ @Data
+ public class DecoratedMultipleChoiceQuestion extends DecoratedQuiz {
+ private String questionShowPoll;
+ private List answersList;
+
+ public DecoratedMultipleChoiceQuestion(SimplePageItem item)
+ {
+ super(item);
+ answersList = new ArrayList();
+ }
+
+ public DecoratedMultipleChoiceQuestion(SimplePageItem item, String questionText, String questionCorrectText, String questionIncorrectText, String questionGraded)
+ {
+ super(item, questionText, questionCorrectText, questionIncorrectText, "multipleChoice", questionGraded);
+ answersList = new ArrayList();
+ }
+
+ public DecoratedMultipleChoiceQuestion(SimplePageItem item, String questionText, String questionCorrectText, String questionIncorrectText, String questionGraded, String questionShowPoll)
+ {
+ super(item, questionText, questionCorrectText, questionIncorrectText, "multipleChoice", questionGraded);
+ this.questionShowPoll = questionShowPoll;
+ answersList = new ArrayList();
+ }
+
+ public void addAnswer(DecoratedAnswerItem answer)
+ {
+ answersList.add(answer);
+ }
+ }
+
+ //for shortanswer questions
+ @NoArgsConstructor
+ @Data
+ public class DecoratedShortAnswerQuestion extends DecoratedQuiz {
+ private String questionAnswer;
+
+ public DecoratedShortAnswerQuestion(SimplePageItem item)
+ {
+ super(item);
+ }
+
+ public DecoratedShortAnswerQuestion(SimplePageItem item, String questionText, String questionCorrectText, String questionIncorrectText, String questionGraded)
+ {
+ super(item, questionText, questionCorrectText, questionIncorrectText, "shortanswer", questionGraded);
+ }
+
+ public DecoratedShortAnswerQuestion(SimplePageItem item, String questionText, String questionCorrectText, String questionIncorrectText, String questionGraded, String questionAnswer)
+ {
+ super(item, questionText, questionCorrectText, questionIncorrectText, "shortanswer", questionGraded);
+ this.questionAnswer = questionAnswer;
+ }
+ }
+
+ //answers for multiple choice questions
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Data
+ public class DecoratedAnswerItem {
+ private long id;
+ private String text;
+ private Boolean correct;
+ }
+
+
+ // --------------------------------------------------------------------------------
+ // PRIVATE METHODS
+ // --------------------------------------------------------------------------------
+ private void checkTool(Site site) {
+ if(site != null)
+ {
+ //check user can access the tool, it might be hidden
+ Collection col = site.getTools(TOOL_COMMON_ID);
+ if(col == null || col.isEmpty())
+ throw new EntityNotFoundException("No tool "+TOOL_COMMON_ID+" in site: " + site.getId(), site.getId());
+
+ for(Object o : col)
+ {
+ ToolConfiguration toolConfig = (ToolConfiguration)o;
+ if(!toolManager.isVisible(site, toolConfig))
+ throw new EntityNotFoundException("No access to tool in site: " + site.getId(), site.getId());
+ }
+ }
+ else
+ throw new EntityNotFoundException("Invalid site", "-null-");
+ }
+
+ private void checkReadPermission(String siteId) {
+ checkReadPermission(siteId, sessionManager.getCurrentSessionUserId());
+ }
+
+ private void checkReadPermission(String siteId, String userId) {
+ if(!securityService.unlock(userId, SimplePage.PERMISSION_LESSONBUILDER_READ, siteService.siteReference(siteId))) {
+ throw new SecurityException("User "+userId+" does not have permission to read lessons on site " + siteId);
+ }
+ }
+
+ private boolean checkUpdatePermission(String siteId) {
+ return checkUpdatePermission(siteId, sessionManager.getCurrentSessionUserId());
+ }
+
+ private boolean checkUpdatePermission(String siteId, String userId) {
+ return securityService.unlock(userId, SimplePage.PERMISSION_LESSONBUILDER_UPDATE, siteService.siteReference(siteId));
+ }
+
+ private synchronized List getUserSites() {
+ List siteList = new ArrayList();
+
+ try
+ {
+ siteList = siteService.getSites(org.sakaiproject.site.api.SiteService.SelectionType.ACCESS, null, null, null, SortType.TITLE_ASC, null);
+ }catch(Exception e){
+ log.warn("getUserSites -> "+e);
+ }
+ return siteList;
+ }
+
+ /**
+ * findAllPages : explores lessonbuilder tree from a base pageItem and fills a list of LessonBase items
+ *
+ * @param pageItem
+ * @param entries
+ * @param pageMap
+ * @param hasUpdatePermission
+ */
+ private void findAllPages(SimplePageItem pageItem, List entries, Map pageMap, boolean hasUpdatePermission) {
+ Long pageId = Long.valueOf(pageItem.getSakaiId());
+ // already done if page is null
+ if (pageMap.get(pageId) == null)
+ return;
+
+ // say done
+ pageMap.remove(pageId);
+ addItem(pageItem, entries, hasUpdatePermission);
+
+ // now recursively do subpages
+ List items = simplePageToolDao.findItemsOnPage(pageId);
+ // subpages done in place
+ for (SimplePageItem item: items) {
+
+ if (item.getType() == SimplePageItem.PAGE)
+ findAllPages(item, entries, pageMap, hasUpdatePermission);
+ else
+ addItem(item, entries, hasUpdatePermission);
+ }
+ }
+
+ /**
+ * findAllPages : explores lessonbuilder tree from a base pageItem and fills a list of DecoratedItem items
+ *
+ * @param pageItem
+ * @param entries
+ * @param pageMap
+ * @param site
+ */
+ private void findAllSimplePages(SimplePageItem pageItem, List entries, Map pageMap, Site site) {
+ Long pageId = Long.valueOf(pageItem.getSakaiId());
+ // already done if page is null
+ if (pageMap.get(pageId) == null)
+ return;
+
+ // say done
+ pageMap.remove(pageId);
+ entries.add(new DecoratedItem(pageItem.getId(), pageItem.getName(), pageItem.getType(), site.getId(), site.getTitle()));
+
+ // now recursively do subpages
+ List items = simplePageToolDao.findItemsOnPage(pageId);
+ // subpages done in place
+ for (SimplePageItem item: items) {
+
+ if (item.getType() == SimplePageItem.PAGE)
+ findAllSimplePages(item, entries, pageMap, site);
+ else
+ entries.add(new DecoratedItem(item.getId(), item.getName(), item.getType(), site.getId(), site.getTitle()));
+ }
+ }
+
+
+
+ /**
+ * addItem : creates a new LessonBase item based on the given SimplePageItem item and adds it to the given list
+ * depending of SimplePageItem's type, the new LessonBase object could be one of the following:
+ * - QUESTION -> DecoratedQuiz (DecoratedMultipleChoiceQuestion or DecoratedShortAnswerQuestion)
+ * - OTHERS -> DecoratedLesson
+ *
+ * @param item
+ * @param list
+ * @param hasUpdatePermission
+ */
+ private void addItem(SimplePageItem item, List list, boolean hasUpdatePermission)
+ {
+ if(list == null)
+ list = new ArrayList();
+
+ if(item != null)
+ {
+ LessonBase lesson = null;
+ //check type
+ switch(item.getType())
+ {
+ case SimplePageItem.QUESTION:
+ if("multipleChoice".equals(item.getAttribute("questionType"))) {
+ lesson = new DecoratedMultipleChoiceQuestion(item,
+ item.getAttribute("questionText"),
+ item.getAttribute("questionCorrectText"),
+ item.getAttribute("questionIncorrectText"),
+ item.getAttribute("questionGraded"),
+ item.getAttribute("questionShowPoll"));
+
+ List answers = simplePageToolDao.findAnswerChoices(item);
+ for(SimplePageQuestionAnswer a : answers)
+ {
+ DecoratedAnswerItem answer = new DecoratedAnswerItem();
+ answer.setId(a.getId());
+ answer.setText(a.getText());
+ //only show correct value if has permissions
+ if(hasUpdatePermission)
+ answer.setCorrect(a.isCorrect());
+
+ ((DecoratedMultipleChoiceQuestion)lesson).addAnswer(answer);
+ }
+
+ } else if("shortanswer".equals(item.getAttribute("questionType"))) {
+ lesson = new DecoratedShortAnswerQuestion(item,
+ item.getAttribute("questionText"),
+ item.getAttribute("questionCorrectText"),
+ item.getAttribute("questionIncorrectText"),
+ item.getAttribute("questionGraded"),
+ item.getAttribute("questionAnswer"));
+ }
+ break;
+ default:
+ lesson = new DecoratedLesson(item);
+ break;
+ }
+
+ list.add(lesson);
+ }
+ }
+
+ @Setter
+ private SecurityService securityService;
+
+ @Setter
+ private SessionManager sessionManager;
+
+ @Setter
+ private SiteService siteService;
+
+ @Setter
+ private ToolManager toolManager;
+
+ @Setter
+ private SimplePageToolDao simplePageToolDao;
+}
Index: tool/src/webapp/WEB-INF/applicationContext.xml
===================================================================
--- tool/src/webapp/WEB-INF/applicationContext.xml (revision 129692)
+++ tool/src/webapp/WEB-INF/applicationContext.xml (working copy)
@@ -350,6 +350,17 @@
+
+
+
+
+
+
+
+
+