(function () {

/* Imports */
var Meteor = Package.meteor.Meteor;
var global = Package.meteor.global;
var meteorEnv = Package.meteor.meteorEnv;
var FS = Package['wekan-cfs-base-package'].FS;
var check = Package.check.check;
var Match = Package.check.Match;
var EJSON = Package.ejson.EJSON;
var HTTP = Package['wekan-cfs-http-methods'].HTTP;

/* Package-scope variables */
var rootUrlPathPrefix, baseUrl, getHeaders, getHeadersByCollection, _existingMountPoints, mountUrls;

(function(){

///////////////////////////////////////////////////////////////////////
//                                                                   //
// packages/cfs_access-point/packages/cfs_access-point.js            //
//                                                                   //
///////////////////////////////////////////////////////////////////////
                                                                     //
(function () {

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                    //
// packages/wekan-cfs-access-point/access-point-common.js                                                                   //
//                                                                                                                    //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                                      //
rootUrlPathPrefix = __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || "";                                             // 1
// Adjust the rootUrlPathPrefix if necessary                                                                          // 2
if (rootUrlPathPrefix.length > 0) {                                                                                   // 3
  if (rootUrlPathPrefix.slice(0, 1) !== '/') {                                                                        // 4
    rootUrlPathPrefix = '/' + rootUrlPathPrefix;                                                                      // 5
  }                                                                                                                   // 6
  if (rootUrlPathPrefix.slice(-1) === '/') {                                                                          // 7
    rootUrlPathPrefix = rootUrlPathPrefix.slice(0, -1);                                                               // 8
  }                                                                                                                   // 9
}                                                                                                                     // 10
                                                                                                                      // 11
// prepend ROOT_URL when isCordova                                                                                    // 12
if (Meteor.isCordova) {                                                                                               // 13
  rootUrlPathPrefix = Meteor.absoluteUrl(rootUrlPathPrefix.replace(/^\/+/, '')).replace(/\/+$/, '');                  // 14
}                                                                                                                     // 15
                                                                                                                      // 16
baseUrl = '/cfs';                                                                                                     // 17
FS.HTTP = FS.HTTP || {};                                                                                              // 18
                                                                                                                      // 19
// Note the upload URL so that client uploader packages know what it is                                               // 20
FS.HTTP.uploadUrl = rootUrlPathPrefix + baseUrl + '/files';                                                           // 21
                                                                                                                      // 22
/**                                                                                                                   // 23
 * @method FS.HTTP.setBaseUrl                                                                                         // 24
 * @public                                                                                                            // 25
 * @param {String} newBaseUrl - Change the base URL for the HTTP GET and DELETE endpoints.                            // 26
 * @returns {undefined}                                                                                               // 27
 */                                                                                                                   // 28
FS.HTTP.setBaseUrl = function setBaseUrl(newBaseUrl) {                                                                // 29
                                                                                                                      // 30
  // Adjust the baseUrl if necessary                                                                                  // 31
  if (newBaseUrl.slice(0, 1) !== '/') {                                                                               // 32
    newBaseUrl = '/' + newBaseUrl;                                                                                    // 33
  }                                                                                                                   // 34
  if (newBaseUrl.slice(-1) === '/') {                                                                                 // 35
    newBaseUrl = newBaseUrl.slice(0, -1);                                                                             // 36
  }                                                                                                                   // 37
                                                                                                                      // 38
  // Update the base URL                                                                                              // 39
  baseUrl = newBaseUrl;                                                                                               // 40
                                                                                                                      // 41
  // Change the upload URL so that client uploader packages know what it is                                           // 42
  FS.HTTP.uploadUrl = rootUrlPathPrefix + baseUrl + '/files';                                                         // 43
                                                                                                                      // 44
  // Remount URLs with the new baseUrl, unmounting the old, on the server only.                                       // 45
  // If existingMountPoints is empty, then we haven't run the server startup                                          // 46
  // code yet, so this new URL will be used at that point for the initial mount.                                      // 47
  if (Meteor.isServer && !FS.Utility.isEmpty(_existingMountPoints)) {                                                 // 48
    mountUrls();                                                                                                      // 49
  }                                                                                                                   // 50
};                                                                                                                    // 51
                                                                                                                      // 52
/*                                                                                                                    // 53
 * FS.File extensions                                                                                                 // 54
 */                                                                                                                   // 55
                                                                                                                      // 56
/**                                                                                                                   // 57
 * @method FS.File.prototype.url Construct the file url                                                               // 58
 * @public                                                                                                            // 59
 * @param {Object} [options]                                                                                          // 60
 * @param {String} [options.store] Name of the store to get from. If not defined, the first store defined in `options.stores` for the collection on the client is used.
 * @param {Boolean} [options.auth=null] Add authentication token to the URL query string? By default, a token for the current logged in user is added on the client. Set this to `false` to omit the token. Set this to a string to provide your own token. Set this to a number to specify an expiration time for the token in seconds.
 * @param {Boolean} [options.download=false] Should headers be set to force a download? Typically this means that clicking the link with this URL will download the file to the user's Downloads folder instead of displaying the file in the browser.
 * @param {Boolean} [options.brokenIsFine=false] Return the URL even if we know it's currently a broken link because the file hasn't been saved in the requested store yet.
 * @param {Boolean} [options.metadata=false] Return the URL for the file metadata access point rather than the file itself.
 * @param {String} [options.uploading=null] A URL to return while the file is being uploaded.                         // 66
 * @param {String} [options.storing=null] A URL to return while the file is being stored.                             // 67
 * @param {String} [options.filename=null] Override the filename that should appear at the end of the URL. By default it is the name of the file in the requested store.
 *                                                                                                                    // 69
 * Returns the HTTP URL for getting the file or its metadata.                                                         // 70
 */                                                                                                                   // 71
FS.File.prototype.url = function(options) {                                                                           // 72
  var self = this;                                                                                                    // 73
  options = options || {};                                                                                            // 74
  options = FS.Utility.extend({                                                                                       // 75
    store: null,                                                                                                      // 76
    auth: null,                                                                                                       // 77
    download: false,                                                                                                  // 78
    metadata: false,                                                                                                  // 79
    brokenIsFine: false,                                                                                              // 80
    uploading: null, // return this URL while uploading                                                               // 81
    storing: null, // return this URL while storing                                                                   // 82
    filename: null // override the filename that is shown to the user                                                 // 83
  }, options.hash || options); // check for "hash" prop if called as helper                                           // 84
                                                                                                                      // 85
  // Primarily useful for displaying a temporary image while uploading an image                                       // 86
  if (options.uploading && !self.isUploaded()) {                                                                      // 87
    return options.uploading;                                                                                         // 88
  }                                                                                                                   // 89
                                                                                                                      // 90
  if (self.isMounted()) {                                                                                             // 91
    // See if we've stored in the requested store yet                                                                 // 92
    var storeName = options.store || self.collection.primaryStore.name;                                               // 93
    if (!self.hasStored(storeName)) {                                                                                 // 94
      if (options.storing) {                                                                                          // 95
        return options.storing;                                                                                       // 96
      } else if (!options.brokenIsFine) {                                                                             // 97
        // We want to return null if we know the URL will be a broken                                                 // 98
        // link because then we can avoid rendering broken links, broken                                              // 99
        // images, etc.                                                                                               // 100
        return null;                                                                                                  // 101
      }                                                                                                               // 102
    }                                                                                                                 // 103
                                                                                                                      // 104
    // Add filename to end of URL if we can determine one                                                             // 105
    var filename = options.filename || self.name({store: storeName});                                                 // 106
    if (typeof filename === "string" && filename.length) {                                                            // 107
      filename = '/' + filename;                                                                                      // 108
    } else {                                                                                                          // 109
      filename = '';                                                                                                  // 110
    }                                                                                                                 // 111
                                                                                                                      // 112
    // TODO: Could we somehow figure out if the collection requires login?                                            // 113
    var authToken = '';                                                                                               // 114
    if (Meteor.isClient && typeof Accounts !== "undefined" && typeof Accounts._storedLoginToken === "function") {     // 115
      if (options.auth !== false) {                                                                                   // 116
        // Add reactive deps on the user                                                                              // 117
        Meteor.userId();                                                                                              // 118
                                                                                                                      // 119
        var authObject = {                                                                                            // 120
          authToken: Accounts._storedLoginToken() || ''                                                               // 121
        };                                                                                                            // 122
                                                                                                                      // 123
        // If it's a number, we use that as the expiration time (in seconds)                                          // 124
        if (options.auth === +options.auth) {                                                                         // 125
          authObject.expiration = FS.HTTP.now() + options.auth * 1000;                                                // 126
        }                                                                                                             // 127
                                                                                                                      // 128
        // Set the authToken                                                                                          // 129
        var authString = JSON.stringify(authObject);                                                                  // 130
        authToken = FS.Utility.btoa(authString);                                                                      // 131
      }                                                                                                               // 132
    } else if (typeof options.auth === "string") {                                                                    // 133
      // If the user supplies auth token the user will be responsible for                                             // 134
      // updating                                                                                                     // 135
      authToken = options.auth;                                                                                       // 136
    }                                                                                                                 // 137
                                                                                                                      // 138
    // Construct query string                                                                                         // 139
    var params = {};                                                                                                  // 140
    if (authToken !== '') {                                                                                           // 141
      params.token = authToken;                                                                                       // 142
    }                                                                                                                 // 143
    if (options.download) {                                                                                           // 144
      params.download = true;                                                                                         // 145
    }                                                                                                                 // 146
    if (options.store) {                                                                                              // 147
      // We use options.store here instead of storeName because we want to omit the queryString                       // 148
      // whenever possible, allowing users to have "clean" URLs if they want. The server will                         // 149
      // assume the first store defined on the server, which means that we are assuming that                          // 150
      // the first on the client is also the first on the server. If that's not the case, the                         // 151
      // store option should be supplied.                                                                             // 152
      params.store = options.store;                                                                                   // 153
    }                                                                                                                 // 154
    var queryString = FS.Utility.encodeParams(params);                                                                // 155
    if (queryString.length) {                                                                                         // 156
      queryString = '?' + queryString;                                                                                // 157
    }                                                                                                                 // 158
                                                                                                                      // 159
    // Determine which URL to use                                                                                     // 160
    var area;                                                                                                         // 161
    if (options.metadata) {                                                                                           // 162
      area = '/record';                                                                                               // 163
    } else {                                                                                                          // 164
      area = '/files';                                                                                                // 165
    }                                                                                                                 // 166
                                                                                                                      // 167
    // Construct and return the http method url                                                                       // 168
    return rootUrlPathPrefix + baseUrl + area + '/' + self.collection.name + '/' + self._id + filename + queryString; // 169
  }                                                                                                                   // 170
                                                                                                                      // 171
};                                                                                                                    // 172
                                                                                                                      // 173
                                                                                                                      // 174
                                                                                                                      // 175
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}).call(this);






(function () {

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                    //
// packages/wekan-cfs-access-point/access-point-handlers.js                                                                 //
//                                                                                                                    //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                                      //
getHeaders = [];                                                                                                      // 1
getHeadersByCollection = {};                                                                                          // 2
                                                                                                                      // 3
FS.HTTP.Handlers = {};                                                                                                // 4
                                                                                                                      // 5
/**                                                                                                                   // 6
 * @method FS.HTTP.Handlers.Del                                                                                       // 7
 * @public                                                                                                            // 8
 * @returns {any} response                                                                                            // 9
 *                                                                                                                    // 10
 * HTTP DEL request handler                                                                                           // 11
 */                                                                                                                   // 12
FS.HTTP.Handlers.Del = function httpDelHandler(ref) {                                                                 // 13
  var self = this;                                                                                                    // 14
  var opts = FS.Utility.extend({}, self.query || {}, self.params || {});                                              // 15
                                                                                                                      // 16
  // If DELETE request, validate with 'remove' allow/deny, delete the file, and return                                // 17
  FS.Utility.validateAction(ref.collection.files._validators['remove'], ref.file, self.userId);                       // 18
                                                                                                                      // 19
  /*                                                                                                                  // 20
   * From the DELETE spec:                                                                                            // 21
   * A successful response SHOULD be 200 (OK) if the response includes an                                             // 22
   * entity describing the status, 202 (Accepted) if the action has not                                               // 23
   * yet been enacted, or 204 (No Content) if the action has been enacted                                             // 24
   * but the response does not include an entity.                                                                     // 25
   */                                                                                                                 // 26
  self.setStatusCode(200);                                                                                            // 27
                                                                                                                      // 28
  return {                                                                                                            // 29
    deleted: !!ref.file.remove()                                                                                      // 30
  };                                                                                                                  // 31
};                                                                                                                    // 32
                                                                                                                      // 33
/**                                                                                                                   // 34
 * @method FS.HTTP.Handlers.GetList                                                                                   // 35
 * @public                                                                                                            // 36
 * @returns {Object} response                                                                                         // 37
 *                                                                                                                    // 38
 * HTTP GET file list request handler                                                                                 // 39
 */                                                                                                                   // 40
FS.HTTP.Handlers.GetList = function httpGetListHandler() {                                                            // 41
  // Not Yet Implemented                                                                                              // 42
  // Need to check publications and return file list based on                                                         // 43
  // what user is allowed to see                                                                                      // 44
};                                                                                                                    // 45
                                                                                                                      // 46
/*                                                                                                                    // 47
  requestRange will parse the range set in request header - if not possible it                                        // 48
  will throw fitting errors and autofill range for both partial and full ranges                                       // 49
                                                                                                                      // 50
  throws error or returns the object:                                                                                 // 51
  {                                                                                                                   // 52
    start                                                                                                             // 53
    end                                                                                                               // 54
    length                                                                                                            // 55
    unit                                                                                                              // 56
    partial                                                                                                           // 57
  }                                                                                                                   // 58
*/                                                                                                                    // 59
var requestRange = function(req, fileSize) {                                                                          // 60
  if (req) {                                                                                                          // 61
    if (req.headers) {                                                                                                // 62
      var rangeString = req.headers.range;                                                                            // 63
                                                                                                                      // 64
      // Make sure range is a string                                                                                  // 65
      if (rangeString === ''+rangeString) {                                                                           // 66
                                                                                                                      // 67
        // range will be in the format "bytes=0-32767"                                                                // 68
        var parts = rangeString.split('=');                                                                           // 69
        var unit = parts[0];                                                                                          // 70
                                                                                                                      // 71
        // Make sure parts consists of two strings and range is of type "byte"                                        // 72
        if (parts.length == 2 && unit == 'bytes') {                                                                   // 73
          // Parse the range                                                                                          // 74
          var range = parts[1].split('-');                                                                            // 75
          var start = Number(range[0]);                                                                               // 76
          var end = Number(range[1]);                                                                                 // 77
                                                                                                                      // 78
          // Fix invalid ranges?                                                                                      // 79
          if (range[0] != start) start = 0;                                                                           // 80
          if (range[1] != end || !end) end = fileSize - 1;                                                            // 81
                                                                                                                      // 82
          // Make sure range consists of a start and end point of numbers and start is less than end                  // 83
          if (start < end) {                                                                                          // 84
                                                                                                                      // 85
            var partSize = 0 - start + end + 1;                                                                       // 86
                                                                                                                      // 87
            // Return the parsed range                                                                                // 88
            return {                                                                                                  // 89
              start: start,                                                                                           // 90
              end: end,                                                                                               // 91
              length: partSize,                                                                                       // 92
              size: fileSize,                                                                                         // 93
              unit: unit,                                                                                             // 94
              partial: (partSize < fileSize)                                                                          // 95
            };                                                                                                        // 96
                                                                                                                      // 97
          } else {                                                                                                    // 98
            throw new Meteor.Error(416, "Requested Range Not Satisfiable");                                           // 99
          }                                                                                                           // 100
                                                                                                                      // 101
        } else {                                                                                                      // 102
          // The first part should be bytes                                                                           // 103
          throw new Meteor.Error(416, "Requested Range Unit Not Satisfiable");                                        // 104
        }                                                                                                             // 105
                                                                                                                      // 106
      } else {                                                                                                        // 107
        // No range found                                                                                             // 108
      }                                                                                                               // 109
                                                                                                                      // 110
    } else {                                                                                                          // 111
      // throw new Error('No request headers set for _parseRange function');                                          // 112
    }                                                                                                                 // 113
  } else {                                                                                                            // 114
    throw new Error('No request object passed to _parseRange function');                                              // 115
  }                                                                                                                   // 116
                                                                                                                      // 117
  return {                                                                                                            // 118
    start: 0,                                                                                                         // 119
    end: fileSize - 1,                                                                                                // 120
    length: fileSize,                                                                                                 // 121
    size: fileSize,                                                                                                   // 122
    unit: 'bytes',                                                                                                    // 123
    partial: false                                                                                                    // 124
  };                                                                                                                  // 125
};                                                                                                                    // 126
                                                                                                                      // 127
/**                                                                                                                   // 128
 * @method FS.HTTP.Handlers.Get                                                                                       // 129
 * @public                                                                                                            // 130
 * @returns {any} response                                                                                            // 131
 *                                                                                                                    // 132
 * HTTP GET request handler                                                                                           // 133
 */                                                                                                                   // 134
FS.HTTP.Handlers.Get = function httpGetHandler(ref) {                                                                 // 135
  var self = this;                                                                                                    // 136
  // Once we have the file, we can test allow/deny validators                                                         // 137
  // XXX: pass on the "share" query eg. ?share=342hkjh23ggj for shared url access?                                    // 138
  FS.Utility.validateAction(ref.collection._validators['download'], ref.file, self.userId /*, self.query.shareId*/);  // 139
                                                                                                                      // 140
  var storeName = ref.storeName;                                                                                      // 141
                                                                                                                      // 142
  // If no storeName was specified, use the first defined storeName                                                   // 143
  if (typeof storeName !== "string") {                                                                                // 144
    // No store handed, we default to primary store                                                                   // 145
    storeName = ref.collection.primaryStore.name;                                                                     // 146
  }                                                                                                                   // 147
                                                                                                                      // 148
  // Get the storage reference                                                                                        // 149
  var storage = ref.collection.storesLookup[storeName];                                                               // 150
                                                                                                                      // 151
  if (!storage) {                                                                                                     // 152
    throw new Meteor.Error(404, "Not Found", 'There is no store "' + storeName + '"');                                // 153
  }                                                                                                                   // 154
                                                                                                                      // 155
  // Get the file                                                                                                     // 156
  var copyInfo = ref.file.copies[storeName];                                                                          // 157
                                                                                                                      // 158
  if (!copyInfo) {                                                                                                    // 159
    throw new Meteor.Error(404, "Not Found", 'This file was not stored in the ' + storeName + ' store');              // 160
  }                                                                                                                   // 161
                                                                                                                      // 162
  // Set the content type for file                                                                                    // 163
  if (typeof copyInfo.type === "string") {                                                                            // 164
    self.setContentType(copyInfo.type);                                                                               // 165
  } else {                                                                                                            // 166
    self.setContentType('application/octet-stream');                                                                  // 167
  }                                                                                                                   // 168
                                                                                                                      // 169
  // Add 'Content-Disposition' header if requested a download/attachment URL                                          // 170
  if (typeof ref.download !== "undefined") {                                                                          // 171
    var filename = ref.filename || copyInfo.name;                                                                     // 172
    self.addHeader('Content-Disposition', 'attachment; filename="' + filename + '"');                                 // 173
  } else {                                                                                                            // 174
    self.addHeader('Content-Disposition', 'inline');                                                                  // 175
  }                                                                                                                   // 176
                                                                                                                      // 177
  // Get the contents range from request                                                                              // 178
  var range = requestRange(self.request, copyInfo.size);                                                              // 179
                                                                                                                      // 180
  // Some browsers cope better if the content-range header is                                                         // 181
  // still included even for the full file being returned.                                                            // 182
  self.addHeader('Content-Range', range.unit + ' ' + range.start + '-' + range.end + '/' + range.size);               // 183
                                                                                                                      // 184
  // If a chunk/range was requested instead of the whole file, serve that'                                            // 185
  if (range.partial) {                                                                                                // 186
    self.setStatusCode(206, 'Partial Content');                                                                       // 187
  } else {                                                                                                            // 188
    self.setStatusCode(200, 'OK');                                                                                    // 189
  }                                                                                                                   // 190
                                                                                                                      // 191
  // Add any other global custom headers and collection-specific custom headers                                       // 192
  FS.Utility.each(getHeaders.concat(getHeadersByCollection[ref.collection.name] || []), function(header) {            // 193
    self.addHeader(header[0], header[1]);                                                                             // 194
  });                                                                                                                 // 195
                                                                                                                      // 196
  // Inform clients about length (or chunk length in case of ranges)                                                  // 197
  self.addHeader('Content-Length', range.length);                                                                     // 198
                                                                                                                      // 199
  // Last modified header (updatedAt from file info)                                                                  // 200
  self.addHeader('Last-Modified', copyInfo.updatedAt.toUTCString());                                                  // 201
                                                                                                                      // 202
  // Inform clients that we accept ranges for resumable chunked downloads                                             // 203
  self.addHeader('Accept-Ranges', range.unit);                                                                        // 204
                                                                                                                      // 205
  if (FS.debug) console.log('Read file "' + (ref.filename || copyInfo.name) + '" ' + range.unit + ' ' + range.start + '-' + range.end + '/' + range.size);
                                                                                                                      // 207
  var readStream = storage.adapter.createReadStream(ref.file, {start: range.start, end: range.end});                  // 208
                                                                                                                      // 209
  readStream.on('error', function(err) {                                                                              // 210
    // Send proper error message on get error                                                                         // 211
    if (err.message && err.statusCode) {                                                                              // 212
      self.Error(new Meteor.Error(err.statusCode, err.message));                                                      // 213
    } else {                                                                                                          // 214
      self.Error(new Meteor.Error(503, 'Service unavailable'));                                                       // 215
    }                                                                                                                 // 216
  });                                                                                                                 // 217
                                                                                                                      // 218
  readStream.pipe(self.createWriteStream());                                                                          // 219
};                                                                                                                    // 220

const originalHandler = FS.HTTP.Handlers.Get;
FS.HTTP.Handlers.Get = function (ref) {
//console.log(ref.filename);
  try {
     var userAgent = (this.requestHeaders['user-agent']||'').toLowerCase();

        if(userAgent.indexOf('msie') >= 0 || userAgent.indexOf('trident') >= 0 || userAgent.indexOf('chrome') >= 0) {
            ref.filename =  encodeURIComponent(ref.filename);
        } else if(userAgent.indexOf('firefox') >= 0) {
            ref.filename = Buffer.from(ref.filename).toString('binary');
        } else {
            /* safari*/
            ref.filename = Buffer.from(ref.filename).toString('binary');
        }
   } catch (ex){
        ref.filename = 'tempfix';
   }
   return originalHandler.call(this, ref);
};
                                                                                                                      // 221
/**                                                                                                                   // 222
 * @method FS.HTTP.Handlers.PutInsert                                                                                 // 223
 * @public                                                                                                            // 224
 * @returns {Object} response object with _id property                                                                // 225
 *                                                                                                                    // 226
 * HTTP PUT file insert request handler                                                                               // 227
 */                                                                                                                   // 228
FS.HTTP.Handlers.PutInsert = function httpPutInsertHandler(ref) {                                                     // 229
  var self = this;                                                                                                    // 230
  var opts = FS.Utility.extend({}, self.query || {}, self.params || {});                                              // 231
                                                                                                                      // 232
  FS.debug && console.log("HTTP PUT (insert) handler");                                                               // 233
                                                                                                                      // 234
  // Create the nice FS.File                                                                                          // 235
  var fileObj = new FS.File();                                                                                        // 236
                                                                                                                      // 237
  // Set its name                                                                                                     // 238
  fileObj.name(opts.filename || null);                                                                                // 239
                                                                                                                      // 240
  // Attach the readstream as the file's data                                                                         // 241
  fileObj.attachData(self.createReadStream(), {type: self.requestHeaders['content-type'] || 'application/octet-stream'});
                                                                                                                      // 243
  // Validate with insert allow/deny                                                                                  // 244
  FS.Utility.validateAction(ref.collection.files._validators['insert'], fileObj, self.userId);                        // 245
                                                                                                                      // 246
  // Insert file into collection, triggering readStream storage                                                       // 247
  ref.collection.insert(fileObj);                                                                                     // 248
                                                                                                                      // 249
  // Send response                                                                                                    // 250
  self.setStatusCode(200);                                                                                            // 251
                                                                                                                      // 252
  // Return the new file id                                                                                           // 253
  return {_id: fileObj._id};                                                                                          // 254
};                                                                                                                    // 255
                                                                                                                      // 256
/**                                                                                                                   // 257
 * @method FS.HTTP.Handlers.PutUpdate                                                                                 // 258
 * @public                                                                                                            // 259
 * @returns {Object} response object with _id and chunk properties                                                    // 260
 *                                                                                                                    // 261
 * HTTP PUT file update chunk request handler                                                                         // 262
 */                                                                                                                   // 263
FS.HTTP.Handlers.PutUpdate = function httpPutUpdateHandler(ref) {                                                     // 264
  var self = this;                                                                                                    // 265
  var opts = FS.Utility.extend({}, self.query || {}, self.params || {});                                              // 266
                                                                                                                      // 267
  var chunk = parseInt(opts.chunk, 10);                                                                               // 268
  if (isNaN(chunk)) chunk = 0;                                                                                        // 269
                                                                                                                      // 270
  FS.debug && console.log("HTTP PUT (update) handler received chunk: ", chunk);                                       // 271
                                                                                                                      // 272
  // Validate with insert allow/deny; also mounts and retrieves the file                                              // 273
  FS.Utility.validateAction(ref.collection.files._validators['insert'], ref.file, self.userId);                       // 274
                                                                                                                      // 275
  self.createReadStream().pipe( FS.TempStore.createWriteStream(ref.file, chunk) );                                    // 276
                                                                                                                      // 277
  // Send response                                                                                                    // 278
  self.setStatusCode(200);                                                                                            // 279
                                                                                                                      // 280
  return { _id: ref.file._id, chunk: chunk };                                                                         // 281
};                                                                                                                    // 282
                                                                                                                      // 283
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}).call(this);






(function () {

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                    //
// packages/wekan-cfs-access-point/access-point-server.js                                                                   //
//                                                                                                                    //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                                      //
var path = Npm.require("path");                                                                                       // 1
                                                                                                                      // 2
HTTP.publishFormats({                                                                                                 // 3
  fileRecordFormat: function (input) {                                                                                // 4
    // Set the method scope content type to json                                                                      // 5
    this.setContentType('application/json');                                                                          // 6
    if (FS.Utility.isArray(input)) {                                                                                  // 7
      return EJSON.stringify(FS.Utility.map(input, function (obj) {                                                   // 8
        return FS.Utility.cloneFileRecord(obj);                                                                       // 9
      }));                                                                                                            // 10
    } else {                                                                                                          // 11
      return EJSON.stringify(FS.Utility.cloneFileRecord(input));                                                      // 12
    }                                                                                                                 // 13
  }                                                                                                                   // 14
});                                                                                                                   // 15
                                                                                                                      // 16
/**                                                                                                                   // 17
 * @method FS.HTTP.setHeadersForGet                                                                                   // 18
 * @public                                                                                                            // 19
 * @param {Array} headers - List of headers, where each is a two-item array in which item 1 is the header name and item 2 is the header value.
 * @param {Array|String} [collections] - Which collections the headers should be added for. Omit this argument to add the header for all collections.
 * @returns {undefined}                                                                                               // 22
 */                                                                                                                   // 23
FS.HTTP.setHeadersForGet = function setHeadersForGet(headers, collections) {                                          // 24
  if (typeof collections === "string") {                                                                              // 25
    collections = [collections];                                                                                      // 26
  }                                                                                                                   // 27
  if (collections) {                                                                                                  // 28
    FS.Utility.each(collections, function(collectionName) {                                                           // 29
      getHeadersByCollection[collectionName] = headers || [];                                                         // 30
    });                                                                                                               // 31
  } else {                                                                                                            // 32
    getHeaders = headers || [];                                                                                       // 33
  }                                                                                                                   // 34
};                                                                                                                    // 35
                                                                                                                      // 36
/**                                                                                                                   // 37
 * @method FS.HTTP.publish                                                                                            // 38
 * @public                                                                                                            // 39
 * @param {FS.Collection} collection                                                                                  // 40
 * @param {Function} func - Publish function that returns a cursor.                                                   // 41
 * @returns {undefined}                                                                                               // 42
 *                                                                                                                    // 43
 * Publishes all documents returned by the cursor at a GET URL                                                        // 44
 * with the format baseUrl/record/collectionName. The publish                                                         // 45
 * function `this` is similar to normal `Meteor.publish`.                                                             // 46
 */                                                                                                                   // 47
FS.HTTP.publish = function fsHttpPublish(collection, func) {                                                          // 48
  var name = baseUrl + '/record/' + collection.name;                                                                  // 49
  // Mount collection listing URL using http-publish package                                                          // 50
  HTTP.publish({                                                                                                      // 51
    name: name,                                                                                                       // 52
    defaultFormat: 'fileRecordFormat',                                                                                // 53
    collection: collection,                                                                                           // 54
    collectionGet: true,                                                                                              // 55
    collectionPost: false,                                                                                            // 56
    documentGet: true,                                                                                                // 57
    documentPut: false,                                                                                               // 58
    documentDelete: false                                                                                             // 59
  }, func);                                                                                                           // 60
                                                                                                                      // 61
  FS.debug && console.log("Registered HTTP method GET URLs:\n\n" + name + '\n' + name + '/:id\n');                    // 62
};                                                                                                                    // 63
                                                                                                                      // 64
/**                                                                                                                   // 65
 * @method FS.HTTP.unpublish                                                                                          // 66
 * @public                                                                                                            // 67
 * @param {FS.Collection} collection                                                                                  // 68
 * @returns {undefined}                                                                                               // 69
 *                                                                                                                    // 70
 * Unpublishes a restpoint created by a call to `FS.HTTP.publish`                                                     // 71
 */                                                                                                                   // 72
FS.HTTP.unpublish = function fsHttpUnpublish(collection) {                                                            // 73
  // Mount collection listing URL using http-publish package                                                          // 74
  HTTP.unpublish(baseUrl + '/record/' + collection.name);                                                             // 75
};                                                                                                                    // 76
                                                                                                                      // 77
_existingMountPoints = {};                                                                                            // 78
                                                                                                                      // 79
/**                                                                                                                   // 80
 * @method defaultSelectorFunction                                                                                    // 81
 * @private                                                                                                           // 82
 * @returns { collection, file }                                                                                      // 83
 *                                                                                                                    // 84
 * This is the default selector function                                                                              // 85
 */                                                                                                                   // 86
var defaultSelectorFunction = function() {                                                                            // 87
  var self = this;                                                                                                    // 88
  // Selector function                                                                                                // 89
  //                                                                                                                  // 90
  // This function will have to return the collection and the                                                         // 91
  // file. If file not found undefined is returned - if null is returned the                                          // 92
  // search was not possible                                                                                          // 93
  var opts = FS.Utility.extend({}, self.query || {}, self.params || {});                                              // 94
                                                                                                                      // 95
  // Get the collection name from the url                                                                             // 96
  var collectionName = opts.collectionName;                                                                           // 97
                                                                                                                      // 98
  // Get the id from the url                                                                                          // 99
  var id = opts.id;                                                                                                   // 100
                                                                                                                      // 101
  // Get the collection                                                                                               // 102
  var collection = FS._collections[collectionName];                                                                   // 103
                                                                                                                      // 104
  // Get the file if possible else return null                                                                        // 105
  var file = (id && collection)? collection.findOne({ _id: id }): null;                                               // 106
                                                                                                                      // 107
  // Return the collection and the file                                                                               // 108
  return {                                                                                                            // 109
    collection: collection,                                                                                           // 110
    file: file,                                                                                                       // 111
    storeName: opts.store,                                                                                            // 112
    download: opts.download,                                                                                          // 113
    filename: opts.filename                                                                                           // 114
  };                                                                                                                  // 115
};                                                                                                                    // 116
                                                                                                                      // 117
/*                                                                                                                    // 118
 * @method FS.HTTP.mount                                                                                              // 119
 * @public                                                                                                            // 120
 * @param {array of string} mountPoints mount points to map rest functinality on                                      // 121
 * @param {function} selector_f [selector] function returns `{ collection, file }` for mount points to work with      // 122
 *                                                                                                                    // 123
*/                                                                                                                    // 124
FS.HTTP.mount = function(mountPoints, selector_f) {                                                                   // 125
  // We take mount points as an array and we get a selector function                                                  // 126
  var selectorFunction = selector_f || defaultSelectorFunction;                                                       // 127
                                                                                                                      // 128
  var accessPoint = {                                                                                                 // 129
    'stream': true,                                                                                                   // 130
    'auth': expirationAuth,                                                                                           // 131
    'post': function(data) {                                                                                          // 132
      // Use the selector for finding the collection and file reference                                               // 133
      var ref = selectorFunction.call(this);                                                                          // 134
                                                                                                                      // 135
      // We dont support post - this would be normal insert eg. of filerecord?                                        // 136
      throw new Meteor.Error(501, "Not implemented", "Post is not supported");                                        // 137
    },                                                                                                                // 138
    'put': function(data) {                                                                                           // 139
      // Use the selector for finding the collection and file reference                                               // 140
      var ref = selectorFunction.call(this);                                                                          // 141
                                                                                                                      // 142
      // Make sure we have a collection reference                                                                     // 143
      if (!ref.collection)                                                                                            // 144
        throw new Meteor.Error(404, "Not Found", "No collection found");                                              // 145
                                                                                                                      // 146
      // Make sure we have a file reference                                                                           // 147
      if (ref.file === null) {                                                                                        // 148
        // No id supplied so we will create a new FS.File instance and                                                // 149
        // insert the supplied data.                                                                                  // 150
        return FS.HTTP.Handlers.PutInsert.apply(this, [ref]);                                                         // 151
      } else {                                                                                                        // 152
        if (ref.file) {                                                                                               // 153
          return FS.HTTP.Handlers.PutUpdate.apply(this, [ref]);                                                       // 154
        } else {                                                                                                      // 155
          throw new Meteor.Error(404, "Not Found", 'No file found');                                                  // 156
        }                                                                                                             // 157
      }                                                                                                               // 158
    },                                                                                                                // 159
    'get': function(data) {                                                                                           // 160
      // Use the selector for finding the collection and file reference                                               // 161
      var ref = selectorFunction.call(this);                                                                          // 162
                                                                                                                      // 163
      // Make sure we have a collection reference                                                                     // 164
      if (!ref.collection)                                                                                            // 165
        throw new Meteor.Error(404, "Not Found", "No collection found");                                              // 166
                                                                                                                      // 167
      // Make sure we have a file reference                                                                           // 168
      if (ref.file === null) {                                                                                        // 169
        // No id supplied so we will return the published list of files ala                                           // 170
        // http.publish in json format                                                                                // 171
        return FS.HTTP.Handlers.GetList.apply(this, [ref]);                                                           // 172
      } else {                                                                                                        // 173
        if (ref.file) {                                                                                               // 174
          return FS.HTTP.Handlers.Get.apply(this, [ref]);                                                             // 175
        } else {                                                                                                      // 176
          throw new Meteor.Error(404, "Not Found", 'No file found');                                                  // 177
        }                                                                                                             // 178
      }                                                                                                               // 179
    },                                                                                                                // 180
    'delete': function(data) {                                                                                        // 181
      // Use the selector for finding the collection and file reference                                               // 182
      var ref = selectorFunction.call(this);                                                                          // 183
                                                                                                                      // 184
      // Make sure we have a collection reference                                                                     // 185
      if (!ref.collection)                                                                                            // 186
        throw new Meteor.Error(404, "Not Found", "No collection found");                                              // 187
                                                                                                                      // 188
      // Make sure we have a file reference                                                                           // 189
      if (ref.file) {                                                                                                 // 190
        return FS.HTTP.Handlers.Del.apply(this, [ref]);                                                               // 191
      } else {                                                                                                        // 192
        throw new Meteor.Error(404, "Not Found", 'No file found');                                                    // 193
      }                                                                                                               // 194
    }                                                                                                                 // 195
  };                                                                                                                  // 196
                                                                                                                      // 197
  var accessPoints = {};                                                                                              // 198
                                                                                                                      // 199
  // Add debug message                                                                                                // 200
  FS.debug && console.log('Registered HTTP method URLs:');                                                            // 201
                                                                                                                      // 202
  FS.Utility.each(mountPoints, function(mountPoint) {                                                                 // 203
    // Couple mountpoint and accesspoint                                                                              // 204
    accessPoints[mountPoint] = accessPoint;                                                                           // 205
    // Remember our mountpoints                                                                                       // 206
    _existingMountPoints[mountPoint] = mountPoint;                                                                    // 207
    // Add debug message                                                                                              // 208
    FS.debug && console.log(mountPoint);                                                                              // 209
  });                                                                                                                 // 210
                                                                                                                      // 211
  // XXX: HTTP:methods should unmount existing mounts in case of overwriting?                                         // 212
  HTTP.methods(accessPoints);                                                                                         // 213
                                                                                                                      // 214
};                                                                                                                    // 215
                                                                                                                      // 216
/**                                                                                                                   // 217
 * @method FS.HTTP.unmount                                                                                            // 218
 * @public                                                                                                            // 219
 * @param {string | array of string} [mountPoints] Optional, if not specified all mountpoints are unmounted           // 220
 *                                                                                                                    // 221
 */                                                                                                                   // 222
FS.HTTP.unmount = function(mountPoints) {                                                                             // 223
  // The mountPoints is optional, can be string or array if undefined then                                            // 224
  // _existingMountPoints will be used                                                                                // 225
  var unmountList;                                                                                                    // 226
  // Container for the mount points to unmount                                                                        // 227
  var unmountPoints = {};                                                                                             // 228
                                                                                                                      // 229
  if (typeof mountPoints === 'undefined') {                                                                           // 230
    // Use existing mount points - unmount all                                                                        // 231
    unmountList = _existingMountPoints;                                                                               // 232
  } else if (mountPoints === ''+mountPoints) {                                                                        // 233
    // Got a string                                                                                                   // 234
    unmountList = [mountPoints];                                                                                      // 235
  } else if (mountPoints.length) {                                                                                    // 236
    // Got an array                                                                                                   // 237
    unmountList = mountPoints;                                                                                        // 238
  }                                                                                                                   // 239
                                                                                                                      // 240
  // If we have a list to unmount                                                                                     // 241
  if (unmountList) {                                                                                                  // 242
    // Iterate over each item                                                                                         // 243
    FS.Utility.each(unmountList, function(mountPoint) {                                                               // 244
      // Check _existingMountPoints to make sure the mount point exists in our                                        // 245
      // context / was created by the FS.HTTP.mount                                                                   // 246
      if (_existingMountPoints[mountPoint]) {                                                                         // 247
        // Mark as unmount                                                                                            // 248
        unmountPoints[mountPoint] = false;                                                                            // 249
        // Release                                                                                                    // 250
        delete _existingMountPoints[mountPoint];                                                                      // 251
      }                                                                                                               // 252
    });                                                                                                               // 253
    FS.debug && console.log('FS.HTTP.unmount:');                                                                      // 254
    FS.debug && console.log(unmountPoints);                                                                           // 255
    // Complete unmount                                                                                               // 256
    HTTP.methods(unmountPoints);                                                                                      // 257
  }                                                                                                                   // 258
};                                                                                                                    // 259
                                                                                                                      // 260
// ### FS.Collection maps on HTTP pr. default on the following restpoints:                                            // 261
// *                                                                                                                  // 262
//    baseUrl + '/files/:collectionName/:id/:filename',                                                               // 263
//    baseUrl + '/files/:collectionName/:id',                                                                         // 264
//    baseUrl + '/files/:collectionName'                                                                              // 265
//                                                                                                                    // 266
// Change/ replace the existing mount point by:                                                                       // 267
// ```js                                                                                                              // 268
//   // unmount all existing                                                                                          // 269
//   FS.HTTP.unmount();                                                                                               // 270
//   // Create new mount point                                                                                        // 271
//   FS.HTTP.mount([                                                                                                  // 272
//    '/cfs/files/:collectionName/:id/:filename',                                                                     // 273
//    '/cfs/files/:collectionName/:id',                                                                               // 274
//    '/cfs/files/:collectionName'                                                                                    // 275
//  ]);                                                                                                               // 276
//  ```                                                                                                               // 277
//                                                                                                                    // 278
mountUrls = function mountUrls() {                                                                                    // 279
  // We unmount first in case we are calling this a second time                                                       // 280
  FS.HTTP.unmount();                                                                                                  // 281
                                                                                                                      // 282
  FS.HTTP.mount([                                                                                                     // 283
    baseUrl + '/files/:collectionName/:id/:filename',                                                                 // 284
    baseUrl + '/files/:collectionName/:id',                                                                           // 285
    baseUrl + '/files/:collectionName'                                                                                // 286
  ]);                                                                                                                 // 287
};                                                                                                                    // 288
                                                                                                                      // 289
// Returns the userId from URL token                                                                                  // 290
var expirationAuth = function expirationAuth() {                                                                      // 291
  var self = this;                                                                                                    // 292
                                                                                                                      // 293
  // Read the token from '/hello?token=base64'                                                                        // 294
  var encodedToken = self.query.token;                                                                                // 295
                                                                                                                      // 296
  FS.debug && console.log("token: "+encodedToken);                                                                    // 297
                                                                                                                      // 298
  if (!encodedToken || !Meteor.users) return false;                                                                   // 299
                                                                                                                      // 300
  // Check the userToken before adding it to the db query                                                             // 301
  // Set the this.userId                                                                                              // 302
  var tokenString = FS.Utility.atob(encodedToken);                                                                    // 303
                                                                                                                      // 304
  var tokenObject;                                                                                                    // 305
  try {                                                                                                               // 306
    tokenObject = JSON.parse(tokenString);                                                                            // 307
  } catch(err) {                                                                                                      // 308
    throw new Meteor.Error(400, 'Bad Request');                                                                       // 309
  }                                                                                                                   // 310
                                                                                                                      // 311
  // XXX: Do some check here of the object                                                                            // 312
  var userToken = tokenObject.authToken;                                                                              // 313
  if (userToken !== ''+userToken) {                                                                                   // 314
    throw new Meteor.Error(400, 'Bad Request');                                                                       // 315
  }                                                                                                                   // 316
                                                                                                                      // 317
  // If we have an expiration token we should check that it's still valid                                             // 318
  if (tokenObject.expiration != null) {                                                                               // 319
    // check if its too old                                                                                           // 320
    var now = Date.now();                                                                                             // 321
    if (tokenObject.expiration < now) {                                                                               // 322
      FS.debug && console.log('Expired token: ' + tokenObject.expiration + ' is less than ' + now);                   // 323
      throw new Meteor.Error(500, 'Expired token');                                                                   // 324
    }                                                                                                                 // 325
  }                                                                                                                   // 326
                                                                                                                      // 327
  // We are not on a secure line - so we have to look up the user...                                                  // 328
  var user = Meteor.users.findOne({                                                                                   // 329
    $or: [                                                                                                            // 330
      {'services.resume.loginTokens.hashedToken': Accounts._hashLoginToken(userToken)},                               // 331
      {'services.resume.loginTokens.token': userToken}                                                                // 332
    ]                                                                                                                 // 333
  });                                                                                                                 // 334
                                                                                                                      // 335
  // Set the userId in the scope                                                                                      // 336
  return user && user._id;                                                                                            // 337
};                                                                                                                    // 338
                                                                                                                      // 339
HTTP.methods(                                                                                                         // 340
  {'/cfs/servertime': {                                                                                               // 341
    get: function(data) {                                                                                             // 342
      return Date.now().toString();                                                                                   // 343
    }                                                                                                                 // 344
  }                                                                                                                   // 345
});                                                                                                                   // 346
                                                                                                                      // 347
// Unify client / server api                                                                                          // 348
FS.HTTP.now = function() {                                                                                            // 349
  return Date.now();                                                                                                  // 350
};                                                                                                                    // 351
                                                                                                                      // 352
// Start up the basic mount points                                                                                    // 353
Meteor.startup(function () {                                                                                          // 354
  mountUrls();                                                                                                        // 355
});                                                                                                                   // 356
                                                                                                                      // 357
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}).call(this);

///////////////////////////////////////////////////////////////////////

}).call(this);


/* Exports */
if (typeof Package === 'undefined') Package = {};
Package['wekan-cfs-access-point'] = {};

})();
