express-admin
Advanced tools
+3
-2
| language: node_js | ||
| node_js: | ||
| - node | ||
| - 0.12 | ||
| - 0.10 | ||
| - 8 | ||
| - 6 | ||
| - 4 | ||
| services: | ||
@@ -7,0 +8,0 @@ - mysql |
+28
-28
| { | ||
| "name": "express-admin", | ||
| "version": "1.3.1", | ||
| "version": "1.3.2", | ||
| "description": "MySql, MariaDB, SQLite and PostgreSQL database admin built with Express and Bootstrap", | ||
@@ -15,36 +15,36 @@ "keywords": [ | ||
| ], | ||
| "license" : "MIT", | ||
| "homepage" : "https://github.com/simov/express-admin", | ||
| "author" : "Simeon Velichkov <simeonvelichkov@gmail.com> (https://simov.github.io)", | ||
| "license": "MIT", | ||
| "homepage": "https://github.com/simov/express-admin", | ||
| "author": "Simeon Velichkov <simeonvelichkov@gmail.com> (https://simov.github.io)", | ||
| "repository": { | ||
| "type" : "git", | ||
| "url" : "https://github.com/simov/express-admin.git" | ||
| "type": "git", | ||
| "url": "https://github.com/simov/express-admin.git" | ||
| }, | ||
| "dependencies": { | ||
| "express" : "4.4.4", | ||
| "morgan" : "1.1.1", | ||
| "body-parser" : "1.4.3", | ||
| "express": "4.4.4", | ||
| "morgan": "1.1.1", | ||
| "body-parser": "1.4.3", | ||
| "connect-multiparty": "1.1.0", | ||
| "cookie-parser" : "1.3.1", | ||
| "express-session" : "1.5.1", | ||
| "csurf" : "1.2.2", | ||
| "method-override" : "2.0.2", | ||
| "serve-static" : "1.2.3", | ||
| "consolidate" : "0.9.1", | ||
| "hogan.js" : "3.0.2", | ||
| "mysql" : "2.2.0", | ||
| "mysql-validator" : "0.1.6", | ||
| "async" : "0.9.0", | ||
| "pwd" : "1.1.0", | ||
| "commander" : "1.3.2", | ||
| "colors" : "0.6.1", | ||
| "slugify" : "0.1.0", | ||
| "sr-pagination" : "1.0.1", | ||
| "deep-copy" : "1.0.0", | ||
| "xsql" : "1.0.1", | ||
| "moment" : "2.8.3", | ||
| "cookie-parser": "1.3.1", | ||
| "express-session": "1.5.1", | ||
| "csurf": "1.2.2", | ||
| "method-override": "2.0.2", | ||
| "serve-static": "1.2.3", | ||
| "consolidate": "0.9.1", | ||
| "hogan.js": "3.0.2", | ||
| "mysql": "2.2.0", | ||
| "mysql-validator": "0.1.6", | ||
| "async": "0.9.0", | ||
| "pwd": "1.1.0", | ||
| "commander": "1.3.2", | ||
| "colors": "0.6.1", | ||
| "slugify": "0.1.0", | ||
| "sr-pagination": "1.0.1", | ||
| "deep-copy": "1.0.0", | ||
| "xsql": "1.0.1", | ||
| "moment": "2.8.3", | ||
| "express-admin-static": "2.2.2" | ||
| }, | ||
| "devDependencies": { | ||
| "mocha" : "1.20.1", | ||
| "mocha": "1.20.1", | ||
| "should": "4.0.4", | ||
@@ -51,0 +51,0 @@ "supertest": "0.15.0", |
@@ -21,5 +21,11 @@ | ||
| {{>inline}} | ||
| {{^view.readonly}} | ||
| <fieldset id="controls"> | ||
| <button type="submit" class="btn btn-default form-control" name="action[another]">{{string.save-add}}</button> | ||
| <button type="submit" class="btn btn-default form-control" name="action[continue]">{{string.save-continue}}</button> | ||
| <button type="submit" class="btn btn-primary form-control" name="action[save]">{{string.save}}</button> | ||
| {{#show.delete}} | ||
@@ -29,8 +35,2 @@ <button type="submit" class="btn btn-danger form-control" name="action[remove]">{{string.delete}}</button> | ||
| <button type="submit" class="btn btn-default form-control" name="action[another]">{{string.save-add}}</button> | ||
| <button type="submit" class="btn btn-default form-control" name="action[continue]">{{string.save-continue}}</button> | ||
| <button type="submit" class="btn btn-primary form-control" name="action[save]">{{string.save}}</button> | ||
| <input type="hidden" name="_csrf" value="{{csrf}}" /> | ||
@@ -37,0 +37,0 @@ </fieldset> |
Sorry, the diff of this file is not supported yet
| var fs = require('fs'), | ||
| path = require('path'), | ||
| recursive = require('recursive-fs'), | ||
| should = require('should'), | ||
| pwd = require('pwd'); | ||
| var project = require('../../lib/app/project'); | ||
| describe('project', function () { | ||
| var dpath = path.join(__dirname, 'project'); | ||
| var data = { | ||
| mysql: {database: 'express-admin-test', user: 'liolio', password: 'karamba'}, | ||
| server: {port: '3000'}, | ||
| user: {name: 'admin', pass: '11aaAA'} | ||
| }; | ||
| before(function (done) { | ||
| fs.mkdir(dpath, done); | ||
| }); | ||
| it('the config files shouldn\'t exist', function (done) { | ||
| project.exists(dpath).should.equal(false); | ||
| done(); | ||
| }); | ||
| it('the config files should exist', function (done) { | ||
| project.create(dpath, data, function (err) { | ||
| if (err) return done(err); | ||
| project.exists(dpath).should.equal(true); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('the config data should be correct', function (done) { | ||
| should.deepEqual(require('./project/custom'), {}); | ||
| should.deepEqual(require('./project/settings'), {}); | ||
| should.deepEqual(require('./project/config'), data); | ||
| var users = require('./project/users'); | ||
| users.admin.name.should.equal('admin'); | ||
| users.admin.admin.should.equal(true); | ||
| pwd.hash('11aaAA', users.admin.salt, function (err, hash) { | ||
| if (err) return done(err); | ||
| users.admin.hash.should.equal(hash); | ||
| done(); | ||
| }); | ||
| }); | ||
| after(function (done) { | ||
| recursive.rmdirr(dpath, function (err) { | ||
| done(err); | ||
| }); | ||
| }); | ||
| }); |
| var should = require('should'); | ||
| var routes = require('../../lib/app/routes'); | ||
| describe('routes (app)', function () { | ||
| it('skip tables hidden in mainview', function (done) { | ||
| var settings = { | ||
| table1: {table:{pk:'1'}, mainview:{show:true}, slug:'table1'}, | ||
| table2: {table:{pk:'2'}, mainview:{show:false}, slug:'table2'} | ||
| }; | ||
| var r = routes.init(settings, {}); | ||
| should.deepEqual(r.editview, /^\/(table1)\/(.+|add)\/?$/); | ||
| done(); | ||
| }); | ||
| it('skip tables without primary key', function (done) { | ||
| var settings = { | ||
| table1: {table:{pk:'1'}, mainview:{show:true}, slug:'table1'}, | ||
| table2: {table:{pk:''}, mainview:{show:true}, slug:'table2'} | ||
| }; | ||
| var r = routes.init(settings, {}); | ||
| should.deepEqual(r.editview, /^\/(table1)\/(.+|add)\/?$/); | ||
| done(); | ||
| }); | ||
| it('return match anything regex on zero table slugs', function (done) { | ||
| var settings = { | ||
| table1: {table:{pk:''}, mainview:{show:true}, slug:'table1'}, | ||
| table2: {table:{pk:''}, mainview:{show:true}, slug:'table2'} | ||
| }; | ||
| var r = routes.init(settings, {}); | ||
| should.deepEqual(r.editview, /.*\/(.+|add)\/?$/); | ||
| done(); | ||
| }); | ||
| // custom views | ||
| it('skip custom views without app key', function (done) { | ||
| var custom = { | ||
| custom1: {app: {mainview:{show:true}, slug:'custom1'}}, | ||
| custom2: {public: {local:{path:'...', js:['..']}}} | ||
| }; | ||
| var r = routes.init({}, custom); | ||
| should.deepEqual(r.custom, /^\/(custom1)(?:\/.*)?\/?$/); | ||
| done(); | ||
| }); | ||
| it('skip custom views hidden in mainview', function (done) { | ||
| var custom = { | ||
| custom1: {app: {mainview:{show:true}, slug:'custom1'}}, | ||
| custom2: {app: {mainview:{show:false}, slug:'custom2'}} | ||
| }; | ||
| var r = routes.init({}, custom); | ||
| should.deepEqual(r.custom, /^\/(custom1)(?:\/.*)?\/?$/); | ||
| done(); | ||
| }); | ||
| it('return null on zero custom view slugs', function (done) { | ||
| var custom = { | ||
| custom1: {app: {mainview:{show:false}, slug:'custom1'}}, | ||
| custom2: {public: {local:{path:'...', js:['..']}}} | ||
| }; | ||
| var r = routes.init({}, custom); | ||
| should.deepEqual(r.custom, null); | ||
| done(); | ||
| }); | ||
| }); |
| var should = require('should'); | ||
| var settings = require('../../lib/app/settings'); | ||
| describe('settings', function () { | ||
| it.skip('should not add table without primary key', function (done) { | ||
| done(); | ||
| }); | ||
| it('set table primary key', function (done) { | ||
| var data = { | ||
| table1: { | ||
| id: { | ||
| type: 'int(11)', | ||
| allowNull: false, | ||
| key: 'pri', | ||
| defaultValue: null, | ||
| extra: 'auto_increment' | ||
| }, | ||
| name: { | ||
| type: 'varchar(45)', | ||
| allowNull: false, | ||
| key: '', | ||
| defaultValue: null, | ||
| extra: '' | ||
| } | ||
| } | ||
| } | ||
| var result = settings.refresh({}, data); | ||
| result.table1.table.pk.should.equal('id'); | ||
| done(); | ||
| }); | ||
| it('add new column', function (done) { | ||
| var config = { | ||
| table1: { | ||
| columns:[{name:'id'}] | ||
| } | ||
| }; | ||
| var data = { | ||
| table1: { | ||
| id: { | ||
| type: 'int(11)', | ||
| allowNull: false, | ||
| key: 'pri', | ||
| defaultValue: null, | ||
| extra: 'auto_increment' | ||
| }, | ||
| name: { | ||
| type: 'varchar(45)', | ||
| allowNull: false, | ||
| key: '', | ||
| defaultValue: null, | ||
| extra: '' | ||
| } | ||
| } | ||
| } | ||
| var result = settings.refresh(config, data); | ||
| should.deepEqual(result.table1.columns[0], config.table1.columns[0]); | ||
| result.table1.columns[1].name.should.equal('name'); | ||
| done(); | ||
| }); | ||
| it('add new table', function (done) { | ||
| var config = { | ||
| table1: { | ||
| columns:[{name:'id'}] | ||
| } | ||
| }; | ||
| var data = { | ||
| table2: { | ||
| id: { | ||
| type: 'int(11)', | ||
| allowNull: false, | ||
| key: 'pri', | ||
| defaultValue: null, | ||
| extra: 'auto_increment' | ||
| } | ||
| } | ||
| } | ||
| var result = settings.refresh(config, data); | ||
| should.deepEqual(result.table1, config.table1); | ||
| should.exist(result.table2); | ||
| done(); | ||
| }); | ||
| }); |
| var path = require('path'); | ||
| validate = require(path.resolve(__dirname, '../../lib/app/validate')); | ||
| describe('validate', function () { | ||
| it('should test admin password validation', function (done) { | ||
| var test = { | ||
| valid: [ 'aaAA11' ], | ||
| invalid: [ 'aAA11', 'aaA11', 'aaAA1'] | ||
| }; | ||
| for (var i=0; i < test.valid.length; i++) { | ||
| validate.adminPassword(test.valid[i]).should.equal(true); | ||
| } | ||
| for (var i=0; i < test.invalid.length; i++) { | ||
| validate.adminPassword(test.invalid[i]).should.equal(false); | ||
| } | ||
| done(); | ||
| }); | ||
| }); |
| var fs = require('fs'), | ||
| path = require('path'), | ||
| should = require('should'); | ||
| var app = require('../../app'); | ||
| describe('database initialization', function () { | ||
| it('return an error on wrong database', function (done) { | ||
| var args = {config: {mysql:{ | ||
| database:'non-existent', user: 'liolio', password: 'karamba' | ||
| }}}; | ||
| app.initDatabase(args, function (err) { | ||
| err.code.should.equal('ER_DBACCESS_DENIED_ERROR'); | ||
| err.message.should.equal("ER_DBACCESS_DENIED_ERROR: Access denied for user 'liolio'@'localhost' to database 'non-existent'"); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('return an error on wrong user name', function (done) { | ||
| var args = {config: {mysql:{ | ||
| database:'express-admin-simple', user: 'liolio1', password: 'karamba' | ||
| }}}; | ||
| app.initDatabase(args, function (err) { | ||
| err.message.should.equal("ER_ACCESS_DENIED_ERROR: Access denied for user 'liolio1'@'localhost' (using password: YES)"); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('return an error on wrong user\'s password', function (done) { | ||
| var args = {config: {mysql:{ | ||
| database:'express-admin-simple', user: 'liolio', password: 'karamba1' | ||
| }}}; | ||
| app.initDatabase(args, function (err) { | ||
| err.message.should.equal("ER_ACCESS_DENIED_ERROR: Access denied for user 'liolio'@'localhost' (using password: YES)"); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('return an error on empty schema', function (done) { | ||
| var args = { | ||
| config: {mysql:{ | ||
| database:'express-admin-empty', user: 'liolio', password: 'karamba' | ||
| }}, | ||
| dpath: __dirname, | ||
| settings: {} | ||
| }; | ||
| app.initDatabase(args, function (err) { | ||
| err.message.should.equal('Empty schema!'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('write the settings to the hard drive', function (done) { | ||
| var args = { | ||
| config: {mysql:{ | ||
| database:'express-admin-simple', user: 'liolio', password: 'karamba' | ||
| }}, | ||
| dpath: __dirname, | ||
| settings: {} | ||
| }; | ||
| app.initDatabase(args, function (err) { | ||
| if (err) return done(err); | ||
| should.notDeepEqual(require(path.join(__dirname, 'settings.json')), {}); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('refresh the settings', function (done) { | ||
| var args = { | ||
| config: {mysql:{ | ||
| database:'express-admin-simple', user: 'liolio', password: 'karamba' | ||
| }}, | ||
| dpath: __dirname, | ||
| settings: {} | ||
| }; | ||
| app.initDatabase(args, function (err) { | ||
| if (err) return done(err); | ||
| should.notDeepEqual(args.settings, {}); | ||
| done(); | ||
| }); | ||
| }); | ||
| after(function () { | ||
| fs.unlinkSync(path.join(__dirname, 'settings.json')); | ||
| }); | ||
| }); |
| var express = require('express'), | ||
| supertest = require('supertest'); | ||
| var expressAdmin = require('../../app'); | ||
| describe('embedding', function () { | ||
| var app = null; | ||
| before(function (done) { | ||
| app = express(); | ||
| app.get('/', function (req, res) { | ||
| res.send('Hello World'); | ||
| }); | ||
| var admin = expressAdmin.initServer({ | ||
| config: {app:{}}, | ||
| langs:{en:{'access-denied':'test'}} | ||
| }); | ||
| app.use('/admin', admin); | ||
| done(); | ||
| }); | ||
| it('serve holder app route', function (done) { | ||
| supertest(app) | ||
| .get('/') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.text.should.equal('Hello World'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('serve admin route', function (done) { | ||
| supertest(app) | ||
| .get('/admin/login') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.text.should.match(/Express Admin/); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); |
| var fs = require('fs'), | ||
| path = require('path'), | ||
| supertest = require('supertest'); | ||
| var app = require('../../app'); | ||
| describe('server initialization', function () { | ||
| // test auth status middleware | ||
| describe('static files', function () { | ||
| it('serve a static file from public dir', function (done) { | ||
| supertest(app.initServer({})) | ||
| .get('/express-admin.css') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.status.should.equal(200); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('serve a static file from express-admin-static dir', function (done) { | ||
| supertest(app.initServer({})) | ||
| .get('/csslib/bootstrap.min.css') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.status.should.equal(200); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| describe('custom static files', function () { | ||
| var args = {config:{app:{}}, langs:{en:{'access-denied':'test'}}}; | ||
| it('skip on missing public key', function (done) { | ||
| args.custom = {view1:{css:['/custom.css']}}; | ||
| supertest(app.initServer(args)) | ||
| .get('/custom.css') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.status.should.equal(302); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('skip on missing public.local key', function (done) { | ||
| args.custom = {view1:{public:{css:['/custom.css']}}}; | ||
| supertest(app.initServer(args)) | ||
| .get('/custom.css') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.status.should.equal(302); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('skip on missing public.local.path key', function (done) { | ||
| args.custom = {view1:{public:{local:{css:['/custom.css']}}}}; | ||
| supertest(app.initServer(args)) | ||
| .get('/custom.css') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.status.should.equal(302); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('skip on non existing location', function (done) { | ||
| args.custom = {view1:{public:{local:{ | ||
| path:path.resolve(__dirname, '../fixtures/non-existing'), | ||
| css:['/custom.css']}}}}; | ||
| supertest(app.initServer(args)) | ||
| .get('/custom.css') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.status.should.equal(302); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('serve a static file from custom dir', function (done) { | ||
| args.custom = {view1:{public:{local:{ | ||
| path:path.resolve(__dirname, '../fixtures/custom'), | ||
| css:['/custom.css']}}}}; | ||
| supertest(app.initServer(args)) | ||
| .get('/custom.css') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.status.should.equal(200); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| describe('server wide middleware', function () { | ||
| var args = {config:{app:{}}, langs:{en:{'access-denied':'test'}}}; | ||
| it('set lang cookie to en by default', function (done) { | ||
| supertest(app.initServer(args)) | ||
| .get('/') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.headers['set-cookie'][0] | ||
| .should.match(/lang=en; Max-Age=900000; Path=\/; Expires=.*/i); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('set session cookie under the express-admin key', function (done) { | ||
| supertest(app.initServer(args)) | ||
| .get('/') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.headers['set-cookie'][1] | ||
| .should.match(/express-admin=.*; Path=\/; HttpOnly/i); | ||
| done(); | ||
| }); | ||
| }); | ||
| it.skip('set template variables', function (done) { | ||
| // template variables should be tested separately | ||
| done(); | ||
| }); | ||
| it.skip('set special var used in custom views', function (done) { | ||
| // this will be tested in custom views below | ||
| done(); | ||
| }); | ||
| }); | ||
| describe('custom views', function () { | ||
| var args = {config:{app:{}}, | ||
| settings: {table1:{slug:'table1', table:{pk:'id'}, mainview:{show:true}}}, | ||
| langs:{en:{'access-denied':'test'}}, debug:true}; | ||
| it('skip on missing app key', function (done) { | ||
| args.custom = {view1:{ | ||
| slug:'view1', verbose:'view1', mainview:{show:true}}}; | ||
| supertest(app.initServer(args)) | ||
| .get('/view1') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.text.should.match(/<h1>404<\/h1>/); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('skip on missing app.path key', function (done) { | ||
| args.custom = {view1:{app:{ | ||
| slug:'view1', verbose:'view1', mainview:{show:true}}}}; | ||
| supertest(app.initServer(args)) | ||
| .get('/view1') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.text.should.match(/<h1>404<\/h1>/); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('skip on non existing location', function (done) { | ||
| args.custom = {view1:{app:{ | ||
| path: path.resolve(__dirname, '../fixtures/custom/app'), | ||
| slug:'view1', verbose:'view1', mainview:{show:true}}}}; | ||
| supertest(app.initServer(args)) | ||
| .get('/view1') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.text.should.match(/<h1>404<\/h1>/); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('serve custom view', function (done) { | ||
| args.custom = {view1:{app:{ | ||
| path: path.resolve(__dirname, '../fixtures/custom/app.js'), | ||
| slug:'view1', verbose:'view1', mainview:{show:true}}}}; | ||
| supertest(app.initServer(args)) | ||
| .get('/view1') | ||
| .end(function (err, res) { | ||
| if (err) return done(err); | ||
| res.text.should.match(/<p>This is the simplest custom view that you can get.<\/p>/); | ||
| done(); | ||
| }); | ||
| }); | ||
| it.skip('add an all callback for rendering at the end', function (done) { | ||
| done(); | ||
| }); | ||
| }); | ||
| }); |
| var fs = require('fs'), | ||
| path = require('path'), | ||
| should = require('should'); | ||
| var app = require('../../app'), | ||
| cli = require('../../lib/app/cli'); | ||
| describe('settings initialization', function () { | ||
| // route variables | ||
| describe('upload', function () { | ||
| before(function () { | ||
| if (fs.existsSync(path.join(__dirname, 'upload'))) | ||
| fs.rmdirSync(path.join(__dirname, 'upload')); | ||
| }); | ||
| it('set default upload location', function (done) { | ||
| var args = {config:{app:{}}}; | ||
| app.initSettings(args); | ||
| args.config.app.upload.should.match(/^\/.*\/public\/upload$/); | ||
| done(); | ||
| }); | ||
| it('set upload location as specified in config', function (done) { | ||
| var args = {config:{app:{upload:path.join(__dirname, 'upload')}}}; | ||
| app.initSettings(args); | ||
| args.config.app.upload.should.equal(path.join(__dirname, 'upload')); | ||
| done(); | ||
| }); | ||
| it('create upload directory if not exists', function (done) { | ||
| fs.existsSync(path.join(__dirname, 'upload')).should.equal(true); | ||
| done(); | ||
| }); | ||
| after(function () { | ||
| fs.rmdirSync(path.join(__dirname, 'upload')); | ||
| }); | ||
| }); | ||
| describe('langs/slugs', function () { | ||
| it('load all available languages', function (done) { | ||
| var files = fs.readdirSync(path.resolve(__dirname, '../../config/lang')); | ||
| var args = {config:{app:{}}}; | ||
| app.initSettings(args); | ||
| Object.keys(args.langs).length.should.equal(files.length); | ||
| for (var i=0; i < files.length; i++) { | ||
| var name = files[i].replace(path.extname(files[i]), ''); | ||
| should.exists(args.langs[name]); | ||
| } | ||
| done(); | ||
| }); | ||
| it('creates slug to table name mapping', function (done) { | ||
| var args = {config:{app:{}}, | ||
| settings:{table1:{slug:'slug1'}, table2:{slug:'slug2'}}}; | ||
| app.initSettings(args); | ||
| should.deepEqual(args.slugs, {slug1:'table1', slug2:'table2'}); | ||
| done(); | ||
| }); | ||
| }); | ||
| describe('debug', function () { | ||
| it('set debug mode through config', function (done) { | ||
| var args = {config:{app:{debug:true}}}; | ||
| app.initSettings(args); | ||
| args.debug.should.equal(true); | ||
| done(); | ||
| }); | ||
| it('set debug mode through cli', function (done) { | ||
| var args = {config:{app:{}}}; | ||
| cli.dev = true; | ||
| app.initSettings(args); | ||
| args.debug.should.equal(true); | ||
| done(); | ||
| }); | ||
| }); | ||
| describe('events', function () { | ||
| it('add default mocks if custom event hooks are not defined', function (done) { | ||
| var args = {config:{app:{}}, | ||
| custom:{view1:{}, app2:{}}}; | ||
| app.initSettings(args); | ||
| args.events.preSave('req', 'res', args, function () { | ||
| args.events.postSave('req', 'res', args, done); | ||
| }); | ||
| }); | ||
| it('load custom event hooks', function (done) { | ||
| var args = {config:{app:{}}, | ||
| custom:{view1:{}, app2:{ | ||
| events:path.resolve(__dirname, '../fixtures/custom/events.js')}}}; | ||
| app.initSettings(args); | ||
| args.events.preSave('req', 'res', args, function () { | ||
| args.preSave.should.equal(true); | ||
| args.events.postSave('req', 'res', args, function () { | ||
| args.postSave.should.equal(true); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
| // template variables | ||
| describe('root', function () { | ||
| it('set app root to empty string by default', function (done) { | ||
| var args = {config:{app:{}}}; | ||
| app.initSettings(args); | ||
| args.config.app.root.should.equal(''); | ||
| done(); | ||
| }); | ||
| it('set app root as specified in config', function (done) { | ||
| var args = {config:{app:{root:'/admin'}}}; | ||
| app.initSettings(args); | ||
| args.config.app.root.should.equal('/admin'); | ||
| done(); | ||
| }); | ||
| it('remove trailing / from app root', function (done) { | ||
| var args = {config:{app:{root:'/admin/'}}}; | ||
| app.initSettings(args); | ||
| args.config.app.root.should.equal('/admin'); | ||
| done(); | ||
| }); | ||
| }); | ||
| describe('layouts/themes/languages', function () { | ||
| it('set layouts flag as specified in config', function (done) { | ||
| var args = {config:{app:{layouts:false}}}; | ||
| app.initSettings(args); | ||
| args.layouts.should.equal(false); | ||
| done(); | ||
| }); | ||
| it('skip themes if disabled in config', function (done) { | ||
| var args = {config:{app:{themes:false}}}; | ||
| app.initSettings(args); | ||
| should.equal(args.themes, null); | ||
| done(); | ||
| }); | ||
| it('load themes if enabled in config', function (done) { | ||
| var args = {config:{app:{themes:true}}}; | ||
| app.initSettings(args); | ||
| should.deepEqual(args.themes.theme, require('../../config/themes')); | ||
| done(); | ||
| }); | ||
| it('skip languages if disabled in config', function (done) { | ||
| var args = {config:{app:{languages:false}}}; | ||
| app.initSettings(args); | ||
| should.equal(args.languages, null); | ||
| done(); | ||
| }); | ||
| it('load languages if enabled in config', function (done) { | ||
| var args = {config:{app:{languages:true}}}; | ||
| app.initSettings(args); | ||
| var files = fs.readdirSync(path.resolve(__dirname, '../../config/lang')); | ||
| Object.keys(args.languages.language).length.should.equal(files.length); | ||
| done(); | ||
| }); | ||
| }); | ||
| describe('static', function () { | ||
| it('load static libs', function (done) { | ||
| var args = {config:{app:{}}}; | ||
| app.initSettings(args); | ||
| delete args.libs.external | ||
| should.deepEqual(args.libs, require('../../config/libs')); | ||
| done(); | ||
| }); | ||
| it('append custom local libs to the static libs', function (done) { | ||
| var args = {config:{app:{}}, custom:{ | ||
| app1:{public:{local:{css:['/1.css'], js:['/1.js']}}} | ||
| }}; | ||
| app.initSettings(args); | ||
| args.libs.css.indexOf('/1.css').should.not.equal(-1); | ||
| args.libs.js.indexOf('/1.js').should.not.equal(-1); | ||
| done(); | ||
| }); | ||
| it('append custom external libs to the static external libs', function (done) { | ||
| var args = {config:{app:{}}, custom:{ | ||
| app1:{public:{external:{css:['//1.css'], js:['//1.js']}}} | ||
| }}; | ||
| app.initSettings(args); | ||
| args.libs.external.css.indexOf('//1.css').should.not.equal(-1); | ||
| args.libs.external.js.indexOf('//1.js').should.not.equal(-1); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); |
| { | ||
| "initial": [ | ||
| "manyToOne[controls][records][0][pk]", | ||
| "manyToOne[controls][records][0][columns][controls_choice_id]", | ||
| "manyToOne[controls][records][0][columns][group]", | ||
| "manyToOne[controls][records][0][columns][text]", | ||
| "manyToOne[controls][records][0][columns][date]", | ||
| "manyToOne[controls][records][0][columns][textarea]", | ||
| "manyToOne[controls][blank][index][insert]", | ||
| "manyToOne[controls][blank][index][columns][controls_choice_id]", | ||
| "manyToOne[controls][blank][index][columns][group]", | ||
| "manyToOne[controls][blank][index][columns][text]", | ||
| "manyToOne[controls][blank][index][columns][date]", | ||
| "manyToOne[controls][blank][index][columns][textarea]" | ||
| ], | ||
| "one": [ | ||
| "manyToOne[controls][records][1][insert]", | ||
| "manyToOne[controls][records][1][columns][controls_choice_id]", | ||
| "manyToOne[controls][records][1][columns][group]", | ||
| "manyToOne[controls][records][1][columns][text]", | ||
| "manyToOne[controls][records][1][columns][date]", | ||
| "manyToOne[controls][records][1][columns][textarea]" | ||
| ], | ||
| "two": [ | ||
| "manyToOne[controls][records][2][insert]", | ||
| "manyToOne[controls][records][2][columns][controls_choice_id]", | ||
| "manyToOne[controls][records][2][columns][group]", | ||
| "manyToOne[controls][records][2][columns][text]", | ||
| "manyToOne[controls][records][2][columns][date]", | ||
| "manyToOne[controls][records][2][columns][textarea]" | ||
| ] | ||
| } |
| function addAnother () { | ||
| $('.add-another').trigger('click'); | ||
| } | ||
| function removeInline (index) { | ||
| $('tr:not(.blank) .remove').eq(index).trigger('click'); | ||
| } |
| <!DOCTYPE html> | ||
| <html> | ||
| <head> | ||
| <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> | ||
| <title>Express Admin Browser Tests</title> | ||
| <!-- style --> | ||
| <link href="/csslib/mocha.css" rel="stylesheet" type="text/css" media="all" /> | ||
| <style type="text/css"> | ||
| #admin { width: 100%; height: 600px; border: 0; } | ||
| </style> | ||
| <!-- test libs --> | ||
| <script src="/jslib/mocha.js" type="text/javascript" charset="utf-8"></script> | ||
| <script src="/jslib/chai.js" type="text/javascript" charset="utf-8"></script> | ||
| <!-- components --> | ||
| <script src="sr-file.js" type="text/javascript" charset="utf-8"></script> | ||
| <!-- jquery --> | ||
| <script src="/jslib/jquery-1.7.2.min.js" type="text/javascript" charset="utf-8"></script> | ||
| <!-- test suite --> | ||
| <script src="tests.js" type="text/javascript" charset="utf-8"></script> | ||
| </head> | ||
| <body> | ||
| <div id="mocha"></div> | ||
| <iframe id="admin" src="http://examples/controls/1"></iframe> | ||
| </body> | ||
| </html> |
| (function (name, root, factory) { | ||
| if (typeof exports == 'object') { | ||
| module.exports = factory(); | ||
| } else if (typeof define == 'function' && define.amd) { | ||
| define(factory); | ||
| } else { | ||
| root[name] = factory(); | ||
| } | ||
| }('file', this, function () { | ||
| var api = {}; | ||
| /** | ||
| * Read a file. | ||
| * | ||
| * @param {String} path | ||
| * @param {Function} callback | ||
| * @return {String} xhr.responseText | ||
| * @api public | ||
| */ | ||
| api.load = function (path, cb) { | ||
| var xhr = new XMLHttpRequest(), | ||
| params = '?preventCache='+new Date(); | ||
| xhr.onreadystatechange = function() { | ||
| if (xhr.readyState == 4) { | ||
| cb(null, xhr.responseText); | ||
| } | ||
| }; | ||
| xhr.open('GET', path+params, true); | ||
| try { | ||
| xhr.send(); | ||
| } catch (e) { | ||
| return cb(new Error('Couldn\'t load file')); | ||
| } | ||
| } | ||
| /** | ||
| * Read a list of files. | ||
| * | ||
| * @param {Array} paths | ||
| * @param {Function} callback | ||
| * @return {Object} result | ||
| * @api public | ||
| */ | ||
| api.loadList = function (paths, cb) { | ||
| var result = {}; | ||
| (function loop (index) { | ||
| if (index == paths.length) return cb(null, result); | ||
| file.load(paths[index], function (err, text) { | ||
| if (err) return cb(err); | ||
| result[paths[index]] = text; | ||
| loop(++index); | ||
| }); | ||
| }(0)); | ||
| } | ||
| return api; | ||
| })); |
| var should = chai.should(); | ||
| mocha.setup({ | ||
| ui: 'bdd', | ||
| globals: [''] | ||
| }); | ||
| var iframe = null, admin = null, fixtures = null; | ||
| $(function () { | ||
| $('#admin').on('load', function (e) { | ||
| var script = this.contentWindow.document.createElement('script'); | ||
| script.type = 'text/javascript'; | ||
| script.src = '/tests/iframe.js'; | ||
| this.contentWindow.document.body.appendChild(script); | ||
| iframe = this; | ||
| admin = $(this).contents(); | ||
| window.setTimeout(function () { | ||
| mocha.run(); | ||
| },1); | ||
| }); | ||
| }); | ||
| describe('admin', function () { | ||
| before(function (done) { | ||
| file.load('fixtures.json', function (err, data) { | ||
| fixtures = JSON.parse(data); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('initial keys', function (done) { | ||
| var keys = []; | ||
| $('#many tbody tr', admin).each(function (index) { | ||
| keys.push(getControl(this).attr('name')); | ||
| }); | ||
| keys.should.deep.equal(fixtures.initial); | ||
| done(); | ||
| }); | ||
| it('add one', function (done) { | ||
| iframe.contentWindow.addAnother(); | ||
| var keys = []; | ||
| $('#many tbody tr', admin).each(function (index) { | ||
| keys.push(getControl(this).attr('name')); | ||
| }); | ||
| keys.should.deep.equal(fixtures.initial.concat(fixtures.one)); | ||
| done(); | ||
| }); | ||
| it('add two', function (done) { | ||
| iframe.contentWindow.addAnother(); | ||
| var keys = []; | ||
| $('#many tbody tr', admin).each(function (index) { | ||
| keys.push(getControl(this).attr('name')); | ||
| }); | ||
| keys.should.deep.equal(fixtures.initial.concat(fixtures.one.concat(fixtures.two))); | ||
| done(); | ||
| }); | ||
| it('remove first', function (done) { | ||
| iframe.contentWindow.removeInline(0); | ||
| var keys = []; | ||
| $('#many tbody tr', admin).each(function (index) { | ||
| keys.push(getControl(this).attr('name')); | ||
| }); | ||
| keys.should.deep.equal(fixtures.initial.concat(fixtures.one)); | ||
| done(); | ||
| }); | ||
| }); | ||
| function getControl (self) { | ||
| if ($('.jumbotron > input', self).length) | ||
| return $('.jumbotron > input', self); | ||
| if ($('.form-group .form-control', self).length) | ||
| return $('.form-group .form-control', self); | ||
| } |
| var fs = require('fs'), | ||
| path = require('path'), | ||
| should = require('should'), | ||
| recursive = require('recursive-fs'); | ||
| require('colors'); | ||
| var prompt = require('./prompt'); | ||
| describe('app (cli)', function () { | ||
| before(function (done) { | ||
| var dpath = path.resolve(__dirname, 'project'); | ||
| recursive.rmdirr(dpath, function (err) { | ||
| fs.mkdirSync(path.resolve(__dirname, 'project')); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('return an error on non existing directory', function (done) { | ||
| var params = [ | ||
| path.resolve(__dirname, 'wrapper.js'), 'non-existing-dir', '-test-app'], | ||
| expected = 'Config directory path doesn\'t exists!'.red; | ||
| prompt.start(params, expected, function (err) { | ||
| done(err); | ||
| }); | ||
| }); | ||
| it('prompt for data on non existing config files', function (done) { | ||
| var params = [ | ||
| path.resolve(__dirname, 'wrapper.js'), | ||
| path.resolve(__dirname, 'project'), '-test-app']; | ||
| var data = [ | ||
| {in: 'mysql', out: 'Database name:'}, | ||
| {in: 'express-admin-simple', out: 'Database user:'}, | ||
| {in: 'liolio', out: 'Database password:'}, | ||
| {in: 'karamba', out: 'Server port:'}, | ||
| {in: '\n', out: 'Admin user:'}, | ||
| {in: 'admin', out: 'Admin password:'}, | ||
| {in: '11aaAA', out: 'end'} | ||
| ]; | ||
| prompt.start(params, 'Database type:', function (err) { | ||
| if (err) return done(err); | ||
| (function loop (i, cb) { | ||
| if (i == data.length) return cb(); | ||
| prompt.next(data[i].in, data[i].out, function (err) { | ||
| if (err) return cb(err); | ||
| loop(++i, cb); | ||
| }); | ||
| }(0, function (err) { | ||
| if (err) return done(err); | ||
| should.deepEqual(require('./project/custom'), {}); | ||
| should.deepEqual(require('./project/settings'), {}); | ||
| should.deepEqual(require('./project/config'), { | ||
| mysql: {database: 'express-admin-simple', user: 'liolio', password:'karamba'}, | ||
| server: {port: 3000}, | ||
| app: {layouts: true, themes: true, languages: true} | ||
| }); | ||
| JSON.stringify(require('./project/users')) | ||
| .should.match(/\{"admin":\{"name":"admin","admin":true,"salt":".*","hash":".*"\}\}/); | ||
| done(); | ||
| })); | ||
| }); | ||
| }); | ||
| it('start the admin on existing config files', function (done) { | ||
| var params = [ | ||
| path.resolve(__dirname, 'wrapper.js'), | ||
| path.resolve(__dirname, 'project'), '-test-app']; | ||
| prompt.start(params, 'end', function () { | ||
| done(); | ||
| }); | ||
| }); | ||
| after(function (done) { | ||
| var dpath = path.resolve(__dirname, 'project'); | ||
| recursive.rmdirr(dpath, done); | ||
| }); | ||
| }); |
-109
| var path = require('path'); | ||
| require('colors'); | ||
| var prompt = require('./prompt'); | ||
| describe('arguments (cli)', function () { | ||
| var mpath = path.resolve(__dirname, 'wrapper.js'), | ||
| tpath = path.resolve('../some/test/path'); | ||
| it('get config path without flags', function (done) { | ||
| var params = [mpath, tpath, '-test-args']; | ||
| prompt.start(params, tpath, done); | ||
| }); | ||
| it('get config path from --dev flag', function (done) { | ||
| var params = [mpath, '-v', tpath, '-test-args']; | ||
| prompt.start(params, tpath, done); | ||
| }); | ||
| }); | ||
| describe('prompt for mysql (cli)', function () { | ||
| before(function (done) { | ||
| var params = [path.resolve(__dirname, 'wrapper.js'), '-test-prompt']; | ||
| prompt.start(params, 'Database type:', done); | ||
| }); | ||
| // database | ||
| it('return error message on wrong database type', function (done) { | ||
| var expected = 'Valid database type is: mysql, sqlite or pg!'.red | ||
| + 'Database type:'; | ||
| prompt.next('mariadb', expected, done); | ||
| }); | ||
| it('set mysql as default database type', function (done) { | ||
| prompt.next('\n', 'Database name:', done); | ||
| }); | ||
| it('return error message on missing database credentials', function (done) { | ||
| var expected = 'Database credentials are required!'.red + 'Database name:'; | ||
| prompt.next('\n', expected, done); | ||
| }); | ||
| it('prompt for database name', function (done) { | ||
| prompt.next('express-admin', 'Database user:', done); | ||
| }); | ||
| it('prompt for database user', function (done) { | ||
| prompt.next('liolio', 'Database password:', done); | ||
| }); | ||
| it('prompt for database password', function (done) { | ||
| prompt.next('karamba', 'Server port:', done); | ||
| }); | ||
| // server | ||
| it('set 3000 as default server port', function (done) { | ||
| prompt.next('\n', 'Admin user:', done); | ||
| }); | ||
| // admin | ||
| it('return error message on missing admin user name', function (done) { | ||
| var expected = 'Administrator user name is required!'.red + 'Admin user:'; | ||
| prompt.next('\n', expected, done); | ||
| }); | ||
| it('prompt for admin user name', function (done) { | ||
| prompt.next('admin', 'Admin password:', done); | ||
| }); | ||
| it('return error message on invalid password', function (done) { | ||
| var expected = ('Must contains at least:' | ||
| + '2 lower case letters, 2 upper case letters and 2 digits').red | ||
| + 'Admin password:'; | ||
| prompt.next('11aaAa', expected, done); | ||
| }); | ||
| it('have mysql set up', function (done) { | ||
| var expected = '{"mysql":{"database":"express-admin","user":"liolio",'+ | ||
| '"password":"karamba"},"server":{"port":3000},'+ | ||
| '"user":{"name":"admin","pass":"11aaAA"}}'; | ||
| prompt.next('11aaAA', expected, done); | ||
| }); | ||
| }); | ||
| describe('prompt for pg (cli)', function () { | ||
| before(function (done) { | ||
| var params = [path.resolve(__dirname, 'wrapper.js'), '-test-prompt']; | ||
| prompt.start(params, 'Database type:', function () { | ||
| prompt.next('pg', 'Database name:', function () { | ||
| prompt.next('express-admin', 'Database user:', function () { | ||
| prompt.next('liolio', 'Database password:', done); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
| it('prompt for database schema', function (done) { | ||
| prompt.next('karamba', 'Database schema:', done); | ||
| }); | ||
| it('use the public schema by default', function (done) { | ||
| prompt.next('\n', 'Server port:', done); | ||
| }); | ||
| it('set the server port', function (done) { | ||
| prompt.next('4444', 'Admin user:', function () { | ||
| prompt.next('admin', 'Admin password:', done); | ||
| }); | ||
| }); | ||
| it('have pg set up', function (done) { | ||
| var expected = '{"pg":{"database":"express-admin","user":"liolio",'+ | ||
| '"password":"karamba","schema":"public"},"server":{"port":4444},'+ | ||
| '"user":{"name":"admin","pass":"11aaAA"}}'; | ||
| prompt.next('11aaAA', expected, done); | ||
| }); | ||
| }); |
| var spawn = require('child_process').spawn; | ||
| var child = null, | ||
| output = '', | ||
| expected = '', | ||
| response = null, | ||
| timeout = null; | ||
| exports.start = function (params, expect, callback) { | ||
| this.next(null, expect, callback); | ||
| child = spawn('node', params); | ||
| child.stdin.setEncoding('utf8'); | ||
| child.stdout.on('data', function (data) { | ||
| // console.log('> ' + data); | ||
| output += data.toString().trim().replace(/\r?\n|\r/g, ''); | ||
| if (output == expected || expected == 'end') response(); | ||
| clearTimeout(timeout); | ||
| timeout = setTimeout(function () { | ||
| response(new Error('Operation timed out!')); | ||
| }, 1500); | ||
| }); | ||
| child.stderr.on('data', function (data) { | ||
| // console.log('! ' + data); | ||
| output += data.toString().trim().replace(/\r?\n|\r/g, ''); | ||
| clearTimeout(timeout); | ||
| timeout = setTimeout(function () { | ||
| response(new Error(output)); | ||
| }, 1000); | ||
| }); | ||
| child.on('exit', function (code, signal) { | ||
| // console.log('$ ' + code + ' ' + signal); | ||
| }); | ||
| } | ||
| exports.next = function (input, expect, callback) { | ||
| output = ''; | ||
| expected = expect; | ||
| response = callback; | ||
| if (input != null) child.stdin.write(input); | ||
| } |
| var path = require('path'); | ||
| cli = require('../../lib/app/cli'), | ||
| app = require('../../app'); | ||
| var test = ''; | ||
| for (var i=0; i < process.argv.length; i++) { | ||
| if (process.argv[i].indexOf('-test') == 0) { | ||
| test = process.argv[i]; | ||
| break; | ||
| } | ||
| } | ||
| switch (test) { | ||
| case '-test-args': | ||
| console.log(cli.getConfigPath()); | ||
| break; | ||
| case '-test-prompt': | ||
| cli.promptForData(function (err, result) { | ||
| if (err) console.log(JSON.stringify({err: err.message})); | ||
| console.log(JSON.stringify(result)); | ||
| }); | ||
| break; | ||
| case '-test-app': | ||
| var args = { | ||
| dpath: path.resolve(cli.getConfigPath()) | ||
| } | ||
| app.initCommandLine(args, function () { | ||
| console.log('end'); | ||
| }); | ||
| break; | ||
| } |
| var path = require('path'), | ||
| should = require('should'), | ||
| Xsql = require('xsql'); | ||
| var Client = require('../../lib/db/client'), | ||
| qb = require('../../lib/qb'); | ||
| describe.skip('client (db)', function () { | ||
| describe('factory', function () { | ||
| it('return an error on not supported db type', function (done) { | ||
| var client = new Client({mongodb:{}}); | ||
| client.message.should.equal('Not supported database type!'); | ||
| done(); | ||
| }); | ||
| it('create db client instance based on config key', function (done) { | ||
| should.exist((new Client({mysql:{}})).client.createConnection); | ||
| should.exist((new Client({pg:{}})).client.Client); | ||
| should.exist((new Client({sqlite:{}})).client.Database); | ||
| done(); | ||
| }); | ||
| }); | ||
| describe('connect', function () { | ||
| it('set global var for sql modules', function (done) { | ||
| var client = new Client({mysql:{}}); | ||
| done(); | ||
| }); | ||
| it.skip('mysql - connects to database', function (done) { | ||
| var config = {mysql: | ||
| {database:'express-admin-examples', user:'liolio', password:'karamba'}}; | ||
| var client = new Client(config); | ||
| client.connect(config.mysql, function (err) { | ||
| if (err) return done(err); | ||
| client.config.schema.should.equal('express-admin-examples'); | ||
| client.connection.destroy(); | ||
| done(); | ||
| }); | ||
| }); | ||
| it.skip('pg - connects to database / set public schema by default', function (done) { | ||
| var config = {pg: | ||
| {database:'express-admin-examples', user:'liolio', password:'karamba'}}; | ||
| var client = new Client(config); | ||
| client.connect(config.pg, function (err) { | ||
| if (err) return done(err); | ||
| client.config.schema.should.equal('public'); | ||
| client.connection.end(); | ||
| done(); | ||
| }); | ||
| }); | ||
| it.skip('pg - connects to database / set schema name through config', function (done) { | ||
| var config = {pg: {database:'express-admin-examples', schema:'express', | ||
| user:'liolio', password:'karamba'}}; | ||
| var client = new Client(config); | ||
| client.connect(config.pg, function (err) { | ||
| if (err) return done(err); | ||
| client.config.schema.should.equal('express'); | ||
| client.connection.end(); | ||
| done(); | ||
| }); | ||
| }); | ||
| it.skip('sqlite - connects to database', function (done) { | ||
| var config = {sqlite:{database:sqlitedb}}; | ||
| var client = new Client(config); | ||
| client.connect(config.sqlite, function (err) { | ||
| if (err) return done(err); | ||
| client.config.schema.should.equal(''); | ||
| client.connection.close(); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| describe.skip('query', function () { | ||
| it('mysql - execute query', function (done) { | ||
| var config = {mysql: | ||
| {database:'express-admin-examples', user:'liolio', password:'karamba'}}; | ||
| var client = new Client(config); | ||
| client.connect(config.mysql, function (err) { | ||
| if (err) return done(err); | ||
| client.query('select * from `user`;', function (err, rows) { | ||
| if (err) return done(err); | ||
| rows.length.should.equal(3); | ||
| client.connection.destroy(); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| it('pg - execute query', function (done) { | ||
| var config = {pg: | ||
| {database:'express-admin-examples', user:'liolio', password:'karamba'}}; | ||
| var client = new Client(config); | ||
| client.connect(config.pg, function (err) { | ||
| if (err) return done(err); | ||
| client.query('select * from "user";', function (err, rows) { | ||
| if (err) return done(err); | ||
| rows.length.should.equal(3); | ||
| client.connection.end(); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| it('sqlite - execute query', function (done) { | ||
| var config = {sqlite:{database:sqlitedb}}; | ||
| var client = new Client(config); | ||
| client.connect(config.sqlite, function (err) { | ||
| if (err) return done(err); | ||
| client.query('select * from `user`;', function (err, rows) { | ||
| if (err) return done(err); | ||
| rows.length.should.equal(3); | ||
| client.connection.close(); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| it.skip('pg - insert query', function (done) { | ||
| // insert | ||
| done(new Error('Not implemented!')); | ||
| // remove | ||
| }); | ||
| it.skip('sqlite - insert query', function (done) { | ||
| // insert | ||
| done(new Error('Not implemented!')); | ||
| // remove | ||
| }); | ||
| }); | ||
| describe.skip('mysql - column settings', function () { | ||
| var columns = null; | ||
| before(function (done) { | ||
| var config = {mysql: | ||
| {database:'express-admin-examples', user:'liolio', password:'karamba'}}; | ||
| var client = new Client(config); | ||
| client.connect(config.mysql, function (err) { | ||
| if (err) return done(err); | ||
| var x = new Xsql({dialect:client.name, schema:client.config.schema}); | ||
| qb(x); | ||
| var sql = qb.partials.columns('controls', 'express-admin-examples'); | ||
| client.query(sql, function (err, rows) { | ||
| if (err) return done(err); | ||
| columns = client.getColumnsInfo(rows); | ||
| // console.log(JSON.stringify(columns, null, 4)); | ||
| client.connection.destroy(); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| it('set allow null', function (done) { | ||
| columns.id.allowNull.should.equal(false); | ||
| columns.text.allowNull.should.equal(true); | ||
| done(); | ||
| }); | ||
| it('set pk', function (done) { | ||
| columns.id.key.should.equal('pri'); | ||
| columns.text.key.should.equal(''); | ||
| done(); | ||
| }); | ||
| it.skip('set default value', function (done) { | ||
| done(); | ||
| }); | ||
| }); | ||
| describe.skip('pg - column settings', function () { | ||
| var columns = null; | ||
| before(function (done) { | ||
| var config = {pg: | ||
| {database:'express-admin-examples', user:'liolio', password:'karamba'}}; | ||
| var client = new Client(config); | ||
| client.connect(config.pg, function (err) { | ||
| if (err) return done(err); | ||
| var x = new Xsql({dialect:client.name, schema:client.config.schema}); | ||
| qb(x); | ||
| var sql = qb.partials.columns('controls', 'public'); | ||
| client.query(sql, function (err, rows) { | ||
| if (err) return done(err); | ||
| columns = client.getColumnsInfo(rows); | ||
| // console.log(JSON.stringify(columns, null, 4)); | ||
| client.connection.end(); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| it('set allow null', function (done) { | ||
| columns.id.allowNull.should.equal(false); | ||
| columns.text.allowNull.should.equal(true); | ||
| done(); | ||
| }); | ||
| it('set pk', function (done) { | ||
| columns.id.key.should.equal('pri'); | ||
| columns.text.key.should.equal(''); | ||
| done(); | ||
| }); | ||
| it.skip('set default value', function (done) { | ||
| done(); | ||
| }); | ||
| }); | ||
| describe.skip('sqlite - column settings', function () { | ||
| var columns = null; | ||
| before(function (done) { | ||
| var config = {sqlite:{database:sqlitedb}}; | ||
| var client = new Client(config); | ||
| client.connect(config.sqlite, function (err) { | ||
| if (err) return done(err); | ||
| var x = new Xsql({dialect:client.name, schema:client.config.schema}); | ||
| qb(x); | ||
| var sql = qb.partials.columns('controls', ''); | ||
| client.query(sql, function (err, rows) { | ||
| if (err) return done(err); | ||
| columns = client.getColumnsInfo(rows); | ||
| // console.log(JSON.stringify(columns, null, 4)); | ||
| client.connection.close(); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| it('set allow null', function (done) { | ||
| columns.text.allowNull.should.equal(true); | ||
| done(); | ||
| }); | ||
| it('set pk', function (done) { | ||
| columns.text.key.should.equal(''); | ||
| done(); | ||
| }); | ||
| it.skip('set default value', function (done) { | ||
| done(); | ||
| }); | ||
| }); | ||
| describe.skip('pg - data types', function () { | ||
| var columns = null; | ||
| before(function (done) { | ||
| var config = {pg: | ||
| {database:'express-admin-examples', user:'liolio', password:'karamba'}}; | ||
| var client = new Client(config); | ||
| client.connect(config.pg, function (err) { | ||
| if (err) return done(err); | ||
| var x = new Xsql({dialect:client.name, schema:client.config.schema}); | ||
| qb(x); | ||
| var sql = qb.partials.columns('controls', 'public'); | ||
| client.query(sql, function (err, rows) { | ||
| if (err) return done(err); | ||
| columns = client.getColumnsInfo(rows); | ||
| // console.log(JSON.stringify(columns, null, 4)); | ||
| client.connection.end(); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| it('double precision', function (done) { | ||
| columns.double.type.should.equal('double'); | ||
| done(); | ||
| }); | ||
| it.skip('numeric', function (done) { | ||
| done(); | ||
| }); | ||
| it.skip('numeric(0,0)', function (done) { | ||
| done(); | ||
| }); | ||
| it('time without time zone', function (done) { | ||
| columns.time.type.should.equal('time'); | ||
| done(); | ||
| }); | ||
| it('timestamp without time zone', function (done) { | ||
| columns.datetime.type.should.equal('timestamp'); | ||
| done(); | ||
| }); | ||
| it.skip('character', function (done) { | ||
| done(); | ||
| }); | ||
| it('character varying', function (done) { | ||
| columns.text.type.should.equal('varchar(45)'); | ||
| done(); | ||
| }); | ||
| it('boolean', function (done) { | ||
| columns.boolean.type.should.equal('char'); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); |
| var fs = require('fs'), | ||
| path = require('path'), | ||
| should = require('should'); | ||
| var Client = require('../../lib/db/client'), | ||
| schema = require('../../lib/db/schema'); | ||
| describe('schema (db)', function () { | ||
| var client = null; | ||
| before(function (done) { | ||
| var options = {database: 'express-admin-simple', user:'liolio', password:'karamba'}; | ||
| client = new Client({mysql:true}); | ||
| client.connect(options, done); | ||
| }); | ||
| it('get table names', function (done) { | ||
| schema.getTables(client, 'tables', function (err, tables) { | ||
| if (err) return done(err); | ||
| tables.join().should.equal( | ||
| 'item,property,purchase,recipe,recipe_ref,recipe_type,subtype,type,user'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('get table columns info', function (done) { | ||
| schema.getTables(client, 'tables', function (err, tables) { | ||
| if (err) return done(err); | ||
| schema.getColumns(client, tables[0], function (err, info) { | ||
| if (err) return done(err); | ||
| var columns = Object.keys(info); | ||
| columns.join().should.equal('id,name,notes'); | ||
| // may test column properties too | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| it('get schema columns info', function (done) { | ||
| schema.getData(client, function (err, columns) { | ||
| if (err) return done(err); | ||
| var tables = Object.keys(columns); | ||
| tables.join().should.equal( | ||
| 'item,property,purchase,recipe,recipe_ref,recipe_type,subtype,type,user'); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| describe.skip('schema mysql|pg', function () { | ||
| function getColumnsInfo (dbType, cb) { | ||
| var config = {}; | ||
| config[dbType] = {database:'express-admin-types', user:'liolio', password:'karamba'}; | ||
| db.connect(config, function (err) { | ||
| if (err) return cb(err); | ||
| var schema = new Schema(db); | ||
| schema.getAllColumns(cb); | ||
| }); | ||
| } | ||
| it('generate correct settings', function (done) { | ||
| getColumnsInfo('mysql', function (err, mysql) { | ||
| if (err) return done(err); | ||
| getColumnsInfo('pg', function (err, pg) { | ||
| if (err) return done(err); | ||
| // pk | ||
| mysql.datatypes.int.key.should.equal('pri'); | ||
| mysql.datatypes.int.key.should.equal(pg.datatypes.int.key); | ||
| // allow null | ||
| mysql.datatypes.int.allowNull.should.equal(false); | ||
| mysql.datatypes.int.allowNull.should.equal(pg.datatypes.int.allowNull); | ||
| should.deepEqual(pg.datatypes, { | ||
| boolean: { type: 'boolean', allowNull: true, key: '', defaultValue: null }, | ||
| smallint: { type: 'smallint', allowNull: true, key: '', defaultValue: null }, | ||
| int: { type: 'integer', allowNull: false, key: 'pri',defaultValue: null }, | ||
| integer: { type: 'integer', allowNull: true, key: '', defaultValue: null }, | ||
| bigint: { type: 'bigint', allowNull: true, key: '', defaultValue: null }, | ||
| real: { type: 'real', allowNull: true, key: '', defaultValue: null }, | ||
| float: { type: 'double', allowNull: true, key: '', defaultValue: null }, | ||
| 'float(3)': { type: 'real', allowNull: true, key: '', defaultValue: null }, | ||
| double: { type: 'double', allowNull: true, key: '', defaultValue: null }, | ||
| decimal: { type: 'decimal', allowNull: true, key: '', defaultValue: null }, | ||
| 'decimal(6)': { type: 'decimal(6,0)', allowNull: true, key: '', defaultValue: null }, | ||
| 'decimal(6,2)': { type: 'decimal(6,2)', allowNull: true, key: '', defaultValue: null }, | ||
| numeric: { type: 'decimal', allowNull: true, key: '', defaultValue: null }, | ||
| 'numeric(20)': { type: 'decimal(20,0)', allowNull: true, key: '', defaultValue: null }, | ||
| 'numeric(20,5)': { type: 'decimal(20,5)', allowNull: true, key: '', defaultValue: null }, | ||
| date: { type: 'date', allowNull: true, key: '', defaultValue: null }, | ||
| time: { type: 'time', allowNull: true, key: '', defaultValue: null }, | ||
| timestamp: { type: 'timestamp', allowNull: true, key: '', defaultValue: null }, | ||
| bit: { type: 'bit(1)', allowNull: true, key: '', defaultValue: null }, | ||
| char: { type: 'char(1)', allowNull: true, key: '', defaultValue: null }, | ||
| 'varchar(45)': { type: 'varchar(45)', allowNull: true, key: '', defaultValue: null }, | ||
| text: { type: 'text', allowNull: true, key: '', defaultValue: null } | ||
| }); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| }); |
| var should = require('should'), | ||
| Xsql = require('xsql'); | ||
| var Client = require('../../lib/db/client'), | ||
| data = require('../../lib/data'), | ||
| editview = require('../../lib/editview/index'), | ||
| qb = require('../../lib/qb'); | ||
| describe('data (editview)', function () { | ||
| var db = {}; | ||
| before(function (done) { | ||
| var options = { | ||
| database: 'express-admin-simple', | ||
| user: 'liolio', | ||
| password: 'karamba' | ||
| }; | ||
| db.client = new Client({mysql:true}); | ||
| db.client.connect(options, function (err) { | ||
| if (err) return done(err); | ||
| var x = new Xsql({dialect:db.client.name, schema:db.client.config.schema}); | ||
| qb = qb(x); | ||
| done(); | ||
| }); | ||
| }); | ||
| // _removeHidden | ||
| it('remove all columns configured to be excluded from the editview', function (done) { | ||
| var columns = [ | ||
| {name: 'pk', editview: {show: false}}, | ||
| {name: 'fk', editview: {show: false}}, | ||
| {name: 'name', editview: {show: true}} | ||
| ]; | ||
| var result = editview._removeHidden(columns); | ||
| columns.length.should.equal(3); | ||
| result.length.should.equal(1); | ||
| result[0].name.should.equal('name'); | ||
| done(); | ||
| }); | ||
| // _getData - get the referenced table data (oneToMany || manyToMany) | ||
| it('return the referenced table\'s data', function (done) { | ||
| var ref = {table: 'item', pk: 'id', columns: ['name']}; | ||
| data.otm._getData({db: db}, ref, function (err, rows) { | ||
| if (err) return done(err); | ||
| should.deepEqual(rows, [ | ||
| { __pk: '4', __text: 'cherries' }, | ||
| { __pk: '5', __text: 'chocolate' }, | ||
| { __pk: '1', __text: 'coffee' }, | ||
| { __pk: '3', __text: 'energy' }, | ||
| { __pk: '2', __text: 'tea' } | ||
| ]); | ||
| done(); | ||
| }); | ||
| }); | ||
| // getOneToMany - populates each column's value with its referenced table data | ||
| it('populate column\'s value configured through oneToMany key', function (done) { | ||
| var args = { | ||
| db: db, | ||
| config: { | ||
| columns: [ | ||
| { | ||
| control: {select: true}, | ||
| oneToMany: {table: 'item', pk: 'id', columns: ['name']} | ||
| } | ||
| ] | ||
| } | ||
| }; | ||
| data.otm.get(args, function (err) { | ||
| if (err) return done(err); | ||
| should.deepEqual(args.config.columns[0].value, [ | ||
| { __pk: '4', __text: 'cherries' }, | ||
| { __pk: '5', __text: 'chocolate' }, | ||
| { __pk: '1', __text: 'coffee' }, | ||
| { __pk: '3', __text: 'energy' }, | ||
| { __pk: '2', __text: 'tea' } | ||
| ]); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('populate column\'s value configured through manyToMany\'s ref key', function (done) { | ||
| var args = { | ||
| db: db, | ||
| config: { | ||
| columns: [ | ||
| { | ||
| control: {select: true, multiple: true}, | ||
| manyToMany: { | ||
| ref: { | ||
| table: 'recipe_type', pk: 'id', columns: ['name'] | ||
| } | ||
| } | ||
| } | ||
| ] | ||
| } | ||
| }; | ||
| data.otm.get(args, function (err) { | ||
| if (err) return done(err); | ||
| should.deepEqual(args.config.columns[0].value, [ | ||
| { __pk: '1', __text: 'type1' }, | ||
| { __pk: '2', __text: 'type2' }, | ||
| { __pk: '3', __text: 'type3' }, | ||
| { __pk: '4', __text: 'type4' }, | ||
| { __pk: '5', __text: 'type5' } | ||
| ]); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('skip columns without control type set to select', function (done) { | ||
| var args = { | ||
| db: db, | ||
| config: { | ||
| columns: [ | ||
| { | ||
| control: {text: true}, | ||
| oneToMany: {table: 'item', pk: 'id', columns: ['name']} | ||
| } | ||
| ] | ||
| } | ||
| }; | ||
| data.otm.get(args, function (err) { | ||
| if (err) return done(err); | ||
| should.strictEqual(args.config.columns[0].value, undefined); | ||
| done(); | ||
| }); | ||
| }); | ||
| // creates a sql select query for getting a record from table | ||
| it('prepend table\'s __pk to the list of columns to be selected', function (done) { | ||
| var args = { | ||
| id: 5, | ||
| fk: null, | ||
| config: { | ||
| table: {name: 'recipe', pk: 'id'}, | ||
| columns: [ | ||
| {name: 'column1'} | ||
| ] | ||
| } | ||
| }; | ||
| qb.tbl.select(args).should.match(/.*`recipe`.`id` as `__pk`.*/); | ||
| done(); | ||
| }); | ||
| it('exclude manyToMany columns from the list of columns to select', function (done) { | ||
| var args = { | ||
| id: 5, | ||
| fk: null, | ||
| config: { | ||
| table: {name: 'recipe', pk: 'id'}, | ||
| columns: [ | ||
| {name: 'column1'}, | ||
| {name: 'column2', manyToMany: {}} | ||
| ] | ||
| } | ||
| }; | ||
| qb.tbl.select(args) | ||
| .should.match(/^select `recipe`.`id` as `__pk`,`recipe`.`column1` from.*/); | ||
| done(); | ||
| }); | ||
| it('create a query for a regular table using its pk', function (done) { | ||
| var args = { | ||
| id: 5, | ||
| fk: null, | ||
| config: { | ||
| table: {name: 'recipe', pk: 'id'}, | ||
| columns: [ | ||
| {name: 'column1'} | ||
| ] | ||
| } | ||
| }; | ||
| qb.tbl.select(args).should.match(/.*where `recipe`.`id`=5 ;$/); | ||
| done(); | ||
| }); | ||
| it('create a query for a referenced table using its fk', function (done) { | ||
| var args = { | ||
| id: 5, | ||
| fk: 'recipe_id', | ||
| config: { | ||
| table: {name: 'recipe', pk: 'id'}, | ||
| columns: [ | ||
| {name: 'column1'} | ||
| ] | ||
| } | ||
| }; | ||
| qb.tbl.select(args).should.match(/.*where `recipe`.`recipe_id`=5 ;$/); | ||
| done(); | ||
| }); | ||
| // getRecords - get record/s for a table | ||
| it('return table\'s record/s from a database', function (done) { | ||
| var args = { | ||
| db: db, | ||
| post: null, | ||
| id: 5, | ||
| fk: null, | ||
| config: { | ||
| table: {name: 'item', pk: 'id'}, | ||
| columns: [{name: 'name'}, {name: 'notes'}] | ||
| } | ||
| }; | ||
| data.tbl.get(args, function (err, rows) { | ||
| if (err) return done(err); | ||
| should.deepEqual(rows, [{columns: {__pk: '5', name: 'chocolate', notes: ''}}]); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('return table\'s record/s from a post request', function (done) { | ||
| var args = { | ||
| db: db, | ||
| post: { | ||
| item: { | ||
| records: [{pk: 5, columns: {name: 'chocolate', notes: 'milka'}}] | ||
| } | ||
| }, | ||
| id: 5, | ||
| fk: null, | ||
| config: { | ||
| table: {name: 'item', pk: 'id'} | ||
| } | ||
| }; | ||
| data.tbl.get(args, function (err, rows) { | ||
| if (err) return done(err); | ||
| should.deepEqual(rows, [{pk: 5, columns:{name: 'chocolate', notes: 'milka'}}]); | ||
| done(); | ||
| }); | ||
| }); | ||
| // getIds - get manyToMany's link table child primary keys | ||
| it('store manyToMany\'s link table child primary keys in column itself after database select', function (done) { | ||
| var args = { | ||
| db: db, | ||
| config: { | ||
| columns: [ | ||
| { | ||
| name: 'recipeTypes', | ||
| manyToMany: { | ||
| link: { | ||
| table: 'recipe_ref', | ||
| parentPk: 'recipe_id', | ||
| childPk: 'recipe_type_id' | ||
| } | ||
| } | ||
| } | ||
| ] | ||
| } | ||
| }; | ||
| var rows = [{columns: {__pk: 1}}]; | ||
| data.mtm.get(args, rows, function (err) { | ||
| if (err) return done(err); | ||
| should.deepEqual(rows[0].columns.recipeTypes, ['2', '4', '5']); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('store manyToMany\'s link table child primary keys in the record\'s ids key after post request', function (done) { | ||
| var args = { | ||
| db: db, | ||
| post: true, | ||
| config: { | ||
| columns: [ | ||
| { | ||
| name: 'recipeTypes', | ||
| manyToMany: { | ||
| link: { | ||
| table: 'recipe_ref', | ||
| parentPk: 'recipe_id', | ||
| childPk: 'recipe_type_id' | ||
| } | ||
| } | ||
| } | ||
| ] | ||
| } | ||
| }; | ||
| var rows = [{columns: {__pk: 1}}]; | ||
| data.mtm.get(args, rows, function (err) { | ||
| if (err) return done(err); | ||
| should.deepEqual(rows[0].ids.recipeTypes, ['2', '4', '5']); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); |
| var should = require('should'); | ||
| var format = require('../../lib/format'); | ||
| describe('format (editview)', function () { | ||
| // setActiveSingle | ||
| it('set the active element for an oneToMany select control', function (done) { | ||
| var column = { | ||
| value: [ | ||
| { __pk: '4', __text: 'cherries' }, | ||
| { __pk: '5', __text: 'chocolate' }, | ||
| { __pk: '1', __text: 'coffee' }, | ||
| { __pk: '3', __text: 'energy' }, | ||
| { __pk: '2', __text: 'tea' } | ||
| ] | ||
| }; | ||
| format.form.setActiveSingle(column, 1); | ||
| column.value[2].selected.should.equal(true); | ||
| done(); | ||
| }); | ||
| // setActiveMultiple | ||
| it('set the active element for a manyToMany select control', function (done) { | ||
| var column = { | ||
| value: [ | ||
| { __pk: '4', __text: 'cherries' }, | ||
| { __pk: '5', __text: 'chocolate' }, | ||
| { __pk: '1', __text: 'coffee' }, | ||
| { __pk: '3', __text: 'energy' }, | ||
| { __pk: '2', __text: 'tea' } | ||
| ] | ||
| }; | ||
| format.form.setActiveMultiple(column, [5,2]); | ||
| column.value[1].selected.should.equal(true); | ||
| column.value[4].selected.should.equal(true); | ||
| done(); | ||
| }); | ||
| // value | ||
| it('get column\'s default value', function (done) { | ||
| var column = {control: {text: true}, defaultValue: 22.50}; | ||
| format.form.value(column, '').should.equal(22.50); | ||
| done(); | ||
| }); | ||
| it('skip value formatting on empty string', function (done) { | ||
| var column = {control: {text: true}}; | ||
| format.form.value(column, '').should.equal(''); | ||
| done(); | ||
| }); | ||
| it('return null on missing date value', function (done) { | ||
| var column = {control: {date: true}}; | ||
| should.equal(format.form.value(column, null), null); | ||
| done(); | ||
| }); | ||
| it('return the date values formatted as YYYY-MM-DD', function (done) { | ||
| var column = {control: {date: true}}; | ||
| format.form.value(column, '2013-10-23 00:00:00').should.equal('2013-10-23'); | ||
| done(); | ||
| }); | ||
| it('set the active item for a oneToMany select control', function (done) { | ||
| var column = { | ||
| control: {select: true}, | ||
| value: [ | ||
| { __pk: '4', __text: 'cherries' }, | ||
| { __pk: '5', __text: 'chocolate' }, | ||
| { __pk: '1', __text: 'coffee' }, | ||
| { __pk: '3', __text: 'energy' }, | ||
| { __pk: '2', __text: 'tea' } | ||
| ] | ||
| }; | ||
| format.form.value(column, 1); | ||
| column.value[2].selected.should.equal(true); | ||
| done(); | ||
| }); | ||
| it('set the active items for a manyToMany select control', function (done) { | ||
| var column = { | ||
| control: {select: true, multiple: true}, | ||
| value: [ | ||
| { __pk: '4', __text: 'cherries' }, | ||
| { __pk: '5', __text: 'chocolate' }, | ||
| { __pk: '1', __text: 'coffee' }, | ||
| { __pk: '3', __text: 'energy' }, | ||
| { __pk: '2', __text: 'tea' } | ||
| ] | ||
| }; | ||
| format.form.value(column, [5,2]); | ||
| column.value[1].selected.should.equal(true); | ||
| column.value[4].selected.should.equal(true); | ||
| done(); | ||
| }); | ||
| }); |
| var should = require('should'); | ||
| var validate = require('../../lib/editview/validate'); | ||
| describe('validate (editview)', function () { | ||
| // validate | ||
| it('return an error if a column isn\'t allowed to be null', function (done) { | ||
| var column = {name: 'price', allowNull: false, control: {}}, | ||
| message = 'Column '+column.name+' cannot be empty.'; | ||
| // text | ||
| validate.value(column, '').message.should.equal(message); | ||
| // select multiple | ||
| validate.value(column, []).message.should.equal(message); | ||
| // | ||
| validate.value(column, null).message.should.equal(message); | ||
| done(); | ||
| }); | ||
| it('return null (no error) if the column is allowed to be null', function (done) { | ||
| var column = {name: 'price', allowNull: true}; | ||
| should.equal(validate.value(column, null), null); | ||
| done(); | ||
| }); | ||
| }); |
| var express = require('express'); | ||
| var app = module.exports = express(); | ||
| var path = require('path'); | ||
| app.set('views', __dirname); | ||
| app.get('/view1', function (req, res, next) { | ||
| var relative = path.relative(res.locals._admin.views, app.get('views')); | ||
| res.locals.partials = { | ||
| content: path.join(relative, 'view') | ||
| }; | ||
| next(); | ||
| }); |
| exports.preSave = function (req, res, args, next) { | ||
| args.preSave = true; | ||
| next(); | ||
| } | ||
| exports.postSave = function (req, res, args, next) { | ||
| args.postSave = true; | ||
| next(); | ||
| } |
| <p>This is the simplest custom view that you can get.</p> |
| -- MySQL dump 10.13 Distrib 5.5.31, for debian-linux-gnu (i686) | ||
| -- | ||
| -- Host: localhost Database: express-admin-simple | ||
| -- ------------------------------------------------------ | ||
| -- Server version 5.5.31-0ubuntu0.12.04.1 | ||
| /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; | ||
| /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; | ||
| /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; | ||
| /*!40101 SET NAMES utf8 */; | ||
| /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; | ||
| /*!40103 SET TIME_ZONE='+00:00' */; | ||
| /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; | ||
| /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; | ||
| /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; | ||
| /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; | ||
| -- | ||
| -- Table structure for table `item` | ||
| -- | ||
| DROP TABLE IF EXISTS `item`; | ||
| /*!40101 SET @saved_cs_client = @@character_set_client */; | ||
| /*!40101 SET character_set_client = utf8 */; | ||
| CREATE TABLE `item` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `name` varchar(45) NOT NULL, | ||
| `notes` text, | ||
| PRIMARY KEY (`id`), | ||
| UNIQUE KEY `name_UNIQUE` (`name`) | ||
| ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; | ||
| /*!40101 SET character_set_client = @saved_cs_client */; | ||
| -- | ||
| -- Dumping data for table `item` | ||
| -- | ||
| LOCK TABLES `item` WRITE; | ||
| /*!40000 ALTER TABLE `item` DISABLE KEYS */; | ||
| INSERT INTO `item` VALUES (1,'coffee',''),(2,'tea',''),(3,'energy',''),(4,'cherries',''),(5,'chocolate',''); | ||
| /*!40000 ALTER TABLE `item` ENABLE KEYS */; | ||
| UNLOCK TABLES; | ||
| -- | ||
| -- Table structure for table `property` | ||
| -- | ||
| DROP TABLE IF EXISTS `property`; | ||
| /*!40101 SET @saved_cs_client = @@character_set_client */; | ||
| /*!40101 SET character_set_client = utf8 */; | ||
| CREATE TABLE `property` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `item_id` int(11) NOT NULL, | ||
| `name` varchar(45) NOT NULL, | ||
| PRIMARY KEY (`id`), | ||
| UNIQUE KEY `name_UNIQUE` (`name`), | ||
| KEY `fk_property_item1_idx` (`item_id`), | ||
| CONSTRAINT `fk_property_item1` FOREIGN KEY (`item_id`) REFERENCES `item` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION | ||
| ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; | ||
| /*!40101 SET character_set_client = @saved_cs_client */; | ||
| -- | ||
| -- Dumping data for table `property` | ||
| -- | ||
| LOCK TABLES `property` WRITE; | ||
| /*!40000 ALTER TABLE `property` DISABLE KEYS */; | ||
| INSERT INTO `property` VALUES (1,1,'caffeine'),(2,2,'hot'),(3,3,'stimulant'); | ||
| /*!40000 ALTER TABLE `property` ENABLE KEYS */; | ||
| UNLOCK TABLES; | ||
| -- | ||
| -- Table structure for table `purchase` | ||
| -- | ||
| DROP TABLE IF EXISTS `purchase`; | ||
| /*!40101 SET @saved_cs_client = @@character_set_client */; | ||
| /*!40101 SET character_set_client = utf8 */; | ||
| CREATE TABLE `purchase` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `item_id` int(11) NOT NULL, | ||
| `user_id` int(11) DEFAULT NULL, | ||
| `cache` decimal(6,2) unsigned NOT NULL, | ||
| `date` datetime DEFAULT NULL, | ||
| PRIMARY KEY (`id`), | ||
| KEY `fk_purchase_user_idx` (`user_id`), | ||
| KEY `fk_purchase_item1_idx` (`item_id`), | ||
| CONSTRAINT `fk_purchase_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, | ||
| CONSTRAINT `fk_purchase_item1` FOREIGN KEY (`item_id`) REFERENCES `item` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION | ||
| ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8; | ||
| /*!40101 SET character_set_client = @saved_cs_client */; | ||
| -- | ||
| -- Dumping data for table `purchase` | ||
| -- | ||
| LOCK TABLES `purchase` WRITE; | ||
| /*!40000 ALTER TABLE `purchase` DISABLE KEYS */; | ||
| INSERT INTO `purchase` VALUES (1,1,3,17.50,'2012-01-27 00:00:00'),(2,3,2,18.99,'2012-05-23 00:00:00'),(3,5,1,5.40,'2012-07-06 00:00:00'),(4,4,2,20.00,'2012-03-09 00:00:00'),(5,2,3,50.00,'2012-12-29 00:00:00'),(6,1,1,18.00,'2012-11-16 00:00:00'),(7,3,2,9.00,'2012-09-18 00:00:00'),(8,4,3,3.50,'2012-08-03 00:00:00'),(9,5,1,19.00,'2012-10-09 00:00:00'),(10,4,2,2.00,'2012-05-13 00:00:00'),(11,3,3,1.00,'2012-09-21 00:00:00'),(12,1,2,12.60,'2012-12-26 00:00:00'),(13,2,1,40.00,'2012-11-18 00:00:00'),(14,3,2,16.00,'2012-04-15 00:00:00'),(15,4,3,9.00,'2012-11-06 00:00:00'); | ||
| /*!40000 ALTER TABLE `purchase` ENABLE KEYS */; | ||
| UNLOCK TABLES; | ||
| -- | ||
| -- Table structure for table `recipe` | ||
| -- | ||
| DROP TABLE IF EXISTS `recipe`; | ||
| /*!40101 SET @saved_cs_client = @@character_set_client */; | ||
| /*!40101 SET character_set_client = utf8 */; | ||
| CREATE TABLE `recipe` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `item_id` int(11) NOT NULL, | ||
| `name` varchar(45) NOT NULL, | ||
| PRIMARY KEY (`id`), | ||
| UNIQUE KEY `name_UNIQUE` (`name`), | ||
| KEY `fk_sub_item_item1` (`item_id`), | ||
| CONSTRAINT `fk_sub_item_item10` FOREIGN KEY (`item_id`) REFERENCES `item` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION | ||
| ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; | ||
| /*!40101 SET character_set_client = @saved_cs_client */; | ||
| -- | ||
| -- Dumping data for table `recipe` | ||
| -- | ||
| LOCK TABLES `recipe` WRITE; | ||
| /*!40000 ALTER TABLE `recipe` DISABLE KEYS */; | ||
| INSERT INTO `recipe` VALUES (1,1,'recipe 1'),(2,1,'recipe 2'),(3,1,'recipe 3'),(4,2,'recipe 4'),(5,2,'recipe 5'),(6,3,'recipe 6'),(7,3,'recipe 7'),(8,4,'recipe 8'),(9,5,'recipe 9'); | ||
| /*!40000 ALTER TABLE `recipe` ENABLE KEYS */; | ||
| UNLOCK TABLES; | ||
| -- | ||
| -- Table structure for table `recipe_ref` | ||
| -- | ||
| DROP TABLE IF EXISTS `recipe_ref`; | ||
| /*!40101 SET @saved_cs_client = @@character_set_client */; | ||
| /*!40101 SET character_set_client = utf8 */; | ||
| CREATE TABLE `recipe_ref` ( | ||
| `recipe_id` int(11) NOT NULL, | ||
| `recipe_type_id` int(11) NOT NULL, | ||
| PRIMARY KEY (`recipe_id`,`recipe_type_id`), | ||
| KEY `fk_recipe_has_recipe_type_recipe_type1_idx` (`recipe_type_id`), | ||
| KEY `fk_recipe_has_recipe_type_recipe1_idx` (`recipe_id`), | ||
| CONSTRAINT `fk_recipe_has_recipe_type_recipe1` FOREIGN KEY (`recipe_id`) REFERENCES `recipe` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, | ||
| CONSTRAINT `fk_recipe_has_recipe_type_recipe_type1` FOREIGN KEY (`recipe_type_id`) REFERENCES `recipe_type` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION | ||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8; | ||
| /*!40101 SET character_set_client = @saved_cs_client */; | ||
| -- | ||
| -- Dumping data for table `recipe_ref` | ||
| -- | ||
| LOCK TABLES `recipe_ref` WRITE; | ||
| /*!40000 ALTER TABLE `recipe_ref` DISABLE KEYS */; | ||
| INSERT INTO `recipe_ref` VALUES (2,1),(3,1),(7,1),(1,2),(2,2),(3,2),(6,2),(8,2),(9,2),(2,3),(7,3),(1,4),(5,4),(7,4),(9,4),(1,5),(6,5); | ||
| /*!40000 ALTER TABLE `recipe_ref` ENABLE KEYS */; | ||
| UNLOCK TABLES; | ||
| -- | ||
| -- Table structure for table `recipe_type` | ||
| -- | ||
| DROP TABLE IF EXISTS `recipe_type`; | ||
| /*!40101 SET @saved_cs_client = @@character_set_client */; | ||
| /*!40101 SET character_set_client = utf8 */; | ||
| CREATE TABLE `recipe_type` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `name` varchar(45) NOT NULL, | ||
| `notes` text NOT NULL, | ||
| PRIMARY KEY (`id`) | ||
| ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; | ||
| /*!40101 SET character_set_client = @saved_cs_client */; | ||
| -- | ||
| -- Dumping data for table `recipe_type` | ||
| -- | ||
| LOCK TABLES `recipe_type` WRITE; | ||
| /*!40000 ALTER TABLE `recipe_type` DISABLE KEYS */; | ||
| INSERT INTO `recipe_type` VALUES (1,'type1',''),(2,'type2',''),(3,'type3',''),(4,'type4',''),(5,'type5',''); | ||
| /*!40000 ALTER TABLE `recipe_type` ENABLE KEYS */; | ||
| UNLOCK TABLES; | ||
| -- | ||
| -- Table structure for table `subtype` | ||
| -- | ||
| DROP TABLE IF EXISTS `subtype`; | ||
| /*!40101 SET @saved_cs_client = @@character_set_client */; | ||
| /*!40101 SET character_set_client = utf8 */; | ||
| CREATE TABLE `subtype` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `name` varchar(45) NOT NULL, | ||
| PRIMARY KEY (`id`) | ||
| ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; | ||
| /*!40101 SET character_set_client = @saved_cs_client */; | ||
| -- | ||
| -- Dumping data for table `subtype` | ||
| -- | ||
| LOCK TABLES `subtype` WRITE; | ||
| /*!40000 ALTER TABLE `subtype` DISABLE KEYS */; | ||
| INSERT INTO `subtype` VALUES (1,'sub1'),(2,'sub2'),(3,'sub3'),(4,'sub4'),(5,'sub5'); | ||
| /*!40000 ALTER TABLE `subtype` ENABLE KEYS */; | ||
| UNLOCK TABLES; | ||
| -- | ||
| -- Table structure for table `type` | ||
| -- | ||
| DROP TABLE IF EXISTS `type`; | ||
| /*!40101 SET @saved_cs_client = @@character_set_client */; | ||
| /*!40101 SET character_set_client = utf8 */; | ||
| CREATE TABLE `type` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `item_id` int(11) NOT NULL, | ||
| `subtype_id` int(11) NOT NULL, | ||
| `name` varchar(45) NOT NULL, | ||
| PRIMARY KEY (`id`), | ||
| UNIQUE KEY `name_UNIQUE` (`name`), | ||
| KEY `fk_sub_item_item1_idx` (`item_id`), | ||
| KEY `fk_type_subtype1_idx` (`subtype_id`), | ||
| CONSTRAINT `fk_sub_item_item1` FOREIGN KEY (`item_id`) REFERENCES `item` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, | ||
| CONSTRAINT `fk_type_subtype1` FOREIGN KEY (`subtype_id`) REFERENCES `subtype` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION | ||
| ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; | ||
| /*!40101 SET character_set_client = @saved_cs_client */; | ||
| -- | ||
| -- Dumping data for table `type` | ||
| -- | ||
| LOCK TABLES `type` WRITE; | ||
| /*!40000 ALTER TABLE `type` DISABLE KEYS */; | ||
| INSERT INTO `type` VALUES (1,1,2,'Espresso'),(2,1,4,'Cappuccino'),(3,1,5,'Caffe Latte'),(4,2,2,'Earl Grey'),(5,2,3,'Darjeeling'),(6,3,1,'Red Bull'),(7,3,3,'Monster'),(8,4,4,'Bigaro Byurla'),(9,5,5,'Milka'); | ||
| /*!40000 ALTER TABLE `type` ENABLE KEYS */; | ||
| UNLOCK TABLES; | ||
| -- | ||
| -- Table structure for table `user` | ||
| -- | ||
| DROP TABLE IF EXISTS `user`; | ||
| /*!40101 SET @saved_cs_client = @@character_set_client */; | ||
| /*!40101 SET character_set_client = utf8 */; | ||
| CREATE TABLE `user` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `firstname` varchar(45) NOT NULL, | ||
| `lastname` varchar(45) DEFAULT NULL, | ||
| PRIMARY KEY (`id`) | ||
| ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; | ||
| /*!40101 SET character_set_client = @saved_cs_client */; | ||
| -- | ||
| -- Dumping data for table `user` | ||
| -- | ||
| LOCK TABLES `user` WRITE; | ||
| /*!40000 ALTER TABLE `user` DISABLE KEYS */; | ||
| INSERT INTO `user` VALUES (1,'joro','b'),(2,'guess','who'),(3,'simo','cool'); | ||
| /*!40000 ALTER TABLE `user` ENABLE KEYS */; | ||
| UNLOCK TABLES; | ||
| /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; | ||
| /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; | ||
| /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; | ||
| /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; | ||
| /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; | ||
| /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; | ||
| /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; | ||
| /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; | ||
| -- Dump completed on 2013-06-02 13:26:46 |
| var fs = require('fs'), | ||
| path = require('path'), | ||
| mysql = require('mysql'); | ||
| var fpath = path.resolve(__dirname, 'fixtures/simple/dump.sql'); | ||
| fs.readFile(fpath, 'utf8', function (err, simple) { | ||
| if (err) throw err; | ||
| var connection = mysql.createConnection({ | ||
| user: 'liolio', | ||
| password: 'karamba', | ||
| multipleStatements: true | ||
| }); | ||
| connection.query('USE `express-admin-simple`;', function (err) { | ||
| if (err) throw err; | ||
| connection.query(simple, function (err) { | ||
| if (err) throw err; | ||
| process.exit(); | ||
| }); | ||
| }); | ||
| }); |
Sorry, the diff of this file is not supported yet
| var should = require('should'); | ||
| var auth = require('../../routes/auth'), | ||
| user = require('../../lib/app/user'); | ||
| describe('user authentication', function () { | ||
| describe('restrict', function () { | ||
| it('should pass in debug mode', function (done) { | ||
| var req = {}, | ||
| res = {locals:{_admin:{debug:true}}}; | ||
| auth.restrict(req, res, done); | ||
| }); | ||
| it('should pass on existing user\'s session', function (done) { | ||
| var req = {session:{user:{}}}, | ||
| res = {locals:{_admin:{debug:false}}}; | ||
| auth.restrict(req, res, done); | ||
| }); | ||
| it('should redirect to login page on missing user\'s session', function (done) { | ||
| var req = {session:{user:null}}, | ||
| res = {locals:{_admin:{debug:false}, root:'', | ||
| string:{'access-denied':'Access denied!'}}}; | ||
| res.redirect = function (path) { | ||
| path.should.equal('/login'); | ||
| req.session.error.should.equal('Access denied!'); | ||
| done(); | ||
| } | ||
| auth.restrict(req, res); | ||
| }); | ||
| }); | ||
| describe('login', function () { | ||
| it('should redirect to login page on non existent user name', function (done) { | ||
| var req = {body:{username:'liolio'},session:{}}, | ||
| res = {locals:{_admin:{users:{user1:{},user2:{}}}, root:'', | ||
| string:{'find-user':'Cannot find user!'}}}; | ||
| res.redirect = function (path) { | ||
| path.should.equal('/login'); | ||
| req.session.error.should.equal('Cannot find user!'); | ||
| req.session.username.should.equal('liolio'); | ||
| done(); | ||
| } | ||
| auth.login(req, res); | ||
| }); | ||
| it('should redirect to login page on invalid user\'s password', function (done) { | ||
| var req = {body:{username:'liolio',password:'wrong'},session:{}}, | ||
| res = {locals:{_admin:{users: | ||
| {liolio:{name:'liolio',pass:'karamba',salt:'',hash:''}}}, root:'', | ||
| string:{'invalid-password':'Invalid password!'}}}; | ||
| res.redirect = function (path) { | ||
| path.should.equal('/login'); | ||
| req.session.error.should.equal('Invalid password!'); | ||
| req.session.username.should.equal('liolio'); | ||
| done(); | ||
| } | ||
| auth.login(req, res); | ||
| }); | ||
| it('should redirect to index page on successful login', function (done) { | ||
| user.create('liolio', 'karamba', true, function (err, user) { | ||
| if (err) return done(err); | ||
| var req = {body:{username:'liolio',password:'karamba'},session:{}}, | ||
| res = {locals:{_admin:{users:{liolio:user}}, root:''}}; | ||
| req.session.regenerate = function (cb) {cb()} | ||
| res.redirect = function (path) { | ||
| path.should.equal('/'); | ||
| should.deepEqual(req.session.user, user); | ||
| done(); | ||
| } | ||
| auth.login(req, res); | ||
| }); | ||
| }); | ||
| }); | ||
| describe('logout', function () { | ||
| it('should redirect to login page on logout', function (done) { | ||
| var req = {session:{}}, | ||
| res = {locals:{root:''}}; | ||
| req.session.destroy = function (cb) {cb()} | ||
| res.redirect = function (path) { | ||
| path.should.equal('/login'); | ||
| done(); | ||
| } | ||
| auth.logout(req, res); | ||
| }); | ||
| }); | ||
| }); |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
12
-42.86%0
-100%146899
-36.6%75
-29.25%3214
-37.26%