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 this.handleMetadata("url");
 30 this.handleMetadata("description");
 31 this.handleMetadata("contentType");
 32 this.handleMetadata("contentLength");
 33 this.handleMetadata("fileName");
 34 
 35 /**
 36  * 
 37  */
 38 File.remove = function() {
 39    if (this.constructor === File) {
 40       this.getFile().remove();
 41       this.remove();
 42    }
 43    return;
 44 }
 45 
 46 /**
 47  * 
 48  * @param {String} name
 49  */
 50 File.getName = function(name) {
 51    if (name) {
 52       //return name.replace(/[^\w\d\s._-]/g, String.EMPTY);
 53       return String(name).trim().replace(/[\/\\:;?+\[\]{}|#"`<>^]/g, String.EMPTY);
 54    }
 55    return null;
 56 }
 57 
 58 /**
 59  * @name File
 60  * @constructor
 61  * @property {Date} created
 62  * @property {User} creator
 63  * @property {Metadata} metadata
 64  * @property {Date} modified
 65  * @property {User} modifier
 66  * @property {String} name
 67  * @property {Number} parent_id
 68  * @property {String} parent_type
 69  * @property {String} prototype
 70  * @property {Number} requests
 71  * @property {Site} site
 72  * @extends HopObject
 73  */
 74 File.prototype.constructor = function() {
 75    this.creator = this.modifier = session.user;
 76    this.created = this.modified = new Date;
 77    this.requests = 0;
 78    return this;
 79 }
 80 
 81 /**
 82  * 
 83  * @param {String} action
 84  * @return {Boolean}
 85  */
 86 File.prototype.getPermission = function(action) {
 87    switch (action) {
 88       case ".":
 89       case "main":
 90       return true;
 91       case "delete":
 92       case "edit":
 93       return this._parent.getPermission("main") &&
 94             this.creator === session.user || 
 95             Membership.require(Membership.MANAGER) ||
 96             User.require(User.PRIVILEGED);            
 97    }
 98    return false;
 99 }
100 
101 File.prototype.main_action = function() {
102    if (Membership.require(Membership.SUBSCRIBER) &&
103          User.require(User.REGULAR)) {
104       this.requests += 1;
105    }
106    return res.redirect(this.getUrl());
107 }
108 
109 File.prototype.edit_action = function() {
110    if (req.postParams.save) {
111       try {
112          this.update(req.postParams);
113          res.message = gettext("The changes were saved successfully.");
114          res.redirect(this._parent.href());
115       } catch (ex) {
116          res.message = ex;
117          app.log(ex);
118       }
119    }
120    
121    res.data.action = this.href(req.action);
122    res.data.title = gettext("Edit File");
123    res.data.body = this.renderSkinAsString("$File#edit");
124    return this.site.renderSkin("Site#page");
125 }
126 
127 /**
128  * 
129  * @param {String} name
130  * @returns {Object}
131  */
132 File.prototype.getFormValue = function(name) {
133    var self = this;
134    
135    var getOrigin = function(str) {
136       var origin = req.postParams.file_origin || self.origin;
137       if (origin && origin.contains("://")) {
138          return origin;
139       }
140       return null;
141    }
142    
143    if (req.isPost()) {
144       if (name === "file") {
145          return getOrigin();
146       }
147       return req.postParams[name];
148    }
149    switch (name) {
150       case "file":
151       return getOrigin();
152    }
153    return this[name];
154 }
155 
156 /**
157  * 
158  * @param {Object} data
159  */
160 File.prototype.update = function(data) {
161    if (data.uploadError) {
162       app.log(data.uploadError);
163       // Looks like the file uploaded has exceeded the upload limit ...
164       throw Error(gettext("File size is exceeding the upload limit."));
165    }
166       
167    if (!data.file_origin) {
168       if (this.isTransient()) { 
169          throw Error(gettext("There was nothing to upload. Please be sure to choose a file."));
170       }
171    } else if (data.file_origin !== this.origin) {
172       var mime = data.file;
173       if (mime.contentLength < 1) {
174          mime = getURL(data.file_origin);
175          if (!mime) {
176             throw Error(gettext("Could not fetch the file from the given URL."));
177          }
178       }
179 
180       this.origin = data.file_origin;
181       var mimeName = mime.normalizeFilename(mime.name);
182       this.contentLength = mime.contentLength;
183       this.contentType = mime.contentType;
184       
185       if (!this.name) {
186           var name = File.getName(data.name) || mimeName.split(".")[0];
187           this.name = this.site.files.getAccessName(name);
188       }
189 
190       // Make the file persistent before proceeding with writing 
191       // it to disk (also see Helma bug #607)
192       this.isTransient() && this.persist();
193 
194       var extension = mimeName.substr(mimeName.lastIndexOf(".")) || String.EMPTY;
195       var fileName = this.name + extension;
196       if (fileName !== this.fileName) {
197          // Remove existing file if the file name has changed
198          this.getFile().remove();
199       }
200       this.fileName = fileName;
201       var file = this.getFile();
202       mime.writeToFile(file.getParent(), file.getName());
203    }
204       
205    // FIXME: one day? 
206    //this.setTags(data.tags || data.tag_array); 
207    this.description = data.description;
208    this.touch();
209    return;
210 }
211 
212 /**
213  * 
214  */
215 File.prototype.url_macro = function() {
216    return res.write(this.url || this.getUrl());
217 }
218 
219 /**
220  * 
221  * @param {Object} param
222  */
223 File.prototype.contentLength_macro = function(param) {
224    return res.write((this.contentLength / 1024).format("###,###") + " KB");
225 }
226 
227 /**
228  * 
229  */
230 File.prototype.getFile = function() {
231    var site = this.site || res.handlers.site;
232    return site.getStaticFile("files/" + this.fileName);
233 }
234 
235 /**
236  * 
237  */
238 File.prototype.getUrl = function() {
239    var site = this.site || res.handlers.site;
240    return site.getStaticUrl("files/" + this.fileName);
241 }
242