001: /*
002: * Copyright (C) 2006 Methodhead Software LLC. All rights reserved.
003: *
004: * This file is part of TransferCM.
005: *
006: * TransferCM is free software; you can redistribute it and/or modify it under the
007: * terms of the GNU General Public License as published by the Free Software
008: * Foundation; either version 2 of the License, or (at your option) any later
009: * version.
010: *
011: * TransferCM is distributed in the hope that it will be useful, but WITHOUT ANY
012: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
013: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
014: * details.
015: *
016: * You should have received a copy of the GNU General Public License along with
017: * TransferCM; if not, write to the Free Software Foundation, Inc., 51 Franklin St,
018: * Fifth Floor, Boston, MA 02110-1301 USA
019: */
020:
021: package com.methodhead.shim;
022:
023: import org.apache.struts.action.Action;
024: import org.apache.struts.action.ActionMapping;
025: import org.apache.struts.action.ActionForm;
026: import org.apache.struts.action.DynaActionForm;
027: import org.apache.struts.action.ActionForward;
028:
029: import javax.servlet.http.HttpServletRequest;
030: import javax.servlet.http.HttpServletResponse;
031: import com.methodhead.util.OperationContext;
032:
033: import com.methodhead.auth.AuthUtil;
034: import com.methodhead.auth.AuthUser;
035: import com.methodhead.sitecontext.SiteContext;
036: import org.apache.commons.lang.StringUtils;
037: import java.io.File;
038: import java.util.List;
039: import java.util.ArrayList;
040: import java.util.Comparator;
041: import java.util.Collections;
042: import com.methodhead.auth.AuthAction;
043: import com.methodhead.util.StrutsUtil;
044: import com.methodhead.tree.FoldingTreeNode;
045: import java.util.Enumeration;
046: import org.apache.log4j.Logger;
047:
048: public class EditorAction extends AuthAction {
049:
050: // constructors /////////////////////////////////////////////////////////////
051:
052: // constants ////////////////////////////////////////////////////////////////
053:
054: // classes //////////////////////////////////////////////////////////////////
055:
056: // methods //////////////////////////////////////////////////////////////////
057:
058: /**
059: * NOT UNIT TESTED Returns <tt>true</tt> if <tt>path</tt> doesn't contain any
060: * invalid characters sequences (<tt>..</tt>).
061: */
062: public static boolean isValidPath(String path) {
063:
064: if (path == null)
065: return false;
066:
067: return path.indexOf("..") == -1;
068: }
069:
070: /**
071: * Sets <code>form.images</code> to a <code>List</code> of {@link Thumbnail
072: * Thumbnail}s for images in the directory specified by
073: * <code>form.path</code>. If a thumbnail doesn't exist for a particular
074: * image (this occures when the {@link Thumbnailer thumbnailer} has trouble
075: * processing an image), the thumbnail's <code>thumbPath</code> is set to
076: * <code>approot/images/invalid-thumb.gif</code>
077: */
078: protected ActionForward doListImages(OperationContext op,
079: ShimPolicy policy) throws Exception {
080:
081: String msg = ((ShimPolicy) policy)
082: .isEditorListImagesAuthorized(op);
083: if (msg != null) {
084: StrutsUtil.addMessage(op.request, msg, null, null, null);
085: return op.mapping.findForward("accessDenied");
086: }
087:
088: //
089: // get some things we'll need
090: //
091: SiteContext siteContext = SiteContext.getContext(op.request);
092:
093: //
094: // validate path
095: //
096: String path = (String) op.form.get("path");
097: if (StringUtils.isBlank(path) || !isValidPath(path)) {
098: path = "";
099: }
100:
101: if (logger_.isDebugEnabled()) {
102: logger_.debug("Listing images for path \"" + path + "\"");
103: }
104:
105: //
106: // get source directory
107: //
108: File srcDir = new File(op.request.getSession()
109: .getServletContext().getRealPath(
110: "/" + siteContext.getInt("id") + "/" + path));
111:
112: if (!srcDir.exists() || !srcDir.isDirectory())
113: throw new ShimException("Source directory is invalid \""
114: + srcDir + "\"");
115:
116: //
117: // get thumbs dir creating it if necessary
118: //
119: File thumbsDir = new File(op.request.getSession()
120: .getServletContext().getRealPath(
121: "/" + siteContext.getInt("id") + "/thumbs/"
122: + path));
123:
124: if (!thumbsDir.exists())
125: thumbsDir.mkdirs();
126: else if (!thumbsDir.isDirectory())
127: throw new ShimException(
128: "Thumbs directory exists, but is not a directory \""
129: + thumbsDir + "\"");
130:
131: //
132: // sync the thumbnails
133: //
134: policy.newThumbnailer().syncDir(srcDir, thumbsDir);
135:
136: //
137: // build the images list
138: //
139: File[] files = srcDir.listFiles();
140:
141: if (files == null)
142: throw new ShimException("Couldn't list files for \""
143: + srcDir + "\"");
144:
145: if (!"".equals(path))
146: path = path + "/";
147:
148: List thumbs = new ArrayList();
149: for (int i = 0; i < files.length; i++) {
150: String fileName = files[i].getName().toLowerCase();
151: if (fileName.endsWith(".jpg") || fileName.endsWith(".gif")
152: || fileName.endsWith(".png")) {
153:
154: Thumbnail thumbnail = new Thumbnail();
155: thumbnail.setName(files[i].getName());
156: thumbnail.setImagePath(path + files[i].getName());
157: thumbnail.setThumbPath("thumbs/" + path
158: + files[i].getName() + ".jpg");
159: thumbnail.setSize(files[i].length());
160:
161: //
162: // null out thumb path if the thumb doesn't exist
163: //
164: File thumb = new File(thumbsDir, files[i].getName()
165: + ".jpg");
166:
167: if (!thumb.exists()) {
168: thumbnail.setThumbPath(null);
169: }
170:
171: thumbs.add(thumbnail);
172: }
173: }
174:
175: //
176: // sort the thumbnails
177: //
178: Collections.sort(thumbs, new Comparator() {
179: public int compare(Object o1, Object o2) {
180: return ((Thumbnail) o1).getName().compareToIgnoreCase(
181: ((Thumbnail) o2).getName());
182: }
183: });
184:
185: op.form.set("images", thumbs);
186:
187: return op.mapping.findForward("form");
188: }
189:
190: protected ActionForward doPickImage(OperationContext op,
191: ShimPolicy policy) throws Exception {
192:
193: String msg = ((ShimPolicy) policy)
194: .isEditorPickImageAuthorized(op);
195: if (msg != null) {
196: StrutsUtil.addMessage(op.request, msg, null, null, null);
197: return op.mapping.findForward("accessDenied");
198: }
199:
200: op.form.set("path", "");
201:
202: return op.mapping.findForward("form");
203: }
204:
205: protected ActionForward doDisplayFiles(OperationContext op,
206: ShimPolicy policy) throws Exception {
207:
208: String msg = ((ShimPolicy) policy)
209: .isEditorDisplayFilesAuthorized(op);
210: if (msg != null) {
211: StrutsUtil.addMessage(op.request, msg, null, null, null);
212: return op.mapping.findForward("accessDenied");
213: }
214:
215: //
216: // get some things we'll need
217: //
218: SiteContext siteContext = SiteContext.getContext(op.request);
219:
220: //
221: // validate path
222: //
223: String path = (String) op.form.get("path");
224: if (StringUtils.isBlank(path) || !isValidPath(path)) {
225: path = "";
226: }
227:
228: //
229: // get source directory
230: //
231: File srcDir = new File(op.request.getSession()
232: .getServletContext().getRealPath(
233: "/" + siteContext.getInt("id") + "/" + path));
234:
235: if (!srcDir.exists() || !srcDir.isDirectory())
236: throw new ShimException("Source directory is invalid \""
237: + srcDir + "\"");
238:
239: //
240: // build the files list
241: //
242: File[] files = srcDir.listFiles();
243:
244: if (files == null)
245: throw new ShimException("Couldn't list files for \""
246: + srcDir + "\"");
247:
248: if (!"".equals(path))
249: path = path + "/";
250:
251: List infos = new ArrayList();
252: for (int i = 0; i < files.length; i++) {
253: if (!files[i].isDirectory()) {
254:
255: FileInfo info = new FileInfo();
256: info.setName(files[i].getName());
257: info.setPath(path + files[i].getName());
258: info.setSize(files[i].length());
259:
260: String fileName = files[i].getName().toLowerCase();
261: if (fileName.endsWith(".jpg")
262: || fileName.endsWith(".gif")
263: || fileName.endsWith(".png"))
264: info.setIconHint("IMG");
265:
266: infos.add(info);
267: }
268: }
269:
270: //
271: // sort the infos
272: //
273: Collections.sort(infos, new Comparator() {
274: public int compare(Object o1, Object o2) {
275: return ((FileInfo) o1).getName().compareToIgnoreCase(
276: ((FileInfo) o2).getName());
277: }
278: });
279:
280: op.form.set("files", infos);
281:
282: return op.mapping.findForward("form");
283: }
284:
285: protected ActionForward doPickFile(OperationContext op,
286: ShimPolicy policy) throws Exception {
287:
288: String msg = ((ShimPolicy) policy)
289: .isEditorPickFileAuthorized(op);
290: if (msg != null) {
291: StrutsUtil.addMessage(op.request, msg, null, null, null);
292: return op.mapping.findForward("accessDenied");
293: }
294:
295: op.form.set("path", "");
296:
297: return op.mapping.findForward("form");
298: }
299:
300: protected ActionForward doListPages(
301: OperationContext op,
302: ShimPolicy policy )
303: throws
304: Exception {
305:
306: String msg = ( ( ShimPolicy )policy ).isEditorListPagesAuthorized( op );
307: if ( msg != null ) {
308: StrutsUtil.addMessage( op.request, msg, null, null, null );
309: return op.mapping.findForward( "accessDenied" );
310: }
311:
312: logger_.debug( "doPickPage()" );
313:
314: //
315: // copy the site map tree
316: //
317: SiteMapTree siteMapTree = ShimUtils.getSiteMapTree( op.request );
318: FoldingTreeNode root =
319: ( FoldingTreeNode )siteMapTree.copy(
320: ( FoldingTreeNode )siteMapTree.getRoot() );
321:
322: SiteMap siteMap = ShimUtils.getSiteMap( op.request );
323:
324: //
325: // update the urls
326: //
327: for (
328: Enumeration enum = root.depthFirstEnumeration();
329: enum.hasMoreElements(); ) {
330:
331: FoldingTreeNode node = ( FoldingTreeNode )enum.nextElement();
332:
333: //
334: // this hurts; would be better to simply store the alias in the sitemap
335: // tree
336: //
337: Link link = siteMap.find( ( ( Integer )node.getUserObject() ).intValue() );
338:
339: node.setUrl(
340: "javascript:onPageClick(" + link.getPageId() + ",'" + ShimUtils.getLinkUrl( link ) + "')" );
341: }
342:
343: op.form.set( "node", root );
344:
345: return op.mapping.findForward( "form" );
346: }
347:
348: protected ActionForward doPickPage(OperationContext op,
349: ShimPolicy policy) throws Exception {
350:
351: String msg = ((ShimPolicy) policy)
352: .isEditorPickPageAuthorized(op);
353: if (msg != null) {
354: StrutsUtil.addMessage(op.request, msg, null, null, null);
355: return op.mapping.findForward("accessDenied");
356: }
357:
358: return op.mapping.findForward("form");
359: }
360:
361: public ActionForward doExecute(ActionMapping mapping,
362: ActionForm form, HttpServletRequest request,
363: HttpServletResponse response) throws Exception {
364:
365: //
366: // get some things we'll need
367: //
368: DynaActionForm dynaForm = (DynaActionForm) form;
369: ShimPolicy policy = ShimUtils.getPolicy(mapping);
370: AuthUser user = AuthUtil.getUser(request);
371:
372: //
373: // mapping authorized?
374: //
375: if (!policy.isMappingAuthorized(user, mapping.getPath()))
376: return mapping.findForward("accessDenied");
377:
378: OperationContext op = new OperationContext(mapping, dynaForm,
379: request, response, user);
380:
381: //
382: // execute the appopriate method
383: //
384: if (mapping.getPath().equals("/listImages")) {
385: return doListImages(op, policy);
386: }
387: if (mapping.getPath().equals("/pickImage")) {
388: return doPickImage(op, policy);
389: }
390: if (mapping.getPath().equals("/displayFiles")) {
391: return doDisplayFiles(op, policy);
392: }
393: if (mapping.getPath().equals("/pickFile")) {
394: return doPickFile(op, policy);
395: }
396: if (mapping.getPath().equals("/listPages")) {
397: return doListPages(op, policy);
398: }
399: if (mapping.getPath().equals("/pickPage")) {
400: return doPickPage(op, policy);
401: }
402:
403: throw new Exception("Unexpected mapping path \""
404: + mapping.getPath() + "\"");
405: }
406:
407: // properties ///////////////////////////////////////////////////////////////
408:
409: // attributes ///////////////////////////////////////////////////////////////
410:
411: private static Logger logger_ = Logger
412: .getLogger(EditorAction.class);
413: }
|