json-object-editor
Version:
JOE the Json Object Editor | Platform Edition
944 lines (857 loc) • 34.2 kB
JavaScript
console.time('Server on '+JOE.webconfig.port);
var express = require('express');
var https = require('https');
var fs = require('fs');
var compress = require('compression');
var serverPath = '../';
var server = express();
var http = require('http').Server(server);
var https = require('https');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var basicAuth = require('basic-auth');
var path = require('path');
var pem = require('pem');
var os = require('os');
const $J = require('./UniversalShorthand');
var rd = require('renderizer')({templatesDir:path.resolve(JOE.joedir,JOE.webconfig.templatesDir)});
function coloredLog(message) {
console.log(JOE.Utils.color('[server]', 'module'), message);
}
var authBool = JOE.isAuthorized = function(req,res){
var users = (JOE.Data && JOE.Data.user) || [];
if(req.cookies._j_user && req.cookies._j_token){
var User = users.where({name:req.cookies._j_user,token:req.cookies._j_token})[0]||false;
if(User){
req.User = User;
return true;
}
}
var user = basicAuth(req);
var ip = req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress;
if (!user || !user.name || !user.pass) {
return false;
};
//console.log('a user',user);
var User = users.where({name:user.name,password:user.pass})[0]||false;
//console.log(User);
if(User || !users.length){
req.User = User||{};
res.cookie('_j_user',User.name);
res.cookie('_j_token',User.token);
return true;
}
else {
return false;
}
}
var auth = JOE.auth = function (req, res, next) {
function unauthorized(res) {
if(JOE.webconfig.authorization && JOE.webconfig.authorization.url && !req.query.noSSO){
var state = req.originalUrl;
let url = JOE.webconfig.authorization.url+'&state='+state;
res.redirect(url);
return;
}
res.set('WWW-Authenticate', 'Basic realm=Authorization Required');
return res.send(401);
};
var authorized = authBool(req,res);
if(authorized){
return next();
}else{
return unauthorized(res);
}
};
function stringFunctions(propObject){
for(var p in propObject){
if(typeof propObject[p] == 'function'){
//propObject[p] = '(' + propObject[p].toString() + ')';
propObject[p] = '(' + propObject[p].toString().replace(/\\n/g,'\\n') + ')';
}else if(typeof propObject[p] == "object"){
stringFunctions(propObject[p]);
}
}
return propObject;
}
server.use(cookieParser());
server.use( bodyParser.json({limit: '50mb'}) ); // to support JSON-encoded bodies
// to support URL-encoded bodies
server.use(bodyParser.urlencoded({
extended: true, limit: '50mb'
}));
server.use(compress());
server.get(JOE.webconfig.joepath+'server/*',function(req,res,next){
res.send('unauthorized');
});
server.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
// Public Privacy & Terms pages
server.get(['/privacy','/privacy-policy'],function(req,res){
const host = req.protocol+'://'+req.get('host');
const name = (JOE && JOE.webconfig && JOE.webconfig.name) || 'JOE';
const updated = new Date().toISOString().split('T')[0];
const contact = (JOE && JOE.Utils && JOE.Utils.Settings && JOE.Utils.Settings('PRIVACY_CONTACT')) || 'admin@example.com';
res.send(`
<!doctype html>
<html><head><meta charset="utf-8"><title>Privacy Policy - ${name}</title></head>
<body style="font-family:system-ui,Segoe UI,Roboto,Arial,sans-serif;padding:20px;max-width:900px;line-height:1.6">
<div id="mcp-nav"></div>
<script src="${JOE.webconfig.joepath}_www/mcp-nav.js"></script>
<h1>Privacy Policy for JOE MCP Interface</h1>
<p><em>Last updated: ${updated}</em></p>
<h3>Data Processed</h3>
<p>The JOE MCP interface allows AI systems to retrieve structured data from the JOE platform, such as schemas, objects, and metadata. It does not store, sell, or share personal data.</p>
<h3>Data Sources</h3>
<p>All information returned by this interface comes from the JOE instance it’s connected to (${host}). Access to internal data is subject to your JOE configuration and authentication.</p>
<h3>Third-Party Access</h3>
<p>This API may be called by authorized OpenAI models or assistants when configured by a verified user. Calls are only executed when explicitly invoked as part of an agent’s reasoning process.</p>
<h3>Logging</h3>
<p>Standard request logs (timestamps, method calls, and errors) may be recorded for security and debugging. Logs do not include object contents or personal data.</p>
<h3>Security</h3>
<p>All connections are made over HTTPS. No credentials or session tokens are shared with external systems.</p>
<h3>Contact</h3>
<p>For privacy concerns, contact ${contact}.</p>
</body></html>`);
});
server.get(['/terms','/terms-of-service'],function(req,res){
const host = req.protocol+'://'+req.get('host');
const name = (JOE && JOE.webconfig && JOE.webconfig.name) || 'JOE';
const updated = new Date().toISOString().split('T')[0];
const contact = (JOE && JOE.Utils && JOE.Utils.Settings && JOE.Utils.Settings('PRIVACY_CONTACT')) || 'admin@example.com';
res.send(`
<!doctype html>
<html><head><meta charset="utf-8"><title>Terms of Service - ${name}</title></head>
<body style="font-family:system-ui,Segoe UI,Roboto,Arial,sans-serif;padding:20px;max-width:900px;line-height:1.6">
<div id="mcp-nav"></div>
<script src="${JOE.webconfig.joepath}_www/mcp-nav.js"></script>
<h1>Terms of Service for JOE MCP Interface</h1>
<p><em>Last updated: ${updated}</em></p>
<p>Use of this interface implies consent to log and process structured data requests for schema and object retrieval purposes. Access is governed by your JOE configuration and authentication. Do not submit sensitive data unless you are authorized to do so.</p>
<p>For questions, contact ${contact}.</p>
</body></html>`);
});
// Secure MCP test/export pages with standard auth (root and JOEPATH paths)
server.get('/mcp-test.html',auth,function(req,res){
res.sendFile(path.join(JOE.joedir,'_www','mcp-test.html'));
});
server.get('/mcp-export.html',auth,function(req,res){
res.sendFile(path.join(JOE.joedir,'_www','mcp-export.html'));
});
server.get('/mcp-schemas.html',auth,function(req,res){
res.sendFile(path.join(JOE.joedir,'_www','mcp-schemas.html'));
});
server.get(JOE.webconfig.joepath+'_www/mcp-test.html',auth,function(req,res){
res.sendFile(path.join(JOE.joedir,'_www','mcp-test.html'));
});
server.get(JOE.webconfig.joepath+'_www/mcp-export.html',auth,function(req,res){
res.sendFile(path.join(JOE.joedir,'_www','mcp-export.html'));
});
server.get(JOE.webconfig.joepath+'_www/mcp-schemas.html',auth,function(req,res){
res.sendFile(path.join(JOE.joedir,'_www','mcp-schemas.html'));
});
// AI Widget test page (Responses + assistants) – auth protected
server.get(['/ai-widget-test.html', JOE.webconfig.joepath + 'ai-widget-test.html'], auth, function(req,res){
res.sendFile(path.join(JOE.joedir,'_www','ai-widget-test.html'));
});
server.use(JOE.webconfig.joepath,express.static(JOE.joedir));
//USER
server.get(['/API/user/:method'],auth,function(req,res,next){
var users = (JOE.Data && JOE.Data.user) || [];
var method = req.params.method;
var User;
if(!req.User){
/* if(req.cookies._j_user && req.cookies._j_token){
User = users.where({name:req.cookies._j_user,token:req.cookies._j_token})[0]||false;
}
if (!User){
var user = basicAuth(req);
if (user.name && user.pass) {
User = users.where({name: user.name, password: user.pass})[0] || false;
}
}*/
res.jsonp({error:'user or method not found'});
return {error:'user or method not found'};
}else{
User = req.User;
}
if (User) {
switch (method) {
case 'current':
//get current user from creds
var payload = $c.merge({}, User);
delete payload.password;
res.jsonp({user: payload});
return payload;
break;
case 'logout':
logit('logging out user '+req.User.name);
req.User = null;
res.jsonp({logout:true});
return next();
break;
case 'apps':
logit('getting apps for '+req.User.name);
userApps = [];
if (req.User.apps && req.User.apps.length) {
req.User.apps.map(function (app) {
if (JOE.Apps.cache[app]) {
userApps.push({
name: app,
title: JOE.Apps.cache[app].title,
description: JOE.Apps.cache[app].description
});
}
});
}
res.jsonp({userApps});
return;//return next();
break;
}
}
});
//SEARCH
server.get(['/API/search/','/API/search/:query'],auth,function(req,res,next){
var bm = new Benchmarker();
function safeParse(q){
if (!q) return {};
if (typeof q === 'object') return q;
try { return JSON.parse(q); } catch(e){ return null; }
}
var raw = req.params.query || req.query.query || {};
var limit = parseInt(req.query.limit||0,10) || 0;
var queryObj = safeParse(raw);
if (queryObj === null){
return res.status(400).jsonp({ error: 'Invalid JSON in query' });
}
// Support mode=fuzzy and query params building $fuzzy
var mode = (req.query.mode||'').toLowerCase();
if (mode === 'fuzzy' && (!queryObj || !queryObj.$fuzzy)){
queryObj = queryObj || {};
var fieldsParam = req.query.fields || '';
var fields = [];
if (fieldsParam){
fields = fieldsParam.split(',').filter(Boolean).map(function(f){
var parts = f.split(':');
if (parts.length>1){
var w = parseFloat(parts[1]);
return { path: parts[0], weight: isNaN(w)? undefined : w };
}
return parts[0];
});
}
queryObj.$fuzzy = {
q: req.query.q || '',
fields: fields.length? fields : undefined,
threshold: (typeof req.query.threshold !== 'undefined')? parseFloat(req.query.threshold) : undefined,
limit: limit || undefined,
offset: (typeof req.query.offset !== 'undefined')? parseInt(req.query.offset,10) : undefined,
highlight: (req.query.highlight==='true'||req.query.highlight==='1') || undefined
};
}
var payload = {query:queryObj};
payload.results = JOE.Cache.search(queryObj);
/*payload.results.map(function(res){
res = $c.copyObject(res);
if(res.password || res.token){
delete res.password;
delete res.token;
}
})*/
payload.count = payload.results.length;
if(limit){ payload.results = payload.results.slice(0,limit); }
payload.results = cleanPayload(payload.results);
payload.benchmark = bm.stop();
res.jsonp(payload);
});
function cleanPayload(results){
results = JSON.parse(JSON.stringify(results));
results.map(r=>{
if(r.password){
r.password = null;
}
})
return results;
}
//ITEM QUERY - secured, preferred
server.get(['/API/item/:collection/fields/:fields','/API/item/:collection/:key/:value','/API/item/:collection'],auth,function(req,res,next){
var st = new Date().getTime();
var collection = req.params.collection || req.query.collection;
var key = req.params.key || req.query.key;
var value = req.params.value || req.query.value;
var fields = req.params.fields || req.query.fields;
var filter = {};
if(key && value){
filter[key] = value;
}
var payload = {collection:collection,filter:filter};
payload.item = (JOE.Data[collection] ||[]).where(filter);
if(key && value){
payload.item = payload.item[0] || false;
}
else if(fields){
// fields = fields.split(',');
// var finalItems = [];
// payload.item.map(i=>{
// let copy = {};
// fields.map(f=>{
// if(f){
// copy[f]=i[f];
// }
// })
// finalItems.push(copy);
// })
payload.item = JOE.Utils.ProjectedItemsFromFields(fields,payload.item);
}
payload.item = cleanPayload(payload.item);
payload.elapsed = new Date().getTime() - st;
res.jsonp(payload);
});
//OBJECT SINGLE ITEM QUERY
server.get(['/API/object/:collection/:key/:value',
'/API/object/:collection/:key/:value/field/:field',
'/API/object/:collection/:key/:value/fields/:fields'
],auth,function(req,res,next){
var collection = req.params.collection || req.query.collection;
var key = req.params.key || req.query.key;
var value = req.params.value || req.query.value;
var field = req.params.field || req.query.field;
var fields = req.params.fields || req.query.fields;
var filter = {};
if(key && value){
filter[key] = value;
}
var object = (JOE.Data[collection] ||[]).where(filter)[0] || false;
if(!object){
res.jsonp({error:'object not found'})
return;
}
if(field){
var pl = {};
pl[field] = object[field];
res.jsonp(pl);
return;
}
if(fields){
fields = fields.split(',');
var pl = {};
fields.map(f=>{
if(f){
pl[f]=object[f];
}
})
res.jsonp(pl);
return;
}
res.jsonp(object);
});
//HISTORY
server.get(['/API/history/:key/:itemid'],auth,function(req,res,next){
var st = new Date().getTime();
var elapsed;
var key = req.params.key;
var id = req.params.itemid || req.query.itemid;
var quick = req.params.quick || false;
var fields = req.params.fields || req.query.fields;
var query = {};
query[key] = id;
if(!id){
res.jsonp({error:'no itemid specified'});
return;
}
JOE.Storage.load('_history',query,function(err,data){
if(err){
res.jsonp({error:err});
return;
}
if(!fields){
elapsed = new Date().getTime() - st;
res.jsonp({query:query,results:data,elapsed})
}else{
var finalItems = JOE.Utils.ProjectedItemsFromFields(fields,data);
elapsed = new Date().getTime() - st;
res.jsonp({query:query,results:finalItems,elapsed})
}
})
});
//COMMENTS
server.get(['/API/comments/:mode/:id'],auth,function(req,res,next){
var mode = req.params.mode;
var id = req.params.id;
var query = false;
var payload={error:'comments request syntax'};
switch(mode){
case 'user':
query = {'user._id':id};
break;
case 'item':
query = {'item._id':id};
break;
}
if(query){
JOE.Storage.load('comments',query,function(err,data){
if(err){
res.jsonp({error:err});
return;
}
res.jsonp({
query:query,
length:data.length,
comments:data
});
})
}else{
res.jsonp(payload);
}
});
//CACHE
server.get(['/API/cache/update','/API/cache/update/:collections'],auth,function(req,res,next){
var collections = (req.params.collections||'').split(',');
try{
JOE.Cache.update(function(){
console.log('cache updated manually');
res.jsonp({event:'cache updated'});
})
}catch(e){
res.jsonp({error:e});
}
});
//DATASET
server.get(['/API/dataset/:names','/API/datasets/:names'],auth,function(req,res,next){
var uBM = new Benchmarker();
var collections = (req.params.names||'').split(',');
var payload = {
datasets:{},
counts:{total:0}
};
/*queryness*/
var query = req.query.query;
if(query){
var queryObj = (typeof query == "object")?query:eval('('+query+')');
var payload = {query:queryObj};
}
var permitted = [];
var isSuper = false;
var isNew = false;
if(!$c.isEmpty(req.User)){
isSuper = (req.User.role == "super");
permitted = req.User.schemas || [];
}else if(!JOE.Data.user || !JOE.Data.user.length){
isNew = true;
}
collections.map(function(c){
if(c){
if(isSuper || isNew || permitted.indexOf(c) != -1){
payload.datasets[c] = JOE.Data[c] || [];
}else{payload.datasets[c] = [];}
payload.counts[c] = payload.datasets[c].length;
payload.counts.total+= payload.datasets[c].length;
}
});
payload.benchmark = uBM.stop();
res.jsonp(payload);
});
//SCHEMA
// GET /API/joe/schemas → ["condition","diagnostic",...]
server.get('/API/list/schemas', auth, function(req, res){
try {
const names =
(global._joe && _joe.schemas && Object.keys(_joe.schemas)) ||
(JOE && JOE.Schemas && JOE.Schemas.schema && Object.keys(JOE.Schemas.schema)) ||
(typeof __collectionNames !== 'undefined' && __collectionNames) ||
[];
res.json(names.sort());
} catch (e) {
res.status(500).json({ error: e.message || 'Unknown error' });
}
});
server.get(['/API/schema/:names','/API/schemas/:names'],auth,function(req,res,next){
var sBM = new Benchmarker();
var schemaname = (req.params.names||'').split(',');
var format = req.query.format;
if(!schemaname || !schemaname.length){
res.jsonp({error:'no schema sent'});
}
var payload = {};
var fields = {};
//'./server/';
var schemapath,fieldspath;
var permitted = [];
var isSuper = false;
var isNew = false;
if(!$c.isEmpty(req.User)){
isSuper = (req.User.role == "super");
permitted = JSON.parse(JSON.stringify(req.User.schemas)) || [];
if(req.User.items && req.User.items.length && req.query.mode=="additionalItems"){
JOE.Cache.search({_id:{$in:req.User.items}}).map(i=>{
permitted.push(i.itemtype);
})
}
permitted = Array.from(new Set(permitted));
}else if(!JOE.Data || !JOE.Data.user || !JOE.Data.user.length){
isNew = true;
}
var useSummary = (req.query.summaryOnly === 'true' || req.query.summaryOnly === true || req.query.summaries === 'true' || req.query.view === 'summary');
schemaname.map(function(s){
if(isSuper || isNew || permitted.indexOf(s) != -1){
payload[s] = useSummary ? (JOE.Schemas.summary && JOE.Schemas.summary[s]) : JOE.Schemas.schema[s];
}
});
var Fraw = (req.query.fields||req.params.fields||'core');
var noFields = (Fraw === 'none') || (useSummary === true);
if (!noFields){
var F = Fraw.split(',');
F.map(function(f){
try {
fieldspath = serverPath+'fields/' + f + '.js';
delete require.cache[require.resolve(fieldspath)];
fields = require(fieldspath);
stringFunctions(fields);
JOE.Fields[f]=fields;
}catch(e){
fields ={error:'field '+f+' not found'};
}
});
}
var bm = sBM.stop();
switch(format){
case 'js':
res.set('Content-Type', 'application/javascript');
var js_payload =JSON.stringify({schemas:payload,fields:fields,benchmark:bm},null, ' ');
res.send('var joe_info = '+js_payload);
break;
default:
res.jsonp({schemas:payload,fields:fields,benchmark:bm, summaryOnly: !!useSummary});
break;
}
});
//PLUGINS
async function pluginHandling(req,res,next){
var pBM = new Benchmarker();
var plugin = req.params.plugin;
var data = $c.merge(req.query,req.body) || {};
//var app = req.params.app;
var method = req.params.method || 'default';
var errors = [];
// if(!plugin || !app){
// errors.push('plugin or app name not supplied');
// }
// var app_obj = JOE.Apps.cache[app];
// if(!app_obj){
// errors.push('app "'+app+'" not found');
// }
// if(!app_obj.plugins || !app_obj.plugins.contains(plugin)){
// errors.push('plugin "'+plugin+'" not found');
// }
var pluginClass = JOE.Apps.plugins[plugin];
var protected;
if(!pluginClass){
errors.push('plugin "'+plugin+'" not initialized')
}
else if(method == "protected" || !pluginClass[method]
|| (pluginClass.protected && pluginClass.protected.indexOf(method) != -1)){
errors.push('method '+method+' not found');
}
if(errors.length){
res.jsonp({errors:errors,failedat:'Server'});
console.log('[plugin] errors:');
console.log(errors);
return;
}
try{
if(typeof pluginClass[method] == "string"){
var response = pluginClass[method];
}else{
if(pluginClass.async && pluginClass.async[method]){
var response = await pluginClass[method](data,req,res);
}else{
var response = pluginClass[method](data,req,res);
}
}
if(response && response.use_callback){
return;
}
if(response && response.unauthorized){
res.set('WWW-Authenticate', 'Basic realm=Authorization Required');
return res.send(401);
}
if(response && (response.errors || response.error)){
var errstr = (response.errors || response.error);
logit(errstr)
res.jsonp(response);
return;
}
if(typeof response == "string"){
res.send(response);
}else{
if(response && response['content-type']){
try{
console.log(response);
res.set('Content-Type', response['content-type']+';charset=utf-8');
res.set('Content-Disposition', 'attachment; filename="'+response.filename+'"');
res.send(response.content);
}catch(e){
console.log('error',e);
res.jsonp({error:e});
}
}else{
res.jsonp(response);
}
}
}catch(e){
console.log(e);
res.jsonp({errors:e});
}
logit(JOE.Utils.color('[plugins]','plugin')+' ran '+plugin+' > '+method+' in '+pBM.stop()+' secs');
}
server.get(['/API/plugin/:plugin','/API/plugin/:plugin/:method'],pluginHandling);
server.post(['/API/plugin/:plugin','/API/plugin/:plugin/:method'],pluginHandling);
//SAVE
server.get(['/API/save/','/API/save/:itemid'],auth,function(req,res,next){
var object,prev_object,message = '';
if(req.params.itemid){
prev_object = $J.get(req.params.itemid);
if(!prev_object){
res.jsonp({status:'error',error:"object not found"});
return;
}
object = Object.assign({},prev_object,req.query);
message = `${object.itemtype||'item'} updated`;
}else{
object = req.query;
}
object.name = decodeURI(object.name);
for(prop in object){
if(typeof object[prop] == "string" && ["true","false"].indexOf(object[prop].toLowerCase()) != -1){
object[prop] = $c.parseBoolean(object[prop]);
}
}
object.joeUpdated = new Date().toISOString();
//TODO: check to make sure schema idprop is present
JOE.Storage.save(object,object.itemtype,function(err,results){
//var object = merge({},results);
var itemtype = results.itemtype;
var _id = results._id;
/*
JOE.Storage.load(itemtype,{'_id':_id},function(err,data){
if(err){
res.jsonp({status:'error',error:err,results:data});
}else{
res.jsonp({status:'success',message:'',error:err,results:data});
JOE.io.emit('item_updated',{results:data})
}
})
*/
JOE.Cache.update(function(){
var updated = $J.get(_id);
JOE.Storage.load(itemtype,{'_id':_id},function(err,data){
if(err){
res.jsonp({status:'error',error:err});
}else{
res.jsonp({status:'success',message:'',error:err,results:updated});
JOE.io.emit('item_updated',{results:updated})
}
})
},[object.itemtype])
},{user:req.User});
});
/*
//UPDATE
server.get('/API/update/:itemid',auth,function(req,res,next){
var object = $J.get(req.params.itemid);
res.jsonp({status:'test',object:object});
if(item.)
//var object = req.query;
return;
//TODO: check to make sure schema idprop is present
JOE.Storage.save(object,object.itemtype,function(err,results){
//var object = merge({},results);
var itemtype = results.itemtype;
var _id = results._id;
JOE.Storage.load(itemtype,{'_id':_id},function(err,data){
if(err){
res.jsonp({status:'error',error:err,results:data});
}else{
res.jsonp({status:'success',error:err,results:data});
io.emit('item_updated',{results:data})
}
});
},{user:req.User});
});
*/
server.get('/',function(req,res,next){
logit('blank request');
if(JOE.Data.site.where({url:''})[0]){
JOE.Sites.parseRoute(req,res,next);
}else{
next();
}
})
server.get(['/'],function(req,res){
fs.readFile(JOE.joedir+'/pages/joe.html', 'utf8', function (err,data) {
var payload={
webconfig:JOE.webconfig
}
res.send(fillTemplate(data,payload));
})
})
//JOE APP
server.get(['/JOE/','/JOE/:appname'],auth,function(req,res,next){
var nonAppExtensions = ['jpeg','jpg','gif','ico','pdf','png','tif','tiff'];
var appname = req.params.appname||'joe';
var ext = appname.substr(appname.lastIndexOf('.')+1);
if(nonAppExtensions.indexOf(ext) != -1){
res.status(404).send('file "'+appname+'"['+ext+'] not found.');
return;
}
var agent = req.headers["user-agent"];
var templatePage = JOE.joedir+'/pages/template.html';
if(agent.indexOf('Trident') != -1 || agent.indexOf('MSIE') != -1|| agent.indexOf('Edge') != -1){
templatePage = JOE.joedir+'/pages/template_ie.html';
}
//console.log(agent);
fs.readFile(templatePage, 'utf8', function (err,data) {
if (err) {
res.json({error:err});
return console.log(err);
}
try{
var apps = [];
//var appspath = serverPath+'Apps.js';
//delete require.cache[require.resolve(appspath)];
//JOE.Apps = require(appspath);//JOE.webconfig.apps;
var Apps = JOE.Apps.cache;
// if(!JOE[appname]){
// res.send({'error':'no app found: '+appname});
// //return;
// }
var currentApp = Apps[appname];
if(!currentApp){
res.send({'error':'app not found'})
return;
}
var currentAppCollections = JOE.Utils.propAsFuncOrValue(currentApp.collections);
if(!$c.isEmpty(req.User)){
if(req.User.apps && req.User.apps.indexOf(appname) == -1){
if(req.User.role !="super"){
res.send({'error':'invalid permission, talk to your admin'});
return;
}
}
}else if(JOE.Data.user && JOE.Data.user.length){
res.send({'error':'invalid permission, try refreshing'});
return;
}
for(var app in Apps){
apps.push(app);
}
var sites = (JOE.Data.site || []).sortBy('url');
var plugins = [];
for(var pl in JOE.Apps.plugins){
plugins.push(pl);
}
var settings ={};
var data_settings = JOE.Data.setting||[];
for(var s = 0, tot = data_settings.length; s <tot;s++){
settings[data_settings[s].name]= data_settings[s].value;
}
var USER = { };
if(!$c.isEmpty(req.User)){
USER.name = req.User.name;
USER.schemas = (req.User.schemas||[]).join(',');
USER.role = req.User.role;
USER.apps = req.User.apps;
USER.items = (req.User.items||[]).join(',');
USER.styles =req.User.styles;
}
//var collections = [];
let uappsObj = [];
var users = (JOE.Data && JOE.Data.user) || [];
var USERAPPS = [];;
if(!users.length){
USERAPPS = [{name:'joe',title:'JOE',description:'The JSON Object Editor'}];
}else if(USER){
USERAPPS = USER.apps;
}
USERAPPS.map(a=>{
let aa = Apps[a]||{};
uappsObj.push({name:a,title:aa.title,description:aa.description});
});
var payload = {
APPNAME:currentApp.title || appname,
APPINFO:JSON.stringify(stringFunctions(currentApp)),
APPS:apps.join(','),
USERAPPS:(USER.apps||apps||[]).join(','),
USERAPPSOBJ:JSON.stringify(uappsObj),
webconfig:JOE.webconfig,
settings:settings,
JOEPATH:JOE.webconfig.joepath,
COLLECTIONS:currentAppCollections.join(),
ALL_COLLECTIONS:JOE.Apps.collections.join(),
DEFAULT_SCHEMAS:JOE.webconfig.default_schemas.join(','),
PLUGINS:plugins.join(),
USER:USER,
STARTDATE:JOE.STARTDATE.toISOString(),
//SCHEMALIST:JOE.Schemas.schemaList.join(','),
//ALL_COLLECTIONS:Apps['joe'].collections.join(),
SITES:sites,
STATS:{
memory:{
current:process.memoryUsage(),
freemem:os.freemem(),
totalmem:os.totalmem()
}
}
};
//logit(console.log('memory',Math.round((process.memoryUsage().rss/1024/1024*100)/100)));
res.send(fillTemplate(data,payload));
}catch(e){
res.json({error:e});
console.log(e);
return console.log('error loading app '+appname+': '+e);
}
});
});
server.get(['/RENDER/:contentType/:templateName'],function(req,res){
var contentType = req.params.contentType;
var templateName = req.params.templateName;
if(!Renderizer.TEMPLATES[contentType] || !Renderizer.TEMPLATES[contentType][templateName]){
res.status(404).send({error:`${contentType} '${templateName}' not found`})
return;
}
var params = Object.assign(req.params,req.query);
res.send(Renderizer.TEMPLATES[contentType][templateName](params,req));
});
JOE.webDir = webDir = JOE.appDir+'/'+JOE.webconfig.webDir+'/';
JOE.Utils.setupFileFolder(webDir,'web');
coloredLog('listening on '+JOE.webconfig.port);
server.use('/',express.static(JOE.webDir));
// Also serve JOE's own _www as a fallback under root (parent app takes priority)
server.use('/',express.static(path.join(JOE.joedir, JOE.webconfig.webDir)));
http.listen(JOE.webconfig.port,function(){
//console.log('joe listening on '+JOE.webconfig.port);
coloredLog('using webDir: '+JOE.webDir);
});
JOE.httpServer = http;
var httpsPort = JOE.webconfig.httpsPort;
if(httpsPort){
var httpsServer = https.Server({key: JOE.Pem.serviceKey, cert: JOE.Pem.certificate}, server);
httpsServer.listen(httpsPort);
coloredLog(' https on '+httpsPort);
JOE.httpsServer = httpsServer;
// pem.createCertificate({selfSigned:true}, function(err, keys){
// if(err){
// console.log(err);
// }
// https.Server({key: keys.serviceKey, cert: keys.certificate}, server).listen(httpsPort);
// console.log(JOE.Utils.color('[server]','module')+' https on '+httpsPort);
// JOE.httpsServer = https;
// });
}
module.exports = server;