      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