New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

apostrophe-snippets

Package Overview
Dependencies
Maintainers
8
Versions
202
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

apostrophe-snippets - npm Package Compare versions

Comparing version 0.0.26 to 0.0.27

329

index.js

@@ -200,2 +200,6 @@ var async = require('async');

self.afterInsert = function(req, data, snippet, callback) {
return callback(null);
};
self.beforeUpdate = function(req, data, snippet, callback) {

@@ -205,2 +209,14 @@ return callback(null);

self.afterUpdate = function(req, data, snippet, callback) {
return callback(null);
};
self.beforeSave = function(req, data, snippet, callback) {
return callback(null);
};
self.afterSave = function(req, data, snippet, callback) {
return callback(null);
};
// Fields to be imported or read from the browser when saving a new item.

@@ -300,8 +316,19 @@ // You can read properties directly or leverage this mechanism to handle the types

snippet.imported = req.aposImported;
self.beforeInsert(req, data, snippet, function(err) {
if (err) {
return callback(err);
}
return self.importSaveItem(req, snippet, callback);
});
async.series([
function(callback) {
self.beforeInsert(req, data, snippet, callback);
},
function(callback) {
self.beforeSave(req, data, snippet, callback);
},
function(callback) {
self.importSaveItem(req, snippet, callback);
},
function(callback) {
self.afterInsert(req, data, snippet, callback);
},
function(callback) {
self.afterSave(req, data, snippet, callback);
},
], callback);
} catch (e) {

@@ -344,8 +371,12 @@ console.log(e);

async.series([ prepare, insert ], send);
async.series([ beforeInsert, beforeSave, insert, afterInsert, afterSave ], send);
function prepare(callback) {
function beforeInsert(callback) {
return self.beforeInsert(req, req.body, snippet, callback);
}
function beforeSave(callback) {
return self.beforeSave(req, req.body, snippet, callback);
}
function insert(callback) {

@@ -355,2 +386,10 @@ return self._apos.putPage(req, slug, snippet, callback);

function afterInsert(callback) {
return self.afterInsert(req, req.body, snippet, callback);
}
function afterSave(callback) {
return self.afterSave(req, req.body, snippet, callback);
}
function send(err) {

@@ -365,3 +404,2 @@ if (err) {

self._app.post(self._action + '/update', function(req, res) {

@@ -412,7 +450,24 @@ var snippet;

snippet.published = published;
return self.beforeUpdate(req, req.body, snippet, callback);
return async.series([
function(callback) {
return self.beforeUpdate(req, req.body, snippet, callback);
},
function(callback) {
return self.beforeSave(req, req.body, snippet, callback);
}
], callback);
}
function update(callback) {
self._apos.putPage(req, originalSlug, snippet, callback);
async.series([
function(callback) {
self._apos.putPage(req, originalSlug, snippet, callback);
},
function(callback) {
self.afterUpdate(req, originalSlug, snippet, callback);
},
function(callback) {
self.afterSave(req, originalSlug, snippet, callback);
}
], callback);
}

@@ -754,39 +809,4 @@

// Given an options object in which options[name] is a string
// set to '0', '1', or 'any', this method corrects options[name] to
// be suitable for use in a MongoDB criteria object. '0' means
// "the property must be false or absent," '1' means "the promperty must be
// true," and 'any' means "we don't care what the property is."
// An empty string is considered equivalent to '0'. This is not
// the same as apos.sanitizeBoolean which is concerned only with
// true or false and does not address "any." This method is used
// with GET or POST form submissions of filter settings.
//
// def should be set to '0', '1' or 'any' and defaults to 'any'.
self.convertBooleanFilterCriteria = function(name, options, def) {
// Consume special options then remove them, turning the rest into mongo criteria
if (def === undefined) {
def = 'any';
}
var value = (options[name] === undefined) ? def : options[name];
if (options[name] !== undefined) {
delete options[name];
}
if (value === 'any') {
// Don't care, show all
} else if ((!value) || (value === '0')) {
// Must be absent or false. Hooray for $ne
options[name] = { $ne: true };
} else {
// Must be true
options[name] = true;
}
};
// Returns recent snippets the current user is permitted to read, in
// alphabetical order by title. If options.editable is true, only
// snippets the current user can edit are returned. If options.sort is
// Returns snippets the current user is permitted to read. If options.editable
// is true, only snippets the current user can edit are returned. If options.sort is
// present, it is passed to mongo's sort() method. All other properties of

@@ -806,2 +826,9 @@ // options are merged with the MongoDB criteria object used to

//
// PERMALINKING
//
// By default no ._url property is set on each item, as you often are rendering items
// on a specific page and want to set the ._url property to match. If you set the
// `permalink` option to true, the ._url property will be set for you, based on
// the findBestPage algorithm.
//
// FETCHING METADATA FOR FILTERS

@@ -839,182 +866,53 @@ //

self.get = function(req, optionsArg, mainCallback) {
if (!mainCallback) {
mainCallback = optionsArg;
optionsArg = {};
}
self.get = function(req, optionsArg, callback) {
var options = {};
var results = null;
extend(true, options, optionsArg);
var editable = options.editable;
if (options.editable !== undefined) {
delete options['editable'];
// For snippets the default sort is alpha
if (!options.sort) {
options.sort = { sortTitle: 1 };
}
var sort = options.sort || { sortTitle: 1 };
delete options.sort;
var limit = options.limit || undefined;
// Don't get cute about when to delete, it never hurts, and if you're not very
// careful you're going to fail to delete if it was set to '0' (see the or above)
delete options.limit;
var skip = options.skip || undefined;
delete options.skip;
var fields = options.fields || undefined;
delete options.fields;
if (!options.type) {
options.type = self._instance;
}
var fetch = options.fetch;
delete options.fetch;
var permalink = options.permalink;
delete options.permalink;
var titleSearch = options.titleSearch || undefined;
if (options.titleSearch !== undefined) {
delete options['titleSearch'];
options.sortTitle = new RegExp(RegExp.quote(self._apos.sortify(titleSearch)));
}
return async.series([ query, metadata, permalinker ], function(err) {
return callback(err, results);
});
self.convertBooleanFilterCriteria('trash', options, '0');
self.convertBooleanFilterCriteria('published', options);
if (options.q && options.q.length) {
// Crude fulltext search support. It would be better to present
// highSearchText results before lowSearchText results, but right now
// we are doing a single query only
options.lowSearchText = self._apos.searchify(options.q);
}
// Don't let an empty or not-so-empty q screw up our query
delete options.q;
options.type = self._instance;
args = {};
if (fields !== undefined) {
args.fields = fields;
}
// TODO: with many snippets there is a performance problem with calling
// permissions separately on them. Pagination will have to be performed
// manually after all permissions have been checked. The A1.5 permissions
// model wasn't perfect but it was something you could do by joining tables.
// We can fix it by just storing the permissions for a page in the page.
var q = self._apos.pages.find(options, args).sort(sort);
// For now we have to implement limit and skip ourselves because of the way
// our permissions callback works. TODO: research whether we can make permissions
// checks something that can be part of our single query to mongodb
// if (limit !== undefined) {
// q.limit(limit);
// }
// if (skip !== undefined) {
// q.skip(skip);
// }
var results = {};
var got;
var total;
async.series([loadSnippets, permissions, skipLimitAndTotal, loadWidgets, fetchExtras], done);
function loadSnippets(callback) {
q.toArray(function(err, snippetsArg) {
function query(callback) {
return self._apos.get(req, options, function(err, resultsArg) {
if (err) {
console.log(err);
return callback(err);
}
results.snippets = snippetsArg;
got = snippets.length;
// This is a good idea, but we need to figure out how to make sure it all
// ends in a browser redirect and doesn't break blog, events or map, and
// also guard against loops
//
// // If this all started with a slug parameter that possibly no longer
// // exists, check the redirect table before giving up. If there is a redirect
// // recursively invoke the whole thing
// if (optionsArg.slug && (!got)) {
// // Check the redirect table
// return self._apos.redirects.findOne({ from: optionsArg.slug }, function(err, redirect) {
// if (redirect) {
// var newOptions = {};
// extend(true, newOptions, optionsArg);
// newOptions.slug = redirect.to;
// return self.get(req, newOptions, mainCallback);
// }
// });
// }
return callback(err);
results = resultsArg;
results.snippets = results.pages;
delete results.pages;
return callback(null);
});
}
function permissions(callback) {
async.filter(results.snippets, function(snippet, callback) {
self._apos.permissions(req, 'edit-page', snippet, function(err) {
if (editable) {
return callback(!err);
} else {
snippet._edit = !err;
// Good way to test the retry mechanism that fills the gap if
// some of the snippets lack permissions for this user
// if (Math.random() < 0.5) {
// console.log('randomly flunking view permissions');
// return callback(false);
// }
self._apos.permissions(req, 'view-page', snippet, function(err) {
return callback(!err);
});
}
});
}, function(snippetsArg) {
snippets = snippetsArg;
function metadata(callback) {
if (fetch) {
return self.fetchMetadataForFilters(fetch, results.criteria, results, callback);
} else {
return callback(null);
});
}
// Brute force strategy is the only one that works with 'skip' and 'total'
// in the mix until we put permissions in the database
function skipLimitAndTotal(callback) {
var limited = [];
var i;
skip = skip || 0;
limit = limit || 1000000000;
results.total = results.snippets.length;
for (i = skip; (i < skip + limit); i++) {
if (results.snippets[i]) {
limited.push(results.snippets[i]);
} else {
break;
}
}
results.snippets = limited;
return callback(null);
}
function loadWidgets(callback) {
// Use eachSeries to avoid devoting overwhelming mongodb resources
// to a single user's request. There could be many snippets on this
// page, and callLoadersForPage is parallel already
async.eachSeries(results.snippets, function(snippet, callback) {
self._apos.callLoadersForPage(req, snippet, callback);
}, function(err) {
return callback(err);
});
}
function fetchExtras(callback) {
if (!fetch) {
function permalinker(callback) {
if (permalink) {
return self.findBestPageForMany(req, results.snippets, callback);
} else {
return callback(null);
}
return self.fetchMetadataForFilters(fetch, options, results, callback);
}
function done(err) {
return mainCallback(null, results);
}
};
// Add additional metadata like available tags to `results`. You should take advantage
// of the mongodb criteria in `criteria` to obtain only options that will
// of the mongodb criteria in `criteria` to display only the choices that will
// return results. For instance, for tags, we fetch only tags that appear on

@@ -1038,6 +936,11 @@ // at least one snippet that meets the other criteria that are currently active.

// Written to accommodate fetching other filters' options easily
async.series([fetchTags], callback);
async.series([fetchTags], function(err) {
if (err) {
return callback(err);
}
return callback(null);
});
function fetchTags(callback) {
if (!fetch.tags) {
console.log('NOT fetching tags');
return callback(null);

@@ -1107,3 +1010,2 @@ }

req.page = req.bestPage;
self.dispatch(req, callback);

@@ -1335,2 +1237,13 @@ }

self.findBestPageForMany = function(req, items, callback) {
async.map(items, function(item, callback) {
return self.findBestPage(req, item, function(err, page) {
if (page) {
item._url = self.permalink(item, page);
}
return callback(err);
});
}, callback);
};
// Returns a "permalink" URL to the snippet, beginning with the

@@ -1337,0 +1250,0 @@ // slug of the specified page. See findBestPage for a good way to

{
"name": "apostrophe-snippets",
"version": "0.0.26",
"version": "0.0.27",
"description": "Reusable content snippets for the Apostrophe content management system. The blog and events modules are built on this foundation, which is also useful in and of itself.",

@@ -5,0 +5,0 @@ "main": "index.js",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc