001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/content/tags/sakai_2-4-1/content-impl/impl/src/java/org/sakaiproject/content/impl/CollectionAccessFormatter.java $
003: * $Id: CollectionAccessFormatter.java 29317 2007-04-20 14:35:20Z ajpoland@iupui.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.content.impl;
021:
022: import java.io.PrintWriter;
023: import java.util.Collections;
024: import java.util.Iterator;
025: import java.util.List;
026:
027: import javax.servlet.http.HttpServletRequest;
028: import javax.servlet.http.HttpServletResponse;
029:
030: import org.sakaiproject.component.cover.ServerConfigurationService;
031: import org.sakaiproject.content.api.ContentCollection;
032: import org.sakaiproject.content.api.ContentResource;
033: import org.sakaiproject.content.cover.ContentHostingService;
034: import org.sakaiproject.entity.api.Entity;
035: import org.sakaiproject.entity.api.Reference;
036: import org.sakaiproject.entity.api.ResourceProperties;
037: import org.sakaiproject.time.api.Time;
038: import org.sakaiproject.user.api.User;
039: import org.sakaiproject.user.api.UserNotDefinedException;
040: import org.sakaiproject.user.cover.UserDirectoryService;
041: import org.sakaiproject.util.Validator;
042:
043: /**
044: * <p>
045: * CollectionAccessFormatter is formatter for collection access.
046: * </p>
047: */
048: public class CollectionAccessFormatter {
049: /**
050: * Format the collection as an HTML display.
051: */
052: public static void format(ContentCollection x, Reference ref,
053: HttpServletRequest req, HttpServletResponse res,
054: String accessPointTrue, String accessPointFalse) {
055: // do not allow directory listings for /attachments and its subfolders
056: if (ContentHostingService.isAttachmentResource(x.getId())) {
057: try {
058: res.sendError(HttpServletResponse.SC_NOT_FOUND);
059: return;
060: } catch (java.io.IOException e) {
061: return;
062: }
063: }
064:
065: PrintWriter out = null;
066: // don't set the writer until we verify that
067: // getallresources is going to work.
068: boolean printedHeader = false;
069: boolean printedDiv = false;
070:
071: String path = ref.getId();
072: String basedir = req.getParameter("sbasedir");
073: // path may have been transformed by an alias
074: // we need origpath to check whether there was as trailing /
075: String origpath = req.getPathInfo();
076: String querystring = req.getQueryString();
077: // set access to /access/content, must skip http://host
078: String access = accessPointFalse;
079: int i = access.indexOf("://");
080: if (i > 0)
081: i = access.indexOf("/", i + 3);
082: if (i > 0)
083: access = access.substring(i);
084:
085: boolean sferyx = true;
086: if (basedir == null || basedir.equals("")) {
087: sferyx = false;
088: basedir = req.getParameter("basedir");
089: }
090: String field = req.getParameter("field");
091:
092: // System.out.println("basedir " + basedir);
093:
094: if (field == null)
095: field = "url";
096:
097: try {
098: List members = x.getMemberResources();
099: // we will need resources. getting them once makes the sort a whole lot faster
100: // System.out.println("before sort have " + members.size());
101:
102: boolean hasCustomSort = false;
103: try {
104: hasCustomSort = x.getProperties().getBooleanProperty(
105: ResourceProperties.PROP_HAS_CUSTOM_SORT);
106: } catch (Exception e) {
107: // use false that's already there
108: }
109:
110: if (sferyx || basedir != null)
111: Collections.sort(members, new ContentHostingComparator(
112: ResourceProperties.PROP_DISPLAY_NAME, true));
113: else if (hasCustomSort)
114: Collections
115: .sort(
116: members,
117: new ContentHostingComparator(
118: ResourceProperties.PROP_CONTENT_PRIORITY,
119: true));
120: else
121: Collections.sort(members, new ContentHostingComparator(
122: ResourceProperties.PROP_DISPLAY_NAME, true));
123:
124: // System.out.println("after sort have " + members.size());
125:
126: Iterator xi = members.iterator();
127:
128: res.setContentType("text/html; charset=UTF-8");
129:
130: out = res.getWriter();
131:
132: if (sferyx) {
133: out
134: .println("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1252\"><title>Control Panel - FileBrowser</title></head><body bgcolor=\"#FFFFFF\" topmargin=\"0\" leftmargin=\"0\"><b><font color=\"#000000\" face=\"Arial\" size=\"3\">Path: "
135: + access
136: + Validator.escapeHtml(path)
137: + "</font></b><table border=\"0\" width=\"100%\" bgcolor=\"#FFFFFF\" cellspacing=\"0\" cellpadding=\"0\">");
138: printedHeader = true;
139:
140: } else {
141: ResourceProperties pl = x.getProperties();
142: out
143: .println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">");
144: out.println("<html><head>");
145: out
146: .println("<title>"
147: + "Index of "
148: + pl
149: .getProperty(ResourceProperties.PROP_DISPLAY_NAME)
150: + "</title>");
151: String webappRoot = ServerConfigurationService
152: .getServerUrl();
153: out
154: .println("<link href=\""
155: + webappRoot
156: + "/library/skin/default/access.css\" type=\"text/css\" rel=\"stylesheet\" media=\"screen\" />");
157: if (basedir != null) {
158: out.println("<script type=\"text/javascript\">");
159: out.println("function seturl(url) {");
160: out.println("window.opener.document.forms[0]."
161: + field + ".value = url; window.close();");
162: out.println("}");
163: out.println("</script>");
164: }
165:
166: out.println("</head><body>");
167: out.println("<div class=\"directoryIndex\">");
168: // for content listing it's best to use a real title
169: if (basedir != null)
170: out.println("<h2>Contents of " + access + path
171: + "</h2>");
172: else {
173: out
174: .println("<h2>"
175: + pl
176: .getProperty(ResourceProperties.PROP_DISPLAY_NAME)
177: + "</h2>");
178: String desc = pl
179: .getProperty(ResourceProperties.PROP_DESCRIPTION);
180: if (desc != null && !desc.equals(""))
181: out.println("<p>" + desc + "</p>");
182: }
183:
184: out.println("<table summary=\"Directory index\">");
185: printedHeader = true;
186: printedDiv = true;
187: }
188:
189: int slashes = countSlashes(path);
190:
191: // basedir will be a full url:
192: // http://host:8080/access/content/group/db5a4d0c-3dfd-4d10-8018-41db42ac7c8b/
193: // possibly with a file name on the end.
194: // xss is just the file name. Compute a prefix
195:
196: String filepref = "";
197: // /content
198: String relaccess = accessPointTrue;
199: if (basedir != null && !basedir.equals("none")) {
200: // start bases after /access/content, since it isn't in path
201: String bases = basedir.substring(basedir
202: .indexOf(relaccess)
203: + relaccess.length());
204: int lastslash = 0;
205: // path is always a directory, so it ends in /
206: // do that for base as well
207: if (!bases.endsWith("/")) {
208: lastslash = bases.lastIndexOf("/");
209: if (lastslash > 0)
210: bases = bases.substring(0, lastslash + 1);
211: }
212: // path and bases should now be comparable, starting
213: // at /user or /group and ending in /
214: // bases: /a/b/c/
215: // path: /a/b/d/
216: // need ../d
217: // this code is used in a context where we know there
218: // actually is overlap
219: while (bases.length() > path.length()
220: || (!bases.equals("/") && !bases.equals(path
221: .substring(0, bases.length())))) {
222: lastslash = bases.lastIndexOf("/",
223: bases.length() - 2);
224: if (lastslash < 0)
225: break;
226: filepref = filepref + "../";
227: bases = bases.substring(0, lastslash + 1);
228: }
229: // bases is now the common part, e.g. /a/b/ /a/b/c
230: // add the rest of path
231: if (path.length() > bases.length())
232: filepref = filepref
233: + Validator.escapeUrl(path.substring(bases
234: .length()));
235: } else if (basedir != null && basedir.equals("none")) {
236: filepref = access + Validator.escapeUrl(path);
237: }
238:
239: // for web content format, need to be able to choose main URL
240:
241: String baseparam = "";
242: if (sferyx)
243: baseparam = "?sbasedir=" + Validator.escapeUrl(basedir);
244: else if (basedir != null)
245: baseparam = "?basedir=" + Validator.escapeUrl(basedir)
246: + "&field=" + Validator.escapeUrl(field);
247:
248: if (slashes > 3) {
249: // go up a level
250: String uplev = path.substring(0, path.length() - 1);
251: uplev = access
252: + uplev
253: .substring(0,
254: uplev.lastIndexOf('/') + 1);
255:
256: if (sferyx)
257: out
258: .println("<tr><td align=\"center\" left=\"50%\" height=\"20\"><b><a href=\"../"
259: + baseparam
260: + "\">Up one level</a></b></td><td width=\"20%\"></td><td width=\"30%\"></td></tr><form name=\"fileSelections\">");
261: else if (basedir != null)
262: out
263: .println("<tr><td><a href=\"../"
264: + baseparam
265: + "\">Up one level</a></td><td><b>Folder</b>"
266: + "</td><td>" + "</td><td>"
267: + "</td><td>" + "</td></tr>");
268: else
269: out
270: .println("<tr><td><a href=\"../\">Up one level</a> [Folder]</td><td></td></tr>");
271: } else if (sferyx)
272: out
273: .println("<tr><td align=\"center\" left=\"50%\" height=\"20\"> </td><td width=\"20%\"></td><td width=\"30%\"></td></tr><form name=\"fileSelections\">");
274:
275: while (xi.hasNext()) {
276: // System.out.println("hasnext");
277: Entity nextres = (Entity) xi.next();
278: ResourceProperties properties = nextres.getProperties();
279: boolean isCollection = properties
280: .getBooleanProperty(ResourceProperties.PROP_IS_COLLECTION);
281: String xs = nextres.getId();
282:
283: ContentResource content = null;
284: if (isCollection) {
285: xs = xs.substring(0, xs.length() - 1);
286: xs = xs.substring(xs.lastIndexOf('/') + 1) + '/';
287: } else {
288: content = (ContentResource) nextres;
289: xs = xs.substring(xs.lastIndexOf('/') + 1);
290: }
291:
292: // System.out.println("id " + xs);
293:
294: try {
295:
296: if (isCollection) {
297: if (sferyx)
298: out
299: .println("<tr><td bgcolor=\"#FFF678\" align=\"LEFT\"><font face=\"Arial\" size=\"3\"> <a href=\""
300: + Validator.escapeUrl(xs)
301: + baseparam
302: + "\">"
303: + Validator.escapeHtml(xs)
304: + "</a></font></td><td bgcolor=\"#FFF678\" align=\"RIGHT\"><font face=\"Arial\" size=\"3\" color=\"#000000\">File Folder</font></td><td> </td></tr>");
305: else if (basedir != null)
306: out
307: .println("<tr><td><button type=button onclick=\"seturl('"
308: + filepref
309: + Validator.escapeHtml(xs)
310: + "')\">Choose</button> <a href=\""
311: + Validator.escapeUrl(xs)
312: + baseparam
313: + "\">"
314: + Validator.escapeHtml(xs)
315: + "</a></td><td><b>Folder</b>"
316: + "</td><td>"
317: + "</td><td>"
318: + "</td><td>"
319: + "</td></tr>");
320: else {
321: String desc = properties
322: .getProperty(ResourceProperties.PROP_DESCRIPTION);
323: if (desc == null)
324: desc = "";
325:
326: out
327: .println("<tr><td><a href=\""
328: + Validator.escapeUrl(xs)
329: + baseparam
330: + "\">"
331: + Validator
332: .escapeHtml(properties
333: .getProperty(ResourceProperties.PROP_DISPLAY_NAME))
334: + "</a> [Folder]</td><td>"
335: + Validator
336: .escapeHtml(desc)
337: + "</td></tr>");
338: }
339: } else {
340: long filesize = ((content.getContentLength() - 1) / 1024) + 1;
341: String createdBy = getUserProperty(properties,
342: ResourceProperties.PROP_CREATOR)
343: .getDisplayName();
344: Time modTime = properties
345: .getTimeProperty(ResourceProperties.PROP_MODIFIED_DATE);
346: String modifiedTime = modTime
347: .toStringLocalShortDate()
348: + " " + modTime.toStringLocalShort();
349: String filetype = content.getContentType();
350:
351: if (sferyx)
352: out
353: .println("<tr><td bgcolor=\"#FFFFFF\" align=\"LEFT\"><font face=\"Arial\" size=\"3\"> </font><input type=\"submit\" name=\"selectedFiles\" value=\""
354: + filepref
355: + Validator.escapeUrl(xs)
356: + "\"></td><td bgcolor=\"#FFFFFF\" align=\"RIGHT\"><font face=\"Arial\" size=\"3\">"
357: + filesize
358: + "</font></td><td bgcolor=\"#FFFFFF\" align=\"LEFT\"><font face=\"Arial\" size=\"3\"> "
359: + modifiedTime
360: + "</font></td></tr>");
361: else if (basedir != null)
362: out
363: .println("<tr><td><button type=button onclick=\"seturl('"
364: + filepref
365: + Validator.escapeHtml(xs)
366: + "')\">Choose</button> "
367: + Validator.escapeHtml(xs)
368: + "</td><td>"
369: + filesize
370: + "</td><td>"
371: + createdBy
372: + "</td><td>"
373: + filetype
374: + "</td><td>"
375: + modifiedTime
376: + "</td></tr>");
377: else {
378: String desc = properties
379: .getProperty(ResourceProperties.PROP_DESCRIPTION);
380: if (desc == null)
381: desc = "";
382:
383: out
384: .println("<tr><td><a href=\""
385: + Validator.escapeUrl(xs)
386: + "\" target=_blank>"
387: + Validator
388: .escapeHtml(properties
389: .getProperty(ResourceProperties.PROP_DISPLAY_NAME))
390: + "</a></td><td>"
391: + Validator
392: .escapeHtml(desc)
393: + "</td></tr>");
394: }
395: }
396: } catch (Throwable ignore) {
397: if (sferyx)
398: out
399: .println("<tr><td bgcolor=\"#FFFFFF\" align=\"LEFT\"><font face=\"Arial\" size=\"3\"> </font><input type=\"submit\" name=\"selectedFiles\" value=\""
400: + filepref
401: + Validator.escapeHtml(xs)
402: + "\"></td><td bgcolor=\"#FFFFFF\" align=\"RIGHT\"><font face=\"Arial\" size=\"3\"> </font></td><td bgcolor=\"#FFFFFF\" align=\"LEFT\"><font face=\"Arial\" size=\"3\"> </font></td></tr>");
403: else if (basedir != null)
404: out
405: .println("<tr><td><button type=button onclick=\"seturl('"
406: + filepref
407: + Validator.escapeHtml(xs)
408: + "')\">Choose</button> "
409: + Validator.escapeHtml(xs)
410: + "</td><td>"
411: + "</td><td>"
412: + "</td><td>"
413: + "</td><td>"
414: + "</td></tr>");
415: else
416: out.println("<tr><td><a href=\""
417: + Validator.escapeUrl(xs)
418: + "\" target=_blank>"
419: + Validator.escapeHtml(xs)
420: + "</a></td><td></tr>");
421: }
422: }
423:
424: } catch (Throwable ignore) {
425: }
426:
427: if (out != null && printedHeader) {
428: out.println("</table>");
429: if (printedDiv)
430: out.println("</div>");
431: out.println("</body></html>");
432: }
433: }
434:
435: public static int countSlashes(String s) {
436: int count = 0;
437: int loc = s.indexOf('/');
438:
439: while (loc >= 0) {
440: count++;
441: loc++;
442: loc = s.indexOf('/', loc);
443: }
444:
445: return count;
446: }
447:
448: protected static User getUserProperty(ResourceProperties props,
449: String name) {
450: String id = props.getProperty(name);
451: if (id != null) {
452: try {
453: return UserDirectoryService.getUser(id);
454: } catch (UserNotDefinedException e) {
455: }
456: }
457:
458: return null;
459: }
460: }
|