001: package org.sakaiproject.site.tool.helper.order.impl;
002:
003: import java.util.Comparator;
004: import java.util.HashSet;
005: import java.util.Iterator;
006: import java.util.LinkedHashMap;
007: import java.util.List;
008: import java.util.Map;
009: import java.util.Properties;
010: import java.util.Set;
011: import java.util.Vector;
012:
013: import org.sakaiproject.component.api.ServerConfigurationService;
014: import org.sakaiproject.exception.IdUnusedException;
015: import org.sakaiproject.exception.PermissionException;
016: import org.sakaiproject.site.api.Site;
017: import org.sakaiproject.site.api.SitePage;
018: import org.sakaiproject.site.api.ToolConfiguration;
019: import org.sakaiproject.site.api.SiteService;
020: import org.sakaiproject.tool.api.Tool;
021: import org.sakaiproject.tool.api.ToolManager;
022: import org.sakaiproject.tool.api.ToolSession;
023: import org.sakaiproject.tool.api.SessionManager;
024: import org.sakaiproject.util.SortedIterator;
025: import org.sakaiproject.util.Web;
026:
027: /**
028: *
029: * @author Joshua Ryan joshua.ryan@asu.edu
030: *
031: */
032: public class SitePageEditHandler {
033: public Site site = null;
034: public SiteService siteService = null;
035: public ToolManager toolManager = null;
036: public SessionManager sessionManager = null;
037: public ServerConfigurationService serverConfigurationService;
038: private Map pages = null;
039: private Set unhideables = null;
040: public String state = null;
041: public boolean update = false;
042: public boolean done = false;
043:
044: //Just something dumb to bind to in order to supress warning messages
045: public String nil = null;
046:
047: private final String TOOL_CFG_FUNCTIONS = "functions.require";
048: private final String SITE_UPD = "site.upd";
049: private final String HELPER_ID = "sakai.tool.helper.id";
050: private final String UNHIDEABLES_CFG = "poh.unhideables";
051: // Tool session attribute name used to schedule a whole page refresh.
052: public static final String ATTR_TOP_REFRESH = "sakai.vppa.top.refresh";
053:
054: /**
055: * Gets the current tool
056: * @return Tool
057: */
058: public Tool getCurrentTool() {
059: return toolManager.getCurrentTool();
060: }
061:
062: /**
063: * Generates the currentPlacementId as used by the portal to name the iframe the tool lives in
064: * @return String currentPlacementId
065: */
066: public String getCurrentPlacementId() {
067: return Web.escapeJavascript("Main"
068: + toolManager.getCurrentPlacement().getId());
069: }
070:
071: /**
072: * Gets the pages for the current site
073: * @return Map of pages (id, page)
074: */
075: public Map getPages() {
076: if (site == null) {
077: init();
078: }
079: if (update) {
080: pages = new LinkedHashMap();
081: if (site != null) {
082: List pageList = site.getOrderedPages();
083: for (int i = 0; i < pageList.size(); i++) {
084:
085: SitePage page = (SitePage) pageList.get(i);
086: pages.put(page.getId(), page);
087: }
088: }
089: }
090: return pages;
091: }
092:
093: /**
094: * Initialization method, just gets the current site in preperation for other calls
095: *
096: */
097: public void init() {
098: if (site == null) {
099: String siteId = null;
100: try {
101: siteId = sessionManager.getCurrentToolSession()
102: .getAttribute(HELPER_ID + ".siteId").toString();
103: } catch (java.lang.NullPointerException npe) {
104: // Site ID wasn't set in the helper call!!
105: }
106:
107: if (siteId == null) {
108: siteId = toolManager.getCurrentPlacement().getContext();
109: }
110:
111: try {
112: site = siteService.getSite(siteId);
113:
114: } catch (IdUnusedException e) {
115: // The siteId we were given was bogus
116: e.printStackTrace();
117: }
118: }
119: update = siteService.allowUpdateSite(site.getId());
120:
121: String conf = serverConfigurationService
122: .getString(UNHIDEABLES_CFG);
123: if (conf != null) {
124: unhideables = new HashSet();
125: String[] toolIds = conf.split(",");
126: for (int i = 0; i < toolIds.length; i++) {
127: unhideables.add(toolIds[i].trim());
128: }
129: }
130: }
131:
132: /**
133: * Wrapper around siteService to save a site
134: * @param site
135: * @throws IdUnusedException
136: * @throws PermissionException
137: */
138: public void saveSite(Site site) throws IdUnusedException,
139: PermissionException {
140: siteService.save(site);
141: }
142:
143: /**
144: * Gets the list of tools that can be added to the current site
145: * @return List of Tools
146: */
147: public List getAvailableTools() {
148:
149: List tools = new Vector();
150:
151: if (site == null) {
152: init();
153: }
154:
155: Set categories = new HashSet();
156:
157: if (site.getType() == null
158: || siteService.isUserSite(site.getId())) {
159: categories.add("myworkspace");
160: } else {
161: categories.add(site.getType());
162: }
163:
164: Set toolRegistrations = toolManager.findTools(categories, null);
165:
166: SortedIterator i = new SortedIterator(toolRegistrations
167: .iterator(), new ToolComparator());
168: for (; i.hasNext();) {
169: Tool tr = (Tool) i.next();
170: if (tr != null) {
171: //TODO: Find a better way to handle tools that can/will exist multiple times,
172: // should be configurable from sakai.properties, or atlest spring injected
173: if (tr.getId().indexOf("sakai.news") != -1
174: || tr.getId().indexOf("sakai.iframe") != -1) {
175: tools.add(tr);
176: } else if (site.getToolForCommonId(tr.getId()) == null) {
177: tools.add(tr);
178: }
179: }
180: }
181:
182: return tools;
183: }
184:
185: /**
186: * Process the 'Save' post on page ordering.
187: *
188: */
189: public String savePages() {
190: if (state != null) {
191: String[] pages = state.split(" ");
192: for (int i = 0; i < pages.length; i++) {
193: if (pages[i] != null) {
194: SitePage realPage = site.getPage(pages[i]);
195: realPage.setPosition(i);
196: }
197: }
198: site.setCustomPageOrdered(true);
199: try {
200: siteService.save(site);
201: } catch (IdUnusedException e) {
202: // TODO Auto-generated catch block
203: e.printStackTrace();
204: } catch (PermissionException e) {
205: // TODO Auto-generated catch block
206: e.printStackTrace();
207: }
208: }
209:
210: ToolSession session = sessionManager.getCurrentToolSession();
211: session.setAttribute(ATTR_TOP_REFRESH, Boolean.TRUE);
212:
213: return "done";
214: }
215:
216: /**
217: * Allows the Cancel button to return control to the tool calling this helper
218: *
219: */
220: public String cancel() {
221: ToolSession session = sessionManager.getCurrentToolSession();
222: session.setAttribute(ATTR_TOP_REFRESH, Boolean.TRUE);
223:
224: return "done";
225: }
226:
227: public String reset() {
228: site.setCustomPageOrdered(false);
229: try {
230: siteService.save(site);
231: } catch (IdUnusedException e) {
232: // TODO Auto-generated catch block
233: e.printStackTrace();
234: } catch (PermissionException e) {
235: // TODO Auto-generated catch block
236: e.printStackTrace();
237: }
238:
239: return "";
240: }
241:
242: /**
243: * Checks if a given toolId is required or not for the current site being edited
244: *
245: * @param toolId
246: * @return true if the tool is required
247: */
248: public boolean isRequired(String toolId) {
249: if (site == null) {
250: init();
251: }
252:
253: List requiredTools = null;
254: if (site.getType() == null
255: || siteService.isUserSite(site.getId())) {
256: requiredTools = serverConfigurationService
257: .getToolsRequired("myworkspace");
258: } else {
259: requiredTools = serverConfigurationService
260: .getToolsRequired(site.getType());
261: }
262:
263: if (requiredTools != null && requiredTools.contains(toolId)) {
264: return true;
265: }
266: return false;
267: }
268:
269: /**
270: * Checks if users without site.upd can see a page or not
271: *
272: * @param page The SitePage whose visibility is in question
273: * @return true if users with out site.upd can see the page
274: */
275: public boolean isVisible(SitePage page) {
276: List tools = page.getTools();
277: Iterator iPt = tools.iterator();
278:
279: boolean visible = false;
280: while (!visible && iPt.hasNext()) {
281: ToolConfiguration placement = (ToolConfiguration) iPt
282: .next();
283: Properties roleConfig = placement.getConfig();
284: String roleList = roleConfig
285: .getProperty(TOOL_CFG_FUNCTIONS);
286:
287: if (roleList == null || !(roleList.indexOf(SITE_UPD) > -1)) {
288: visible = true;
289: }
290:
291: }
292:
293: return visible;
294: }
295:
296: /**
297: * Checks if the site has been ordered yet
298: *
299: * @return true if the site has custom ordering
300: */
301: public boolean isSiteOrdered() {
302: return site.isCustomPageOrdered();
303: }
304:
305: /**
306: * Checks to see if a given tool is allowed to be hidden.
307: *
308: * Useful for tools that have other requried permissions where setting the page
309: * as visible may not make it visible to all users and thus causes some confusion.
310: *
311: * @return true if this tool is allowed to be hidden
312: */
313: public boolean allowsHide(String toolId) {
314: if (unhideables == null || !unhideables.contains(toolId))
315: return true;
316: return false;
317: }
318:
319: /**
320: * Checks to see if a given SitePage is allowed to be hidden.
321: *
322: * Useful for pages with tools that have other requried permissions where setting
323: * the page as visible may not make it visible to all users and thus causes some
324: * confusion.
325: *
326: * @return true if this tool is allowed to be hidden
327: */
328: public boolean allowsHide(SitePage page) {
329: List tools = page.getTools();
330: Iterator iPt = tools.iterator();
331:
332: boolean hideable = true;
333: while (hideable && iPt.hasNext()) {
334: ToolConfiguration placement = (ToolConfiguration) iPt
335: .next();
336:
337: if (!allowsHide(placement.getToolId())) {
338: hideable = false;
339: }
340: }
341: return hideable;
342: }
343:
344: /**
345: * Hides a page from any user who doesn't have site.upd
346: * Or atleast removes it from the portal navigation list
347: *
348: * @param pageId The Id of the Page
349: * @return true for sucess, false for failuer
350: * @throws IdUnusedException, PermissionException
351: */
352: public boolean hidePage(String pageId) throws IdUnusedException,
353: PermissionException {
354: return pageVisibilityHelper(pageId, false);
355: }
356:
357: /**
358: * Unhides a page from any user who doesn't have site.upd
359: * Or atleast removes it from the portal navigation list
360: *
361: * @param pageId The Id of the Page
362: * @return true for sucess, false for failuer
363: * @throws IdUnusedException, PermissionException
364: */
365: public boolean showPage(String pageId) throws IdUnusedException,
366: PermissionException {
367: return pageVisibilityHelper(pageId, true);
368: }
369:
370: /**
371: * Adds or removes the requirement to have site.upd in order to see
372: * a page
373: * @param pageId The Id of the Page
374: * @param visible
375: * @return true for sucess, false for failuer
376: * @throws IdUnusedException, PermissionException
377: */
378: private boolean pageVisibilityHelper(String pageId, boolean visible)
379: throws IdUnusedException, PermissionException {
380:
381: if (site == null) {
382: init();
383: }
384: SitePage page = site.getPage(pageId);
385: List tools = page.getTools();
386: Iterator iterator = tools.iterator();
387:
388: //If all the tools on a page require site.upd then only users with site.upd will see
389: //the page in the site nav of Charon... not sure about the other Sakai portals floating about
390: while (iterator.hasNext()) {
391: ToolConfiguration placement = (ToolConfiguration) iterator
392: .next();
393: Properties roleConfig = placement.getPlacementConfig();
394: String roleList = roleConfig
395: .getProperty(TOOL_CFG_FUNCTIONS);
396: boolean saveChanges = false;
397:
398: if (roleList == null) {
399: roleList = "";
400: }
401: if (!(roleList.indexOf(SITE_UPD) > -1) && !visible) {
402: if (roleList.length() > 0) {
403: roleList += ",";
404: }
405: roleList += SITE_UPD;
406: saveChanges = true;
407: } else if (visible) {
408: roleList = roleList.replaceAll("," + SITE_UPD, "");
409: roleList = roleList.replaceAll(SITE_UPD, "");
410: saveChanges = true;
411: }
412:
413: if (saveChanges) {
414: roleConfig.setProperty(TOOL_CFG_FUNCTIONS, roleList);
415:
416: placement.save();
417:
418: siteService.save(site);
419: }
420:
421: }
422:
423: return true;
424: }
425:
426: /**
427: * Adds a new single tool page to the current site
428: * @param toolId
429: * @param title
430: * @return the newly added SitePage
431: */
432: public SitePage addPage(String toolId, String title) {
433: SitePage page = null;
434: try {
435: page = site.addPage();
436: page.setTitle(title);
437: page.addTool(toolId);
438: siteService.save(site);
439: } catch (IdUnusedException e) {
440: e.printStackTrace();
441: return null;
442: } catch (PermissionException e) {
443: e.printStackTrace();
444: return null;
445: }
446: init();
447:
448: return page;
449: }
450:
451: /**
452: * ** Copied from SiteAction.java.. should be in a common place such as util?
453: *
454: * @author joshuaryan
455: *
456: */
457: private class ToolComparator implements Comparator {
458: /**
459: * implementing the Comparator compare function
460: * @param o1 The first object
461: * @param o2 The second object
462: * @return The compare result. 1 is o1 < o2; 0 is o1.equals(o2); -1 otherwise
463: */
464: public int compare(Object o1, Object o2) {
465: try {
466: return ((Tool) o1).getTitle().compareTo(
467: ((Tool) o2).getTitle());
468: } catch (Exception e) {
469: }
470: return -1;
471:
472: } // compare
473:
474: } //ToolComparator
475:
476: }
|