Skip to content

Commit f3f67cd

Browse files
committed
First commit
0 parents  commit f3f67cd

File tree

6 files changed

+325
-0
lines changed

6 files changed

+325
-0
lines changed

.gitignore

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.DS_Store
2+
node_modules
3+
*.log
4+
pids
5+
*.pid
6+
*.seed
7+
.grunt
8+

.travis.yml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
language: node_js
2+
node_js:
3+
- 0.11
4+
- 0.10

index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = {};

license

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2014 Sam Thompson <[email protected]>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

package.json

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "acp",
3+
"version": "0.0.1",
4+
"description": "Data-agnostic admin interface generator for CRUD applications",
5+
"main": "index.js",
6+
"scripts": {
7+
"prepublish": "npm prune"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "https://github.com/samt/acpjs"
12+
},
13+
"keywords": [
14+
"admin",
15+
"interface",
16+
"generator",
17+
"crud",
18+
"express"
19+
],
20+
"author": "Sam Thompson <[email protected]>",
21+
"license": "MIT",
22+
"bugs": {
23+
"url": "https://github.com/samt/acpjs/issues"
24+
},
25+
"homepage": "https://github.com/samt/acpjs",
26+
"dependencies": {
27+
"express": "4.x.x"
28+
},
29+
"engines": {
30+
"node": ">= 0.10.0"
31+
}
32+
}

readme.md

