c7291af970
This still leaves a potential issue, where an app gets updated using the cli while not bumping the version and changing the icon, but maybe we can ignore that for now in favor of the browser cache for 99% of the cases
2645 lines
92 KiB
JavaScript
2645 lines
92 KiB
JavaScript
'use strict';
|
|
|
|
/* global $ */
|
|
/* global angular */
|
|
/* global EventSource */
|
|
/* global async */
|
|
|
|
// keep in sync with box/src/apps.js
|
|
var ISTATES = {
|
|
PENDING_INSTALL: 'pending_install',
|
|
PENDING_CLONE: 'pending_clone',
|
|
PENDING_CONFIGURE: 'pending_configure',
|
|
PENDING_UNINSTALL: 'pending_uninstall',
|
|
PENDING_RESTORE: 'pending_restore',
|
|
PENDING_UPDATE: 'pending_update',
|
|
PENDING_BACKUP: 'pending_backup',
|
|
PENDING_RECREATE_CONTAINER: 'pending_recreate_container', // env change or addon change
|
|
PENDING_LOCATION_CHANGE: 'pending_location_change',
|
|
PENDING_DATA_DIR_MIGRATION: 'pending_data_dir_migration',
|
|
PENDING_RESIZE: 'pending_resize',
|
|
PENDING_DEBUG: 'pending_debug',
|
|
PENDING_START: 'pending_start',
|
|
PENDING_STOP: 'pending_stop',
|
|
PENDING_RESTART: 'pending_restart',
|
|
ERROR: 'error',
|
|
INSTALLED: 'installed'
|
|
};
|
|
|
|
var HSTATES = {
|
|
HEALTHY: 'healthy',
|
|
UNHEALTHY: 'unhealthy',
|
|
ERROR: 'error',
|
|
DEAD: 'dead'
|
|
};
|
|
|
|
var RSTATES ={
|
|
RUNNING: 'running',
|
|
STOPPED: 'stopped'
|
|
};
|
|
|
|
var ERROR = {
|
|
ACCESS_DENIED: 'Access Denied',
|
|
ALREADY_EXISTS: 'Already Exists',
|
|
BAD_FIELD: 'Bad Field',
|
|
COLLECTD_ERROR: 'Collectd Error',
|
|
CONFLICT: 'Conflict',
|
|
DATABASE_ERROR: 'Database Error',
|
|
DNS_ERROR: 'DNS Error',
|
|
DOCKER_ERROR: 'Docker Error',
|
|
EXTERNAL_ERROR: 'External Error',
|
|
FS_ERROR: 'FileSystem Error',
|
|
INTERNAL_ERROR: 'Internal Error',
|
|
LOGROTATE_ERROR: 'Logrotate Error',
|
|
NETWORK_ERROR: 'Network Error',
|
|
NOT_FOUND: 'Not found',
|
|
REVERSEPROXY_ERROR: 'ReverseProxy Error',
|
|
TASK_ERROR: 'Task Error',
|
|
UNKNOWN_ERROR: 'Unknown Error' // only used for portin,
|
|
};
|
|
|
|
var ROLES = {
|
|
OWNER: 'owner',
|
|
ADMIN: 'admin',
|
|
USER_MANAGER: 'usermanager',
|
|
USER: 'user'
|
|
};
|
|
|
|
// sync up with tasks.js
|
|
var TASK_TYPES = {
|
|
TASK_APP: 'app',
|
|
TASK_BACKUP: 'backup',
|
|
TASK_UPDATE: 'update',
|
|
TASK_RENEW_CERTS: 'renewcerts',
|
|
TASK_SETUP_DNS_AND_CERT: 'setupDnsAndCert',
|
|
TASK_CLEAN_BACKUPS: 'cleanBackups',
|
|
TASK_SYNC_EXTERNAL_LDAP: 'syncExternalLdap',
|
|
TASK_CHANGE_MAIL_LOCATION: 'changeMailLocation',
|
|
};
|
|
|
|
var SECRET_PLACEHOLDER = String.fromCharCode(0x25CF).repeat(8);
|
|
|
|
// ----------------------------------------------
|
|
// Shared Angular Filters
|
|
// ----------------------------------------------
|
|
|
|
// binary units (non SI) 1024 based
|
|
function prettyByteSize(size, fallback) {
|
|
if (!size) return fallback || 0;
|
|
|
|
var i = Math.floor(Math.log(size) / Math.log(1024));
|
|
return (size / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
|
|
};
|
|
|
|
angular.module('Application').filter('prettyByteSize', function () {
|
|
return function (size, fallback) { return prettyByteSize(size, fallback) || '0 kb'; }
|
|
});
|
|
|
|
angular.module('Application').filter('prettyDiskSize', function () {
|
|
return function (size, fallback) { return prettyByteSize(size, fallback) || 'Not available yet'; }
|
|
});
|
|
|
|
angular.module('Application').filter('markdown2html', function () {
|
|
var converter = new showdown.Converter({
|
|
simplifiedAutoLink: true,
|
|
strikethrough: true,
|
|
tables: true,
|
|
openLinksInNewWindow: true
|
|
});
|
|
|
|
// without this cache, the code runs into some infinite loop (https://github.com/angular/angular.js/issues/3980)
|
|
var cache = {};
|
|
|
|
return function (text) {
|
|
if (cache[text]) return cache[text];
|
|
cache[text] = converter.makeHtml(text);
|
|
return cache[text];
|
|
};
|
|
});
|
|
|
|
|
|
// ----------------------------------------------
|
|
// Cloudron REST API wrapper
|
|
// ----------------------------------------------
|
|
|
|
angular.module('Application').service('Client', ['$http', '$interval', '$timeout', 'md5', 'Notification', function ($http, $interval, $timeout, md5, Notification) {
|
|
var client = null;
|
|
|
|
// variable available only here to avoid this._property pattern
|
|
var token = null;
|
|
|
|
function ClientError(statusCode, messageOrObject) {
|
|
Error.call(this);
|
|
this.name = this.constructor.name;
|
|
this.statusCode = statusCode;
|
|
if (messageOrObject === null || typeof messageOrObject === 'undefined') {
|
|
this.message = 'Empty message or object';
|
|
} else if (typeof messageOrObject === 'string') {
|
|
this.message = messageOrObject;
|
|
} else if (messageOrObject) {
|
|
angular.extend(this, messageOrObject); // status, message, reason and other properties
|
|
}
|
|
}
|
|
|
|
function defaultErrorHandler(callback) {
|
|
function handleServerOffline() {
|
|
if (client.offline) return;
|
|
client.offline = true;
|
|
|
|
(function onlineCheck() {
|
|
$http.get(client.apiOrigin + '/api/v1/cloudron/status', {}).success(function (data, status) {
|
|
client.offline = false;
|
|
client._reconnectListener.forEach(function (handler) { handler(); });
|
|
}).error(function (data, status) {
|
|
$timeout(onlineCheck, 5000);
|
|
});
|
|
})();
|
|
}
|
|
|
|
return function (data, status) {
|
|
// handle request killed by browser (eg. cors issue)
|
|
if (data === null && status === -1) {
|
|
handleServerOffline();
|
|
return callback(new ClientError('Request cancelled by browser'));
|
|
}
|
|
|
|
// re-login will make the code get a new token
|
|
if (status === 401) return client.login();
|
|
|
|
if (status === 500 || status === 501) {
|
|
if (!client.offline) client.error(data);
|
|
} else if (status === 502 || status === 503 || status === 504) {
|
|
// This means the box service is not reachable. We just show offline banner for now
|
|
}
|
|
|
|
if (status >= 500) {
|
|
handleServerOffline();
|
|
return callback(new ClientError(status, data));
|
|
}
|
|
|
|
var obj = data;
|
|
try {
|
|
obj = JSON.parse(data);
|
|
} catch (e) {}
|
|
|
|
callback(new ClientError(status, obj));
|
|
};
|
|
}
|
|
|
|
function defaultSuccessHandler(callback) {
|
|
return function (data, status) {
|
|
return callback(null, data, status);
|
|
};
|
|
}
|
|
|
|
// XHR wrapper to set the auth header
|
|
function get(url, config, callback) {
|
|
if (arguments.length !== 3) {
|
|
console.error('GET', arguments);
|
|
throw('Wrong number of arguments');
|
|
}
|
|
|
|
config = config || {};
|
|
config.headers = config.headers || {};
|
|
config.headers.Authorization = 'Bearer ' + token;
|
|
|
|
return $http.get(client.apiOrigin + url, config)
|
|
.success(defaultSuccessHandler(callback))
|
|
.error(defaultErrorHandler(callback));
|
|
}
|
|
|
|
function head(url, config, callback) {
|
|
if (arguments.length !== 3) {
|
|
console.error('HEAD', arguments);
|
|
throw('Wrong number of arguments');
|
|
}
|
|
|
|
config = config || {};
|
|
config.headers = config.headers || {};
|
|
config.headers.Authorization = 'Bearer ' + token;
|
|
|
|
return $http.head(client.apiOrigin + url, config)
|
|
.success(defaultSuccessHandler(callback))
|
|
.error(defaultErrorHandler(callback));
|
|
}
|
|
|
|
function post(url, data, config, callback) {
|
|
if (arguments.length !== 4) {
|
|
console.error('POST', arguments);
|
|
throw('Wrong number of arguments');
|
|
}
|
|
|
|
data = data || {};
|
|
config = config || {};
|
|
config.headers = config.headers || {};
|
|
config.headers.Authorization = 'Bearer ' + token;
|
|
|
|
return $http.post(client.apiOrigin + url, data, config)
|
|
.success(defaultSuccessHandler(callback))
|
|
.error(defaultErrorHandler(callback));
|
|
}
|
|
|
|
function put(url, data, config, callback) {
|
|
if (arguments.length !== 4) {
|
|
console.error('PUT', arguments);
|
|
throw('Wrong number of arguments');
|
|
}
|
|
|
|
data = data || {};
|
|
config = config || {};
|
|
config.headers = config.headers || {};
|
|
config.headers.Authorization = 'Bearer ' + token;
|
|
|
|
return $http.put(client.apiOrigin + url, data, config)
|
|
.success(defaultSuccessHandler(callback))
|
|
.error(defaultErrorHandler(callback));
|
|
}
|
|
|
|
function del(url, config, callback) {
|
|
if (arguments.length !== 3) {
|
|
console.error('DEL', arguments);
|
|
throw('Wrong number of arguments');
|
|
}
|
|
|
|
config = config || {};
|
|
config.headers = config.headers || {};
|
|
config.headers.Authorization = 'Bearer ' + token;
|
|
|
|
return $http.delete(client.apiOrigin + url, config)
|
|
.success(defaultSuccessHandler(callback))
|
|
.error(defaultErrorHandler(callback));
|
|
}
|
|
|
|
function Client() {
|
|
this.offline = false;
|
|
this._ready = false;
|
|
this._configListener = [];
|
|
this._readyListener = [];
|
|
this._reconnectListener = [];
|
|
this._userInfo = {
|
|
id: null,
|
|
username: null,
|
|
email: null,
|
|
twoFactorAuthenticationEnabled: false,
|
|
source: null,
|
|
avatarUrl: null
|
|
};
|
|
this._config = {
|
|
apiServerOrigin: null,
|
|
webServerOrigin: null,
|
|
fqdn: null,
|
|
ip: null,
|
|
revision: null,
|
|
update: { box: null, apps: null },
|
|
progress: {},
|
|
region: null,
|
|
size: null
|
|
};
|
|
this._installedApps = [];
|
|
this._installedAppsById = {};
|
|
this._appTags = [];
|
|
// window.location fallback for websocket connections which do not have relative uris
|
|
this.apiOrigin = '<%= apiOrigin %>' || window.location.origin;
|
|
this.avatar = '';
|
|
this._appstoreAppCache = [];
|
|
|
|
this.resetAvatar();
|
|
|
|
this.setToken(localStorage.token);
|
|
}
|
|
|
|
Client.prototype.error = function (error, action) {
|
|
var message = '';
|
|
|
|
console.error(error);
|
|
|
|
if (typeof error === 'object') {
|
|
message = error.message || error;
|
|
} else {
|
|
message = error;
|
|
}
|
|
|
|
// give more info in case the error was a request which failed with empty response body,
|
|
// this happens mostly if the box crashes
|
|
if (message === 'Empty message or object') {
|
|
message = 'Got empty response. Click to check the server logs.'
|
|
action = action || '/logs.html?id=box';
|
|
}
|
|
|
|
this.notify('Cloudron Error', message, true, 'error', action);
|
|
};
|
|
|
|
// handles application startup errors, mostly only when dashboard is loaded and api endpoint is down
|
|
Client.prototype.initError = function (error, initFunction) {
|
|
console.error('Application startup error', error);
|
|
|
|
$timeout(initFunction, 5000); // we will try to re-init the app
|
|
};
|
|
|
|
Client.prototype.clearNotifications = function () {
|
|
Notification.clearAll();
|
|
};
|
|
|
|
/*
|
|
|
|
If `action` is a non-empty string, it will be treated as a url, if it is a function, that function will be exectued on click
|
|
|
|
*/
|
|
Client.prototype.notify = function (title, message, persistent, type, action) {
|
|
var options = { title: title, message: message};
|
|
|
|
if (persistent) options.delay = 'never'; // any non Number means never timeout
|
|
|
|
if (action) {
|
|
options.onClick = function (/* params */) {
|
|
// if action is a string, we assume it is a link
|
|
if (typeof action === 'string' && action !== '') window.location = action;
|
|
else if (typeof action === 'function') action();
|
|
else console.warn('Notification action is not supported.', action);
|
|
};
|
|
}
|
|
|
|
if (type === 'error') Notification.error(options);
|
|
else if (type === 'success') Notification.success(options);
|
|
else if (type === 'info') Notification.info(options);
|
|
else if (type === 'warning') Notification.warning(options);
|
|
else throw('Invalid notification type "' + type + '"');
|
|
};
|
|
|
|
Client.prototype.setReady = function () {
|
|
if (this._ready) return;
|
|
|
|
this._ready = true;
|
|
this._readyListener.forEach(function (callback) {
|
|
callback();
|
|
});
|
|
|
|
// clear the listeners, we only callback once!
|
|
this._readyListener = [];
|
|
};
|
|
|
|
Client.prototype.onReady = function (callback) {
|
|
if (this._ready) callback();
|
|
else this._readyListener.push(callback);
|
|
};
|
|
|
|
Client.prototype.onConfig = function (callback) {
|
|
this._configListener.push(callback);
|
|
if (this._config && this._config.apiServerOrigin) callback(this._config);
|
|
};
|
|
|
|
Client.prototype.onReconnect = function (callback) {
|
|
if (this._ready) callback();
|
|
else this._reconnectListener.push(callback);
|
|
};
|
|
|
|
Client.prototype.resetAvatar = function () {
|
|
this.avatar = this.apiOrigin + '/api/v1/cloudron/avatar?' + String(Math.random()).slice(2);
|
|
|
|
var favicon = $('#favicon');
|
|
if (favicon) favicon.attr('href', this.avatar);
|
|
};
|
|
|
|
Client.prototype.setUserInfo = function (userInfo) {
|
|
// In order to keep the angular bindings alive, set each property individually
|
|
this._userInfo.id = userInfo.id;
|
|
this._userInfo.username = userInfo.username;
|
|
this._userInfo.email = userInfo.email;
|
|
this._userInfo.fallbackEmail = userInfo.fallbackEmail;
|
|
this._userInfo.displayName = userInfo.displayName;
|
|
this._userInfo.twoFactorAuthenticationEnabled = userInfo.twoFactorAuthenticationEnabled;
|
|
this._userInfo.role = userInfo.role;
|
|
this._userInfo.source = userInfo.source;
|
|
this._userInfo.avatarUrl = userInfo.avatarUrl + '?s=128&default=mp&ts=' + Date.now(); // we add the timestamp to avoid caching
|
|
this._userInfo.isAtLeastOwner = [ ROLES.OWNER ].indexOf(userInfo.role) !== -1;
|
|
this._userInfo.isAtLeastAdmin = [ ROLES.OWNER, ROLES.ADMIN ].indexOf(userInfo.role) !== -1;
|
|
this._userInfo.isAtLeastUserManager = [ ROLES.OWNER, ROLES.ADMIN, ROLES.USER_MANAGER ].indexOf(userInfo.role) !== -1;
|
|
};
|
|
|
|
Client.prototype.setConfig = function (config) {
|
|
var that = this;
|
|
|
|
angular.copy(config, this._config);
|
|
|
|
<% if (appstore.webOrigin) { -%>
|
|
this._config.webServerOrigin = '<%= appstore.webOrigin %>';
|
|
<% } -%>
|
|
|
|
<% if (appstore.ApiOrigin) { -%>
|
|
this._config.apiServerOrigin = '<%= appstore.apiOrigin %>';
|
|
<% } -%>
|
|
|
|
// => This is just for easier testing
|
|
// this._config.features.userMaxCount = 5;
|
|
// this._config.features.domainMaxCount = 1;
|
|
// this._config.features.externalLdap = false;
|
|
// this._config.features.privateDockerRegistry = false;
|
|
// this._config.features.branding = true;
|
|
// this._config.features.support = true;
|
|
// this._config.features.directoryConfig = true;
|
|
// this._config.features.mailboxMaxCount = 5;
|
|
// this._config.features.emailPremium = false;
|
|
|
|
this._configListener.forEach(function (callback) {
|
|
callback(that._config);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getInstalledApps = function () {
|
|
return this._installedApps;
|
|
};
|
|
|
|
Client.prototype.getAppTags = function () {
|
|
return this._appTags;
|
|
};
|
|
|
|
Client.prototype.getUserInfo = function () {
|
|
return this._userInfo;
|
|
};
|
|
|
|
Client.prototype.getConfig = function () {
|
|
return this._config;
|
|
};
|
|
|
|
Client.prototype.setToken = function (accessToken) {
|
|
if (!accessToken) localStorage.removeItem('token');
|
|
else localStorage.token = accessToken;
|
|
|
|
// set the token closure
|
|
token = accessToken;
|
|
};
|
|
|
|
Client.prototype.getToken = function () {
|
|
return token;
|
|
};
|
|
|
|
Client.prototype.makeURL = function (url) {
|
|
if (url.indexOf('?') === -1) {
|
|
return this.apiOrigin + url + '?access_token=' + token;
|
|
} else {
|
|
return this.apiOrigin + url + '&access_token=' + token;
|
|
}
|
|
};
|
|
|
|
/*
|
|
* Rest API wrappers
|
|
*/
|
|
Client.prototype.config = function (callback) {
|
|
get('/api/v1/config', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200 || typeof data !== 'object') return callback(new ClientError(status, data));
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.userInfo = function (callback) {
|
|
get('/api/v1/profile', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200 || typeof data !== 'object') return callback(new ClientError(status, data));
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.changeCloudronAvatar = function (avatarFile, callback) {
|
|
var fd = new FormData();
|
|
fd.append('avatar', avatarFile);
|
|
|
|
var config = {
|
|
headers: { 'Content-Type': undefined },
|
|
transformRequest: angular.identity
|
|
};
|
|
|
|
post('/api/v1/branding/cloudron_avatar', fd, config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.changeCloudronName = function (name, callback) {
|
|
var data = {
|
|
name: name
|
|
};
|
|
|
|
post('/api/v1/branding/cloudron_name', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.installApp = function (id, manifest, title, config, callback) {
|
|
var that = this;
|
|
var data = {
|
|
appStoreId: id + '@' + manifest.version,
|
|
location: config.location,
|
|
domain: config.domain,
|
|
portBindings: config.portBindings,
|
|
accessRestriction: config.accessRestriction,
|
|
cert: config.cert,
|
|
key: config.key,
|
|
sso: config.sso,
|
|
overwriteDns: config.overwriteDns
|
|
};
|
|
|
|
post('/api/v1/apps/install', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.id);
|
|
});
|
|
};
|
|
|
|
Client.prototype.cloneApp = function (appId, config, callback) {
|
|
var data = {
|
|
location: config.location,
|
|
domain: config.domain,
|
|
portBindings: config.portBindings,
|
|
backupId: config.backupId
|
|
};
|
|
|
|
post('/api/v1/apps/' + appId + '/clone', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.restoreApp = function (appId, backupId, callback) {
|
|
var data = { backupId: backupId };
|
|
|
|
post('/api/v1/apps/' + appId + '/restore', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.backupApp = function (appId, callback) {
|
|
var data = {};
|
|
|
|
post('/api/v1/apps/' + appId + '/backup', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.uninstallApp = function (appId, callback) {
|
|
var data = {};
|
|
|
|
post('/api/v1/apps/' + appId + '/uninstall', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.configureApp = function (id, setting, data, callback) {
|
|
post('/api/v1/apps/' + id + '/configure/' + setting, data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200 && status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.repairApp = function (id, data, callback) {
|
|
post('/api/v1/apps/' + id + '/repair', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200 && status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.updateApp = function (id, manifest, options, callback) {
|
|
var data = {
|
|
appStoreId: manifest.id + '@' + manifest.version,
|
|
skipBackup: !!options.skipBackup
|
|
};
|
|
|
|
post('/api/v1/apps/' + id + '/update', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.startApp = function (id, callback) {
|
|
post('/api/v1/apps/' + id + '/start', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.stopApp = function (id, callback) {
|
|
post('/api/v1/apps/' + id + '/stop', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.restartApp = function (id, callback) {
|
|
post('/api/v1/apps/' + id + '/restart', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.debugApp = function (id, state, callback) {
|
|
var data = {
|
|
debugMode: state ? {
|
|
readonlyRootfs: true,
|
|
cmd: [ '/bin/bash', '-c', 'echo "Repair mode. Use the webterminal or cloudron exec to repair. Sleeping" && sleep infinity' ]
|
|
} : null
|
|
};
|
|
|
|
post('/api/v1/apps/' + id + '/configure/debug_mode', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.version = function (callback) {
|
|
get('/api/v1/cloudron/status', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getStatus = function (callback) {
|
|
get('/api/v1/cloudron/status', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200 || typeof data !== 'object') return callback(new ClientError(status, data));
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setBackupConfig = function (backupConfig, callback) {
|
|
post('/api/v1/settings/backup_config', backupConfig, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getBackupConfig = function (callback) {
|
|
get('/api/v1/settings/backup_config', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.checkBackupConfig = function (callback) {
|
|
get('/api/v1/backups/check', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getSupportConfig = function (callback) {
|
|
get('/api/v1/settings/support_config', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setExternalLdapConfig = function (config, callback) {
|
|
post('/api/v1/settings/external_ldap_config', config, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getExternalLdapConfig = function (callback) {
|
|
get('/api/v1/settings/external_ldap_config', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setDirectoryConfig = function (config, callback) {
|
|
post('/api/v1/settings/directory_config', config, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getDirectoryConfig = function (callback) {
|
|
get('/api/v1/settings/directory_config', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
// network
|
|
Client.prototype.setSysinfoConfig = function (config, callback) {
|
|
post('/api/v1/settings/sysinfo_config', config, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getServerIp = function (callback) {
|
|
get('/api/v1/cloudron/server_ip', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.ip);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getSysinfoConfig = function (callback) {
|
|
get('/api/v1/settings/sysinfo_config', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getBlocklist = function (callback) {
|
|
var config = {};
|
|
|
|
get('/api/v1/network/blocklist', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data.blocklist);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setBlocklist = function (blocklist, callback) {
|
|
post('/api/v1/network/blocklist', { blocklist: blocklist }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setDynamicDnsConfig = function (enabled, callback) {
|
|
post('/api/v1/settings/dynamic_dns', { enabled: enabled }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getDynamicDnsConfig = function (callback) {
|
|
get('/api/v1/settings/dynamic_dns', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.enabled);
|
|
});
|
|
};
|
|
|
|
// branding
|
|
Client.prototype.setFooter = function (footer, callback) {
|
|
post('/api/v1/branding/footer', { footer: footer }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getFooter = function (callback) {
|
|
get('/api/v1/branding/footer', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.footer);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setUnstableAppsConfig = function (enabled, callback) {
|
|
post('/api/v1/settings/unstable_apps', { enabled: enabled }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getUnstableAppsConfig = function (callback) {
|
|
get('/api/v1/settings/unstable_apps', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data.enabled);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setRegistryConfig = function (rc, callback) {
|
|
post('/api/v1/settings/registry_config', rc, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getRegistryConfig = function (callback) {
|
|
get('/api/v1/settings/registry_config', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getUpdateInfo = function (callback) {
|
|
if (!this._userInfo.isAtLeastAdmin) return callback(new Error('Not allowed'));
|
|
|
|
get('/api/v1/cloudron/update', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.checkForUpdates = function (callback) {
|
|
post('/api/v1/cloudron/check_for_updates', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
client.refreshConfig(callback);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setAutoupdatePattern = function (pattern, callback) {
|
|
post('/api/v1/settings/autoupdate_pattern', { pattern: pattern }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getAutoupdatePattern = function (callback) {
|
|
get('/api/v1/settings/autoupdate_pattern', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setTimeZone = function (timeZone, callback) {
|
|
post('/api/v1/settings/time_zone', { timeZone: timeZone }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getTimeZone = function (callback) {
|
|
get('/api/v1/settings/time_zone', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.timeZone);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getRemoteSupport = function (callback) {
|
|
get('/api/v1/support/remote_support', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.enabled);
|
|
});
|
|
};
|
|
|
|
Client.prototype.enableRemoteSupport = function (enable, callback) {
|
|
post('/api/v1/support/remote_support', { enable: enable }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getBackups = function (callback) {
|
|
get('/api/v1/backups', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.backups);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getLatestTaskByType = function (type, callback) {
|
|
get('/api/v1/tasks?page=1&per_page=1&type=' + type, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.tasks.length ? data.tasks[0] : null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getTask = function (taskId, callback) {
|
|
get('/api/v1/tasks/' + taskId, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getTaskLogs = function (taskId, follow, lines, callback) {
|
|
if (follow) {
|
|
var eventSource = new EventSource(client.apiOrigin + '/api/v1/tasks/' + taskId + '/logstream?lines=' + lines + '&access_token=' + token);
|
|
callback(null, eventSource);
|
|
} else {
|
|
get('/api/v1/services/' + taskId + '/logs?lines=' + lines, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
}
|
|
};
|
|
|
|
Client.prototype.startBackup = function (callback) {
|
|
post('/api/v1/backups/create', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.taskId);
|
|
});
|
|
};
|
|
|
|
Client.prototype.cleanupBackups = function (callback) {
|
|
post('/api/v1/backups/cleanup', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.taskId);
|
|
});
|
|
};
|
|
|
|
Client.prototype.stopTask = function (taskId, callback) {
|
|
post('/api/v1/tasks/' + taskId + '/stop', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.restore = function (backupConfig, backupId, version, sysinfoConfig, callback) {
|
|
var data = {
|
|
backupConfig: backupConfig,
|
|
backupId: backupId,
|
|
version: version,
|
|
sysinfoConfig: sysinfoConfig
|
|
};
|
|
|
|
post('/api/v1/cloudron/restore', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.importBackup = function (appId, backupId, backupFormat, backupConfig, callback) {
|
|
var data = {
|
|
backupId: backupId,
|
|
backupFormat: backupFormat,
|
|
backupConfig: backupConfig,
|
|
};
|
|
|
|
post('/api/v1/apps/' + appId + '/import', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getNotifications = function (acknowledged, page, perPage, callback) {
|
|
var config = {
|
|
params: {
|
|
page: page,
|
|
per_page: perPage
|
|
}
|
|
};
|
|
|
|
if (typeof acknowledged === 'boolean') config.params.acknowledged = acknowledged;
|
|
|
|
get('/api/v1/notifications', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.notifications);
|
|
});
|
|
};
|
|
|
|
Client.prototype.ackNotification = function (notificationId, callback) {
|
|
post('/api/v1/notifications/' + notificationId, {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getEvent = function (eventId, callback) {
|
|
get('/api/v1/cloudron/eventlog/' + eventId, {}, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.event);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getEventLogs = function (actions, search, page, perPage, callback) {
|
|
var config = {
|
|
params: {
|
|
actions: actions,
|
|
search: search,
|
|
page: page,
|
|
per_page: perPage
|
|
}
|
|
};
|
|
|
|
get('/api/v1/cloudron/eventlog', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.eventlogs);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getPlatformLogs = function (unit, follow, lines, callback) {
|
|
if (follow) {
|
|
var eventSource = new EventSource(client.apiOrigin + '/api/v1/cloudron/logstream/' + unit + '?lines=' + lines + '&access_token=' + token);
|
|
callback(null, eventSource);
|
|
} else {
|
|
get('/api/v1/cloudron/logs/' + unit + '?lines=' + lines, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
}
|
|
};
|
|
|
|
Client.prototype.getServiceLogs = function (serviceName, follow, lines, callback) {
|
|
if (follow) {
|
|
var eventSource = new EventSource(client.apiOrigin + '/api/v1/services/' + serviceName + '/logstream?lines=' + lines + '&access_token=' + token);
|
|
callback(null, eventSource);
|
|
} else {
|
|
get('/api/v1/services/' + serviceName + '/logs?lines=' + lines, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
}
|
|
};
|
|
|
|
Client.prototype.getApps = function (callback) {
|
|
var that = this;
|
|
|
|
get('/api/v1/apps', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
var apps = data.apps;
|
|
for (var i = 0; i < apps.length; i++) {
|
|
that._appPostProcess(apps[i]); // this will also set the correct iconUrl
|
|
}
|
|
|
|
callback(null, apps);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getAppLogs = function (appId, follow, lines, callback) {
|
|
if (follow) {
|
|
var eventSource = new EventSource(client.apiOrigin + '/api/v1/apps/' + appId + '/logstream?lines=' + lines + '&access_token=' + token);
|
|
callback(null, eventSource);
|
|
} else {
|
|
get('/api/v1/apps/' + appId + '/logs', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
}
|
|
};
|
|
|
|
Client.prototype.getAppBackups = function (appId, callback) {
|
|
get('/api/v1/apps/' + appId + '/backups', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.backups);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getServices = function (callback) {
|
|
get('/api/v1/services', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.services);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getService = function (serviceName, callback) {
|
|
get('/api/v1/services/' + serviceName, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.service);
|
|
});
|
|
};
|
|
|
|
Client.prototype.configureService = function (serviceName, data, callback) {
|
|
post('/api/v1/services/' + serviceName, data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.restartService = function (serviceName, callback) {
|
|
post('/api/v1/services/' + serviceName + '/restart', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getUsers = function (search, page, perPage, callback) {
|
|
if (typeof search === 'function') {
|
|
callback = search;
|
|
search = '';
|
|
page = 1;
|
|
perPage = 5000;
|
|
}
|
|
|
|
var config = {
|
|
params: {
|
|
page: page,
|
|
per_page: perPage
|
|
}
|
|
};
|
|
|
|
if (search) config.params.search = search;
|
|
|
|
get('/api/v1/users', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.users);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getUser = function (userId, callback) {
|
|
get('/api/v1/users/' + userId, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getGroups = function (callback) {
|
|
get('/api/v1/groups', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.groups);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setGroups = function (userId, groupIds, callback) {
|
|
put('/api/v1/users/' + userId + '/groups', { groupIds: groupIds }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getGroup = function (groupId, callback) {
|
|
get('/api/v1/groups/' + groupId, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.createGroup = function (name, callback) {
|
|
var data = {
|
|
name: name
|
|
};
|
|
|
|
post('/api/v1/groups', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.updateGroup = function (id, name, callback) {
|
|
var data = {
|
|
name: name
|
|
};
|
|
|
|
post('/api/v1/groups/' + id, data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setGroupMembers = function (id, userIds, callback) {
|
|
var data = {
|
|
userIds: userIds
|
|
|
|
};
|
|
|
|
put('/api/v1/groups/' + id + '/members', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.removeGroup = function (groupId, callback) {
|
|
var config = {
|
|
data: {},
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
}
|
|
};
|
|
|
|
del('/api/v1/groups/' + groupId, config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getApp = function (appId, callback) {
|
|
var that = this;
|
|
|
|
get('/api/v1/apps/' + appId, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
that._appPostProcess(data);
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getAppWithTask = function (appId, callback) {
|
|
var that = this;
|
|
|
|
this.getApp(appId, function (error, app) {
|
|
if (error) return callback(error);
|
|
|
|
if (!app.taskId) return callback(null, app);
|
|
|
|
that.getTask(app.taskId, function (error, task) {
|
|
if (error) return callback(error);
|
|
|
|
if (task) {
|
|
app.progress = task.percent;
|
|
app.message = task.message;
|
|
app.taskMinutesActive = moment.duration(moment.utc().diff(moment.utc(task.creationTime))).asMinutes();
|
|
} else {
|
|
app.progress = 0;
|
|
app.message = '';
|
|
app.taskMinutesActive = 0;
|
|
}
|
|
|
|
callback(null, app);
|
|
});
|
|
});
|
|
};
|
|
|
|
Client.prototype.getCachedAppSync = function (appId) {
|
|
var appFound = null;
|
|
this._installedApps.some(function (app) {
|
|
if (app.id === appId) {
|
|
appFound = app;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
});
|
|
|
|
return appFound;
|
|
};
|
|
|
|
Client.prototype.createInvite = function (userId, callback) {
|
|
post('/api/v1/users/' + userId + '/create_invite', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.sendInvite = function (userId, callback) {
|
|
post('/api/v1/users/' + userId + '/send_invite', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setup = function (data, callback) {
|
|
post('/api/v1/cloudron/setup', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.createAdmin = function (username, password, email, displayName, callback) {
|
|
var that = this;
|
|
|
|
var data = {
|
|
username: username,
|
|
password: password,
|
|
email: email,
|
|
displayName: displayName
|
|
};
|
|
|
|
post('/api/v1/cloudron/activate', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
that.setToken(data.token);
|
|
that.setUserInfo({ username: username, email: email, admin: true, twoFactorAuthenticationEnabled: false, source: '', avatarUrl: null });
|
|
|
|
callback(null, data.activated);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getTokens = function (callback) {
|
|
get('/api/v1/tokens/', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.tokens);
|
|
});
|
|
};
|
|
|
|
Client.prototype.createToken = function (name, callback) {
|
|
var data = {
|
|
name: name
|
|
};
|
|
|
|
post('/api/v1/tokens', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.token);
|
|
});
|
|
};
|
|
|
|
// FIXME clashes with existing getToken()
|
|
// Client.prototype.getToken = function (id, callback) {
|
|
// get('/api/v1/tokens/' + id, null, function (error, data, status) {
|
|
// if (error) return callback(error);
|
|
// if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
// callback(null, data.token);
|
|
// });
|
|
// };
|
|
|
|
Client.prototype.delToken = function (tokenId, callback) {
|
|
del('/api/v1/tokens/' + tokenId, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.addAppPassword = function (identifier, name, callback) {
|
|
var data = {
|
|
identifier: identifier,
|
|
name: name
|
|
};
|
|
|
|
post('/api/v1/app_passwords', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getAppPasswords = function (callback) {
|
|
get('/api/v1/app_passwords', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.delAppPassword = function (id, callback) {
|
|
del('/api/v1/app_passwords/' + id, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.update = function (options, callback) {
|
|
var data = {
|
|
skipBackup: !!options.skipBackup
|
|
};
|
|
|
|
post('/api/v1/cloudron/update', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.taskId);
|
|
});
|
|
};
|
|
|
|
Client.prototype.isRebootRequired = function (callback) {
|
|
get('/api/v1/cloudron/reboot', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.rebootRequired);
|
|
});
|
|
};
|
|
|
|
Client.prototype.reboot = function (callback) {
|
|
post('/api/v1/cloudron/reboot', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setCertificate = function (certificateFile, keyFile, callback) {
|
|
var data = {
|
|
cert: certificateFile,
|
|
key: keyFile
|
|
};
|
|
|
|
post('/api/v1/settings/certificate', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.disks = function (callback) {
|
|
get('/api/v1/cloudron/disks', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.memory = function (callback) {
|
|
get('/api/v1/cloudron/memory', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.graphs = function (targets, from, options, callback) {
|
|
// if we have a lot of apps, targets can be very large. node will just disconnect since it exceeds header size
|
|
var size = 10, chunks = [];
|
|
for (var i = 0; i < targets.length; i += size) {
|
|
chunks.push(targets.slice(i, i+size));
|
|
}
|
|
|
|
var result = [];
|
|
async.eachSeries(chunks, function (chunk, iteratorCallback) {
|
|
var config = {
|
|
params: {
|
|
target: chunk,
|
|
format: 'json',
|
|
from: from,
|
|
until: 'now'
|
|
}
|
|
};
|
|
|
|
if (options.noNullPoints) config.params.noNullPoints = true;
|
|
|
|
get('/api/v1/cloudron/graphs', config, function (error, data, status) {
|
|
if (error) return iteratorCallback(error);
|
|
if (status !== 200) return iteratorCallback(new ClientError(status, data));
|
|
|
|
// the datapoint returned here is an [value, timestamp]
|
|
result = result.concat(data);
|
|
iteratorCallback(null);
|
|
});
|
|
}, function iteratorDone(error) {
|
|
callback(error, result);
|
|
});
|
|
};
|
|
|
|
Client.prototype.createTicket = function (type, subject, description, appId /* optional */, altEmail /* optional */, callback) {
|
|
var data = {
|
|
type: type,
|
|
subject: subject,
|
|
description: description,
|
|
appId: appId || undefined,
|
|
altEmail: altEmail || undefined
|
|
};
|
|
|
|
post('/api/v1/support/ticket', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.createUser = function (user, callback) {
|
|
var data = {
|
|
email: user.email,
|
|
displayName: user.displayName,
|
|
role: user.role
|
|
};
|
|
|
|
if (user.username !== null) data.username = user.username;
|
|
|
|
post('/api/v1/users', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.updateUser = function (user, callback) {
|
|
var data = {
|
|
email: user.email,
|
|
displayName: user.displayName,
|
|
fallbackEmail: user.fallbackEmail,
|
|
active: user.active,
|
|
role: user.role
|
|
};
|
|
|
|
post('/api/v1/users/' + user.id, data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.removeUser = function (userId, callback) {
|
|
var config = {
|
|
data: {},
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
}
|
|
};
|
|
|
|
del('/api/v1/users/' + userId, config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.updateProfile = function (data, callback) {
|
|
post('/api/v1/profile', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.clearAvatar = function (callback) {
|
|
del('/api/v1/profile/avatar', {}, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.changeAvatar = function (avatarFile, callback) {
|
|
var fd = new FormData();
|
|
fd.append('avatar', avatarFile);
|
|
|
|
var config = {
|
|
headers: { 'Content-Type': undefined },
|
|
transformRequest: angular.identity
|
|
};
|
|
|
|
post('/api/v1/profile/avatar', fd, config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.changePassword = function (currentPassword, newPassword, callback) {
|
|
var data = {
|
|
password: currentPassword,
|
|
newPassword: newPassword
|
|
};
|
|
|
|
post('/api/v1/profile/password', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setTwoFactorAuthenticationSecret = function (callback) {
|
|
var data = {};
|
|
|
|
post('/api/v1/profile/twofactorauthentication', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.enableTwoFactorAuthentication = function (totpToken, callback) {
|
|
var data = {
|
|
totpToken: totpToken
|
|
};
|
|
|
|
post('/api/v1/profile/twofactorauthentication/enable', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.disableTwoFactorAuthentication = function (password, callback) {
|
|
var data = {
|
|
password: password
|
|
};
|
|
|
|
post('/api/v1/profile/twofactorauthentication/disable', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.startExternalLdapSync = function (callback) {
|
|
post('/api/v1/cloudron/sync_external_ldap', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.taskId);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setUserActive = function (userId, active, callback) {
|
|
var data = {
|
|
active: active
|
|
};
|
|
|
|
post('/api/v1/users/' + userId + '/active', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.refreshUserInfo = function (callback) {
|
|
var that = this;
|
|
|
|
callback = typeof callback === 'function' ? callback : function () {};
|
|
|
|
this.userInfo(function (error, result) {
|
|
if (error) return callback(error);
|
|
|
|
that.setUserInfo(result);
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.refreshConfig = function (callback) {
|
|
var that = this;
|
|
|
|
callback = typeof callback === 'function' ? callback : function () {};
|
|
|
|
this.config(function (error, result) {
|
|
if (error) return callback(error);
|
|
|
|
that.getUpdateInfo(function (error, info) { // note: non-admin users may get access denied for this
|
|
if (!error) result.update = info.update; // attach update information to config object
|
|
|
|
that.setConfig(result);
|
|
callback(null);
|
|
});
|
|
});
|
|
};
|
|
|
|
Client.prototype._appPostProcess = function (app) {
|
|
// calculate the icon paths
|
|
app.iconUrl = app.iconUrl ? (this.apiOrigin + app.iconUrl + '?access_token=' + token + '&' + app.manifest.version) : null;
|
|
|
|
// amend the post install confirm state
|
|
app.pendingPostInstallConfirmation = !!localStorage['confirmPostInstall_' + app.id];
|
|
|
|
if (app.manifest.description) { // can be empty for dev apps
|
|
var tmp = app.manifest.description.match(/\<upstream\>(.*)\<\/upstream\>/i);
|
|
app.upstreamVersion = (tmp && tmp[1]) ? tmp[1] : '';
|
|
} else {
|
|
app.upstreamVersion = '';
|
|
}
|
|
|
|
if (!app.manifest.title) app.manifest.title = 'Untitled';
|
|
|
|
if (app.manifest.postInstallMessage) {
|
|
var text= app.manifest.postInstallMessage;
|
|
// we chose - because underscore has special meaning in markdown
|
|
text = text.replace(/\$CLOUDRON-APP-DOMAIN/g, app.fqdn);
|
|
text = text.replace(/\$CLOUDRON-APP-ORIGIN/g, 'https://' + app.fqdn);
|
|
text = text.replace(/\$CLOUDRON-API-DOMAIN/g, this._config.adminFqdn);
|
|
text = text.replace(/\$CLOUDRON-API-ORIGIN/g, 'https://' + this._config.adminFqdn);
|
|
text = text.replace(/\$CLOUDRON-USERNAME/g, this._userInfo.username);
|
|
text = text.replace(/\$CLOUDRON-APP-ID/g, app.id);
|
|
|
|
// [^] matches even newlines. '?' makes it non-greedy
|
|
if (app.sso) text = text.replace(/<nosso>[^]*?<\/nosso>/g, '');
|
|
else text = text.replace(/<sso>[^]*?<\/sso>/g, '');
|
|
|
|
app.manifest.postInstallMessage = text;
|
|
}
|
|
|
|
return app;
|
|
};
|
|
|
|
function binarySearch(array, pred) {
|
|
var lo = -1, hi = array.length;
|
|
while (1 + lo !== hi) {
|
|
var mi = lo + ((hi - lo) >> 1);
|
|
if (pred(array[mi])) {
|
|
hi = mi;
|
|
} else {
|
|
lo = mi;
|
|
}
|
|
}
|
|
return hi;
|
|
}
|
|
|
|
Client.prototype._updateAppCache = function (app) {
|
|
var tmp = {};
|
|
angular.copy(app, tmp);
|
|
|
|
var foundIndex = this._installedApps.findIndex(function (a) { return a.id === app.id; });
|
|
|
|
// we replace new data into the existing reference to keep angular bindings
|
|
if (foundIndex !== -1) {
|
|
angular.copy(tmp, this._installedApps[foundIndex]);
|
|
} else {
|
|
this._installedApps.push(tmp);
|
|
}
|
|
|
|
// add reference to object map with appId keys
|
|
this._installedAppsById[app.id] = this._installedApps[foundIndex];
|
|
|
|
// TODO this not very elegant
|
|
// update app tags
|
|
tmp = this._installedApps
|
|
.map(function (app) { return app.tags || []; }) // return array of arrays
|
|
.reduce(function (a, i) { return a.concat(i); }, []) // merge all arrays into one
|
|
.filter(function (v, i, self) { return self.indexOf(v) === i; }) // filter duplicates
|
|
.sort(function (a, b) { return a.localeCompare(b); }); // sort
|
|
|
|
// keep tag array references
|
|
angular.copy(tmp, this._appTags);
|
|
};
|
|
|
|
Client.prototype.refreshInstalledApps = function (callback) {
|
|
var that = this;
|
|
|
|
this.getApps(function (error, apps) {
|
|
if (error) return callback(error);
|
|
|
|
async.eachLimit(apps, 20, function (app, iteratorCallback) {
|
|
var getTaskFunc = app.taskId ? that.getTask.bind(null, app.taskId) : function (next) { return next(); };
|
|
getTaskFunc(function (error, task) {
|
|
if (error) return iteratorCallback(error);
|
|
|
|
if (task) {
|
|
app.progress = task.percent;
|
|
app.message = task.message;
|
|
app.taskMinutesActive = moment.duration(moment.utc().diff(moment.utc(task.creationTime))).asMinutes();
|
|
} else {
|
|
app.progress = 0;
|
|
app.message = '';
|
|
app.taskMinutesActive = 0;
|
|
}
|
|
|
|
that._updateAppCache(app);
|
|
|
|
iteratorCallback(null);
|
|
});
|
|
}, function iteratorDone(error) {
|
|
if (error) return callback(error);
|
|
|
|
// filter out old apps, going backwards to allow splicing
|
|
for (var i = that._installedApps.length - 1; i >= 0; --i) {
|
|
if (!apps.some(function (elem) { return (elem.id === that._installedApps[i].id); })) {
|
|
var removed = that._installedApps.splice(i, 1);
|
|
delete that._installedAppsById[removed[0].id];
|
|
}
|
|
}
|
|
|
|
callback(null);
|
|
});
|
|
});
|
|
};
|
|
|
|
Client.prototype.login = function () {
|
|
this.setToken(null);
|
|
|
|
window.location.href = '/login.html?returnTo=/' + encodeURIComponent(window.location.hash);
|
|
};
|
|
|
|
Client.prototype.logout = function () {
|
|
var token = this.getToken();
|
|
this.setToken(null);
|
|
|
|
// invalidates the token
|
|
window.location.href = client.apiOrigin + '/api/v1/cloudron/logout?access_token=' + token;
|
|
};
|
|
|
|
Client.prototype.uploadFile = function (appId, file, progressCallback, callback) {
|
|
var fd = new FormData();
|
|
fd.append('file', file);
|
|
|
|
var config = {
|
|
headers: { 'Content-Type': undefined },
|
|
transformRequest: angular.identity,
|
|
uploadEventHandlers: {
|
|
progress: progressCallback
|
|
}
|
|
};
|
|
|
|
post('/api/v1/apps/' + appId + '/upload?file=' + encodeURIComponent('/tmp/' + file.name), fd, config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.checkDownloadableFile = function (appId, filePath, callback) {
|
|
var config = {
|
|
headers: { 'Content-Type': undefined }
|
|
};
|
|
|
|
head('/api/v1/apps/' + appId + '/download?file=' + encodeURIComponent(filePath), config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.sendTestMail = function (domain, to, callback) {
|
|
var data = {
|
|
to: to
|
|
};
|
|
|
|
post('/api/v1/mail/' + domain + '/send_test_mail', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
// Domains
|
|
Client.prototype.getDomains = function (callback) {
|
|
get('/api/v1/domains', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.domains);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getDomain = function (domain, callback) {
|
|
get('/api/v1/domains/' + domain, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.checkDNSRecords = function (domain, subdomain, callback) {
|
|
get('/api/v1/domains/' + domain + '/dns_check?subdomain=' + subdomain, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.addDomain = function (domain, zoneName, provider, config, fallbackCertificate, tlsConfig, callback) {
|
|
var data = {
|
|
domain: domain,
|
|
provider: provider,
|
|
config: config,
|
|
tlsConfig: tlsConfig
|
|
};
|
|
if (zoneName) data.zoneName = zoneName;
|
|
var that = this;
|
|
|
|
if (fallbackCertificate) data.fallbackCertificate = fallbackCertificate;
|
|
|
|
// hack until we fix the domains.js
|
|
post('/api/v1/domains', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback();
|
|
});
|
|
};
|
|
|
|
Client.prototype.updateDomain = function (domain, zoneName, provider, config, fallbackCertificate, tlsConfig, callback) {
|
|
var data = {
|
|
provider: provider,
|
|
config: config,
|
|
tlsConfig: tlsConfig
|
|
};
|
|
if (zoneName) data.zoneName = zoneName;
|
|
var that = this;
|
|
|
|
if (fallbackCertificate) data.fallbackCertificate = fallbackCertificate;
|
|
|
|
put('/api/v1/domains/' + domain, data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
that.setDnsRecords(domain, callback); // this is done so that an out-of-sync dkim key can be synced
|
|
});
|
|
};
|
|
|
|
Client.prototype.renewCerts = function (domain, callback) {
|
|
post('/api/v1/cloudron/renew_certs', { domain: domain || null }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.taskId);
|
|
});
|
|
};
|
|
|
|
Client.prototype.removeDomain = function (domain, callback) {
|
|
var config = {
|
|
data: {
|
|
},
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
}
|
|
};
|
|
|
|
del('/api/v1/domains/' + domain, config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.prepareDashboardDomain = function (domain, callback) {
|
|
var data = {
|
|
domain: domain
|
|
};
|
|
|
|
post('/api/v1/cloudron/prepare_dashboard_domain', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.taskId);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setDashboardDomain = function (domain, callback) {
|
|
var data = {
|
|
domain: domain
|
|
};
|
|
|
|
post('/api/v1/cloudron/set_dashboard_domain', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
// Email
|
|
Client.prototype.getMailEventLogs = function (search, types, page, perPage, callback) {
|
|
var config = {
|
|
params: {
|
|
page: page,
|
|
types: types,
|
|
per_page: perPage,
|
|
search: search
|
|
}
|
|
};
|
|
|
|
get('/api/v1/mailserver/eventlog', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data.eventlogs);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getMailUsage = function (domain, callback) {
|
|
var config = {
|
|
params: {
|
|
domain: domain
|
|
}
|
|
};
|
|
|
|
get('/api/v1/mailserver/usage', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data.usage);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getMailLocation = function (callback) {
|
|
var config = {};
|
|
|
|
get('/api/v1/mailserver/location', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data); // { subdomain, domain }
|
|
});
|
|
};
|
|
|
|
Client.prototype.setMailLocation = function (subdomain, domain, callback) {
|
|
post('/api/v1/mailserver/location', { subdomain: subdomain, domain: domain }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, { taskId: data.taskId });
|
|
});
|
|
};
|
|
|
|
Client.prototype.getMaxEmailSize = function (callback) {
|
|
var config = {};
|
|
|
|
get('/api/v1/mailserver/max_email_size', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data.size);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setMaxEmailSize = function (size, callback) {
|
|
post('/api/v1/mailserver/max_email_size', { size: size }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getSpamAcl = function (callback) {
|
|
var config = {};
|
|
|
|
get('/api/v1/mailserver/spam_acl', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setSpamAcl = function (acl, callback) {
|
|
post('/api/v1/mailserver/spam_acl', { whitelist: acl.whitelist, blacklist: acl.blacklist }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getSpamCustomConfig = function (callback) {
|
|
var config = {};
|
|
|
|
get('/api/v1/mailserver/spam_custom_config', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data.config);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setSpamCustomConfig = function (config, callback) {
|
|
post('/api/v1/mailserver/spam_custom_config', { config: config }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getMailConfigForDomain = function (domain, callback) {
|
|
get('/api/v1/mail/' + domain, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.enableMailForDomain = function (domain, enabled, callback) {
|
|
post('/api/v1/mail/' + domain + '/enable', { enabled: enabled }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setDnsRecords = function (domain, callback) {
|
|
post('/api/v1/mail/' + domain + '/dns', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getMailStatusForDomain = function (domain, callback) {
|
|
get('/api/v1/mail/' + domain + '/status', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setMailRelay = function (domain, data, callback) {
|
|
post('/api/v1/mail/' + domain + '/relay', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setMailBanner = function (domain, data, callback) {
|
|
post('/api/v1/mail/' + domain + '/banner', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setCatchallAddresses = function (domain, addresses, callback) {
|
|
post('/api/v1/mail/' + domain + '/catch_all', { addresses: addresses }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setMailFromValidation = function (domain, enabled, callback) {
|
|
post('/api/v1/mail/' + domain + '/mail_from_validation', { enabled: enabled }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
// Mailboxes
|
|
Client.prototype.getMailboxCount = function (domain, callback) {
|
|
get('/api/v1/mail/' + domain + '/mailbox_count', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.count);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getMailboxes = function (domain, search, page, perPage, callback) {
|
|
var config = {
|
|
params: {
|
|
search: search,
|
|
page: page,
|
|
per_page: perPage
|
|
}
|
|
};
|
|
|
|
get('/api/v1/mail/' + domain + '/mailboxes', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.mailboxes);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getMailbox = function (domain, name, callback) {
|
|
get('/api/v1/mail/' + domain + '/mailboxes/' + name, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.mailbox);
|
|
});
|
|
};
|
|
|
|
Client.prototype.addMailbox = function (domain, name, userId, callback) {
|
|
var data = {
|
|
name: name,
|
|
userId: userId
|
|
};
|
|
|
|
post('/api/v1/mail/' + domain + '/mailboxes', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.updateMailbox = function (domain, name, userId, callback) {
|
|
var data = {
|
|
userId: userId
|
|
};
|
|
|
|
post('/api/v1/mail/' + domain + '/mailboxes/' + name, data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.removeMailbox = function (domain, name, deleteMails, callback) {
|
|
var config = {
|
|
data: {
|
|
deleteMails: deleteMails
|
|
},
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
}
|
|
};
|
|
|
|
del('/api/v1/mail/' + domain + '/mailboxes/' + name, config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getAliases = function (name, domain, callback) {
|
|
var config = {
|
|
params: {
|
|
page: 1,
|
|
per_page: 1000
|
|
}
|
|
};
|
|
|
|
get('/api/v1/mail/' + domain + '/mailboxes/' + name + '/aliases', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.aliases);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setAliases = function (name, domain, aliases, callback) {
|
|
var data = {
|
|
aliases: aliases
|
|
};
|
|
|
|
put('/api/v1/mail/' + domain + '/mailboxes/' + name + '/aliases', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.listMailingLists = function (domain, search, page, perPage, callback) {
|
|
var config = {
|
|
params: {
|
|
search: search,
|
|
page: page,
|
|
per_page: perPage
|
|
}
|
|
};
|
|
|
|
get('/api/v1/mail/' + domain + '/lists', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.lists);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getMailingList = function (domain, name, callback) {
|
|
get('/api/v1/mail/' + domain + '/lists/' + name, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.list);
|
|
});
|
|
};
|
|
|
|
Client.prototype.addMailingList = function (domain, name, members, membersOnly, callback) {
|
|
var data = {
|
|
name: name,
|
|
members: members,
|
|
membersOnly: membersOnly
|
|
};
|
|
|
|
post('/api/v1/mail/' + domain + '/lists', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.updateMailingList = function (domain, name, members, membersOnly, callback) {
|
|
var data = {
|
|
members: members,
|
|
membersOnly: membersOnly
|
|
};
|
|
|
|
post('/api/v1/mail/' + domain + '/lists/' + name, data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.removeMailingList = function (domain, name, callback) {
|
|
del('/api/v1/mail/' + domain + '/lists/' + name, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getAppstoreUserToken = function (callback) {
|
|
post('/api/v1/appstore/user_token', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.accessToken);
|
|
});
|
|
};
|
|
|
|
// This will change the location
|
|
Client.prototype.openSubscriptionSetup = function (subscription) {
|
|
// we only allow the owner to do so
|
|
if (!this._userInfo.isAtLeastOwner) return;
|
|
|
|
// basically the user has not setup appstore account yet
|
|
if (!subscription.plan) return window.location.href = '/#/appstore';
|
|
|
|
var that = this;
|
|
|
|
var email = subscription.emailEncoded;
|
|
var cloudronId = subscription.cloudronId;
|
|
|
|
if (!this._userInfo.isAtLeastOwner) return window.location.href = that.getConfig().webServerOrigin + '/console.html#/userprofile?view=subscriptions&email=' + email + '&cloudronId=' + cloudronId;
|
|
|
|
this.getAppstoreUserToken(function (error, token) {
|
|
if (error) console.error('Unable to get appstore user token.', error);
|
|
|
|
var url = that.getConfig().webServerOrigin + '/console.html#/userprofile?view=subscriptions&email=' + email + '&token=' + token;
|
|
|
|
// Only open the subscription setup dialog when no subscription exists
|
|
if (!subscription.plan || subscription.plan.id === 'free') url += '&cloudronId=' + cloudronId
|
|
|
|
window.location.href = url;
|
|
});
|
|
};
|
|
|
|
Client.prototype.getAppstoreAppByIdAndVersion = function (appId, version, callback) {
|
|
var url = '/api/v1/appstore/apps/' + appId;
|
|
if (version && version !== 'latest') url += '/versions/' + version;
|
|
|
|
get(url, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getAppstoreApps = function (callback) {
|
|
var that = this;
|
|
|
|
get('/api/v1/appstore/apps', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
angular.copy(data.apps, that._appstoreAppCache);
|
|
|
|
return callback(null, that._appstoreAppCache);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getAppstoreAppsFast = function (callback) {
|
|
if (this._appstoreAppCache.length !== 0) return callback(null, this._appstoreAppCache);
|
|
|
|
this.getAppstoreApps(callback);
|
|
};
|
|
|
|
Client.prototype.getSubscription = function (callback) {
|
|
if (!this._userInfo.isAtLeastAdmin) return callback(new Error('Not allowed'));
|
|
|
|
get('/api/v1/appstore/subscription', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
// just some helper property, since angular bindings cannot dot his easily
|
|
data.emailEncoded = encodeURIComponent(data.email);
|
|
|
|
callback(null, data); // { email, plan: { id, name }, cancel_at, status }
|
|
});
|
|
};
|
|
|
|
Client.prototype.registerCloudron = function (email, password, totpToken, signup, purpose, callback) {
|
|
var data = {
|
|
email: email,
|
|
password: password,
|
|
signup: signup,
|
|
purpose: purpose
|
|
};
|
|
|
|
if (totpToken) data.totpToken = totpToken;
|
|
|
|
post('/api/v1/appstore/register_cloudron', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
// FileManager API
|
|
// mode can be 'download', 'open', 'link' or 'data'
|
|
Client.prototype.filesGet = function (appId, path, mode, callback) {
|
|
if (mode === 'download') {
|
|
window.open(client.apiOrigin + '/api/v1/apps/' + appId + '/files/' + path + '?download=true&access_token=' + token);
|
|
callback(null);
|
|
} else if (mode === 'open') {
|
|
window.open(client.apiOrigin + '/api/v1/apps/' + appId + '/files/' + path + '?download=false&access_token=' + token);
|
|
callback(null);
|
|
} else if (mode === 'link') {
|
|
callback(null, client.apiOrigin + '/api/v1/apps/' + appId + '/files/' + path + '?download=false&access_token=' + token);
|
|
} else {
|
|
function responseHandler(data, headers, status) {
|
|
if (headers()['content-type'] && headers()['content-type'].indexOf('application/json') !== -1) return JSON.parse(data);
|
|
return data;
|
|
}
|
|
|
|
get('/api/v1/apps/' + appId + '/files/' + path, { transformResponse: responseHandler }, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
}
|
|
};
|
|
|
|
Client.prototype.filesRemove = function (appId, path, callback) {
|
|
del('/api/v1/apps/' + appId + '/files/' + path, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.filesChown = function (appId, path, uid, recursive, callback) {
|
|
put('/api/v1/apps/' + appId + '/files/' + path, { uid: uid, recursive: recursive }, {}, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.filesRename = function (appId, path, newPath, callback) {
|
|
put('/api/v1/apps/' + appId + '/files/' + path, { newFilePath: newPath }, {}, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.filesCreateDirectory = function (appId, path, callback) {
|
|
post('/api/v1/apps/' + appId + '/files/' + path, { directory: path }, {}, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.filesUpload = function (appId, path, file, progressHandler, callback) {
|
|
var fd = new FormData();
|
|
fd.append('file', file);
|
|
|
|
function done(error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
}
|
|
|
|
$http({
|
|
url: client.apiOrigin + '/api/v1/apps/' + appId + '/files/' + path,
|
|
method: 'POST',
|
|
data: fd,
|
|
transformRequest: angular.identity,
|
|
headers: {
|
|
'Content-Type': undefined,
|
|
Authorization: 'Bearer ' + token
|
|
},
|
|
|
|
uploadEventHandlers: {
|
|
progress: function (e) {
|
|
progressHandler(e.loaded);
|
|
}
|
|
}
|
|
}).success(defaultSuccessHandler(done)).error(defaultErrorHandler(done));
|
|
};
|
|
|
|
client = new Client();
|
|
return client;
|
|
}]);
|