1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
var path = require('path');
var format = require('util').format;
var withTrailingSlash = require('okutil').withTrailingSlash;
var withoutTrailingSlash = require('okutil').withoutTrailingSlash;
var assign = require('object-assign');
var express = require('express');
var OKQuery = require('okquery');
var OKView = require('okview');
var OKDB = require('okdb');
var OKResource = require('okresource')
var OKTemplate = require('oktemplate');
var OKServer = require('okserver');
var OKRestEndpoint = require('okrest');
var OKSchema = require('okschema');
/**
* OKCMS!
* Basically takes configuration and gives you a server.
*/
function OKCMS(options) {
if (!(this instanceof OKCMS)) return new OKCMS(options);
options = options || {};
var app = express();
app.enable('strict routing');
var root = this._root = options.root || 'public';
var adminConfig = options.admin || {};
var adminRoot = this._adminRoot = adminConfig.root ||
path.join(__dirname, '../themes/okadmin/public');
var adminPath = this._adminPath = adminConfig.path || '/_admin'
var templateRoot = options.templateRoot || 'templates';
var adminTemplateRoot = options.templateRoot ||
path.join(__dirname, '../themes/okadmin/templates');
var schemaConfig = options.schemas || {};
var resourceConfig = options.resources || [];
var viewConfig = options.views || {
'/': { template: 'index' }
};
var templateProvider = this._templateProvider =
new OKTemplate({root: templateRoot});
var adminTemplateProvider = this._adminTemplateProvider =
new OKTemplate({root: adminTemplateRoot});
var db = new OKDB(options.db || 'fs');
// Special query to get project wide meta data
var meta = this._meta = {
type: 'meta',
get: function() {
return db.getMeta();
}
};
var schemas = this._schemas = this._createSchemas(schemaConfig);
var resources = this._resources =
this._createResources(resourceConfig, db, schemas);
// Create view instances from config
var views = this._views =
this._createViews(viewConfig, db, meta, resources, templateProvider);
var server = this._server = new OKServer({
express: express,
app: app,
views: views,
root: root,
adminRoot: adminRoot,
adminPath: adminPath
});
}
OKCMS.prototype.listen = function listen(port, options) {
options = options || {};
this._server.listen(port);
};
OKCMS.prototype._createSchemas = function(schemaConfig) {
schemaConfig = schemaConfig || {};
return Object.keys(schemaConfig).reduce(function(cache, key) {
var spec = schemaConfig[key];
cache[key] = OKSchema(spec);
return cache;
}, {});
}
OKCMS.prototype._createResources = function(resourceConfig, db, schemaCache) {
resourceConfig = resourceConfig || {};
var typeCache = {};
return resourceConfig.reduce(function(cache, config) {
var type = config.type;
var schema = schemaCache[type];
if (!schema)
throw new Error('Resource config references nonexistent schema');
// If we already created resource class, just skip
if (cache[type])
return cache;
cache[type] = OKResource({
type: type,
db: db,
schema: schema
})
return cache;
}, {});
};
OKCMS.prototype._createViews = function(viewConfig, db,
meta, resourceCache, templateProvider) {
viewConfig = viewConfig || {};
var self = this;
var createQueries = this._createQueries.bind(this);
return Object.keys(viewConfig).reduce(function(cache, route) {
var config = viewConfig[route];
var templateName = config.template || getDefaultTemplate(route, config);
var template = templateProvider.getTemplate(templateName);
if (!template) {
throw new Error(format('No template named "%s" found', templateName));
}
var queryConfig = config.data || [];
var queries = createQueries(queryConfig, resourceCache);
// Don't forget to add that trailing slash if the user forgot
cache[withTrailingSlash(route)] = OKView({
mount: 'get', // User defined views are read only
route: route,
template: template,
queries: queries,
meta: meta
});
return cache;
}, {});
/**
* Returns the default template for a view config
*/
function getDefaultTemplate(route, config) {
// Root route defaults to index
if (/^\/?$/.test(route))
return 'index';
// Otherwise default to the backing resource name
else if (config && config.data && config.data.type)
return config.data.type;
// Otherwise dunno
else
return '404';
}
}
OKCMS.prototype._createQueries = function(queryConfig, resourceCache) {
queryConfig = queryConfig || {};
if (!queryConfig.length)
queryConfig = [queryConfig];
return queryConfig.map(function(config) {
var type = config.type;
var resource = resourceCache[type];
if (!resource)
throw new Error('Query configured with nonexistent resource');
// Default to "select all" query
var query = config.query || '*';
return new OKQuery({
resource: resource,
query: query
});
});
};
module.exports = {
createApp: function(options) {
return new OKCMS(options);
},
OKResource: OKResource,
OKView: OKView,
OKRestEndpoint: OKRestEndpoint
};
|