1 // The Antville Project 2 // http://code.google.com/p/antville 3 // 4 // Copyright 2007-2011 by Tobi Schäfer. 5 // 6 // Copyright 2001–2007 Robert Gaggl, Hannes Wallnöfer, Tobi Schäfer, 7 // Matthias & Michael Platzer, Christoph Lincke. 8 // 9 // Licensed under the Apache License, Version 2.0 (the ``License''); 10 // you may not use this file except in compliance with the License. 11 // You may obtain a copy of the License at 12 // 13 // http://www.apache.org/licenses/LICENSE-2.0 14 // 15 // Unless required by applicable law or agreed to in writing, software 16 // distributed under the License is distributed on an ``AS IS'' BASIS, 17 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 // See the License for the specific language governing permissions and 19 // limitations under the License. 20 // 21 // $Revision$ 22 // $Author$ 23 // $Date$ 24 // $URL$ 25 26 /** 27 * @fileOverview Defines the Comment prototype. 28 */ 29 30 markgettext("File"); 31 markgettext("file"); 32 33 this.handleMetadata("url"); 34 this.handleMetadata("description"); 35 this.handleMetadata("contentType"); 36 this.handleMetadata("contentLength"); 37 this.handleMetadata("fileName"); 38 39 /** 40 * @param {Object} data 41 * @param {Site} site 42 * @param {User} user 43 * @returns {File} 44 */ 45 File.add = function(data, site, user) { 46 site || (site = res.handlers.site); 47 user || (user = session.user); 48 var file = new File; 49 file.site = site; 50 file.requests = 0; 51 file.creator = file.modifier = user; 52 file.created = file.modified = new Date; 53 file.update(data); 54 site.files.add(file); 55 return file; 56 } 57 58 /** 59 * 60 */ 61 File.remove = function() { 62 if (this.constructor === File) { 63 this.getFile().remove(); 64 this.deleteMetadata(); 65 this.remove(); 66 } 67 return; 68 } 69 70 /** 71 * 72 * @param {String} name 73 */ 74 File.getName = function(name) { 75 if (name) { 76 //return name.replace(/[^\w\d\s._-]/g, String.EMPTY); 77 return String(name).trim().replace(/[\/\\:;?+\[\]{}|#"`<>^]/g, String.EMPTY); 78 } 79 return null; 80 } 81 82 /** 83 * 84 * @param {String } url 85 */ 86 File.redirectOnUploadError = function(url) { 87 if (req.data.helma_upload_error) { 88 res.message = gettext("Sorry, the file exceeds the maximum upload limit of {0} kB.", 89 formatNumber(app.appsProperties.uploadLimit)); 90 res.redirect(url); 91 } 92 return; 93 } 94 95 /** 96 * 97 * @param {String} url 98 */ 99 File.redirectOnExceededQuota = function(url) { 100 if (res.handlers.site.getDiskSpace() < 0) { 101 res.message = gettext("Sorry, there is no disk space left. Please try to delete some files or images first."); 102 res.redirect(url); 103 } 104 return; 105 } 106 107 /** 108 * @name File 109 * @constructor 110 * @property {Date} created 111 * @property {User} creator 112 * @property {Metadata} metadata 113 * @property {Date} modified 114 * @property {User} modifier 115 * @property {String} name 116 * @property {Number} parent_id 117 * @property {String} parent_type 118 * @property {String} prototype 119 * @property {Number} requests 120 * @property {Site} site 121 * @extends HopObject 122 */ 123 File.prototype.constructor = function() { 124 return this; 125 } 126 127 /** 128 * 129 * @param {String} action 130 * @return {Boolean} 131 */ 132 File.prototype.getPermission = function(action) { 133 switch (action) { 134 case ".": 135 case "main": 136 return true; 137 case "delete": 138 case "edit": 139 return this._parent.getPermission("main") && 140 this.creator === session.user || 141 Membership.require(Membership.MANAGER) || 142 User.require(User.PRIVILEGED); 143 } 144 return false; 145 } 146 147 File.prototype.main_action = function() { 148 if (Membership.require(Membership.SUBSCRIBER) && 149 User.require(User.REGULAR)) { 150 this.requests += 1; 151 } 152 return res.redirect(this.getUrl()); 153 } 154 155 File.prototype.edit_action = function() { 156 File.redirectOnUploadError(this.href(req.action)); 157 158 if (req.postParams.save) { 159 try { 160 File.redirectOnExceededQuota(this.href(req.action)); 161 this.update(req.postParams); 162 res.message = gettext("The changes were saved successfully."); 163 res.redirect(this._parent.href()); 164 } catch (ex) { 165 res.message = ex; 166 app.log(ex); 167 } 168 } 169 170 res.data.action = this.href(req.action); 171 res.data.title = gettext("Edit File"); 172 res.data.body = this.renderSkinAsString("$File#edit"); 173 return this.site.renderSkin("Site#page"); 174 } 175 176 /** 177 * 178 * @param {String} name 179 * @returns {Object} 180 */ 181 File.prototype.getFormValue = function(name) { 182 var self = this; 183 184 var getOrigin = function(str) { 185 var origin = req.postParams.file_origin || self.origin; 186 if (origin && origin.contains("://")) { 187 return origin; 188 } 189 return null; 190 } 191 192 if (req.isPost()) { 193 if (name === "file") { 194 return getOrigin(); 195 } 196 return req.postParams[name]; 197 } 198 switch (name) { 199 case "file": 200 return getOrigin(); 201 } 202 return this[name]; 203 } 204 205 /** 206 * 207 * @param {Object} data 208 */ 209 File.prototype.update = function(data) { 210 if (data.uploadError) { 211 app.log(data.uploadError); 212 // Looks like the file uploaded has exceeded the upload limit ... 213 throw Error(gettext("File size is exceeding the upload limit.")); 214 } 215 216 if (!data.file_origin) { 217 if (this.isTransient()) { 218 throw Error(gettext("There was nothing to upload. Please be sure to choose a file.")); 219 } 220 } else if (data.file_origin !== this.origin) { 221 var mime = data.file; 222 if (mime.contentLength < 1) { 223 mime = getURL(data.file_origin); 224 if (!mime) { 225 throw Error(gettext("Could not fetch the file from the given URL.")); 226 } 227 } 228 229 this.origin = data.file_origin; 230 var mimeName = mime.normalizeFilename(mime.name); 231 this.contentLength = mime.contentLength; 232 this.contentType = mime.contentType; 233 234 if (!this.name) { 235 var name = File.getName(data.name) || mimeName.split(".")[0]; 236 this.name = this.site.files.getAccessName(name); 237 } 238 239 // Make the file persistent before proceeding with writing 240 // it to disk (also see Helma bug #607) 241 this.isTransient() && this.persist(); 242 243 var extension = mimeName.substr(mimeName.lastIndexOf(".")) || String.EMPTY; 244 var fileName = this.name + extension; 245 if (fileName !== this.fileName) { 246 // Remove existing file if the file name has changed 247 this.getFile().remove(); 248 } 249 this.fileName = fileName; 250 var file = this.getFile(); 251 mime.writeToFile(file.getParent(), file.getName()); 252 } 253 254 // FIXME: one day? 255 //this.setTags(data.tags || data.tag_array); 256 this.description = data.description; 257 this.touch(); 258 return; 259 } 260 261 /** 262 * 263 */ 264 File.prototype.url_macro = function() { 265 return res.write(this.url || this.getUrl()); 266 } 267 268 /** 269 * 270 * @param {Object} param 271 */ 272 File.prototype.contentLength_macro = function(param) { 273 return res.write((this.contentLength / 1024).format("###,###") + " KB"); 274 } 275 276 /** 277 * 278 */ 279 File.prototype.getFile = function() { 280 var site = this.site || res.handlers.site; 281 return site.getStaticFile("files/" + this.fileName); 282 } 283 284 /** 285 * 286 */ 287 File.prototype.getUrl = function() { 288 var site = this.site || res.handlers.site; 289 return site.getStaticUrl("files/" + this.fileName); 290 } 291 292 /** 293 * @returns {String} 294 */ 295 File.prototype.getConfirmText = function() { 296 return gettext("You are about to delete the file {0}.", this.name); 297 } 298