| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 | var path = Npm.require("path");HTTP.publishFormats({  fileRecordFormat: function (input) {    // Set the method scope content type to json    this.setContentType('application/json');    if (FS.Utility.isArray(input)) {      return EJSON.stringify(FS.Utility.map(input, function (obj) {        return FS.Utility.cloneFileRecord(obj);      }));    } else {      return EJSON.stringify(FS.Utility.cloneFileRecord(input));    }  }});/** * @method FS.HTTP.setHeadersForGet * @public * @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} */FS.HTTP.setHeadersForGet = function setHeadersForGet(headers, collections) {  if (typeof collections === "string") {    collections = [collections];  }  if (collections) {    FS.Utility.each(collections, function(collectionName) {      getHeadersByCollection[collectionName] = headers || [];    });  } else {    getHeaders = headers || [];  }};/** * @method FS.HTTP.publish * @public * @param {FS.Collection} collection * @param {Function} func - Publish function that returns a cursor. * @returns {undefined} * * Publishes all documents returned by the cursor at a GET URL * with the format baseUrl/record/collectionName. The publish * function `this` is similar to normal `Meteor.publish`. */FS.HTTP.publish = function fsHttpPublish(collection, func) {  var name = baseUrl + '/record/' + collection.name;  // Mount collection listing URL using http-publish package  HTTP.publish({    name: name,    defaultFormat: 'fileRecordFormat',    collection: collection,    collectionGet: true,    collectionPost: false,    documentGet: true,    documentPut: false,    documentDelete: false  }, func);  FS.debug && console.log("Registered HTTP method GET URLs:\n\n" + name + '\n' + name + '/:id\n');};/** * @method FS.HTTP.unpublish * @public * @param {FS.Collection} collection * @returns {undefined} * * Unpublishes a restpoint created by a call to `FS.HTTP.publish` */FS.HTTP.unpublish = function fsHttpUnpublish(collection) {  // Mount collection listing URL using http-publish package  HTTP.unpublish(baseUrl + '/record/' + collection.name);};_existingMountPoints = {};/** * @method defaultSelectorFunction * @private * @returns { collection, file } * * This is the default selector function */var defaultSelectorFunction = function() {  var self = this;  // Selector function  //  // This function will have to return the collection and the  // file. If file not found undefined is returned - if null is returned the  // search was not possible  var opts = FS.Utility.extend({}, self.query || {}, self.params || {});  // Get the collection name from the url  var collectionName = opts.collectionName;  // Get the id from the url  var id = opts.id;  // Get the collection  var collection = FS._collections[collectionName];  //if Mongo ObjectIds are used, then we need to use that in find statement  if(collection.options.idGeneration && collection.options.idGeneration === 'MONGO') {    // Get the file if possible else return null    var file = (id && collection)? collection.findOne({ _id: new Meteor.Collection.ObjectID(id)}): null;  } else {    var file = (id && collection)? collection.findOne({ _id: id }): null;  }  // Return the collection and the file  return {    collection: collection,    file: file,    storeName: opts.store,    download: opts.download,    filename: opts.filename  };};/* * @method FS.HTTP.mount * @public * @param {array of string} mountPoints mount points to map rest functinality on * @param {function} selector_f [selector] function returns `{ collection, file }` for mount points to work with **/FS.HTTP.mount = function(mountPoints, selector_f) {  // We take mount points as an array and we get a selector function  var selectorFunction = selector_f || defaultSelectorFunction;  var accessPoint = {    'stream': true,    'auth': expirationAuth,    'post': function(data) {      // Use the selector for finding the collection and file reference      var ref = selectorFunction.call(this);      // We dont support post - this would be normal insert eg. of filerecord?      throw new Meteor.Error(501, "Not implemented", "Post is not supported");    },    'put': function(data) {      // Use the selector for finding the collection and file reference      var ref = selectorFunction.call(this);      // Make sure we have a collection reference      if (!ref.collection)        throw new Meteor.Error(404, "Not Found", "No collection found");      // Make sure we have a file reference      if (ref.file === null) {        // No id supplied so we will create a new FS.File instance and        // insert the supplied data.        return FS.HTTP.Handlers.PutInsert.apply(this, [ref]);      } else {        if (ref.file) {          return FS.HTTP.Handlers.PutUpdate.apply(this, [ref]);        } else {          throw new Meteor.Error(404, "Not Found", 'No file found');        }      }    },    'get': function(data) {      // Use the selector for finding the collection and file reference      var ref = selectorFunction.call(this);      // Make sure we have a collection reference      if (!ref.collection)        throw new Meteor.Error(404, "Not Found", "No collection found");      // Make sure we have a file reference      if (ref.file === null) {        // No id supplied so we will return the published list of files ala        // http.publish in json format        return FS.HTTP.Handlers.GetList.apply(this, [ref]);      } else {        if (ref.file) {          return FS.HTTP.Handlers.Get.apply(this, [ref]);        } else {          throw new Meteor.Error(404, "Not Found", 'No file found');        }      }    },    'delete': function(data) {      // Use the selector for finding the collection and file reference      var ref = selectorFunction.call(this);      // Make sure we have a collection reference      if (!ref.collection)        throw new Meteor.Error(404, "Not Found", "No collection found");      // Make sure we have a file reference      if (ref.file) {        return FS.HTTP.Handlers.Del.apply(this, [ref]);      } else {        throw new Meteor.Error(404, "Not Found", 'No file found');      }    }  };  var accessPoints = {};  // Add debug message  FS.debug && console.log('Registered HTTP method URLs:');  FS.Utility.each(mountPoints, function(mountPoint) {    // Couple mountpoint and accesspoint    accessPoints[mountPoint] = accessPoint;    // Remember our mountpoints    _existingMountPoints[mountPoint] = mountPoint;    // Add debug message    FS.debug && console.log(mountPoint);  });  // XXX: HTTP:methods should unmount existing mounts in case of overwriting?  HTTP.methods(accessPoints);};/** * @method FS.HTTP.unmount * @public * @param {string | array of string} [mountPoints] Optional, if not specified all mountpoints are unmounted * */FS.HTTP.unmount = function(mountPoints) {  // The mountPoints is optional, can be string or array if undefined then  // _existingMountPoints will be used  var unmountList;  // Container for the mount points to unmount  var unmountPoints = {};  if (typeof mountPoints === 'undefined') {    // Use existing mount points - unmount all    unmountList = _existingMountPoints;  } else if (mountPoints === ''+mountPoints) {    // Got a string    unmountList = [mountPoints];  } else if (mountPoints.length) {    // Got an array    unmountList = mountPoints;  }  // If we have a list to unmount  if (unmountList) {    // Iterate over each item    FS.Utility.each(unmountList, function(mountPoint) {      // Check _existingMountPoints to make sure the mount point exists in our      // context / was created by the FS.HTTP.mount      if (_existingMountPoints[mountPoint]) {        // Mark as unmount        unmountPoints[mountPoint] = false;        // Release        delete _existingMountPoints[mountPoint];      }    });    FS.debug && console.log('FS.HTTP.unmount:');    FS.debug && console.log(unmountPoints);    // Complete unmount    HTTP.methods(unmountPoints);  }};// ### FS.Collection maps on HTTP pr. default on the following restpoints:// *//    baseUrl + '/files/:collectionName/:id/:filename',//    baseUrl + '/files/:collectionName/:id',//    baseUrl + '/files/:collectionName'//// Change/ replace the existing mount point by:// ```js//   // unmount all existing//   FS.HTTP.unmount();//   // Create new mount point//   FS.HTTP.mount([//    '/cfs/files/:collectionName/:id/:filename',//    '/cfs/files/:collectionName/:id',//    '/cfs/files/:collectionName'//  ]);//  ```//mountUrls = function mountUrls() {  // We unmount first in case we are calling this a second time  FS.HTTP.unmount();  FS.HTTP.mount([    baseUrl + '/files/:collectionName/:id/:filename',    baseUrl + '/files/:collectionName/:id',    baseUrl + '/files/:collectionName'  ]);};// Returns the userId from URL tokenvar expirationAuth = function expirationAuth() {  var self = this;  // Read the token from '/hello?token=base64'  var encodedToken = self.query.token;  FS.debug && console.log("token: "+encodedToken);  if (!encodedToken || !Meteor.users) return false;  // Check the userToken before adding it to the db query  // Set the this.userId  var tokenString = FS.Utility.atob(encodedToken);  var tokenObject;  try {    tokenObject = JSON.parse(tokenString);  } catch(err) {    throw new Meteor.Error(400, 'Bad Request');  }  // XXX: Do some check here of the object  var userToken = tokenObject.authToken;  if (userToken !== ''+userToken) {    throw new Meteor.Error(400, 'Bad Request');  }  // If we have an expiration token we should check that it's still valid  if (tokenObject.expiration != null) {    // check if its too old    var now = Date.now();    if (tokenObject.expiration < now) {      FS.debug && console.log('Expired token: ' + tokenObject.expiration + ' is less than ' + now);      throw new Meteor.Error(500, 'Expired token');    }  }  // We are not on a secure line - so we have to look up the user...  var user = Meteor.users.findOne({    $or: [      {'services.resume.loginTokens.hashedToken': Accounts._hashLoginToken(userToken)},      {'services.resume.loginTokens.token': userToken}    ]  });  // Set the userId in the scope  return user && user._id;};HTTP.methods(  {'/cfs/servertime': {    get: function(data) {      return Date.now().toString();    }  }});// Unify client / server apiFS.HTTP.now = function() {  return Date.now();};// Start up the basic mount pointsMeteor.startup(function () {  mountUrls();});
 |