UNPKG

json-object-editor

Version:

JOE the Json Object Editor | Platform Edition

944 lines (857 loc) 34.2 kB
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;