diff --git a/core/application.js b/core/application.js index 999d657..06dc5c4 100644 --- a/core/application.js +++ b/core/application.js @@ -1,7 +1,41 @@ -var path = require('path'), +var fs = require('fs'), + path = require('path'), diread = require('diread'), _ = require('lodash'), + express = require('express'), + helper = require('./helper'), + define_properties = function(Application, properties) { + var prototype_new_properties = {}; + + Object.keys(properties).forEach(function(property_name) { + var default_properties = { + //configurable: false, + enumerable: true, + //value: undefined, + //writable: false + //get: undefined, + //set: undefined + }, + names = property_name.split(/\s*,\s*/), + + incoming_settings = properties[property_name], + property_settings = {}; + + if(typeof incoming_settings === 'function') { + incoming_settings = { get: incoming_settings }; + } + + property_settings = _.defaults(incoming_settings, default_properties); + + names.forEach(function(name) { + prototype_new_properties[name] = property_settings; + }); + }); + + Object.defineProperties(Application.fn, prototype_new_properties); + Object.freeze(Application.fn); + }, Application = function(options) { if(!(this instanceof Application)) { @@ -14,37 +48,6 @@ Application.make = function(configuration) { return new Application(configuration); }; Application.fn = Application.prototype; -Application.fn._define_properties = function(properties) { - var prototype_new_properties = {}; - - Object.keys(properties).forEach(function(property_name) { - var default_properties = { - //configurable: false, - enumerable: true, - //value: undefined, - //writable: false - //get: undefined, - //set: undefined - }, - names = property_name.split(/\s*,\s*/), - - incoming_settings = properties[property_name], - property_settings = {}; - - if(typeof incoming_settings === 'function') { - incoming_settings = { get: incoming_settings }; - } - - property_settings = _.defaults(incoming_settings, default_properties); - - names.forEach(function(name) { - prototype_new_properties[name] = property_settings; - }); - }); - - Object.defineProperties(Application.fn, prototype_new_properties); - Object.freeze(Application.fn); -}; Application.fn._init_config = function(environment) { var config_path; @@ -142,7 +145,7 @@ Application.fn._initialize_middlware = function(middleware_configs, app) { app.use(module.apply(module, config)); }, init_by_function = function(name, fn) { - fn(app, require('express')); + fn(app, express); }; Object.keys(middleware_configs).forEach(function(middleware_name) { @@ -172,87 +175,19 @@ Application.fn._initialize_middlware = function(middleware_configs, app) { // TODO: move to file and make configurable Application.fn._init_server = function() { - var path = require('path'), - fs = require('fs'), - - express = require('express'), - - app = express(), + var app = express(), config = this._config, app_config = config.application, middleware_configs = app_config.middleware, project_folder = this._project_folder, - backend_folder = this._backend_folder, views_folder = app_config.folders.views, - rest = require('./middleware/rest'), - auth; + rest = require('./middleware/rest'); if(middleware_configs) { this._initialize_middlware(middleware_configs, app); - } else { - // TODO: support previous versions of ifnode - - var multiparty = require('connect-multiparty'), // upload - body_parser = require('body-parser'), - cookie_parser = require('cookie-parser'), - session = require('express-session'), - serve_favicon = require('serve-favicon'), - serve_static = require('serve-static'), - - body_parser_config = app_config.body || app_config.bodyParser, - cookie_parser_config = app_config.cookie_parser || app_config.cookieParser, - multiparty_config = app_config.multiparty, - session_config = app_config.session, - app_static_files = app_config.statics; - - if(typeof app_config.favicon === 'string') { - app.use(serve_favicon(app_config.favicon)); - } - - app.use(body_parser.urlencoded({ extended: true })); - app.use(body_parser.json()); - app.use(multiparty()); - app.use(cookie_parser()); - - if(app_config.session) { - if(session_config.store) { - (function() { - var store_db = config.by_path(session_config.store), - store; - - if(!store_db) { - console.warn('Cannot find database config. Check please'); - return; - } - - if(store_db.type === 'mongoose') { - store = require('connect-mongo')(session); - session_config.store = new store({ - db: store_db.config.database, - port: store_db.config.port - }); - } - // TODO: add more db types for session stores - }()); - } - app.use(session(app_config.session)); - } - - if(Array.isArray(app_static_files)) { - app_static_files.forEach(function(file_path) { - app.use(serve_static(path.resolve(project_folder, file_path))); - }); - } else if(typeof app_static_files === 'string') { - app.use(serve_static(path.resolve(project_folder, app_static_files))); - } - - if(app_config.debug === true) { - // TODO: check logger module (check node-bunyan) - //app.use(logger('dev')); - } } app.set('view engine', app_config.view_engine || 'jade'); @@ -263,216 +198,6 @@ Application.fn._init_server = function() { this._http_server = this._init_http_server(); }; -Application.fn._initialize_controller = function() { - var self = this, - controller_drivers_folder = path.resolve(this._ifnode_core_folder, 'controller-drivers/'), - Controller = require('./controller'); - - if(this._config.application && this._config.application.ws) { - require(path.resolve(controller_drivers_folder, 'ws'))(self, Controller); - } - if(this._config.components && this._config.components.auth) { - require(path.resolve(controller_drivers_folder, 'auth'))(self, Controller); - } - - this._controller = Controller; -}; -Application.fn._initialize_controllers = function() { - var controllers_folder = this.config.application.folders.controllers; - - diread({ - src: path.resolve(this._project_folder, controllers_folder) - }).each(function(controller_file_path) { - require(controller_file_path); - }); -}; -Application.fn._compile_controllers = function() { - var app_controllers = this._controllers, - app_server = this._server; - - Object.keys(app_controllers).forEach(function(controller_id) { - var controller = app_controllers[controller_id] - - app_server.use(controller.root, controller.router); - }); -}; -Application.fn._init_controllers = function() { - this._controllers = {}; - this._initialize_controller(); - this._initialize_controllers(); - this._compile_controllers(); -}; -Application.fn.Controller = function(controller_config) { - var controller = this._controller(controller_config); - - this._controllers[controller.name] = controller; - - return controller; -}; - -Application.fn._initialize_schemas = function() { - var path = require('path'), - model_drivers = require('./model-drivers')({ - user_model_drivers_folder: path.resolve(this._backend_folder, 'components/connections') - }), - - self = this, - db = this._config.db, - app_schemas = this._schemas = {}, - - db_connections_names; - - if(!db) { - return; - } - - db_connections_names = Object.keys(db); - if(!db_connections_names.length) { - return; - } - - self._default_creator = db_connections_names[0]; - db_connections_names.forEach(function(db_connection_name) { - var db_config = db[db_connection_name]; - - if(db_config.default) { - self._default_creator = db_connection_name; - } - - app_schemas[db_connection_name] = model_drivers(db_config); - }); -}; -Application.fn._initialize_models = function() { - var models_folder = this.config.application.folders.models; - - diread({ - src: path.resolve(this._project_folder, models_folder) - }).each(function(model_file_path) { - require(model_file_path); - }); -}; -Application.fn._compile_models = function() { - var model_prototypes = this._model_prototypes, - app_models = this._models, - - compile; - - compile = function(model_id) { - var model_prototype = model_prototypes[model_id], - compiled_model = model_prototype.__schema.compile(), - options = model_prototype.options; - - app_models[model_id] = compiled_model; - - if(options.alias) { - helper.to_array(options.alias).forEach(function(alias) { - if(alias in app_models) { - throw new Error('Alias {' + alias + '} already busy'); - } - - app_models[alias] = compiled_model; - }); - } - }; - - Object.keys(model_prototypes).forEach(compile); - delete this.__model_prototypes; -}; -Application.fn._init_models = function() { - this._model_prototypes = {}; - - this._models = {}; - this._initialize_schemas(); - this._initialize_models(); - this._compile_models(); -}; -Application.fn.Model = function(model_config, options) { - if(typeof options !== 'undefined') { - if(helper.is_plain_object(options)) { - options.type = options.type || this._default_creator; - } else { - options = { type: options }; - } - } else { - options = { type: this._default_creator }; - } - - var schema = this._schemas[options.type](model_config); - - this._model_prototypes[schema.table] = { - __schema: schema, - options: options - }; - - return schema; -}; - -Application.fn._initialize_component_class = function() { - this._component_class = require('./component'); -}; -Application.fn._initialize_components = function() { - var custom_components_folder = this.config.application.folders.components, - - core_components_path = path.resolve(this._ifnode_core_folder, 'components/'), - custom_components_path = path.resolve(this._project_folder, custom_components_folder), - - cb = function(component_file_path) { - require(component_file_path); - }; - - diread({ src: core_components_path }).each(cb); - diread({ src: custom_components_path }).each(cb); -}; -Application.fn._attach_components = function() { - var self = this, - app_components = self._components; - - Object.keys(app_components).forEach(function(component_key) { - var component = app_components[component_key], - component_aliases; - - if(component.disabled) { - return; - } - - component_aliases = component.alias; - - if(typeof component.initialize === 'function') { - component.initialize(component.config); - }; - - self[component.name] = component; - - component_aliases.forEach(function(alias) { - if(alias in self) { - throw new Error('Alias %s already busy in app', alias); - } - - self[alias] = component; - }); - }); -}; - -// TODO: think about helper and write components initialize -Application.fn._init_components = function() { - this._components = {}; - this._initialize_component_class(); - this._initialize_components(); - this._attach_components(); -}; -Application.fn.Component = function(component_options) { - var component = this._components[component_options.name]; - - if(component) { - return component; - } - - component_options.config = this._config.components[component_options.name] || {}; - component = this._component_class(component_options); - - return this._components[component.name] = component; -}; - Application.fn._start_server = function(callback) { var app_instance = this, local_config = this._config.site.local, @@ -493,15 +218,6 @@ Application.fn._start_server = function(callback) { this._http_server.listen.apply(this._http_server, server_params); }; -Application.fn.run = function(callback) { - this.load([ - 'components', - 'models', - 'controllers' - ]); - this._start_server(callback); -}; - Application.fn.init = Application.fn.initialize = function(app_config) { this._id = helper.uid(); this._alias = app_config.alias; @@ -519,21 +235,102 @@ Application.fn.load = function(parts) { 'components': '_init_components', 'models': '_init_models', 'controllers': '_init_controllers' - }; + }, + load_module = { + 'components': ['component'], + 'models': ['schema'], + 'controllers': ['controller'] + }, - if(!Array.isArray(parts)) { - parts = [parts]; - } + list_of_modules = this._modules, + init_modules = function(type) { + var modules = helper.to_array(list_of_modules), + + load_module = { + 'schema': require('./model_schema'), + 'component': require('./component'), + 'controller': require('./controller') + }, + + args = load_module[type]; - parts.forEach(function(load_part) { + modules.forEach(function(module) { + var result; + + if(!(type in module)) { + return; + } + + switch(type) { + case 'schema': + result = args(); + + module[type](self, result); + self.attach_schema(result); + break; + case 'component': + result = module[type](self, args); + self.attach_component(result); + break; + default: + console.log(module[type](self, args)); + } + }); + }; + + helper.to_array(parts).forEach(function(load_part) { + load_module[load_part].forEach(init_modules); self[load_hash[load_part]](); }); return this; }; +Application.fn.register = function(list_of_modules) { + //var self = this, + // modules = helper.to_array(list_of_modules), + // + // load_module = { + // 'schema': [require('./model_schema'), this.Model], + // 'component': require('./component'), + // 'controller': require('./controller') + // }; + // + //Object.keys(load_module).forEach(function(type) { + // var args = load_module[type]; + // + // modules.forEach(function(module) { + // if(!(type in module)) { + // return; + // } + // + // switch(type) { + // case 'schema': + // module[type](self, args[0](), args[1]); + // break; + // default: + // module[type](self, args); + // } + // }); + //}); + this._modules = helper.to_array(list_of_modules); +}; +Application.fn.run = function(callback) { + this.load([ + //'extensions', + 'models', + 'components', + 'controllers' + ]); + this._start_server(callback); +}; + +require('./application/extension')(Application); +require('./application/model')(Application); +require('./application/component')(Application); +require('./application/controller')(Application); // TODO: think how make properties not editable -Application.fn._define_properties({ +define_properties(Application, { 'config': function() { return _.clone(this._config) }, 'server': function() { return this._server }, diff --git a/core/application/component.js b/core/application/component.js new file mode 100644 index 0000000..c7f1ef0 --- /dev/null +++ b/core/application/component.js @@ -0,0 +1,72 @@ +var path = require('path'), + diread = require('diread'), + + Component = require('./../component'); + +module.exports = function(Application) { + Application.fn._components = {}; + Application.fn._initialize_components = function() { + var custom_components_folder = this.config.application.folders.components, + + core_components_path = path.resolve(this._ifnode_core_folder, 'components/'), + custom_components_path = path.resolve(this._project_folder, custom_components_folder), + + cb = function(component_file_path) { + require(component_file_path); + }; + + diread({ src: core_components_path }).each(cb); + diread({ src: custom_components_path }).each(cb); + }; + Application.fn._attach_components = function() { + var self = this, + app_components = self._components; + + Object.keys(app_components).forEach(function(component_key) { + var component = app_components[component_key], + component_aliases; + + if(component.disabled) { + return; + } + + component_aliases = component.alias; + + if(typeof component.initialize === 'function') { + component.initialize(component.config); + } + + self[component.name] = component; + + component_aliases.forEach(function(alias) { + if(alias in self) { + throw new Error('Alias %s already busy in app', alias); + } + + self[alias] = component; + }); + }); + }; + +// TODO: think about helper and write components initialize + Application.fn._init_components = function() { + this._initialize_components(); + this._attach_components(); + }; + + Application.fn.attach_component = function(component) { + this._components[component.name] = component; + }; + Application.fn.Component = function(component_options) { + var component = this._components[component_options.name]; + + if(component) { + return component; + } + + component_options.config = this._config.components[component_options.name] || {}; + component = Component(component_options); + + return this._components[component.name] = component; + }; +}; diff --git a/core/application/controller.js b/core/application/controller.js new file mode 100644 index 0000000..8c55592 --- /dev/null +++ b/core/application/controller.js @@ -0,0 +1,39 @@ +var path = require('path'), + diread = require('diread'), + + helper = require('./../helper'), + Controller = require('./../controller'); + +module.exports = function(Application) { + Application.fn._initialize_controllers = function() { + var controllers_folder = this.config.application.folders.controllers; + + diread({ + src: path.resolve(this._project_folder, controllers_folder) + }).each(function(controller_file_path) { + require(controller_file_path); + }); + }; + Application.fn._compile_controllers = function() { + var app_controllers = this._controllers, + app_server = this._server; + + Object.keys(app_controllers).forEach(function(controller_id) { + var controller = app_controllers[controller_id]; + + app_server.use(controller.root, controller.router); + }); + }; + Application.fn._init_controllers = function() { + this._controllers = {}; + this._initialize_controllers(); + this._compile_controllers(); + }; + Application.fn.Controller = function(controller_config) { + var controller = Controller(controller_config); + + this._controllers[controller.name] = controller; + + return controller; + }; +}; diff --git a/core/application/extension.js b/core/application/extension.js new file mode 100644 index 0000000..352bc49 --- /dev/null +++ b/core/application/extension.js @@ -0,0 +1,2 @@ +module.exports = function(Application) { +}; diff --git a/core/application/model.js b/core/application/model.js new file mode 100644 index 0000000..4d80535 --- /dev/null +++ b/core/application/model.js @@ -0,0 +1,110 @@ +var path = require('path'), + diread = require('diread'), + + helper = require('./../helper'); + +module.exports = function(Application) { + Application.fn._schemas_drivers = {}; + Application.fn._initialize_schemas = function() { + var self = this, + db = this._config.db, + schemas_drivers = this._schemas_drivers, + schemas = this._schemas, + + db_connections_names; + + if(!db) { + return; + } + + db_connections_names = Object.keys(db); + if(!db_connections_names.length) { + return; + } + + self._default_creator = db_connections_names[0]; + db_connections_names.forEach(function(db_connection_name) { + var db_config = db[db_connection_name], + schema_driver = schemas_drivers[db_config.type]; + + if(db_config.default) { + self._default_creator = db_connection_name; + } + + + if(schema_driver.driver) { + schema_driver.driver(db_config); + } + schemas[db_connection_name] = schema_driver; + }); + }; + Application.fn._initialize_models = function() { + var models_folder = this.config.application.folders.models; + + diread({ + src: path.resolve(this._project_folder, models_folder) + }).each(function(model_file_path) { + require(model_file_path); + }); + }; + Application.fn._compile_models = function() { + var model_prototypes = this._model_prototypes, + app_models = this._models, + + compile; + + compile = function(model_id) { + var model_prototype = model_prototypes[model_id], + compiled_model = model_prototype.__schema.compile(), + options = model_prototype.options; + + app_models[model_id] = compiled_model; + + if(options.alias) { + helper.to_array(options.alias).forEach(function(alias) { + if(alias in app_models) { + throw new Error('Alias {' + alias + '} already busy'); + } + + app_models[alias] = compiled_model; + }); + } + }; + + Object.keys(model_prototypes).forEach(compile); + delete this._model_prototypes; + }; + Application.fn._init_models = function() { + this._model_prototypes = {}; + + this._schemas = {}; + this._models = {}; + this._initialize_schemas(); + this._initialize_models(); + this._compile_models(); + }; + + Application.fn.attach_schema = function(Schema) { + this._schemas_drivers[Schema.type] = Schema; + }; + Application.fn.Model = function(model_config, options) { + if(typeof options !== 'undefined') { + if(helper.is_plain_object(options)) { + options.type = options.type || this._default_creator; + } else { + options = { type: options }; + } + } else { + options = { type: this._default_creator }; + } + + var schema = this._schemas[options.type](model_config); + + this._model_prototypes[schema.table] = { + __schema: schema, + options: options + }; + + return schema; + }; +}; diff --git a/core/component.js b/core/component.js index 5bfd8f5..cd6f61a 100644 --- a/core/component.js +++ b/core/component.js @@ -13,6 +13,8 @@ Component.fn.init = function(options) { this._id = helper.uid(); this.name = options.name; + options.config = options.config || {}; + this.alias = options.config.alias || []; this.disabled = options.config.disabled || false; diff --git a/core/components/auth.js b/core/components/auth.js deleted file mode 100644 index 95b04a1..0000000 --- a/core/components/auth.js +++ /dev/null @@ -1,92 +0,0 @@ -var app = require('ifnode')(), - _ = require('lodash'), - passport = require('passport'), - - auth = app.Component({ - name: 'auth' - }); - -auth._init_strategy = function(name, config, process) { - var module_name = 'passport-' + name, - module = require(module_name), - strategy, - - default_passport_strategy = 'Strategy', - custom_passport_strategy = config.passport_strategy || config.passportStrategy; - - strategy = module[custom_passport_strategy || default_passport_strategy]; - - if(!strategy) { - throw new Error('Cannot get module Strategy instance'); - } - - this._passport.use(new strategy(config, process)); -}; - -auth._initialize = function(config) { - var self = this, - passport_instance = this._passport = passport, - - webuser = this._webuser_model = app.models.webuser, - webuser_strategies = webuser.strategy/* || _.omit(webuser, ['serialize', 'deserialize'])*/, - auth_roles = this.roles, - webuser_get_role = webuser.get_role || webuser.getRole, - - supported_strategies = config, - supported_strategies_names = Object.keys(supported_strategies), - auth_config = app.config.auth, - - initialize_passport = function() { - passport_instance.serializeUser(webuser.serialize); - passport_instance.deserializeUser(webuser.deserialize); - - supported_strategies_names.forEach(function(name) { - var process = webuser_strategies[name]; - - if(!process) { - console.warn('Cannot find strategy process'); - process = function() {}; - } - - self._init_strategy(name, supported_strategies[name], process); - }); - }; - - if(webuser.roles) { - webuser.roles(function(err, roles) { - if(err) { throw new Error(err); } - if(Array.isArray(roles)) { - auth_roles = auth_roles.concat(roles); - } - - self.user_role_field = webuser.user_role_field || webuser.userRoleField; - initialize_passport(); - }); - } else { - initialize_passport(); - } - - if(typeof webuser_get_role === 'function') { - this.get_role = webuser_get_role.bind(webuser); - } -}; - -auth.initialize = function() { - this.default_roles = { - all: '*', - guest: '?', - authenticated: '@' - }; - this.roles = _.values(this.default_roles); -}; -auth.authenticate = function(strategy, options, cb) { - return this._passport.authenticate(strategy, options, cb); -}; - -auth.attach = function(server) { - this._initialize(this.config); - server.use(this._passport.initialize(this._passport)); - server.use(this._passport.session(this._passport)); - - return this; -}; diff --git a/core/controller-drivers/auth.js b/core/controller-drivers/auth.js deleted file mode 100644 index e413772..0000000 --- a/core/controller-drivers/auth.js +++ /dev/null @@ -1,133 +0,0 @@ -var _ = require('lodash'); - -module.exports = function(app, Controller) { - var auth = app.auth.attach(app.server), - user_role_field = auth.user_role_field, - default_roles = auth.default_roles, - - auth_middleware; - - Controller.fn.roles = auth.roles; - Controller.fn.default_role = default_roles.all; - - Controller.fn._default_config.access = [default_roles.all]; - Controller.fn._page_access_denied = function(request, response) { - response.status(401).send('Unauthorized user'); - }; - - Controller.process_config(function(controller_config) { - var access_options = controller_config.access, - only_options = controller_config.only, - - process = function(options, defualt) { - if(!options) { - options = defualt; - } else if(!Array.isArray(options)) { - options = [options]; - } - - return options; - }; - - controller_config.access = process(controller_config.access, [this.default_role]); - controller_config.only = process(controller_config.only, [this.default_role]); - - return controller_config; - }); - - auth_middleware = function(self, request, options, can_callback, cannot_callback, error_callback) { - var is_authenticated = request.isAuthenticated(), - get_role = function(callback) { - var auth_get_role = auth.get_role, - user_role; - - if(typeof auth_get_role === 'function') { - return auth_get_role(request.user, callback); - } - - if(user_role_field) { - user_role = request.user[user_role_field]; - - if(typeof user_role === 'function') { - user_role = user_role(); - } - } else { - user_role = default_roles.authenticated; - } - - callback(null, user_role); - }; - - if(_.contains(options, self.default_role)) { - return can_callback(); - } - - if(is_authenticated) { - get_role(function(err, user_role) { - if(err) { return error_callback(err); } - - if( - !_.contains(options, default_roles.authenticated) && - !_.contains(options, user_role) - ) { - return cannot_callback(); - } - - can_callback(); - }); - return; - } else if(!_.contains(options, default_roles.guest)) { - return cannot_callback(); - } - - can_callback(); - }; - - Controller.populate(function() { - var self = this; - - return function(request, response, next, next_router) { - response.access_denied = response.accessDenied = function() { - self._page_access_denied.call(self, request, response); - }; - next(); - }; - }); - Controller.middleware([ - function only_middleware(options) { - var self = this, - roles = self.roles, - only_options = options.only; - - return function only_middleware(request, response, next_handler, next_route) { - auth_middleware(self, request, only_options, - next_handler, - next_route, - next_route - ); - } - }, - function access_middleware(options) { - var self = this, - roles = self.roles, - access_options = options.access; - - return function access_middleware(request, response, next_handler, next_route) { - var args = app.helper.to_array(arguments); - - auth_middleware(self, request, access_options, - next_handler, - function() { - self._page_access_denied.apply(self, args); - }, - next_route - ); - }; - } - ]); - - Controller.fn.access_denied = Controller.fn.accessDenied = function(callback) { - this._page_access_denied = callback; - return this; - }; -}; diff --git a/core/controller-drivers/router.js b/core/controller-drivers/router.js deleted file mode 100644 index e69de29..0000000 diff --git a/core/controller-drivers/ws/clients.js b/core/controller-drivers/ws/clients.js deleted file mode 100644 index 2ac8b4c..0000000 --- a/core/controller-drivers/ws/clients.js +++ /dev/null @@ -1,54 +0,0 @@ -var _ = require('lodash'), - - Clients = function(options) { - this._options = options || {}; - this._clients = {}; - }; - -Clients.fn = Clients.prototype; - -Clients.fn.get = function(client_id) { - return this._clients[client_id]; -}; - -Clients.fn.add = function(client_id, data) { - data = data || {}; - data.client_id = client_id; - this._clients[client_id] = data; -}; - -Clients.fn.remove = function(client_id) { - delete this._clients[client_id]; -}; - -Clients.fn.all = function() { - return this._clients; -}; - -/* Underscore functions */ - -Clients.fn.each = function(iterator, context) { - _.each(this._clients, iterator, context || this); -}; - -Clients.fn.pluck = function(property_name) { - return _.pluck(this._clients, property_name); -}; - -Clients.fn.filter = function(iterator, context) { - return _.filter(this._clients, iterator, context || this); -}; - -Clients.fn.where = function(properties) { - return _.where(this._clients, properties); -}; - -Clients.fn.find_where = Clients.fn.findWhere = function(properties) { - return _.findWhere(this._clients, properties); -}; - -Clients.fn.map = function(iterator, context) { - return _.findWhere(this._clients, iterator, context || this); -}; - -module.exports = Clients; diff --git a/core/controller-drivers/ws/index.js b/core/controller-drivers/ws/index.js deleted file mode 100644 index 4e26aeb..0000000 --- a/core/controller-drivers/ws/index.js +++ /dev/null @@ -1,79 +0,0 @@ -var url = require('url'), - clients = require('./clients'); - -var create_ws_namespace = function(pathname, options) { - if(pathname in this._ws) { - throw new Error('Root: %s, Already exist: %s', this._root, pathname); - } - - var full_path; - - pathname = pathname.replace(/^\/|\/$/g, ''); - full_path = url.resolve(this._root, pathname); - - this.ws[pathname] = this._ws_driver.of(full_path); - this.ws[pathname].emit_clients = this.ws[pathname].emitClients = emit_clients; - - if(options.alias) { - this.ws[options.alias] = this.ws[pathname]; - } - - return this.ws[pathname]; -}; - -var ws_handler = function(url, options, callback) { - var self = this, - params = self._regulize_route_params([url, options, callback]), - ws_namespace; - - url = params[0]; - options = params[1]; - callback = params[2][0]; - - if(!self._ws) { - self._ws = {}; - } - - if(!(url in self._ws)) { - ws_namespace = create_ws_namespace.call(self, url, options); - } - - ws_namespace.on('connection', function(ws) { - //if(!this._access_right()) { - // return this.access_denied(); - //} - - callback.call(self, ws); - }); -}; - -var emit_clients = function(clients, event, data) { - var self = this; - - clients.forEach(function(client_id){ - self.to(client_id).emit(event, data); - }); -}; - -module.exports = function(app, Controller) { - var socketio = require('socket.io'), - ws_driver = socketio(app._http_server); - - ws_driver.on('connection', function(ws) { - Controller.fn.ws.clients.add(ws.id, ws.request._query); - - ws.on('disconnect', function() { - Controller.fn.ws.clients.remove(ws.id); - }); - }); - - ws_driver.on('disconnect', function (ws) { - Controller.fn.ws.clients.remove(ws.id); - }); - - Controller.fn._ws_driver = ws_driver; - Controller.fn.ws = ws_handler; - Controller.fn.ws.clients = new clients({ - controller: Controller - }); -}; diff --git a/core/controller.js b/core/controller.js index ffd787f..d58680b 100644 --- a/core/controller.js +++ b/core/controller.js @@ -1,10 +1,22 @@ -var helper = require('./helper'), - - _ = require('lodash'), +var _ = require('lodash'), async = require('async'), - express = require('express'); + express = require('express'), -var Controller = function(config) { + helper = require('./helper'), + is_plain_object = helper.is_plain_object, + is_url = function(url) { + if(_.isUndefined(url)) { + return false; + } + if(!_.isString(url)) { + throw new Error('Url wrong type. Must be string'); + } + return true; + }, + + Controller; + +Controller = function(config) { if(!(this instanceof Controller)) { return new Controller(config); } @@ -12,35 +24,6 @@ var Controller = function(config) { }; Controller.fn = Controller.prototype; -Controller.fn.is_url = function(url) { - if(_.isUndefined(url)) { - return false; - } - if(!_.isString(url)) { - throw new Error('Url wrong type. Must be string'); - } - return true; -}; -Controller.fn._is_options = Controller.fn._is_config = function(obj) { -// if(_.isUndefined(obj)) { -// return false; -// } -// -// if(!helper.is_plain_object(obj)) { -// throw new Error('Access option wrong type. Must be object'); -// } -// -// return true; - return helper.is_plain_object(obj); -}; -Controller.fn.is_callback = function(callback) { -// if(!_.isFunction(callback)) { -// throw new Error('Callback wrong type. Must be only function'); -// } -// -// return true; - return _.isFunction(callback); -}; Controller.fn._default_config = { root: '/', @@ -55,11 +38,7 @@ Controller.process_config = function(processor) { }; var add_fn = function(list, fns) { - if(!Array.isArray(fns)) { - fns = [fns]; - } - - fns.forEach(function(fn) { + helper.to_array(fns).forEach(function(fn) { if(typeof fn === 'function') { list.push(fn); } else { @@ -88,11 +67,11 @@ Controller.fn._page_not_found = function(request, response, next) { Controller.fn._process_config = function(controller_config) { var self = this; - if(!this._is_config(controller_config)) { + if(!is_plain_object(controller_config)) { controller_config = this._default_config; } - controller_config.root = this.is_url(controller_config.root) ? + controller_config.root = is_url(controller_config.root) ? controller_config.root : this._default_config.root; @@ -159,17 +138,18 @@ Controller.middleware([ Controller.fn._regulize_route_params = function(args) { var url, options, callbacks; - if(this.is_callback(args[0])) { + if(typeof args[0] === 'function') { url = '/'; options = _.clone(this._common_options); callbacks = args; - } else if(this._is_options(args[0])) { + } else if(is_plain_object(args[0])) { url = '/'; options = _.extend(_.clone(this._common_options), args[0]); callbacks = args.slice(1); } else { url = args[0]; - if(this._is_options(args[1])) { + + if(is_plain_object(args[1])) { options = _.extend(_.clone(this._common_options), args[1]); callbacks = args.slice(2); } else { @@ -190,7 +170,7 @@ Controller.fn._generate_url = function(method) { user_callbacks = params[2], callbacks = [], - tmp, i, len; + i, len; console.log('method: %s, root: %s, url: %s, options: %s', method, this._root, url, options, user_callbacks); @@ -212,8 +192,7 @@ Controller.fn._generate_url = function(method) { this._router[method](url, function(request, response, next_route) { async.eachSeries(callbacks, function(callback, next_callback) { var next_handler = function(options) { - var is_error = options instanceof Error, - is_plain_object = helper.is_plain_object(options); + var is_error = options instanceof Error; if(is_error) { return next_route(options); diff --git a/core/middleware/cors.js b/core/middleware/cors.js deleted file mode 100644 index 35aa0b8..0000000 --- a/core/middleware/cors.js +++ /dev/null @@ -1,11 +0,0 @@ -function cors() { - return function (req, res, next) { - res.header('Access-Control-Allow-Origin', '*'); - res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); - res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-Access-Token, X-Revision, Content-Type'); - - next(); - }; -} - -module.exports = cors; \ No newline at end of file diff --git a/core/middleware/index.js b/core/middleware/index.js deleted file mode 100644 index 215f385..0000000 --- a/core/middleware/index.js +++ /dev/null @@ -1,8 +0,0 @@ -var middleware = function(app) { - return { - auth: require('./auth')(app), - rest: require('./rest') - } -}; - -module.exports = middleware; diff --git a/core/middleware/rest.js b/core/middleware/rest.js index f00b1c6..7134da5 100644 --- a/core/middleware/rest.js +++ b/core/middleware/rest.js @@ -102,5 +102,5 @@ REST = function(request, response, next) { }; module.exports = function() { - return REST + return REST; }; diff --git a/core/model-drivers/index.js b/core/model-drivers/index.js deleted file mode 100644 index db26485..0000000 --- a/core/model-drivers/index.js +++ /dev/null @@ -1,45 +0,0 @@ -var _ = require('lodash'), - diread = require('diread'), - - drivers = {}, - initialize = function(options) { - - drivers = _.extend( - initialize_core_model_drivers(), - initialize_user_drivers(options) - ); - }, - initialize_user_drivers = function(options) { - var user_drivers_dir = options.user_model_drivers_folder, - user_drivers = {}; - - diread({ src: user_drivers_dir }).each(function(driver_path, file_name) { - user_drivers[file_name] = require(driver_path); - }); - - return user_drivers; - }, - initialize_core_model_drivers = function() { - return { - mongoose: require('./mongoose'), - knex: require('./knex'), - redis: require('./redis'), - virtual: require('./virtual') - }; - }, - - get_driver = function(db) { - var driver = drivers[db.type]; - - if(!driver) { - throw Error('Cannot find driver: %s', db.type); - } - - return driver(db.config); - }; - -module.exports = function(options) { - initialize(options); - - return get_driver; -}; diff --git a/core/model-drivers/knex.js b/core/model-drivers/knex.js deleted file mode 100644 index bf1f5d8..0000000 --- a/core/model-drivers/knex.js +++ /dev/null @@ -1,28 +0,0 @@ -var Schema = function(model_config) { - if(!(this instanceof Schema)) { - return new Schema(model_config); - } - - this.table = model_config.table; - this.init(model_config); -}; -Schema.fn = Schema.prototype; - -Schema.connect_driver = function(db_config) { - var knex = require('knex')(db_config); - Schema.fn._driver = knex; -}; -Schema.fn.init = function() { - this.driver = Schema.fn._driver; - this.all = function(){ - return this.driver(this.table); - } -}; -Schema.fn.compile = function() { - return this; -}; - -module.exports = function(db_config) { - Schema.connect_driver(db_config); - return Schema; -}; diff --git a/core/model-drivers/mongoose.js b/core/model-drivers/mongoose.js deleted file mode 100644 index 63f3077..0000000 --- a/core/model-drivers/mongoose.js +++ /dev/null @@ -1,75 +0,0 @@ -var _ = require('lodash'), - - Schema = function(model_config) { - if(!(this instanceof Schema)) { - return new Schema(model_config); - } - - this._model_config = model_config; - - this.table = model_config.table; - this._columns = model_config.columns || {}; - this._schema_config = _.defaults(model_config.config || {}, this._default_schema_config); - //this._schema_config = _.extend(this._default_schema_config, model_config.config || {}); - this.init(model_config); - }; -Schema.fn = Schema.prototype; - -Schema.connect_driver = function(db_config) { - var mongoose = require('mongoose'); - mongoose.connect(db_config.url); - - Schema.fn._driver = mongoose; -} -Schema.fn.init = function() { - this._initialize_schema(); - this.statics = this._schema.statics = {}; - this.methods = this._schema.methods = {}; -}; -Schema.fn.compile = function() { - this._model = this._driver.model(this.table, this._schema); - - return this._model; -}; - -Schema.fn._default_schema_config = { - id: false, - versionKey: false, - strict: true -}; - -Schema.fn._initialize_schema = function() { - if( - !Object.keys(this._columns).length && - this._schema_config.strict === this._default_schema_config.strict - ) { - this._schema_config.strict = false; - } - - this._schema = this._driver.Schema(this._columns, this._schema_config); - - //this._schema.set('toJSON', { - // transform: function (doc, ret, options) { - // ret.id = ret._id; - // delete ret._id; - // } - //}); -}; -Schema.fn.get_original_schema = function() { - return this._schema; -}; -Schema.fn.model = function() { - return this._model; -}; -Schema.fn.create = function() { - return this._model.create.apply(this._model, arguments); -}; -Schema.fn.pre = function() { - return this._schema.pre.apply(this._schema, arguments); -}; - -module.exports = function(db_config) { - Schema.connect_driver(db_config); - - return Schema; -}; diff --git a/core/model-drivers/redis.js b/core/model-drivers/redis.js deleted file mode 100644 index da199b1..0000000 --- a/core/model-drivers/redis.js +++ /dev/null @@ -1,38 +0,0 @@ -var Schema = function(model_config) { - if(!(this instanceof Schema)) { - return new Schema(model_config); - } - this.table = model_config.table; - this.statics = {}; -}; -Schema.fn = Schema.prototype; - -Schema.connect_driver = function(db_config) { - var redis = require('redis'), - redis_params = []; - - if(db_config.host && db_config.port) { - redis_params = [db_config.port, db_config.host]; - } - if(db_config.options) { - redis_params.push(db_config.options); - } - - Schema.fn._driver = redis.createClient.apply(redis, redis_params); -}; -Schema.fn.compile = function() { - var model = this._driver; - - for(var i in this.statics) { - if(typeof this.statics[i] === 'function') { - model[i] = this.statics[i].bind(this._driver); - } - } - - return model; -}; - -module.exports = function(db_config) { - Schema.connect_driver(db_config); - return Schema; -}; diff --git a/core/model-drivers/virtual.js b/core/model-drivers/virtual.js deleted file mode 100644 index bc3ae34..0000000 --- a/core/model-drivers/virtual.js +++ /dev/null @@ -1,36 +0,0 @@ -var _ = require('lodash'), - - Schema = function(model_config) { - if(!(this instanceof Schema)) { - return new Schema(model_config); - } - - this.name = model_config.name; - this.table = model_config.table || this.name; - this.init(model_config); - }; - -Schema.fn = Schema.prototype; - -Schema.fn.init = function(config) { - var self = this, - options = _.omit(config, [ - 'name', - 'table' - ]); - - Object.keys(options).forEach(function(key) { - if(key in self) { - throw new Error('Key ' + key + ' already busy'); - } - - self[key] = options[key]; - }); -}; -Schema.fn.compile = function() { - return this; -}; - -module.exports = function(db_config) { - return Schema; -}; diff --git a/core/model_schema.js b/core/model_schema.js new file mode 100644 index 0000000..e0a72e8 --- /dev/null +++ b/core/model_schema.js @@ -0,0 +1,15 @@ +var SchemaFactory = function() { + var Schema = function(model_config) { + if(!(this instanceof Schema)) { + return new Schema(model_config); + } + + (this.init || this.initialize).call(this, model_config); + }; + + Schema.fn = Schema.prototype; + + return Schema; +}; + +module.exports = SchemaFactory; diff --git a/ideas b/ideas index b07b823..9bbef34 100644 --- a/ideas +++ b/ideas @@ -1,25 +1,4 @@ - Controller: - --- опция only -var c = app.Controller(); - -c.get('/login', { only: '?' }, function(req, res, next) { - console.log('login page') - next() -}); -c.get('/', function(req, res, next) { - console.log('main page') -}); - -# ://localhost/login -незалогиненый юзер: -login page -main page - -залогиненый юзер: -main page - - -- проброс данных параметров в root контроллера var insight_controller = app.Controller({ root: '/api/insight/:id' }); @@ -59,29 +38,9 @@ insight_controller .del('/:element_id', function() {}) .method(['put', 'patch'], '/:element_id', function() {}); --- Model: --- виртуальные модели (модель не связана с базой данных) -var virtual_model = app.Model({}, 'virtual'); -- Global - --- опция components в конфиге приложения -module.exports = { - components: { - emailer: { - alias: ['e', 'mail'], - config: { - - } - } - } -} -... -var app = require('ifnode')(); -app.e === app.mail === app.emailer - - -- опции models/controllers для системных настроек (порядок загрузки, алиасы, тип коннектора и пр.) module.exports = { models: { @@ -99,20 +58,7 @@ module.exports = { } } -<<<<<<< HEAD - --- policies: --- кастомные роли юзеров для доступа к роутам контроллера - - --- policies: --- кастомные роли юзеров для доступа к роутам контроллера - --- понятие extensions +-- Extensions Добавление готовых нодджс модулей в ифнод или своих кастомных. Экстеншены либо не привязаны к ифноду, либо получают из какой-то конфиг -======= --- Policies: --- кастомные роли юзеров для доступа к роутам контроллера ->>>>>>> fc55b20c61b63efd511367d25ab754ef711099a8 diff --git a/package.json b/package.json index 5791a97..6f0106d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ifnode", - "version": "0.1.13", + "version": "1.0.0", "description": "Node.js MVC Framework", "main": "index.js", "scripts": { @@ -18,17 +18,11 @@ "license": "MIT", "dependencies": { "diread": "latest", - "express": "4.9.7", - - "jade": "latest", - "async": "latest", "lodash": "latest", "node-uuid": "latest", - "redis": "latest", - "knex": "latest", - "mongoose": "latest" + "express": "latest" }, "devDependencies": { "mocha": "latest"