2015-07-20 00:09:47 -07:00
'use strict' ;
exports = module . exports = {
reboot : reboot ,
2018-11-25 17:02:01 +01:00
isRebootRequired : isRebootRequired ,
2015-07-20 00:09:47 -07:00
getConfig : getConfig ,
2017-04-07 18:45:36 +02:00
getDisks : getDisks ,
2018-06-28 17:43:20 -07:00
getUpdateInfo : getUpdateInfo ,
2015-07-20 00:09:47 -07:00
update : update ,
2016-06-07 20:24:41 -07:00
feedback : feedback ,
2017-04-18 15:15:35 -07:00
checkForUpdates : checkForUpdates ,
2017-08-07 16:49:37 +02:00
getLogs : getLogs ,
2018-11-11 09:29:11 -08:00
getLogStream : getLogStream ,
getStatus : getStatus ,
2018-12-08 18:18:45 -08:00
setDashboardDomain : setDashboardDomain
2015-07-20 00:09:47 -07:00
} ;
2017-11-14 20:34:25 -08:00
var appstore = require ( '../appstore.js' ) ,
2017-11-16 00:09:55 -08:00
AppstoreError = require ( '../appstore.js' ) . AppstoreError ,
2017-11-14 20:34:25 -08:00
assert = require ( 'assert' ) ,
2016-06-07 20:24:41 -07:00
async = require ( 'async' ) ,
2015-07-20 00:09:47 -07:00
cloudron = require ( '../cloudron.js' ) ,
CloudronError = cloudron . CloudronError ,
HttpError = require ( 'connect-lastmile' ) . HttpError ,
HttpSuccess = require ( 'connect-lastmile' ) . HttpSuccess ,
2018-07-31 11:35:23 -07:00
updater = require ( '../updater.js' ) ,
2016-07-02 16:03:21 -05:00
updateChecker = require ( '../updatechecker.js' ) ,
2018-07-31 11:35:23 -07:00
UpdaterError = require ( '../updater.js' ) . UpdaterError ,
2016-07-02 16:03:21 -05:00
_ = require ( 'underscore' ) ;
2015-07-20 00:09:47 -07:00
2016-05-01 13:15:30 -07:00
function auditSource ( req ) {
2016-05-01 13:29:11 -07:00
var ip = req . headers [ 'x-forwarded-for' ] || req . connection . remoteAddress || null ;
2016-05-01 13:15:30 -07:00
return { ip : ip , username : req . user ? req . user . username : null , userId : req . user ? req . user . id : null } ;
}
2015-07-20 00:09:47 -07:00
function reboot ( req , res , next ) {
2018-11-25 17:02:29 +01:00
// Finish the request, to let the appstore know we triggered the reboot
2015-07-20 00:09:47 -07:00
next ( new HttpSuccess ( 202 , { } ) ) ;
2018-11-25 17:02:29 +01:00
cloudron . reboot ( function ( ) { } ) ;
2015-07-20 00:09:47 -07:00
}
2018-11-25 17:02:01 +01:00
function isRebootRequired ( req , res , next ) {
cloudron . isRebootRequired ( function ( error , result ) {
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
next ( new HttpSuccess ( 200 , { rebootRequired : result } ) ) ;
} ) ;
}
2015-07-20 00:09:47 -07:00
function getConfig ( req , res , next ) {
cloudron . getConfig ( function ( error , cloudronConfig ) {
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
next ( new HttpSuccess ( 200 , cloudronConfig ) ) ;
} ) ;
}
2017-04-07 18:45:36 +02:00
function getDisks ( req , res , next ) {
cloudron . getDisks ( function ( error , result ) {
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
next ( new HttpSuccess ( 200 , result ) ) ;
} ) ;
}
2015-07-20 00:09:47 -07:00
function update ( req , res , next ) {
// this only initiates the update, progress can be checked via the progress route
2018-07-31 11:35:23 -07:00
updater . updateToLatest ( auditSource ( req ) , function ( error ) {
if ( error && error . reason === UpdaterError . ALREADY _UPTODATE ) return next ( new HttpError ( 422 , error . message ) ) ;
if ( error && error . reason === UpdaterError . BAD _STATE ) return next ( new HttpError ( 409 , error . message ) ) ;
2015-07-20 00:09:47 -07:00
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
next ( new HttpSuccess ( 202 , { } ) ) ;
} ) ;
}
2018-06-28 17:43:20 -07:00
function getUpdateInfo ( req , res , next ) {
next ( new HttpSuccess ( 200 , { update : updateChecker . getUpdateInfo ( ) } ) ) ;
}
2016-06-07 20:24:41 -07:00
function checkForUpdates ( req , res , next ) {
2018-11-13 10:38:15 -08:00
// it can take a while sometimes to get all the app updates one by one
req . clearTimeout ( ) ;
2016-06-07 20:24:41 -07:00
async . series ( [
updateChecker . checkAppUpdates ,
updateChecker . checkBoxUpdates
] , function ( ) {
next ( new HttpSuccess ( 200 , { update : updateChecker . getUpdateInfo ( ) } ) ) ;
} ) ;
}
2015-08-04 14:31:40 +02:00
function feedback ( req , res , next ) {
assert . strictEqual ( typeof req . user , 'object' ) ;
2017-11-14 20:34:25 -08:00
const VALID _TYPES = [ 'feedback' , 'ticket' , 'app_missing' , 'app_error' , 'upgrade_request' ] ;
if ( typeof req . body . type !== 'string' || ! req . body . type ) return next ( new HttpError ( 400 , 'type must be string' ) ) ;
if ( VALID _TYPES . indexOf ( req . body . type ) === - 1 ) return next ( new HttpError ( 400 , 'unknown type' ) ) ;
2015-08-04 16:59:35 +02:00
if ( typeof req . body . subject !== 'string' || ! req . body . subject ) return next ( new HttpError ( 400 , 'subject must be string' ) ) ;
if ( typeof req . body . description !== 'string' || ! req . body . description ) return next ( new HttpError ( 400 , 'description must be string' ) ) ;
2018-03-05 17:03:54 +01:00
if ( req . body . appId && typeof req . body . appId !== 'string' ) return next ( new HttpError ( 400 , 'appId must be string' ) ) ;
2015-08-04 14:31:40 +02:00
2018-01-21 14:50:24 +01:00
appstore . sendFeedback ( _ . extend ( req . body , { email : req . user . email , displayName : req . user . displayName } ) , function ( error ) {
2017-11-16 00:09:55 -08:00
if ( error && error . reason === AppstoreError . BILLING _REQUIRED ) return next ( new HttpError ( 402 , 'Login to App Store to create support tickets. You can also email support@cloudron.io' ) ) ;
if ( error ) return next ( new HttpError ( 503 , 'Error contacting cloudron.io. Please email support@cloudron.io' ) ) ;
2017-11-14 20:34:25 -08:00
next ( new HttpSuccess ( 201 , { } ) ) ;
} ) ;
2015-08-04 15:39:14 +02:00
2015-08-04 14:31:40 +02:00
}
2017-04-18 15:15:35 -07:00
function getLogs ( req , res , next ) {
2018-06-11 20:09:38 +02:00
assert . strictEqual ( typeof req . params . unit , 'string' ) ;
2017-04-18 15:15:35 -07:00
var lines = req . query . lines ? parseInt ( req . query . lines , 10 ) : 100 ;
if ( isNaN ( lines ) ) return next ( new HttpError ( 400 , 'lines must be a number' ) ) ;
2017-04-18 20:32:57 -07:00
var options = {
lines : lines ,
follow : false ,
format : req . query . format
} ;
2018-06-11 20:09:38 +02:00
cloudron . getLogs ( req . params . unit , options , function ( error , logStream ) {
2017-04-18 15:15:35 -07:00
if ( error && error . reason === CloudronError . BAD _FIELD ) return next ( new HttpError ( 404 , 'Invalid type' ) ) ;
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
res . writeHead ( 200 , {
'Content-Type' : 'application/x-logs' ,
'Content-Disposition' : 'attachment; filename="log.txt"' ,
'Cache-Control' : 'no-cache' ,
'X-Accel-Buffering' : 'no' // disable nginx buffering
} ) ;
logStream . pipe ( res ) ;
} ) ;
}
2017-08-07 16:49:37 +02:00
function getLogStream ( req , res , next ) {
2018-06-11 20:09:38 +02:00
assert . strictEqual ( typeof req . params . unit , 'string' ) ;
2017-08-07 16:49:37 +02:00
var lines = req . query . lines ? parseInt ( req . query . lines , 10 ) : - 10 ; // we ignore last-event-id
if ( isNaN ( lines ) ) return next ( new HttpError ( 400 , 'lines must be a valid number' ) ) ;
function sse ( id , data ) { return 'id: ' + id + '\ndata: ' + data + '\n\n' ; }
if ( req . headers . accept !== 'text/event-stream' ) return next ( new HttpError ( 400 , 'This API call requires EventStream' ) ) ;
var options = {
lines : lines ,
2017-08-07 18:26:03 +02:00
follow : true ,
2017-08-07 16:49:37 +02:00
format : req . query . format
} ;
2018-06-11 20:09:38 +02:00
cloudron . getLogs ( req . params . unit , options , function ( error , logStream ) {
2017-08-07 16:49:37 +02:00
if ( error && error . reason === CloudronError . BAD _FIELD ) return next ( new HttpError ( 404 , 'Invalid type' ) ) ;
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
res . writeHead ( 200 , {
'Content-Type' : 'text/event-stream' ,
'Cache-Control' : 'no-cache' ,
'Connection' : 'keep-alive' ,
'X-Accel-Buffering' : 'no' , // disable nginx buffering
'Access-Control-Allow-Origin' : '*'
} ) ;
res . write ( 'retry: 3000\n' ) ;
res . on ( 'close' , logStream . close ) ;
logStream . on ( 'data' , function ( data ) {
var obj = JSON . parse ( data ) ;
res . write ( sse ( obj . monotonicTimestamp , JSON . stringify ( obj ) ) ) ; // send timestamp as id
} ) ;
logStream . on ( 'end' , res . end . bind ( res ) ) ;
logStream . on ( 'error' , res . end . bind ( res , null ) ) ;
} ) ;
}
2018-11-11 09:29:11 -08:00
2018-12-08 18:18:45 -08:00
function setDashboardDomain ( req , res , next ) {
2018-12-07 16:15:21 -08:00
if ( ! req . body . domain || typeof req . body . domain !== 'string' ) return next ( new HttpError ( 400 , 'domain must be a string' ) ) ;
2018-12-08 18:18:45 -08:00
cloudron . setDashboardDomain ( req . body . domain , function ( error ) {
2018-12-07 16:15:21 -08:00
if ( error && error . reason === CloudronError . BAD _FIELD ) return next ( new HttpError ( 404 , error . message ) ) ;
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
2018-12-07 16:39:22 -08:00
next ( new HttpSuccess ( 204 , { } ) ) ;
2018-12-07 16:15:21 -08:00
} ) ;
}
2018-11-11 09:29:11 -08:00
function getStatus ( req , res , next ) {
cloudron . getStatus ( function ( error , status ) {
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
next ( new HttpSuccess ( 200 , status ) ) ;
} ) ;
}