Rename 'plugins' to 'apps'

Fixes #1988
This commit is contained in:
John O'Nolan 2014-01-21 15:45:27 +07:00
parent 185f3c65cd
commit 7ebd104f3f
18 changed files with 193 additions and 193 deletions

2
.gitignore vendored
View File

@ -43,7 +43,7 @@ projectFilesBackup
/_site
/content/tmp/*
/content/data/*
/content/plugins/**/*
/content/apps/**/*
/content/themes/**/*
/content/images/**/*
!/content/themes/casper/**

View File

@ -23,8 +23,8 @@ var path = require('path'),
'content/images/README.md',
'!content/themes/**',
'content/themes/casper/**',
'!content/plugins/**',
'content/plugins/README.md',
'!content/apps/**',
'content/apps/README.md',
'!node_modules/**',
'!core/test/**',
'!core/client/assets/sass/**',

3
content/apps/README.md Normal file
View File

@ -0,0 +1,3 @@
# Content / Apps
Coming soon, Ghost apps will appear here.

View File

@ -1,3 +0,0 @@
# Content / Plugins
Coming soon, Ghost plugins will appear here.

92
core/server/apps/index.js Normal file
View File

@ -0,0 +1,92 @@
var _ = require('underscore'),
when = require('when'),
errors = require('../errorHandling'),
api = require('../api'),
loader = require('./loader'),
// Holds the available apps
availableApps = {};
function getInstalledApps() {
return api.settings.read('installedApps').then(function (installed) {
installed.value = installed.value || '[]';
try {
installed = JSON.parse(installed.value);
} catch (e) {
return when.reject(e);
}
return installed;
});
}
function saveInstalledApps(installedApps) {
return getInstalledApps().then(function (currentInstalledApps) {
var updatedAppsInstalled = _.uniq(installedApps.concat(currentInstalledApps));
return api.settings.edit('installedApps', updatedAppsInstalled);
});
}
module.exports = {
init: function () {
var appsToLoad;
try {
// We have to parse the value because it's a string
api.settings.read('activeApps').then(function (aApps) {
appsToLoad = JSON.parse(aApps.value) || [];
});
} catch (e) {
errors.logError(
'Failed to parse activeApps setting value: ' + e.message,
'Your apps will not be loaded.',
'Check your settings table for typos in the activeApps value. It should look like: ["app-1", "app2"] (double quotes required).'
);
return when.resolve();
}
// Grab all installed apps, install any not already installed that are in appsToLoad.
return getInstalledApps().then(function (installedApps) {
var loadedApps = {},
recordLoadedApp = function (name, loadedApp) {
// After loading the app, add it to our hash of loaded apps
loadedApps[name] = loadedApp;
return when.resolve(loadedApp);
},
loadPromises = _.map(appsToLoad, function (app) {
// If already installed, just activate the app
if (_.contains(installedApps, app)) {
return loader.activateAppByName(app).then(function (loadedApp) {
return recordLoadedApp(app, loadedApp);
});
}
// Install, then activate the app
return loader.installAppByName(app).then(function () {
return loader.activateAppByName(app);
}).then(function (loadedApp) {
return recordLoadedApp(app, loadedApp);
});
});
return when.all(loadPromises).then(function () {
// Save our installed apps to settings
return saveInstalledApps(_.keys(loadedApps));
}).then(function () {
// Extend the loadedApps onto the available apps
_.extend(availableApps, loadedApps);
}).otherwise(function (err) {
errors.logError(
err.message || err,
'The app will not be loaded',
'Check with the app creator, or read the app documentation for more details on app requirements'
);
});
});
},
availableApps: availableApps
};

View File

@ -0,0 +1,70 @@
var path = require('path'),
_ = require('underscore'),
when = require('when'),
appProxy = require('./proxy'),
config = require('../config'),
loader;
// Get a relative path to the given apps root, defaults
// to be relative to __dirname
function getAppRelativePath(name, relativeTo) {
relativeTo = relativeTo || __dirname;
return path.relative(relativeTo, path.join(config.paths().appPath, name));
}
function getAppByName(name) {
// Grab the app class to instantiate
var AppClass = require(getAppRelativePath(name)),
app;
// Check for an actual class, otherwise just use whatever was returned
if (_.isFunction(AppClass)) {
app = new AppClass(appProxy);
} else {
app = AppClass;
}
return app;
}
// The loader is responsible for loading apps
loader = {
// Load a app and return the instantiated app
installAppByName: function (name) {
var app = getAppByName(name);
// Check for an install() method on the app.
if (!_.isFunction(app.install)) {
return when.reject(new Error("Error loading app named " + name + "; no install() method defined."));
}
// Wrapping the install() with a when because it's possible
// to not return a promise from it.
return when(app.install(appProxy)).then(function () {
return when.resolve(app);
});
},
// Activate a app and return it
activateAppByName: function (name) {
var app = getAppByName(name);
// Check for an activate() method on the app.
if (!_.isFunction(app.activate)) {
return when.reject(new Error("Error loading app named " + name + "; no activate() method defined."));
}
// Wrapping the activate() with a when because it's possible
// to not return a promise from it.
return when(app.activate(appProxy)).then(function () {
return when.resolve(app);
});
}
};
module.exports = loader;

View File

@ -11,14 +11,14 @@ var moment = require('moment'),
corePath = path.resolve(appRoot, 'core/'),
contentPath = path.resolve(appRoot, 'content/'),
themePath = path.resolve(contentPath + '/themes'),
pluginPath = path.resolve(contentPath + '/plugins'),
appPath = path.resolve(contentPath + '/apps'),
themeDirectories = requireTree(themePath),
pluginDirectories = requireTree(pluginPath),
appDirectories = requireTree(appPath),
localPath = '',
configUrl = '',
availableThemes,
availablePlugins;
availableApps;
function paths() {
@ -32,7 +32,7 @@ function paths() {
'contentPath': contentPath,
'corePath': corePath,
'themePath': themePath,
'pluginPath': pluginPath,
'appPath': appPath,
'imagesPath': path.resolve(contentPath, 'images/'),
'imagesRelPath': 'content/images',
'adminViews': path.join(corePath, '/server/views/'),
@ -41,7 +41,7 @@ function paths() {
'lang': path.join(corePath, '/shared/lang/'),
'debugPath': subdir + '/ghost/debug/',
'availableThemes': availableThemes,
'availablePlugins': availablePlugins
'availableApps': availableApps
};
}
@ -56,9 +56,9 @@ function update(configURL) {
localPath = localPath.replace(/\/$/, '');
}
return when.all([themeDirectories, pluginDirectories]).then(function (paths) {
return when.all([themeDirectories, appDirectories]).then(function (paths) {
availableThemes = paths[0];
availablePlugins = paths[1];
availableApps = paths[1];
return;
});
}

View File

@ -68,11 +68,11 @@
"defaultValue": "casper"
}
},
"plugin": {
"activePlugins": {
"app": {
"activeApps": {
"defaultValue": "[]"
},
"installedPlugins": {
"installedApps": {
"defaultValue": "[]"
}
}

View File

@ -18,7 +18,7 @@ var crypto = require('crypto'),
middleware = require('./middleware'),
models = require('./models'),
permissions = require('./permissions'),
plugins = require('./plugins'),
apps = require('./apps'),
routes = require('./routes'),
packageInfo = require('../../package.json'),
@ -71,7 +71,7 @@ function initDbHashAndFirstRun() {
}
// Sets up the express server instance.
// Instantiates the ghost singleton, helpers, routes, middleware, and plugins.
// Instantiates the ghost singleton, helpers, routes, middleware, and apps.
// Finally it starts the http server.
function setup(server) {
@ -200,8 +200,8 @@ function setup(server) {
}
// Initialize plugins then start the server
plugins.init().then(function () {
// Initialize apps then start the server
apps.init().then(function () {
// ## Start Ghost App
if (getSocket()) {

View File

@ -1,92 +0,0 @@
var _ = require('underscore'),
when = require('when'),
errors = require('../errorHandling'),
api = require('../api'),
loader = require('./loader'),
// Holds the available plugins
availablePlugins = {};
function getInstalledPlugins() {
return api.settings.read('installedPlugins').then(function (installed) {
installed.value = installed.value || '[]';
try {
installed = JSON.parse(installed.value);
} catch (e) {
return when.reject(e);
}
return installed;
});
}
function saveInstalledPlugins(installedPlugins) {
return getInstalledPlugins().then(function (currentInstalledPlugins) {
var updatedPluginsInstalled = _.uniq(installedPlugins.concat(currentInstalledPlugins));
return api.settings.edit('installedPlugins', updatedPluginsInstalled);
});
}
module.exports = {
init: function () {
var pluginsToLoad;
try {
// We have to parse the value because it's a string
api.settings.read('activePlugins').then(function (aPlugins) {
pluginsToLoad = JSON.parse(aPlugins.value) || [];
});
} catch (e) {
errors.logError(
'Failed to parse activePlugins setting value: ' + e.message,
'Your plugins will not be loaded.',
'Check your settings table for typos in the activePlugins value. It should look like: ["plugin-1", "plugin2"] (double quotes required).'
);
return when.resolve();
}
// Grab all installed plugins, install any not already installed that are in pluginsToLoad.
return getInstalledPlugins().then(function (installedPlugins) {
var loadedPlugins = {},
recordLoadedPlugin = function (name, loadedPlugin) {
// After loading the plugin, add it to our hash of loaded plugins
loadedPlugins[name] = loadedPlugin;
return when.resolve(loadedPlugin);
},
loadPromises = _.map(pluginsToLoad, function (plugin) {
// If already installed, just activate the plugin
if (_.contains(installedPlugins, plugin)) {
return loader.activatePluginByName(plugin).then(function (loadedPlugin) {
return recordLoadedPlugin(plugin, loadedPlugin);
});
}
// Install, then activate the plugin
return loader.installPluginByName(plugin).then(function () {
return loader.activatePluginByName(plugin);
}).then(function (loadedPlugin) {
return recordLoadedPlugin(plugin, loadedPlugin);
});
});
return when.all(loadPromises).then(function () {
// Save our installed plugins to settings
return saveInstalledPlugins(_.keys(loadedPlugins));
}).then(function () {
// Extend the loadedPlugins onto the available plugins
_.extend(availablePlugins, loadedPlugins);
}).otherwise(function (err) {
errors.logError(
err.message || err,
'The plugin will not be loaded',
'Check with the plugin creator, or read the plugin documentation for more details on plugin requirements'
);
});
});
},
availablePlugins: availablePlugins
};

View File

@ -1,70 +0,0 @@
var path = require('path'),
_ = require('underscore'),
when = require('when'),
appProxy = require('./proxy'),
config = require('../config'),
loader;
// Get a relative path to the given plugins root, defaults
// to be relative to __dirname
function getPluginRelativePath(name, relativeTo) {
relativeTo = relativeTo || __dirname;
return path.relative(relativeTo, path.join(config.paths().pluginPath, name));
}
function getPluginByName(name) {
// Grab the plugin class to instantiate
var PluginClass = require(getPluginRelativePath(name)),
plugin;
// Check for an actual class, otherwise just use whatever was returned
if (_.isFunction(PluginClass)) {
plugin = new PluginClass(appProxy);
} else {
plugin = PluginClass;
}
return plugin;
}
// The loader is responsible for loading plugins
loader = {
// Load a plugin and return the instantiated plugin
installPluginByName: function (name) {
var plugin = getPluginByName(name);
// Check for an install() method on the plugin.
if (!_.isFunction(plugin.install)) {
return when.reject(new Error("Error loading plugin named " + name + "; no install() method defined."));
}
// Wrapping the install() with a when because it's possible
// to not return a promise from it.
return when(plugin.install(appProxy)).then(function () {
return when.resolve(plugin);
});
},
// Activate a plugin and return it
activatePluginByName: function (name) {
var plugin = getPluginByName(name);
// Check for an activate() method on the plugin.
if (!_.isFunction(plugin.activate)) {
return when.reject(new Error("Error loading plugin named " + name + "; no activate() method defined."));
}
// Wrapping the activate() with a when because it's possible
// to not return a promise from it.
return when(plugin.activate(appProxy)).then(function () {
return when.resolve(plugin);
});
}
};
module.exports = loader;

View File

@ -2,7 +2,7 @@ var errors = require('../errorHandling'),
storage;
function get_storage() {
// TODO: this is where the check for storage plugins should go
// TODO: this is where the check for storage apps should go
// Local file system is the default
var storageChoice = 'localfilesystem';

View File

@ -16,7 +16,7 @@
// - post count - total number of posts
// - user count - total number of users
// - theme - name of the currently active theme
// - apps - names of any active plugins
// - apps - names of any active apps
var crypto = require('crypto'),
exec = require('child_process').exec,
@ -51,7 +51,7 @@ function updateCheckData() {
ops.push(api.settings.read('dbHash').otherwise(errors.rejectError));
ops.push(api.settings.read('activeTheme').otherwise(errors.rejectError));
ops.push(api.settings.read('activePlugins')
ops.push(api.settings.read('activeApps')
.then(function (apps) {
try {
apps = JSON.parse(apps.value);

View File

@ -6,7 +6,7 @@ var should = require('should'),
filters = require('../../server/filters'),
// Stuff we are testing
appProxy = require('../../server/plugins/proxy');
appProxy = require('../../server/apps/proxy');
describe('App Proxy', function () {

View File

@ -294,7 +294,7 @@ describe('Config', function () {
'contentPath',
'corePath',
'themePath',
'pluginPath',
'appPath',
'imagesPath',
'imagesRelPath',
'adminViews',
@ -303,7 +303,7 @@ describe('Config', function () {
'lang',
'debugPath',
'availableThemes',
'availablePlugins'
'availableApps'
);
});

View File

@ -11,7 +11,7 @@ var _ = require('underscore'),
'updated_by', 'published_at', 'published_by', 'page', 'author', 'user', 'tags'],
// TODO: remove databaseVersion, dbHash
settings: ['databaseVersion', 'dbHash', 'title', 'description', 'email', 'logo', 'cover', 'defaultLang',
"permalinks", 'postsPerPage', 'forceI18n', 'activeTheme', 'activePlugins', 'installedPlugins',
"permalinks", 'postsPerPage', 'forceI18n', 'activeTheme', 'activeApps', 'installedApps',
'availableThemes', 'nextUpdateCheck', 'displayUpdateNotification'],
tag: ['id', 'uuid', 'name', 'slug', 'description', 'parent_id',
'meta_title', 'meta_description', 'created_at', 'created_by', 'updated_at', 'updated_by'],

View File

@ -284,9 +284,9 @@
{
"id": 13,
"uuid": "f3afce35-5166-453e-86c3-50dfff74dca7",
"key": "activePlugins",
"key": "activeApps",
"value": "[]",
"type": "plugin",
"type": "app",
"created_at": 1388318310831,
"created_by": 1,
"updated_at": 1388318310831,
@ -295,9 +295,9 @@
{
"id": 14,
"uuid": "2ea560a3-2304-449d-a62b-f7b622987510",
"key": "installedPlugins",
"key": "installedApps",
"value": "[]",
"type": "plugin",
"type": "app",
"created_at": 1388318310831,
"created_by": 1,
"updated_at": 1388318310831,