View Javadoc
1   //
2   // $Id: CoppermineUploadPolicy.java 143 2007-05-14 02:07:27 +0000 (lun., 14 mai
3   // 2007) felfert $
4   //
5   // jupload - A file upload applet.
6   // Copyright 2007 The JUpload Team
7   //
8   // Created: 2006-05-07
9   // Creator: etienne_sf
10  // Last modified: $Date: 2010-07-08 13:57:30 +0200 (jeu., 08 juil. 2010) $
11  //
12  // This program is free software; you can redistribute it and/or modify it under
13  // the terms of the GNU General Public License as published by the Free Software
14  // Foundation; either version 2 of the License, or (at your option) any later
15  // version. This program is distributed in the hope that it will be useful, but
16  // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18  // details. You should have received a copy of the GNU General Public License
19  // along with this program; if not, write to the Free Software Foundation, Inc.,
20  // 675 Mass Ave, Cambridge, MA 02139, USA.
21  
22  package wjhk.jupload2.policies;
23  
24  import java.util.regex.Matcher;
25  import java.util.regex.Pattern;
26  
27  import wjhk.jupload2.context.JUploadContext;
28  import wjhk.jupload2.exception.JUploadException;
29  import wjhk.jupload2.exception.JUploadExceptionUploadFailed;
30  import wjhk.jupload2.exception.JUploadExceptionUploadFailedSuccessNotFound;
31  import wjhk.jupload2.filedata.FileData;
32  import wjhk.jupload2.filedata.PictureFileData;
33  
34  // TODO cookies handling: desc to be mve to UploadPolicy presentation.
35  /**
36   * Specific UploadPolicy for the coppermine picture gallery. It is based on the
37   * PictureUploadPolicy, and some specific part to add the uploaded pictures to a
38   * coppermine existing album. <BR>
39   * Specific features for this policy are:
40   * <UL>
41   * <LI>Album handling : the setProperty("albumId", n) can be called from
42   * javascript, when the user selects another album (with n is the numeric id for
43   * the selected album). This needs that the MAYSCRIPT HTML parameter is set, in
44   * the APPLET tag (see the example below). The upload can not start if the user
45   * didn't first select an album.
46   * <LI>If an error occurs, the applet asks the user if he wants to send a mail
47   * to the webmaster. If he answered yes, the full debug output is submitted to
48   * the URL pointed by urlToSendErrorTo. This URL should send a mail to the
49   * manager of the Coppermine galery.
50   * </UL>
51   * <A NAME="example1"> <H3>Call of the applet from a php script in coppermine</H3>
52   * </A> You'll find below an example of how to put the applet into a PHP page: <BR>
53   * <XMP> <?php $URL = $CONFIG['site_url'] . 'xp_publish.php'; $lang =
54   * $lang_translation_info['lang_country_code']; $max_upl_width_height =
55   * $CONFIG['max_upl_width_height']; ?> <APPLET NAME="JUpload"
56   * CODE="wjhk.jupload2.JUploadApplet" ARCHIVE="plugins/jupload/wjhk.jupload.jar"
57   * <!-- Applet display size, on the navigator page --> WIDTH="500" HEIGHT="700"
58   * <!-- The applet call some javascript function, so we must allow it : -->
59   * MAYSCRIPT > <!-- First, mandatory parameters --> <PARAM NAME="postURL"
60   * VALUE="$URL"> <PARAM NAME="uploadPolicy" VALUE="CoppermineUploadPolicy"> <!--
61   * Then, optional parameters --> <PARAM NAME="lang" VALUE="$lang"> <PARAM
62   * NAME="maxPicHeight" VALUE="$max_upl_width_height"> <PARAM NAME="maxPicWidth"
63   * VALUE="$max_upl_width_height"> <PARAM NAME="debugLevel" VALUE="0"> Java 1.4
64   * or higher plugin required. </APPLET> </XMP> <A NAME="example1"> <H3>Example
65   * 2: albumId set by a javascript call.</H3> </A> <XMP> <script
66   * language="javascript" type="text/javascript"> function onAlbumChange() { if
67   * (document.form_album.album_id.selectedIndex >= 0) {
68   * document.applets['JUpload'].setProperty('albumId',
69   * document.form_album.album_id.value); document.form_album.album_name.value =
70   * document
71   * .form_album.album_id.options[document.form_album.album_id.selectedIndex
72   * ].text; document.form_album.album_description.value =
73   * description[document.form_album.album_id.value]; } else {
74   * document.JUpload.setProperty('albumId', '');
75   * document.form_album.album_name.value = '';
76   * document.form_album.album_description.value = ''; } } </script> </XMP>
77   * 
78   * @author etienne_sf
79   * @version $Revision: 1367 $
80   */
81  public class CoppermineUploadPolicy extends PictureUploadPolicy {
82  
83  	/**
84  	 * The coppermine's album id where picture must be uploaded.
85  	 */
86  	private int albumId;
87  
88  	/**
89  	 * The number of pictures to download in the current upload. This number is
90  	 * stored in the {@link #beforeUpload()} method, which is called at the
91  	 * beginning of each upload.
92  	 */
93  	private int nbPictureInUpload = 0;
94  
95  	/**
96  	 * @param juploadContext
97  	 *            Identifier for the current applet. It's necessary, to read
98  	 *            information from the navigator.
99  	 * @throws JUploadException
100 	 */
101 	public CoppermineUploadPolicy(JUploadContext juploadContext)
102 			throws JUploadException {
103 		// Let's call our mother ! :-)
104 		super(juploadContext);
105 
106 		// Let's read the albumId from the applet parameter. It can be unset,
107 		// but the user must then choose
108 		// an album before upload.
109 		this.albumId = getContext().getParameter(PROP_ALBUM_ID,
110 				DEFAULT_ALBUM_ID);
111 	}
112 
113 	/**
114 	 * @see wjhk.jupload2.policies.UploadPolicy#onFileSelected(wjhk.jupload2.filedata.FileData)
115 	 */
116 	@Override
117 	public void onFileSelected(FileData fileData) {
118 		if (fileData != null && fileData instanceof PictureFileData) {
119 			// The selected file is a picture, we let PictureUploadPolicy manage
120 			// it.
121 			super.onFileSelected(fileData);
122 		} else {
123 			// he selected file is not a picture. We simulate the fact that no
124 			// more picture is selected, so that the preview picture is cleared.
125 			super.onFileSelected(null);
126 		}
127 	}
128 
129 	/**
130 	 * This method only handles the <I>albumId</I> parameter, which is the only
131 	 * applet parameter that is specific to this class. The super.setProperty
132 	 * method is called for other properties.
133 	 * 
134 	 * @see wjhk.jupload2.policies.UploadPolicy#setProperty(java.lang.String,
135 	 *      java.lang.String)
136 	 */
137 	@Override
138 	public void setProperty(String prop, String value) throws JUploadException {
139 		displayDebug("[CoppermineUploadPolicy] Call of setProperty: " + prop
140 				+ " => " + value, 30);
141 
142 		// Check if it's a local property.
143 		if (prop.equals(PROP_ALBUM_ID)) {
144 			this.albumId = getContext().parseInt(value, 0);
145 			displayDebug("Post URL (modified in CoppermineUploadPolicy) = "
146 					+ getPostURL(), 10);
147 		} else {
148 			// Otherwise, transmission to the mother class.
149 			super.setProperty(prop, value);
150 		}
151 	}
152 
153 	/**
154 	 * @see wjhk.jupload2.policies.UploadPolicy#getPostURL()
155 	 */
156 	@Override
157 	public String getPostURL() {
158 		// Within the coppermine PHP script, that contains the call to this
159 		// applet, the postURL given contains the full URL, without the album
160 		// id. So we ask for this postURL, and just concatenate the albumId on
161 		// the fly.
162 		String postURL = super.getPostURL();
163 		return postURL + (postURL.contains("?") ? "&" : "?") + "album="
164 				+ this.albumId;
165 	}
166 
167 	/**
168 	 * This method checks that an album id has been given, and then stores the
169 	 * number of files that are to be uploaded, before upload, then call its
170 	 * superclass. This number is then used to display to the user the list of
171 	 * pictures he just uploaded.
172 	 * 
173 	 * @see wjhk.jupload2.policies.UploadPolicy#beforeUpload()
174 	 */
175 	@Override
176 	public boolean beforeUpload() {
177 		if (this.albumId <= 0) {
178 			alert("chooseAlbumFirst");
179 			return false;
180 		}
181 
182 		// We note the number of files to upload.
183 		this.nbPictureInUpload = getContext().getUploadPanel().getFilePanel()
184 				.getFilesLength();
185 
186 		// Default : Let's ask the mother.
187 		return super.beforeUpload();
188 	}
189 
190 	/** @see wjhk.jupload2.policies.UploadPolicy#afterUpload(Exception, String) */
191 	@Override
192 	public void afterUpload(Exception e, String serverOutput)
193 			throws JUploadException {
194 		int nbPictureAfterUpload = getContext().getUploadPanel().getFilePanel()
195 				.getFilesLength();
196 		if (nbPictureAfterUpload > this.nbPictureInUpload) {
197 			displayErr("CoppermineUploadPolicy.afterUpload: The number of uploaded files is negative! ("
198 					+ (this.nbPictureInUpload - nbPictureAfterUpload) + ")");
199 		} else if (nbPictureAfterUpload == this.nbPictureInUpload) {
200 			displayWarn("CoppermineUploadPolicy.afterUpload: No file were uploaded! ("
201 					+ (nbPictureAfterUpload - this.nbPictureInUpload) + ")");
202 		} else if (getDebugLevel() >= 100) {
203 			alertStr("No switch to property page, because debug level is "
204 					+ getDebugLevel() + " (>=100)");
205 		} else if (e == null) {
206 			// Let's display an alert box, to explain what to do to the
207 			// user: he will be redirected to the coppermine page that
208 			// allow him to associate names and comments to the uploaded
209 			// pictures.
210 			alert("coppermineUploadOk");
211 
212 			// Let's change the afterUploadURL value, so we can call the
213 			// standard afterUpload method (DefaultUploadPolicy).
214 
215 			// Since JUpload 4.2.0, CPG 1.5 upload is done againts the
216 			// /upload.php script, to use
217 			// the Coppermine upload API ofr plugins.
218 			String postURL = getPostURL();
219 			if (postURL.contains("/upload.php?")) {
220 				setAfterUploadURL(postURL.substring(0, getPostURL()
221 						.lastIndexOf("/upload.php?"))
222 						+ "/index.php?file=jupload/jupload&action=edit_uploaded_pics&album="
223 						+ this.albumId
224 						+ "&nb_pictures="
225 						+ (this.nbPictureInUpload - nbPictureAfterUpload));
226 			} else {
227 				setAfterUploadURL(postURL.substring(0, getPostURL()
228 						.lastIndexOf('/'))
229 						+ "/jupload&action=edit_uploaded_pics&album="
230 						+ this.albumId
231 						+ "&nb_pictures="
232 						+ (this.nbPictureInUpload - nbPictureAfterUpload));
233 			} // ... and call the standard behavior.
234 			super.afterUpload(e, serverOutput);
235 		}
236 	}
237 
238 	/** @see DefaultUploadPolicy#checkUploadSuccess(int, String, String) */
239 	public boolean checkUploadSuccess(int status, String msg, String body)
240 			throws JUploadException {
241 		try {
242 			return super.checkUploadSuccess(status, msg, body);
243 		} catch (JUploadExceptionUploadFailedSuccessNotFound e) {
244 			// We got here, if the standard return analysis did not find any
245 			// error or success status. Let's try a 'Coppermine specific'
246 			// analysis now.
247 			Pattern patternMessage = Pattern
248 					.compile(".*cpg_user_message\">(.*)</span>");
249 			Matcher matcherMessage;
250 			String line;
251 			Pattern pMultiline = Pattern.compile("[\\r\\n]", Pattern.MULTILINE);
252 			String[] lines = pMultiline.split(body);
253 			StringBuffer sbBodyWithUniformCRLF = new StringBuffer(body.length());
254 			for (int i = 0; i < lines.length; i += 1) {
255 				line = lines[i];
256 				sbBodyWithUniformCRLF.append(line).append("\r\n");
257 
258 				// FIXME some empty lines are given by the server
259 				// Let's remove the empty line: with the p pattern, a multiline
260 				// is generated each time a \r\n is received, that is: for each
261 				// line.
262 				if (line == null || line.equals("")) {
263 					// An empty line. Let's go the next line.
264 					continue;
265 				}
266 
267 				// Is it 'message line' ?
268 				matcherMessage = patternMessage.matcher(line);
269 				if (matcherMessage.matches()) {
270 					String errmsg = "An error occurs during upload (but the applet couldn't find the error message)";
271 					if (matcherMessage.groupCount() > 0) {
272 						if (!matcherMessage.group(1).equals("")) {
273 							// Let's do a (very simple) formatting: one line to
274 							// 100 characters
275 							errmsg = formatMessage(matcherMessage.group(1));
276 						}
277 					}
278 					this.lastResponseMessage = errmsg;
279 					throw new JUploadExceptionUploadFailed(errmsg);
280 				}// if(matcherMessage.matches())
281 			}// while(st.hasMoreTokens())
282 
283 			// We didn't find any precise message. Let's transmit the default
284 			// one.
285 			throw e;
286 		}
287 	}
288 
289 	/** @see DefaultUploadPolicy#displayParameterStatus() */
290 	@Override
291 	public void displayParameterStatus() {
292 		super.displayParameterStatus();
293 
294 		displayDebug("======= Parameters managed by CoppermineUploadPolicy", 30);
295 		displayDebug(PROP_ALBUM_ID + " : " + this.albumId, 30);
296 		displayDebug("", 30);
297 	}
298 
299 }