New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

express-admin

Package Overview
Dependencies
Maintainers
1
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

express-admin - npm Package Compare versions

Comparing version
1.3.1
to
1.3.2
+3
-2
.travis.yml
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);
});
});
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);
});
});
});