+259
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
# ACP
2+
3+
[![Build Status](https://travis-ci.org/samt/acpjs.png)](https://travis-ci.org/samt/acpjs)
4+
5+
Data-agnostic admin interface generator for CRUD applications
6+
7+
## Abstract
8+
9+
The problem with crud apps is they are all are basically the same, yet we find
10+
it necessary to always rewrite the same code over and over. We have a set of
11+
requirements that remain relatively constant:
12+
13+
- Views Types
14+
- Summary (Dashboard) view of data for graphing or general display
15+
- Unordered List-view (or table) of items in a collection
16+
- Ordred list-view (or table) of items in a collection for sorting
17+
- Log views (uneditable display of entries)
18+
- Insert/update Item view within a collection
19+
- Functionality
20+
- View all collections in appropriate view types
21+
- Validation of data prior to database
22+
- Deny badly formed data (email addresses must have an "@" sign)
23+
- Deny duplicate entries (i.e. duplicate username fields)
24+
- Deny baed upon custom, applicaiton-specific criteria
25+
- Pagination
26+
- Filter/Search
27+
- Form controls in editing views
28+
29+
In addition, we always have data coming in from somewhere. Sometimes it's all
30+
from a database, sometimes it's from flat files, and even sometimes it's from
31+
the network. The problem with other frameworks is they are all dependent on one
32+
type of data retrieval. If you try to exit the box they put you in, you're
33+
going to have a bad time.
34+
35+
## Requirements
36+
37+
- node >= 0.8.0
38+
- express >= 4.x.x (if using with existing app)
39+
40+
## Installation
41+
42+
```
43+
npm install acp
44+
```
45+
46+
## Usage
47+
48+
### Basic
49+
50+
```javascript
51+
var acp = require('acp');
52+
var adm = acp();
53+
54+
adm.listen(3000); // identical to express's app.listen()
55+
```
56+
57+
### With an existing express app
58+
59+
Because acp is an express application, we can simply mount it on top of another
60+
application currently being set up. This allows you to write your own custom
61+
user-facing front-end and allow you to use acp to mange your data behind.
62+
63+
```javascript
64+
var adm = acp();
65+
var app = express();
66+
67+
// ...
68+
69+
app.use('/admin', adm); // mount on "admin"
70+
71+
app.listen(3000); // do not listen with adm
72+
```
73+
74+
### Define Collections
75+
76+
A collection is any set of data that you wish to manage. You can pull it from
77+
your database, flat files, remote systems, etc.
78+
79+
```javascript
80+
var acp = require('acp');
81+
var adm = acp();
82+
83+
var userCollection = adm.define('Users', {
84+
primaryKey: 'id', // defaults to 'id'
85+
mount: 'auto', // defaults to 'auto. Mounts CRUD pages on url-safe version of the collection name
86+
create: createUser,// function(record, cb) , cb(err, record),
87+
readOne: getOneUser,// function ( primaryKey ),
88+
read: getUsers, // function( { start: 0, limit: 10 }),
89+
update: updateUser, // function ( primaryKey, record ),
90+
delete: deleteUser, // function ( primaryKey | record ), cb(Error err, bool deleted)
91+
count: countUsers, // function (cb), cb(Error err, number count),
92+
fields: {
93+
id: { type: 'auto', primary: true }, // auto_int sets nice defaults
94+
slug: { type: 'string', filter: [ ACP.Filter.urlSafe, },
95+
name: { type: 'string', validate: function (n) {
96+
return /[a-z0-9_\-]{4,10}/i.test(n);
97+
}},
98+
email: { type: 'string', validate: [ ACP.Validate.email, function (email, next) { // validate can take an array
99+
db.query('SELECT * FROM users WHERE email = ?', [ email ], function (err, rows) {
100+
if (err) throw err;
101+
next( !rows.length );
102+
});
103+
}]}
104+
}
105+
});
106+
107+
adm.listen(3000);
108+
```
109+
110+
### Arbitrary Page
111+
112+
```javascript
113+
var acp = require('acp');
114+
var admin = acp();
115+
116+
// same arguments as .define()
117+
admin.page('Dashboard', {
118+
mount: '/',
119+
widgets: [ // table of widgets
120+
[w1, w2, w3],
121+
[w4, w5]
122+
]
123+
});
124+
```
125+
126+
## API
127+
128+
### Class `ACP`
129+
130+
This is the main class of the Admin Control Panel Interface.
131+
132+
#### `ACP.define(name, options)`
133+
134+
Defines a collection of data to keep track of
135+
136+
- `name` String: Name of the collection, usually pular
137+
- `options` Object:
138+
- `primaryKey` String: Field name of the primary key.
139+
- `disableCrud` Boolean: (optional) Disable crud functionality? default:
140+
false
141+
- `mount` String: (optional) 'auto' to mount on root with generated slug
142+
(default), '/routname' otherwise.
143+
- `orderedBy` String: (optional) Field name to order by if ordered list.
144+
false or null otherwise. Default: false
145+
- `create` Function: callback to store a new record.
146+
Params: `record`, `callback(err, record`)
147+
- `update` Function: callback to update a record.
148+
Params: `record`, `callback (err, record)`
149+
- `readOne` Function: callback to read one record.
150+
Params: `primaryKey`, `callback(err, record)`
151+
- `read` Function: callback to get the collection.
152+
Params: `filter` Array< _ACP.Filter_ >, `callback(err, recs)`
153+
- `delete` Function callback to delete a record.
154+
Params: `primaryKey`, `callback(err, deleted?)`
155+
- `count` Function callback to count all records.
156+
Params: `Array<ACP.Filter>, callback(err, count)`
157+
- `fields` Array<ACP.Field>: Field List
158+
159+
#### `ACP.page(name, options)`
160+
161+
- `name` String: Name of the page
162+
- `options` Object:
163+
- `mount` String: (optional) 'auto' to mount on root with generated slug
164+
(default), '/routname' otherwise.
165+
- `widgets` Array< Array<ACP.Widget> >: Widget table. Outer Array: Rows;
166+
inner Array: Columns
167+
168+
### Class `ACP.Filter`
169+
170+
Plain object.
171+
172+
- `field_name` Object:
173+
- `eq` Mixed: Returned values must be equal.
174+
- `ne` Mixed: Returned values must not be equal
175+
- `gt` Mixed: Returned values must be greater than
176+
- `lt` Mixed: Returned values must be less than
177+
- `gte` Mixed: Returned values must be greater than or equals
178+
- `lte` Mixed: Returns values must be less than or equals
179+
180+
For example:
181+
182+
```javascript
183+
{ email: { ne: '[email protected] '} }
184+
```
185+
186+
### Class `ACP.Field`
187+
188+
Is just a plain object with the following properties:
189+
190+
- `type` String: 'auto', 'number', 'string', 'text', 'bool', 'datetime', 'date'
191+
- `primary` Boolean: Is primary key? Default: false. Overridden if primaryKey is set in collection
192+
- `editable` Boolean: Can the user edit this field?
193+
- `filter` Function|Array<Function>: Filter (modify values) of the record
194+
- `validate` Function|Array<Function>: Validate a field. performed AFTER filters
195+
- `options` Array<String>|Plain Object: (Optional) if this is a dropdown/radio/checkbox list, any
196+
- `input` Flag: ACP.TEXT, ACP.PASSWORD, ACP.EMAIL, ACP.DROPDOWN,
197+
ACP.DROPDOWN_MULI, ACP.DATE_PICKER, ACP.DATETIME_PICKER, ACP.RADIO, ACP.CHECKBOX
198+
199+
### Class `ACP.Widget`
200+
201+
- `size` Number: 1-12, grid width. Default: 3
202+
- `template` String: Either a built in template or user-defined custom path
203+
- `read` Function: Callback to read data to populate the widget width
204+
- `title` String: Widget title
205+
206+
### Class `ACP.Filter`
207+
208+
Contains the functions to validate automatically
209+
210+
- `ACP.Filter.urlSafe`: Makes a URL safe string (RFC 3986)
211+
- `ACP.Filter.slug`: Makes the string into a clean URL-safe sting [a-z0-9\-_]
212+
- `ACP.Filter.boolean`: Converts strings from <form>s "1" or "0" into true boolean values
213+
- `ACP.Filter.datetime`: Parses the date to an ISO 8601 compliant string
214+
- `ACP.Filter.jsDate`: Turns field into a JavaScript `Date` object
215+
216+
### Class `ACP.Validate`
217+
218+
Contains the functions to validate automatically
219+
220+
- `ACP.Validate.email`: Validates an email
221+
- `ACP.Validate.url`: Validates a URL
222+
- `ACP.Validate.foreignKey(collectionName)`: Validates that there exists a primary key in the collection
223+
- `ACP.Validate.unique`: Validates that there are no records with the same value in this field
224+
225+
## Concepts
226+
227+
### Data Agnostic
228+
229+
When you create a collection, you specify where the data comes from, how it is
230+
inserted, how it is updated, and what validations need to take place. There are
231+
validation macros you can use for extremely common validations, such as email
232+
addresses, url-safe strings, and checking for duplicates in other models. You
233+
may also specify filters which take data pre-validation and operate on it.
234+
235+
### Reusable interfaces
236+
237+
You don't have to write your own views. You specify where and when you
238+
want things to appear and it just makes it for you.
239+
240+
### Built with express
241+
242+
To make hooking it into your stack easier, it is made to either piggy-back off
243+
of your current express application or you can specify to run it standalone.
244+
245+
### Security
246+
247+
Because this is going to give a user a one-stop-shop for mangling the database,
248+
we wanted to ensure only the people you give access will have access. There are
249+
few layers of security we've added on:
250+
251+
- Specify what session data must be set before access
252+
- Optionally enable "reauth" if the user hasn't been active within a
253+
specified amount of time
254+
- Session keys in the URL as query vars for additional session validation
255+
- Referrer checking
256+
257+
## License
258+
259+
The MIT License

0 commit comments

Comments
 (0)