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.update(data); 51 file.creator = file.modifier = user; 52 site.files.add(file); 53 return file; 54 } 55 56 /** 57 * 58 */ 59 File.remove = function() { 60 if (this.constructor === File) { 61 this.getFile().remove(); 62 this.deleteMetadata(); 63 this.remove(); 64 } 65 return; 66 } 67 68 /** 69 * 70 * @param {String} name 71 */ 72 File.getName = function(name) { 73 if (name) { 74 //return name.replace(/[^\w\d\s._-]/g, String.EMPTY); 75 return String(name).trim().replace(/[\/\\:;?+\[\]{}|#"`<>^]/g, String.EMPTY); 76 } 77 return null; 78 } 79 80 /** 81 * 82 * @param {String } url 83 */ 84 File.redirectOnUploadError = function(url) { 85 if (req.data.helma_upload_error) { 86 res.message = gettext("Sorry, the file exceeds the maximum upload limit of {0} kB.", 87 formatNumber(app.appsProperties.uploadLimit)); 88 res.redirect(url); 89 } 90 return; 91 } 92 93 /** 94 * 95 * @param {String} url 96 */ 97 File.redirectOnExceededQuota = function(url) { 98 if (res.handlers.site.getDiskSpace() < 0) { 99 res.message = gettext("Sorry, there is no disk space left. Please try to delete some files or images first."); 100 res.redirect(url); 101 } 102 return; 103 } 104 105 /** 106 * @name File 107 * @constructor 108 * @property {Date} created 109 * @property {User} creator 110 * @property {Metadata} metadata 111 * @property {Date} modified 112 * @property {User} modifier 113 * @property {String} name 114 * @property {Number} parent_id 115 * @property {String} parent_type 116 * @property {String} prototype 117 * @property {Number} requests 118 * @property {Site} site 119 * @extends HopObject 120 */ 121 File.prototype.constructor = function() { 122 this.creator = this.modifier = session.user; 123 this.created = this.modified = new Date; 124 this.requests = 0; 125 return this; 126 } 127 128 /** 129 * 130 * @param {String} action 131 * @return {Boolean} 132 */ 133 File.prototype.getPermission = function(action) { 134 switch (action) { 135 case ".": 136 case "main": 137 return true; 138 case "delete": 139 case "edit": 140 return this._parent.getPermission("main") && 141 this.creator === session.user || 142 Membership.require(Membership.MANAGER) || 143 User.require(User.PRIVILEGED); 144 } 145 return false; 146 } 147 148 File.prototype.main_action = function() { 149 if (Membership.require(Membership.SUBSCRIBER) && 150 User.require(User.REGULAR)) { 151 this.requests += 1; 152 } 153 return res.redirect(this.getUrl()); 154 } 155 156 File.prototype.edit_action = function() { 157 File.redirectOnUploadError(this.href(req.action)); 158 159 if (req.postParams.save) { 160 try { 161 File.redirectOnExceededQuota(this.href(req.action)); 162 this.update(req.postParams); 163 res.message = gettext("The changes were saved successfully."); 164 res.redirect(this._parent.href()); 165 } catch (ex) { 166 res.message = ex; 167 app.log(ex); 168 } 169 } 170 171 res.data.action = this.href(req.action); 172 res.data.title = gettext("Edit File"); 173 res.data.body = this.renderSkinAsString("$File#edit"); 174 return this.site.renderSkin("Site#page"); 175 } 176 177 /** 178 * 179 * @param {String} name 180 * @returns {Object} 181 */ 182 File.prototype.getFormValue = function(name) { 183 var self = this; 184 185 var getOrigin = function(str) { 186 var origin = req.postParams.file_origin || self.origin; 187 if (origin && origin.contains("://")) { 188 return origin; 189 } 190 return null; 191 } 192 193 if (req.isPost()) { 194 if (name === "file") { 195 return getOrigin(); 196 } 197 return req.postParams[name]; 198 } 199 switch (name) { 200 case "file": 201 return getOrigin(); 202 } 203 return this[name]; 204 } 205 206 /** 207 * 208 * @param {Object} data 209 */ 210 File.prototype.update = function(data) { 211 if (data.uploadError) { 212 app.log(data.uploadError); 213 // Looks like the file uploaded has exceeded the upload limit ... 214 throw Error(gettext("File size is exceeding the upload limit.")); 215 } 216 217 if (!data.file_origin) { 218 if (this.isTransient()) { 219 throw Error(gettext("There was nothing to upload. Please be sure to choose a file.")); 220 } 221 } else if (data.file_origin !== this.origin) { 222 var mime = data.file; 223 if (mime.contentLength < 1) { 224 mime = getURL(data.file_origin); 225 if (!mime) { 226 throw Error(gettext("Could not fetch the file from the given URL.")); 227 } 228 } 229 230 this.origin = data.file_origin; 231 var mimeName = mime.normalizeFilename(mime.name); 232 this.contentLength = mime.contentLength; 233 this.contentType = mime.contentType; 234 235 if (!this.name) { 236 var name = File.getName(data.name) || mimeName.split(".")[0]; 237 this.name = this.site.files.getAccessName(name); 238 } 239 240 // Make the file persistent before proceeding with writing 241 // it to disk (also see Helma bug #607) 242 this.isTransient() && this.persist(); 243 244 var extension = mimeName.substr(mimeName.lastIndexOf(".")) || String.EMPTY; 245 var fileName = this.name + extension; 246 if (fileName !== this.fileName) { 247 // Remove existing file if the file name has changed 248 this.getFile().remove(); 249 } 250 this.fileName = fileName; 251 var file = this.getFile(); 252 mime.writeToFile(file.getParent(), file.getName()); 253 } 254 255 // FIXME: one day? 256 //this.setTags(data.tags || data.tag_array); 257 this.description = data.description; 258 this.touch(); 259 return; 260 } 261 262 /** 263 * 264 */ 265 File.prototype.url_macro = function() { 266 return res.write(this.url || this.getUrl()); 267 } 268 269 /** 270 * 271 * @param {Object} param 272 */ 273 File.prototype.contentLength_macro = function(param) { 274 return res.write((this.contentLength / 1024).format("###,###") + " KB"); 275 } 276 277 /** 278 * 279 */ 280 File.prototype.getFile = function() { 281 var site = this.site || res.handlers.site; 282 return site.getStaticFile("files/" + this.fileName); 283 } 284 285 /** 286 * 287 */ 288 File.prototype.getUrl = function() { 289 var site = this.site || res.handlers.site; 290 return site.getStaticUrl("files/" + this.fileName); 291 } 292 293 /** 294 * @returns {String} 295 */ 296 File.prototype.getConfirmText = function() { 297 return gettext("You are about to delete the file {0}.", this.name); 298 } 299