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