made a separate route instead of reusing install route. this was because we want to copy over all the old app config as much as possible.
4184 lines
157 KiB
JavaScript
4184 lines
157 KiB
JavaScript
'use strict';
|
|
|
|
/* global $, angular, async */
|
|
|
|
// keep in sync with box/src/notfications.js
|
|
const NOTIFICATION_TYPES = {
|
|
ALERT_CLOUDRON_INSTALLED: 'cloudronInstalled',
|
|
ALERT_CLOUDRON_UPDATED: 'cloudronUpdated',
|
|
ALERT_CLOUDRON_UPDATE_FAILED: 'cloudronUpdateFailed',
|
|
ALERT_CERTIFICATE_RENEWAL_FAILED: 'certificateRenewalFailed',
|
|
ALERT_BACKUP_CONFIG: 'backupConfig',
|
|
ALERT_DISK_SPACE: 'diskSpace',
|
|
ALERT_MAIL_STATUS: 'mailStatus',
|
|
ALERT_REBOOT: 'reboot',
|
|
ALERT_BOX_UPDATE: 'boxUpdate',
|
|
ALERT_UPDATE_UBUNTU: 'ubuntuUpdate',
|
|
ALERT_MANUAL_APP_UPDATE: 'manualAppUpdate',
|
|
ALERT_APP_OOM: 'appOutOfMemory',
|
|
ALERT_APP_UPDATED: 'appUpdated',
|
|
ALERT_BACKUP_FAILED: 'backupFailed',
|
|
};
|
|
|
|
// 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_IMPORT: 'pending_import',
|
|
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_SERVICES_CHANGE: 'pending_services_change',
|
|
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',
|
|
MAIL_MANAGER: 'mailmanager',
|
|
USER_MANAGER: 'usermanager',
|
|
USER: 'user'
|
|
};
|
|
|
|
// sync up with tokens.js
|
|
const TOKEN_TYPES = {
|
|
ID_WEBADMIN: 'cid-webadmin', // dashboard
|
|
ID_DEVELOPMENT: 'cid-development', // dashboard development
|
|
ID_CLI: 'cid-cli', // cloudron cli
|
|
ID_SDK: 'cid-sdk', // created by user via dashboard
|
|
};
|
|
|
|
// sync up with tasks.js
|
|
var TASK_TYPES = {
|
|
TASK_APP: 'app',
|
|
TASK_BACKUP: 'backup',
|
|
TASK_UPDATE: 'update',
|
|
TASK_CHECK_CERTS: 'checkCerts',
|
|
TASK_PREPARE_DASHBOARD_LOCATION: 'prepareDashboardLocation',
|
|
TASK_CLEAN_BACKUPS: 'cleanBackups',
|
|
TASK_SYNC_EXTERNAL_LDAP: 'syncExternalLdap',
|
|
TASK_CHANGE_MAIL_LOCATION: 'changeMailLocation',
|
|
TASK_SYNC_DNS_RECORDS: 'syncDnsRecords',
|
|
TASK_UPDATE_DISK_USAGE: 'updateDiskUsage',
|
|
TASK_SYNC_DYNDNS: 'syncDyndns',
|
|
};
|
|
|
|
const APP_TYPES = {
|
|
APP: 'app', //default
|
|
LINK: 'link',
|
|
PROXIED: 'proxied'
|
|
};
|
|
|
|
var SECRET_PLACEHOLDER = String.fromCharCode(0x25CF).repeat(8);
|
|
|
|
// List is from http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
|
|
const REGIONS_S3 = [
|
|
{ name: 'Africa (Cape Town)', value: 'af-south-1' },
|
|
{ name: 'Asia Pacific (Hong Kong)', value: 'ap-east-1' },
|
|
{ name: 'Asia Pacific (Hyderabad)', value: 'ap-south-2' },
|
|
{ name: 'Asia Pacific (Jakarta)', value: 'ap-southeast-3' },
|
|
{ name: 'Asia Pacific (Melbourne)', value: 'ap-southeast-4' },
|
|
{ name: 'Asia Pacific (Mumbai)', value: 'ap-south-1' },
|
|
{ name: 'Asia Pacific (Osaka)', value: 'ap-northeast-3' },
|
|
{ name: 'Asia Pacific (Seoul)', value: 'ap-northeast-2' },
|
|
{ name: 'Asia Pacific (Singapore)', value: 'ap-southeast-1' },
|
|
{ name: 'Asia Pacific (Sydney)', value: 'ap-southeast-2' },
|
|
{ name: 'Asia Pacific (Tokyo)', value: 'ap-northeast-1' },
|
|
{ name: 'Canada (Central)', value: 'ca-central-1' },
|
|
{ name: 'China (Beijing)', value: 'cn-north-1' },
|
|
{ name: 'China (Ningxia)', value: 'cn-northwest-1' },
|
|
{ name: 'Middle East (Bahrain)', value: 'me-south-1' },
|
|
{ name: 'Middle East (UAE)', value: 'me-central-1' },
|
|
{ name: 'EU (Frankfurt)', value: 'eu-central-1' },
|
|
{ name: 'EU (Ireland)', value: 'eu-west-1' },
|
|
{ name: 'EU (London)', value: 'eu-west-2' },
|
|
{ name: 'EU (Milan)', value: 'eu-south-1' },
|
|
{ name: 'EU (Paris)', value: 'eu-west-3' },
|
|
{ name: 'EU (Spain)', value: 'eu-south-2' },
|
|
{ name: 'EU (Stockholm)', value: 'eu-north-1' },
|
|
{ name: 'EU (Zurich)', value: 'eu-central-2' },
|
|
{ name: 'South America (São Paulo)', value: 'sa-east-1' },
|
|
{ name: 'US East (N. Virginia)', value: 'us-east-1' },
|
|
{ name: 'US East (Ohio)', value: 'us-east-2' },
|
|
{ name: 'US West (N. California)', value: 'us-west-1' },
|
|
{ name: 'US West (Oregon)', value: 'us-west-2' },
|
|
];
|
|
|
|
// https://wasabi.com/locations/
|
|
const REGIONS_WASABI = [
|
|
{ name: 'Amsterdam (EU Central 1)', value: 'https://s3.eu-central-1.wasabisys.com' },
|
|
{ name: 'Frankfurt (EU Central 2)', value: 'https://s3.eu-central-2.wasabisys.com' },
|
|
{ name: 'London (EU West 1)', value: 'https://s3.eu-west-1.wasabisys.com' },
|
|
{ name: 'Oregon (US West 1)', value: 'https://s3.us-west-1.wasabisys.com' },
|
|
{ name: 'Osaka (AP Northeast 2)', value: 'https://s3.ap-northeast-2.wasabisys.com' },
|
|
{ name: 'Paris (EU West 2)', value: 'https://s3.eu-west-2.wasabisys.com' },
|
|
{ name: 'Plano (US Central 1)', value: 'https://s3.us-central-1.wasabisys.com' },
|
|
{ name: 'Singapore (AP Southeast 1)', value: 'https://s3.ap-southeast-1.wasabisys.com' },
|
|
{ name: 'Sydney (AP Southeast 2)', value: 'https://s3.ap-southeast-2.wasabisys.com' },
|
|
{ name: 'Tokyo (AP Northeast 1)', value: 'https://s3.ap-northeast-1.wasabisys.com' },
|
|
{ name: 'Toronto (CA Central 1)', value: 'https://s3.ca-central-1.wasabisys.com' },
|
|
{ name: 'Virginia (US East 1)', value: 'https://s3.us-east-1.wasabisys.com' },
|
|
{ name: 'Virginia (US East 2)', value: 'https://s3.us-east-2.wasabisys.com' }
|
|
];
|
|
|
|
const REGIONS_HETZNER = [
|
|
{ name: 'Falkenstein (FSN1)', value: 'https://fsn1.your-objectstorage.com' },
|
|
{ name: 'Helsinki (HEL1)', value: 'https://hel1.your-objectstorage.com' },
|
|
{ name: 'Nuremberg (NBG1)', value: 'https://nbg1.your-objectstorage.com' }
|
|
];
|
|
|
|
// https://docs.digitalocean.com/products/platform/availability-matrix/
|
|
const REGIONS_DIGITALOCEAN = [
|
|
{ name: 'AMS3', value: 'https://ams3.digitaloceanspaces.com' },
|
|
{ name: 'FRA1', value: 'https://fra1.digitaloceanspaces.com' },
|
|
{ name: 'LON1', value: 'https://lon1.digitaloceanspaces.com' },
|
|
{ name: 'NYC3', value: 'https://nyc3.digitaloceanspaces.com' },
|
|
{ name: 'SFO2', value: 'https://sfo2.digitaloceanspaces.com' },
|
|
{ name: 'SFO3', value: 'https://sfo3.digitaloceanspaces.com' },
|
|
{ name: 'SGP1', value: 'https://sgp1.digitaloceanspaces.com' },
|
|
{ name: 'SYD1', value: 'https://syd1.digitaloceanspaces.com' }
|
|
];
|
|
|
|
// https://www.exoscale.com/datacenters/
|
|
const REGIONS_EXOSCALE = [
|
|
{ name: 'Vienna (AT-VIE-1)', value: 'https://sos-at-vie-1.exo.io' },
|
|
{ name: 'Vienna (AT-VIE-2)', value: 'https://sos-at-vie-2.exo.io' },
|
|
{ name: 'Sofia (BG-SOF-1)', value: 'https://sos-bg-sof-1.exo.io' },
|
|
{ name: 'Zurich (CH-DK-2)', value: 'https://sos-ch-dk-2.exo.io' },
|
|
{ name: 'Geneva (CH-GVA-2)', value: 'https://sos-ch-gva-2.exo.io' },
|
|
{ name: 'Frankfurt (DE-FRA-1)', value: 'https://sos-de-fra-1.exo.io' },
|
|
{ name: 'Munich (DE-MUC-1)', value: 'https://sos-de-muc-1.exo.io' },
|
|
];
|
|
|
|
// https://www.scaleway.com/docs/object-storage-feature/
|
|
const REGIONS_SCALEWAY = [
|
|
{ name: 'Paris (FR-PAR)', value: 'https://s3.fr-par.scw.cloud', region: 'fr-par' }, // default
|
|
{ name: 'Amsterdam (NL-AMS)', value: 'https://s3.nl-ams.scw.cloud', region: 'nl-ams' },
|
|
{ name: 'Warsaw (PL-WAW)', value: 'https://s3.pl-waw.scw.cloud', region: 'nl-ams' }
|
|
];
|
|
|
|
// https://www.linode.com/docs/products/storage/object-storage/guides/urls/
|
|
const REGIONS_LINODE = [
|
|
{ name: 'Amsterdam', value: 'https://nl-ams-1.linodeobjects.com', region: 'nl-ams-1' },
|
|
{ name: 'Atlanta', value: 'https://us-southeast-1.linodeobjects.com', region: 'us-southeast-1' },
|
|
{ name: 'Chennai', value: 'https://in-maa-1.linodeobjects.com', region: 'in-maa-1' },
|
|
{ name: 'Chicago', value: 'https://us-ord-1.linodeobjects.com', region: 'us-ord-1' },
|
|
{ name: 'Frankfurt', value: 'https://eu-central-1.linodeobjects.com', region: 'eu-central-1' },
|
|
{ name: 'Jakarta', value: 'https://id-cgk-1.linodeobjects.com', region: 'id-cgk-1' },
|
|
{ name: 'Los Angeles, CA (USA)', value: 'https://us-lax-1.linodeobjects.com', region: 'us-lax-1' },
|
|
{ name: 'Miami', value: 'https://us-mia-1.linodeobjects.com', region: 'us-mia-1' },
|
|
{ name: 'Milan', value: 'https://it-mil-1.linodeobjects.com', region: 'it-mil-1' },
|
|
{ name: 'Newark', value: 'https://us-east-1.linodeobjects.com', region: 'us-east-1' }, // default
|
|
{ name: 'Osaka', value: 'https://jp-osa-1.linodeobjects.com', region: 'jp-osa-1' },
|
|
{ name: 'Paris', value: 'https://fr-par-1.linodeobjects.com', region: 'fr-par-1' },
|
|
{ name: 'Sao Paulo', value: 'https://br-gru-1.linodeobjects.com', region: 'br-gru-1' },
|
|
{ name: 'Seattle', value: 'https://us-sea-1.linodeobjects.com', region: 'us-sea-1' },
|
|
{ name: 'Singapore', value: 'https://ap-south-1.linodeobjects.com', region: 'ap-south-1' },
|
|
{ name: 'Stockholm', value: 'https://se-sto-1.linodeobjects.com', region: 'se-sto-1' },
|
|
{ name: 'Washington', value: 'https://us-iad-1.linodeobjects.com', region: 'us-iad-1' },
|
|
];
|
|
|
|
// note: ovh also has a storage endpoint but that only supports path style access (https://docs.ovh.com/au/en/storage/object-storage/s3/location/)
|
|
const REGIONS_OVH = [
|
|
{ name: 'Beauharnois (BHS)', value: 'https://s3.bhs.io.cloud.ovh.net', region: 'bhs' }, // default
|
|
{ name: 'Frankfurt (DE)', value: 'https://s3.de.io.cloud.ovh.net', region: 'de' },
|
|
{ name: 'Gravelines (GRA)', value: 'https://s3.gra.io.cloud.ovh.net', region: 'gra' },
|
|
{ name: 'Roubaix (RBX)', value: 'https://s3.rbx.io.cloud.ovh.net', region: 'rbx' },
|
|
{ name: 'Strasbourg (SBG)', value: 'https://s3.sbg.io.cloud.ovh.net', region: 'sbg' },
|
|
{ name: 'London (UK)', value: 'https://s3.uk.io.cloud.ovh.net', region: 'uk' },
|
|
{ name: 'Sydney (SYD)', value: 'https://s3.syd.io.cloud.ovh.net', region: 'syd' },
|
|
{ name: 'Warsaw (WAW)', value: 'https://s3.waw.io.cloud.ovh.net', region: 'waw' },
|
|
];
|
|
|
|
const ENDPOINTS_OVH = [
|
|
{ name: 'OVH Europe', value: 'ovh-eu' },
|
|
{ name: 'OVH US', value: 'ovh-us' },
|
|
{ name: 'OVH North-America', value: 'ovh-ca' },
|
|
{ name: 'SoYouStart Europe', value: 'soyoustart-eu' },
|
|
{ name: 'SoYouStart North-America', value: 'soyoustart-ca' },
|
|
{ name: 'Kimsufi Europe', value: 'kimsufi-eu' },
|
|
{ name: 'Kimsufi North-America', value: 'kimsufi-ca' },
|
|
];
|
|
|
|
// https://docs.ionos.com/cloud/managed-services/s3-object-storage/endpoints
|
|
const REGIONS_IONOS = [
|
|
{ name: 'Berlin (eu-central-3)', value: 'https://s3.eu-central-3.ionoscloud.com', region: 'de' }, // default. contract-owned
|
|
{ name: 'Frankfurt (DE)', value: 'https://s3.eu-central-1.ionoscloud.com', region: 'de' },
|
|
{ name: 'Berlin (eu-central-2)', value: 'https://s3-eu-central-2.ionoscloud.com', region: 'eu-central-2' },
|
|
{ name: 'Logrono (eu-south-2)', value: 'https://s3-eu-south-2.ionoscloud.com', region: 'eu-south-2' },
|
|
];
|
|
|
|
// this is not used anywhere because upcloud needs endpoint URL. we detect region from the URL (https://upcloud.com/data-centres)
|
|
const REGIONS_UPCLOUD = [
|
|
{ name: 'AU-SYD1 (Australia)', value: 'https://au-syd1.upcloudobjects.com', region: 'au-syd1' }, // default
|
|
{ name: 'DE-FRA1 (Germany)', value: 'https://de-fra1.upcloudobjects.com', region: 'de-fra1' },
|
|
{ name: 'ES-MAD1 (Spain)', value: 'https://es-mad1.upcloudobjects.com', region: 'es-mad1' },
|
|
{ name: 'FI-HEL2 (Finland)', value: 'https://fi-hel2.upcloudobjects.com', region: 'fi-hel2' },
|
|
{ name: 'NL-AMS1 (Netherlands)', value: 'https://nl-ams1.upcloudobjects.com', region: 'nl-ams1' },
|
|
{ name: 'PL-WAW1 (Poland)', value: 'https://pl-waw1.upcloudobjects.com', region: 'pl-waw1' },
|
|
{ name: 'SG-SIN1 (Singapore)', value: 'https://sg-sin1.upcloudobjects.com', region: 'sg-sin1' },
|
|
{ name: 'UK-LON1 (United Kingdom)', value: 'https://uk-lon1.upcloudobjects.com', region: 'uk-lon1' },
|
|
{ name: 'US-CHI1 (USA)', value: 'https://us-chi1.upcloudobjects.com', region: 'us-chi1' },
|
|
{ name: 'US-NYC1 (USA)', value: 'https://us-nyc1.upcloudobjects.com', region: 'us-nyc1' },
|
|
{ name: 'US-SJO1 (USA)', value: 'https://us-sjo1.upcloudobjects.com', region: 'us-sjo1' },
|
|
];
|
|
|
|
// region is ignored in vultr (https://www.vultr.com/docs/vultr-object-storage/)
|
|
const REGIONS_VULTR = [
|
|
{ name: 'Amsterdam', value: 'https://ams1.vultrobjects.com', region: 'eu-central-1' },
|
|
{ name: 'Bangalore', value: 'https://blr1.vultrobjects.com', region: 'ap-south-1' },
|
|
{ name: 'New Jersey', value: 'https://ewr1.vultrobjects.com', region: 'us-east-1' },
|
|
{ name: 'Silicon Valley', value: 'https://sjc1.vultrobjects.com', region: 'us-west-1' },
|
|
{ name: 'Singapore', value: 'https://sgp1.vultrobjects.com', region: 'ap-southeast-1' },
|
|
];
|
|
|
|
// https://docs.contabo.com/docs/products/Object-Storage/s3-connection-settings
|
|
const REGIONS_CONTABO = [
|
|
{ name: 'European Union (Germany)', value: 'https://eu2.contabostorage.com' , region: 'us-east-1' },
|
|
{ name: 'Singapore', value: 'https://sin1.contabostorage.com' , region: 'us-east-1' },
|
|
{ name: 'United States', value: 'https://usc1.contabostorage.com' , region: 'us-east-1' }
|
|
];
|
|
|
|
const STORAGE_PROVIDERS = [
|
|
{ name: 'Amazon S3', value: 's3' },
|
|
{ name: 'Backblaze B2 (S3 API)', value: 'backblaze-b2' },
|
|
{ name: 'CIFS Mount', value: 'cifs' },
|
|
{ name: 'Cloudflare R2', value: 'cloudflare-r2' },
|
|
{ name: 'Contabo Object Storage', value: 'contabo-objectstorage' },
|
|
{ name: 'DigitalOcean Spaces', value: 'digitalocean-spaces' },
|
|
{ name: 'External/Local Disk (EXT4 or XFS)', value: 'disk' },
|
|
{ name: 'EXT4 Disk', value: 'ext4' },
|
|
{ name: 'Exoscale SOS', value: 'exoscale-sos' },
|
|
{ name: 'Filesystem', value: 'filesystem' },
|
|
{ name: 'Filesystem (Mountpoint)', value: 'mountpoint' }, // legacy
|
|
{ name: 'Google Cloud Storage', value: 'gcs' },
|
|
{ name: 'Hetzner Object Storage', value: 'hetzner-objectstorage' },
|
|
{ name: 'IDrive e2', value: 'idrive-e2' },
|
|
{ name: 'IONOS (Profitbricks)', value: 'ionos-objectstorage' },
|
|
{ name: 'Linode Object Storage', value: 'linode-objectstorage' },
|
|
{ name: 'Minio', value: 'minio' },
|
|
{ name: 'NFS Mount', value: 'nfs' },
|
|
{ name: 'OVH Object Storage', value: 'ovh-objectstorage' },
|
|
{ name: 'S3 API Compatible (v4)', value: 's3-v4-compat' },
|
|
{ name: 'Scaleway Object Storage', value: 'scaleway-objectstorage' },
|
|
{ name: 'SSHFS Mount', value: 'sshfs' },
|
|
{ name: 'UpCloud Object Storage', value: 'upcloud-objectstorage' },
|
|
{ name: 'Vultr Object Storage', value: 'vultr-objectstorage' },
|
|
{ name: 'Wasabi', value: 'wasabi' },
|
|
{ name: 'XFS Disk', value: 'xfs' },
|
|
];
|
|
|
|
const BACKUP_FORMATS = [
|
|
{ name: 'Tarball (zipped)', value: 'tgz' },
|
|
{ name: 'rsync', value: 'rsync' }
|
|
];
|
|
|
|
// ----------------------------------------------
|
|
// Helper to ensure loading a fallback app icon on first load failure
|
|
// ----------------------------------------------
|
|
function imageErrorHandler(elem) {
|
|
elem.src = elem.getAttribute('fallback-icon');
|
|
}
|
|
|
|
// ----------------------------------------------
|
|
// Shared Angular Filters
|
|
// ----------------------------------------------
|
|
|
|
// https://en.wikipedia.org/wiki/Binary_prefix
|
|
// binary units (IEC) 1024 based
|
|
function prettyBinarySize(size, fallback) {
|
|
if (!size) return fallback || 0;
|
|
if (size === -1) return 'Unlimited';
|
|
|
|
// we can also use KB here (JEDEC)
|
|
var i = Math.floor(Math.log(size) / Math.log(1024));
|
|
return (size / Math.pow(1024, i)).toFixed(3) * 1 + ' ' + ['B', 'KiB', 'MiB', 'GiB', 'TiB'][i];
|
|
}
|
|
|
|
// decimal units (SI) 1000 based
|
|
function prettyDecimalSize(size, fallback) {
|
|
if (!size) return fallback || 0;
|
|
|
|
var i = Math.floor(Math.log(size) / Math.log(1000));
|
|
return (size / Math.pow(1000, i)).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
|
|
}
|
|
|
|
angular.module('Application').filter('prettyDecimalSize', function () {
|
|
return function (size, fallback) { return prettyDecimalSize(size, fallback) || '0 kb'; };
|
|
});
|
|
|
|
angular.module('Application').filter('prettyBinarySize', function () {
|
|
return function (size, fallback) { return prettyBinarySize(size, fallback) || '0 KiB'; };
|
|
});
|
|
|
|
angular.module('Application').filter('prettyDiskSize', function () {
|
|
return function (size, fallback) { return prettyDecimalSize(size, fallback) || 'Not available yet'; };
|
|
});
|
|
|
|
angular.module('Application').filter('trKeyFromPeriod', function () {
|
|
return function (period) {
|
|
if (period === 6) return 'app.graphs.period.6h';
|
|
if (period === 12) return 'app.graphs.period.12h';
|
|
if (period === 24) return 'app.graphs.period.24h';
|
|
if (period === 24*7) return 'app.graphs.period.7d';
|
|
if (period === 24*30) return 'app.graphs.period.30d';
|
|
|
|
return '';
|
|
};
|
|
});
|
|
|
|
angular.module('Application').filter('prettyDate', function ($translate) {
|
|
// http://ejohn.org/files/pretty.js
|
|
return function prettyDate(utc) {
|
|
if (utc === null) return $translate.instant('main.prettyDate.never', {});
|
|
|
|
var date = new Date(utc), // this converts utc into browser timezone and not cloudron timezone!
|
|
diff = (((new Date()).getTime() - date.getTime()) / 1000) + 30, // add 30seconds for clock skew
|
|
day_diff = Math.floor(diff / 86400);
|
|
|
|
if (isNaN(day_diff) || day_diff < 0) return $translate.instant('main.prettyDate.justNow', {});
|
|
|
|
return day_diff === 0 && (diff < 60 && $translate.instant('main.prettyDate.justNow', {}) ||
|
|
moment(utc).locale(navigator.language).format('LT')) ||
|
|
day_diff === 1 && $translate.instant('main.prettyDate.yeserday', {}) ||
|
|
moment(utc).locale(navigator.language).format('L');
|
|
};
|
|
});
|
|
|
|
angular.module('Application').filter('prettyFutureDate', function () {
|
|
return function prettyFutureDate(utc) {
|
|
return moment(utc).fromNow(); // this converts utc into browser timezone and not cloudron timezone!
|
|
};
|
|
});
|
|
|
|
angular.module('Application').filter('prettyLongDate', function () {
|
|
return function prettyLongDate(utc) {
|
|
return moment(utc).locale(navigator.language).format('LLL'); // this converts utc into browser timezone and not cloudron timezone!
|
|
};
|
|
});
|
|
|
|
angular.module('Application').filter('prettyShortDate', function () {
|
|
return function prettyShortDate(utc) {
|
|
return moment(utc).locale(navigator.language).format('L'); // this converts utc into browser timezone and not cloudron timezone!
|
|
};
|
|
});
|
|
|
|
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];
|
|
};
|
|
});
|
|
|
|
angular.module('Application').config(['$translateProvider', function ($translateProvider) {
|
|
$translateProvider.useStaticFilesLoader({
|
|
prefix: 'translation/',
|
|
suffix: '.json'
|
|
});
|
|
$translateProvider.useLocalStorage();
|
|
$translateProvider.preferredLanguage('en');
|
|
$translateProvider.fallbackLanguage('en');
|
|
}]);
|
|
|
|
// Add shorthand "tr" filter to avoid having ot use "translate"
|
|
// This is a copy of the code at https://github.com/angular-translate/angular-translate/blob/master/src/filter/translate.js
|
|
// If we find out how to get that function handle somehow dynamically we can use that, otherwise the copy is required
|
|
function translateFilterFactory($parse, $translate) {
|
|
var translateFilter = function (translationId, interpolateParams, interpolation, forceLanguage) {
|
|
if (!angular.isObject(interpolateParams)) {
|
|
var ctx = this || {
|
|
'__SCOPE_IS_NOT_AVAILABLE': 'More info at https://github.com/angular/angular.js/commit/8863b9d04c722b278fa93c5d66ad1e578ad6eb1f'
|
|
};
|
|
interpolateParams = $parse(interpolateParams)(ctx);
|
|
}
|
|
|
|
return $translate.instant(translationId, interpolateParams, interpolation, forceLanguage);
|
|
};
|
|
|
|
if ($translate.statefulFilter()) {
|
|
translateFilter.$stateful = true;
|
|
}
|
|
|
|
return translateFilter;
|
|
}
|
|
translateFilterFactory.displayName = 'translateFilterFactory';
|
|
angular.module('Application').filter('tr', translateFilterFactory);
|
|
|
|
// checks provision status and redirects to correct view
|
|
// {
|
|
// setup: { active, message, errorMessage }
|
|
// restore { active, message, errorMessage }
|
|
// activated
|
|
// adminFqn
|
|
// }
|
|
// returns true if redirected . currentView is one of dashboard/restore/setup/activation
|
|
function redirectIfNeeded(status, currentView) {
|
|
var search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.split('='); }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
|
|
|
|
if ('develop' in search || localStorage.getItem('develop')) {
|
|
console.warn('Cloudron develop mode on. To disable run localStorage.removeItem(\'develop\')');
|
|
localStorage.setItem('develop', true);
|
|
return false;
|
|
}
|
|
|
|
if (status.activated) {
|
|
console.log('Already activated');
|
|
if (currentView === 'dashboard') {
|
|
// support local development with localhost check
|
|
if (window.location.hostname !== status.adminFqdn && window.location.hostname !== 'localhost' && !window.location.hostname.startsWith('192.')) {
|
|
// user is accessing by IP or by the old admin location (pre-migration)
|
|
window.location.href = '/setup.html' + window.location.search;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
window.location.href = 'https://' + status.adminFqdn + '/';
|
|
return true;
|
|
}
|
|
|
|
if (status.setup.active) {
|
|
console.log('Setup is active');
|
|
if (currentView === 'setup') return false;
|
|
window.location.href = '/setup.html' + window.location.search;
|
|
return true;
|
|
}
|
|
|
|
if (status.restore.active) {
|
|
console.log('Restore is active');
|
|
if (currentView === 'restore') return;
|
|
window.location.href = '/restore.html' + window.location.search;
|
|
return true;
|
|
}
|
|
|
|
if (status.adminFqdn) {
|
|
console.log('adminFqdn is set');
|
|
// if we are here from https://ip/activation.html ,go to https://admin/activation.html
|
|
if (status.adminFqdn !== window.location.hostname) {
|
|
window.location.href = 'https://' + status.adminFqdn + '/activation.html' + (window.location.search);
|
|
return true;
|
|
}
|
|
if (currentView === 'activation') return false;
|
|
window.location.href = 'https://' + status.adminFqdn + '/activation.html' + (window.location.search);
|
|
return true;
|
|
}
|
|
|
|
if (currentView === 'dashboard') {
|
|
window.location.href = '/setup.html' + window.location.search;
|
|
return true;
|
|
}
|
|
|
|
// if we are here, proceed with current view
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------
|
|
// Cloudron REST API wrapper
|
|
// ----------------------------------------------
|
|
|
|
angular.module('Application').service('Client', ['$http', '$interval', '$timeout', 'md5', 'Notification', '$translate', function ($http, $interval, $timeout, md5, Notification, $translate) {
|
|
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;
|
|
|
|
(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) {
|
|
client.offline = true;
|
|
$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) {
|
|
// actual internal server error, most likely a bug or timeout log to console only to not alert the user
|
|
if (!client.offline) {
|
|
console.error(status, data);
|
|
console.log('------\nCloudron Internal Error\n\nIf you see this, please send a mail with above log to support@cloudron.io\n------\n');
|
|
}
|
|
} 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 >= 502) {
|
|
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 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,
|
|
avatarType: null,
|
|
hasBackgroundImage: false
|
|
};
|
|
this._config = {
|
|
consoleServerOrigin: 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 = window.cloudronApiOrigin || window.location.origin;
|
|
this.avatar = '';
|
|
this.background = '';
|
|
this._availableLanguages = ['en'];
|
|
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) 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 + '?ts=' + Date.now(); // we add the timestamp to avoid caching
|
|
this._userInfo.avatarType = userInfo.avatarType;
|
|
this._userInfo.hasBackgroundImage = userInfo.hasBackgroundImage;
|
|
this._userInfo.isAtLeastOwner = [ ROLES.OWNER ].indexOf(userInfo.role) !== -1;
|
|
this._userInfo.isAtLeastAdmin = [ ROLES.OWNER, ROLES.ADMIN ].indexOf(userInfo.role) !== -1;
|
|
this._userInfo.isAtLeastMailManager = [ ROLES.OWNER, ROLES.ADMIN, ROLES.MAIL_MANAGER ].indexOf(userInfo.role) !== -1;
|
|
this._userInfo.isAtLeastUserManager = [ ROLES.OWNER, ROLES.ADMIN, ROLES.MAIL_MANAGER, ROLES.USER_MANAGER ].indexOf(userInfo.role) !== -1;
|
|
};
|
|
|
|
Client.prototype.setConfig = function (config) {
|
|
var that = this;
|
|
|
|
angular.copy(config, this._config);
|
|
|
|
// <% if (appstore.consoleOrigin) { -%>
|
|
// this._config.consoleServerOrigin = '<%= appstore.consoleOrigin %>';
|
|
// <% } -%>
|
|
|
|
this._configListener.forEach(function (callback) {
|
|
callback(that._config);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getInstalledApps = function () {
|
|
return this._installedApps;
|
|
};
|
|
|
|
Client.prototype.getInstalledAppsByAppId = function () {
|
|
return this._installedAppsById;
|
|
};
|
|
|
|
Client.prototype.getAppTags = function () {
|
|
return this._appTags;
|
|
};
|
|
|
|
Client.prototype.getUserInfo = function () {
|
|
return this._userInfo;
|
|
};
|
|
|
|
Client.prototype.getConfig = function () {
|
|
return this._config;
|
|
};
|
|
|
|
Client.prototype.getAvailableLanguages = function () {
|
|
return this._availableLanguages;
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
/*
|
|
* Rest API wrappers
|
|
*/
|
|
Client.prototype.config = function (callback) {
|
|
get('/api/v1/dashboard/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.getProfile = 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.hasCloudronBackground = function (callback) {
|
|
get('/api/v1/branding/cloudron_background', null, function (error, data, status) {
|
|
if (error && error.statusCode !== 404) callback(error);
|
|
else if (error) callback(null, false);
|
|
else callback(null, status === 200);
|
|
});
|
|
};
|
|
|
|
Client.prototype.changeCloudronBackground = function (background, callback) {
|
|
var fd = new FormData();
|
|
if (background) fd.append('background', background);
|
|
|
|
var config = {
|
|
headers: { 'Content-Type': undefined },
|
|
transformRequest: angular.identity
|
|
};
|
|
|
|
post('/api/v1/branding/cloudron_background', fd, config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
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 !== 200) 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 !== 200) return callback(new ClientError(status, data));
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.installApp = function (id, manifest, config, callback) {
|
|
var data = {
|
|
appStoreId: id + '@' + manifest.version,
|
|
subdomain: config.subdomain,
|
|
domain: config.domain,
|
|
secondaryDomains: config.secondaryDomains,
|
|
ports: config.ports,
|
|
accessRestriction: config.accessRestriction,
|
|
cert: config.cert,
|
|
key: config.key,
|
|
sso: config.sso,
|
|
overwriteDns: config.overwriteDns,
|
|
upstreamUri: config.upstreamUri,
|
|
backupId: config.backupId // when restoring from archive
|
|
};
|
|
|
|
post('/api/v1/apps', 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 = {
|
|
subdomain: config.subdomain,
|
|
domain: config.domain,
|
|
secondaryDomains: config.secondaryDomains,
|
|
ports: config.ports,
|
|
backupId: config.backupId,
|
|
overwriteDns: !!config.overwriteDns
|
|
};
|
|
|
|
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.archiveApp = function (appId, backupId, callback) {
|
|
var data = { backupId: backupId };
|
|
|
|
post('/api/v1/apps/' + appId + '/archive', 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.editAppBackup = function (id, backupId, label, preserveSecs, callback) {
|
|
post('/api/v1/apps/' + id + '/backups/' + backupId, { label: label, preserveSecs: preserveSecs }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.ackAppChecklistItem = function (appId, key, acknowledged, callback) {
|
|
put('/api/v1/apps/' + appId + '/checklist/' + key, { done: acknowledged }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
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: false,
|
|
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.getProvisionStatus = function (callback) {
|
|
get('/api/v1/provision/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.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.getPlatformStatus = function (callback) {
|
|
get('/api/v1/services/platform_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) {
|
|
const storageConfig = Object.assign({}, backupConfig);
|
|
delete storageConfig.limits;
|
|
|
|
post('/api/v1/backups/config/storage', storageConfig, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
post('/api/v1/backups/config/limits', backupConfig.limits, 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/backups/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.setBackupPolicy = function (backupPolicy, callback) {
|
|
post('/api/v1/backups/policy', backupPolicy, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getBackupPolicy = function (callback) {
|
|
get('/api/v1/backups/policy', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.policy);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getBackupMountStatus = function (callback) {
|
|
get('/api/v1/backups/mount_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.remountBackupStorage = function (callback) {
|
|
post('/api/v1/backups/remount', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setExternalLdapConfig = function (config, callback) {
|
|
post('/api/v1/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/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.setProfileConfig = function (config, callback) {
|
|
post('/api/v1/user_directory/profile_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.getProfileConfig = function (callback) {
|
|
get('/api/v1/user_directory/profile_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.setUserDirectoryConfig = function (config, callback) {
|
|
post('/api/v1/directory_server/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.getUserDirectoryConfig = function (callback) {
|
|
get('/api/v1/directory_server/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.setIPv4Config = function (config, callback) {
|
|
post('/api/v1/network/ipv4_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.getIPv4Config = function (callback) {
|
|
get('/api/v1/network/ipv4_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.getServerIpv4 = function (callback) {
|
|
get('/api/v1/network/ipv4', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getServerIpv6 = function (callback) {
|
|
get('/api/v1/network/ipv6', 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) {
|
|
get('/api/v1/network/blocklist', null, 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.getTrustedIps = function (callback) {
|
|
get('/api/v1/reverseproxy/trusted_ips', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data.trustedIps);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setTrustedIps = function (trustedIps, callback) {
|
|
post('/api/v1/reverseproxy/trusted_ips', { trustedIps: trustedIps }, 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/network/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/network/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);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setIPv6Config = function (config, callback) {
|
|
post('/api/v1/network/ipv6_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.getIPv6Config = function (callback) {
|
|
get('/api/v1/network/ipv6_config', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
// 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.setRegistryConfig = function (rc, callback) {
|
|
post('/api/v1/docker/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/docker/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) {
|
|
get('/api/v1/updater/updates', 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/updater/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.checkForAppUpdates = function (appId, callback) {
|
|
post('/api/v1/apps/' + appId + '/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/updater/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/updater/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/cloudron/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/cloudron/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.setLanguage = function (language, callback) {
|
|
post('/api/v1/cloudron/language', { language: language }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getLanguage = function (callback) {
|
|
get('/api/v1/cloudron/language', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.language);
|
|
});
|
|
};
|
|
|
|
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.listArchives = function (callback) {
|
|
var config = {
|
|
params: {
|
|
page: 1,
|
|
per_page: 100
|
|
}
|
|
};
|
|
|
|
get('/api/v1/archives', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.archives);
|
|
});
|
|
};
|
|
|
|
Client.prototype.deleteArchive = function (id, callback) {
|
|
del('/api/v1/archives/' + id, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.unarchiveApp = function (archiveId, data, callback) {
|
|
post('/api/v1/archives/' + archiveId + '/unarchive', 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.getBackups = function (callback) {
|
|
var page = 1;
|
|
var perPage = 100;
|
|
var backups = [];
|
|
|
|
function fetchMore() {
|
|
var config = {
|
|
params: {
|
|
page: page,
|
|
per_page: perPage
|
|
}
|
|
};
|
|
|
|
get('/api/v1/backups', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
backups = backups.concat(data.backups);
|
|
|
|
if (data.backups.length < perPage) return callback(null, backups);
|
|
|
|
page++;
|
|
|
|
fetchMore();
|
|
});
|
|
}
|
|
|
|
fetchMore();
|
|
};
|
|
|
|
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.getTasksByType = function (type, callback) {
|
|
get('/api/v1/tasks?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);
|
|
});
|
|
};
|
|
|
|
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.editBackup = function (backupId, label, preserveSecs, callback) {
|
|
post('/api/v1/backups/' + backupId, { label: label, preserveSecs: preserveSecs }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
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 (data, callback) {
|
|
post('/api/v1/provision/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, remotePath, backupFormat, backupConfig, callback) {
|
|
var data = {
|
|
remotePath: remotePath,
|
|
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 (options, page, perPage, callback) {
|
|
var config = {
|
|
params: {
|
|
page: page,
|
|
per_page: perPage
|
|
}
|
|
};
|
|
|
|
if (typeof options.acknowledged === 'boolean') config.params.acknowledged = options.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, acknowledged, callback) {
|
|
post('/api/v1/notifications/' + notificationId, { acknowledged: acknowledged }, 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/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/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.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.getAppBackups = function (appId, callback) {
|
|
var page = 1;
|
|
var perPage = 100;
|
|
var backups = [];
|
|
|
|
function fetchMore() {
|
|
var config = {
|
|
params: {
|
|
page: page,
|
|
per_page: perPage
|
|
}
|
|
};
|
|
|
|
get('/api/v1/apps/' + appId + '/backups', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
backups = backups.concat(data.backups);
|
|
|
|
if (data.backups.length < perPage) return callback(null, backups);
|
|
|
|
page++;
|
|
|
|
fetchMore();
|
|
});
|
|
}
|
|
|
|
fetchMore();
|
|
};
|
|
|
|
Client.prototype.getAppBackupDownloadLink = function (appId, backupId) {
|
|
return client.apiOrigin + '/api/v1/apps/' + appId + '/backups/' + backupId + '/download?access_token=' + token;
|
|
};
|
|
|
|
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.rebuildService = function (serviceName, callback) {
|
|
post('/api/v1/services/' + serviceName + '/rebuild', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getAllUsers = function (callback) {
|
|
var page = 1;
|
|
var perPage = 5000;
|
|
var users = [];
|
|
|
|
function fetchMore() {
|
|
var config = {
|
|
params: {
|
|
page: page,
|
|
per_page: perPage
|
|
}
|
|
};
|
|
|
|
get('/api/v1/users', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
users = users.concat(data.users);
|
|
|
|
if (data.users.length < perPage) return callback(null, users);
|
|
|
|
page++;
|
|
|
|
fetchMore();
|
|
});
|
|
}
|
|
|
|
fetchMore();
|
|
};
|
|
|
|
Client.prototype.getUsers = function (search, active, page, perPage, callback) {
|
|
var config = {
|
|
params: {
|
|
page: page,
|
|
per_page: perPage
|
|
}
|
|
};
|
|
|
|
if (search) config.params.search = search;
|
|
if (active !== null) config.params.active = active ? 'true' : 'false';
|
|
|
|
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.setLocalGroups = function (userId, localGroupIds, callback) {
|
|
put('/api/v1/users/' + userId + '/groups', { groupIds: localGroupIds }, 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.setGroupName = function (id, name, callback) {
|
|
var data = {
|
|
name: name
|
|
};
|
|
|
|
put('/api/v1/groups/' + id + '/name', 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.getAppTask = function (appId, callback) {
|
|
get('/api/v1/apps/' + appId + '/task', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, 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.getAppTask(appId, 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.disableTwoFactorAuthenticationByUserId = function (userId, callback) {
|
|
post('/api/v1/users/' + userId + '/twofactorauthentication_disable', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.detectIp = function (callback) {
|
|
post('/api/v1/provision/detect_ip', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setup = function (data, callback) {
|
|
post('/api/v1/provision/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.getProvisionBlockDevices = function (callback) {
|
|
get('/api/v1/provision/block_devices', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.devices);
|
|
});
|
|
};
|
|
|
|
Client.prototype.createAdmin = function (data, callback) {
|
|
var that = this;
|
|
|
|
post('/api/v1/provision/activate', data, null, function (error, result, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, result));
|
|
|
|
callback(null, result.token);
|
|
});
|
|
};
|
|
|
|
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, scope, callback) {
|
|
var data = {
|
|
name: name,
|
|
scope: scope
|
|
};
|
|
|
|
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);
|
|
});
|
|
};
|
|
|
|
// 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.getOidcClients = function (callback) {
|
|
get('/api/v1/oidc/clients', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.clients);
|
|
});
|
|
};
|
|
|
|
Client.prototype.addOidcClient = function (name, loginRedirectUri, tokenSignatureAlgorithm, callback) {
|
|
var data = {
|
|
name: name,
|
|
loginRedirectUri: loginRedirectUri,
|
|
tokenSignatureAlgorithm: tokenSignatureAlgorithm
|
|
};
|
|
|
|
post('/api/v1/oidc/clients', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.updateOidcClient = function (id, name, loginRedirectUri, tokenSignatureAlgorithm, callback) {
|
|
var data = {
|
|
name: name,
|
|
loginRedirectUri: loginRedirectUri,
|
|
tokenSignatureAlgorithm, tokenSignatureAlgorithm
|
|
};
|
|
|
|
post('/api/v1/oidc/clients/' + id, data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.delOidcClient = function (id, callback) {
|
|
del('/api/v1/oidc/clients/' + id, 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/updater/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/system/info', 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/system/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.getBlockDevices = function (callback) {
|
|
get('/api/v1/system/block_devices', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.devices);
|
|
});
|
|
};
|
|
|
|
Client.prototype.diskUsage = function (callback) {
|
|
get('/api/v1/system/disk_usage', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.refreshDiskUsage = function (callback) {
|
|
post('/api/v1/system/disk_usage', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.taskId);
|
|
});
|
|
};
|
|
|
|
Client.prototype.systemInfo = function (callback) {
|
|
get('/api/v1/system/info', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.info);
|
|
});
|
|
};
|
|
|
|
Client.prototype.cpus = function (callback) {
|
|
get('/api/v1/system/cpus', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.cpus);
|
|
});
|
|
};
|
|
|
|
Client.prototype.memory = function (callback) {
|
|
get('/api/v1/system/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.getAppGraphs = function (appId, fromMinutes, callback) {
|
|
get('/api/v1/apps/' + appId + '/graphs', { params: { fromMinutes: fromMinutes } }, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getSystemGraphs = function (fromMinutes, callback) {
|
|
get('/api/v1/system/graphs', { params: { fromMinutes: fromMinutes } }, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.systemGraphs = 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(options.appId ? '/api/v1/apps/' + options.appId + '/graphs' : '/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 (ticket, callback) {
|
|
// just to be eplicit here
|
|
var data = {
|
|
enableSshSupport: !!ticket.enableSshSupport,
|
|
type: ticket.type,
|
|
subject: ticket.subject,
|
|
description: ticket.description,
|
|
appId: ticket.appId || undefined,
|
|
altEmail: ticket.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.getApplinks = function (callback) {
|
|
var that = this;
|
|
|
|
get('/api/v1/applinks', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
// amend properties to mimick full app
|
|
data.applinks.forEach(function (applink) {
|
|
applink.type = APP_TYPES.LINK;
|
|
applink.fqdn = applink.upstreamUri;
|
|
applink.manifest = { addons: {}};
|
|
applink.installationState = ISTATES.INSTALLED;
|
|
applink.runState = RSTATES.RUNNING;
|
|
applink.health = HSTATES.HEALTHY;
|
|
applink.iconUrl = that.apiOrigin + '/api/v1/applinks/' + applink.id + '/icon?access_token=' + token + '&ts=' + applink.ts;
|
|
applink.accessLevel = that._userInfo.isAtLeastAdmin ? 'admin' : 'user';
|
|
});
|
|
|
|
callback(null, data.applinks);
|
|
});
|
|
};
|
|
|
|
Client.prototype.addApplink = function (applink, callback) {
|
|
post('/api/v1/applinks', applink, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.updateApplink = function (id, data, callback) {
|
|
post('/api/v1/applinks/' + id, data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.removeApplink = function (id, callback) {
|
|
del('/api/v1/applinks/' + id, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.addUser = function (user, callback) {
|
|
var data = {
|
|
email: user.email,
|
|
fallbackEmail: user.fallbackEmail,
|
|
displayName: user.displayName,
|
|
role: user.role
|
|
};
|
|
|
|
if (user.username) data.username = user.username;
|
|
if (user.password) data.password = user.password;
|
|
|
|
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.id);
|
|
});
|
|
};
|
|
|
|
Client.prototype.updateUserProfile = function (userId, data, callback) {
|
|
post('/api/v1/users/' + userId + '/profile', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setRole = function (userId, role, callback) {
|
|
put('/api/v1/users/' + userId + '/role', { role: role }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setActive = function (userId, active, callback) {
|
|
put('/api/v1/users/' + userId + '/active', { active: active }, 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.setProfileDisplayName = function (displayName, callback) {
|
|
post('/api/v1/profile/display_name', { displayName: displayName }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setProfileLanguage = function (language, callback) {
|
|
post('/api/v1/profile/language', { language: language }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setProfileEmail = function (email, password, callback) {
|
|
post('/api/v1/profile/email', { email: email, password: password }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setProfileFallbackEmail = function (fallbackEmail, password, callback) {
|
|
post('/api/v1/profile/fallback_email', { fallbackEmail: fallbackEmail, password: password }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.changeAvatar = function (avatarFileOrType, callback) {
|
|
// Blob type if object
|
|
if (typeof avatarFileOrType === 'object') {
|
|
var fd = new FormData();
|
|
fd.append('avatar', avatarFileOrType);
|
|
|
|
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);
|
|
});
|
|
} else {
|
|
post('/api/v1/profile/avatar', { avatar: avatarFileOrType === 'gravatar' ? 'gravatar' : '' }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
callback(null);
|
|
});
|
|
}
|
|
};
|
|
|
|
Client.prototype.getBackgroundImageUrl = function () {
|
|
return client.apiOrigin + '/api/v1/profile/background_image?access_token=' + token + '&bustcache=' + Date.now();
|
|
};
|
|
|
|
Client.prototype.setBackgroundImage = function (backgroundImage, callback) {
|
|
// Blob type if object
|
|
var fd = new FormData();
|
|
if (backgroundImage) fd.append('backgroundImage', backgroundImage);
|
|
|
|
var config = {
|
|
headers: { 'Content-Type': undefined },
|
|
transformRequest: angular.identity
|
|
};
|
|
|
|
post('/api/v1/profile/background_image', 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.getPasswordResetLink = function (userId, callback) {
|
|
get('/api/v1/users/' + userId + '/password_reset_link', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.sendPasswordResetEmail = function (userId, email, callback) {
|
|
post('/api/v1/users/' + userId + '/send_password_reset_email', { email }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.sendSelfPasswordReset = function (identifier, callback) {
|
|
post('/api/v1/auth/password_reset_request', { identifier }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getInviteLink = function (userId, callback) {
|
|
get('/api/v1/users/' + userId + '/invite_link', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.sendInviteEmail = function (userId, email, callback) {
|
|
post('/api/v1/users/' + userId + '/send_invite_email', { email }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setTwoFactorAuthenticationSecret = function (callback) {
|
|
var data = {};
|
|
|
|
post('/api/v1/profile/twofactorauthentication_secret', 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.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 !== 204) 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 !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setGhost = function (userId, password, expiresAt, callback) {
|
|
var data = { password };
|
|
|
|
if (expiresAt) data.expiresAt = expiresAt;
|
|
|
|
post('/api/v1/users/' + userId + '/ghost', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.startExternalLdapSync = function (callback) {
|
|
post('/api/v1/external_ldap/sync', {}, 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.refreshProfile = function (callback) {
|
|
var that = this;
|
|
|
|
callback = typeof callback === 'function' ? callback : function () {};
|
|
|
|
this.getProfile(function (error, result) {
|
|
if (error) return callback(error);
|
|
|
|
if (result.language !== '' && $translate.use() !== result.language) {
|
|
console.log('Changing users language from ' + $translate.use() + ' to ', result.language);
|
|
$translate.use(result.language);
|
|
}
|
|
|
|
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) {
|
|
if (error) return callback(error);
|
|
|
|
result.update = info.update;
|
|
that.setConfig(result);
|
|
callback(null);
|
|
});
|
|
});
|
|
};
|
|
|
|
Client.prototype.refreshAvailableLanguages = function (callback) {
|
|
var that = this;
|
|
|
|
get('/api/v1/cloudron/languages', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
angular.copy(data.languages, that._availableLanguages);
|
|
|
|
callback(null, data.languages);
|
|
});
|
|
};
|
|
|
|
Client.prototype._appPostProcess = function (app) {
|
|
// calculate the icon paths
|
|
app.iconUrl = app.iconUrl ? (this.apiOrigin + app.iconUrl + '?access_token=' + token + '&ts=' + app.ts) : null;
|
|
|
|
// amend the post install confirm state
|
|
app.pendingPostInstallConfirmation = !!localStorage['confirmPostInstall_' + app.id];
|
|
|
|
if (app.manifest.upstreamVersion) {
|
|
app.upstreamVersion = app.manifest.upstreamVersion;
|
|
} else 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-LOCATION/g, app.subdomain);
|
|
text = text.replace(/\$CLOUDRON-APP-DOMAIN/g, app.domain);
|
|
text = text.replace(/\$CLOUDRON-APP-FQDN/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;
|
|
}
|
|
|
|
app.type = app.manifest.id === 'io.cloudron.builtin.appproxy' ? APP_TYPES.PROXIED : APP_TYPES.APP;
|
|
|
|
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);
|
|
foundIndex = this._installedApps.length-1;
|
|
}
|
|
|
|
// 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) {
|
|
callback = callback || function (error) { if (error) console.error(error); };
|
|
var that = this;
|
|
|
|
this.getApps(function (error, apps) {
|
|
if (error) return callback(error);
|
|
|
|
that.getApplinks(function (error, applinks) {
|
|
if (error) return callback(error);
|
|
|
|
apps = apps.concat(applinks);
|
|
|
|
async.eachLimit(apps, 20, function (app, iteratorCallback) {
|
|
app.ssoAuth = app.sso && (app.manifest.addons['ldap'] || app.manifest.addons['oidc'] || app.manifest.addons['proxyAuth']); // checking app.sso first ensures app.manifest.addons is not null
|
|
|
|
if (app.accessLevel !== 'operator' && app.accessLevel !== 'admin') { // only fetch if we have permissions
|
|
app.progress = 0;
|
|
app.message = '';
|
|
app.taskMinutesActive = 0;
|
|
|
|
that._updateAppCache(app);
|
|
|
|
return iteratorCallback();
|
|
}
|
|
|
|
var getTaskFunc = app.taskId ? that.getAppTask.bind(null, app.id) : 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();
|
|
});
|
|
}, 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);
|
|
|
|
localStorage.setItem('redirectToHash', window.location.hash);
|
|
|
|
// start oidc flow
|
|
window.location.href = this.apiOrigin + '/openid/auth?client_id=' + (window.cloudronApiOrigin ? TOKEN_TYPES.ID_DEVELOPMENT : TOKEN_TYPES.ID_WEBADMIN) + '&scope=openid email profile&response_type=code token&redirect_uri=' + window.location.origin + '/authcallback.html';
|
|
};
|
|
|
|
Client.prototype.logout = function () {
|
|
var that = this;
|
|
|
|
// destroy oidc session in the spirit of true SSO
|
|
del('/api/v1/oidc/sessions', null, function (error, data, status) {
|
|
if (error) console.error('Failed to logout from oidc session');
|
|
|
|
that.setToken(null);
|
|
|
|
window.location.href = '/';
|
|
});
|
|
};
|
|
|
|
Client.prototype.getAppEventLog = function (appId, page, perPage, callback) {
|
|
var config = {
|
|
params: {
|
|
page: page,
|
|
per_page: perPage
|
|
}
|
|
};
|
|
|
|
get('/api/v1/apps/' + appId + '/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.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.updateDomainConfig = 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;
|
|
|
|
post('/api/v1/domains/' + domain + '/config', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
that.setDnsRecords({ domain: domain, type: 'mail' }, callback); // this is done so that an out-of-sync dkim key can be synced
|
|
});
|
|
};
|
|
|
|
Client.prototype.updateDomainWellKnown = function (domain, wellKnown, callback) {
|
|
var data = {
|
|
wellKnown: wellKnown
|
|
};
|
|
var that = this;
|
|
|
|
post('/api/v1/domains/' + domain + '/wellknown', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.renewCerts = function (options, callback) {
|
|
post('/api/v1/reverseproxy/renew_certs', options, 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/dashboard/prepare_location', 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/dashboard/location', 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); // { quotaValue (IEC/1024), quotaLimit (IEC/1024), quotaPercent }
|
|
});
|
|
};
|
|
|
|
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.getMailboxSharing = function (callback) {
|
|
get('/api/v1/mailserver/mailbox_sharing', {}, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data.enabled);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setMailboxSharing = function (enable, callback) {
|
|
post('/api/v1/mailserver/mailbox_sharing', { enable: enable }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getVirtualAllMail = function (callback) {
|
|
get('/api/v1/mailserver/virtual_all_mail', {}, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data.enabled);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setVirtualAllMail = function (enable, callback) {
|
|
post('/api/v1/mailserver/virtual_all_mail', { enable: enable }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getDnsblConfig = function (callback) {
|
|
var config = {};
|
|
|
|
get('/api/v1/mailserver/dnsbl_config', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setDnsblConfig = function (zones, callback) {
|
|
post('/api/v1/mailserver/dnsbl_config', { zones: zones }, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getFtsConfig = function (callback) {
|
|
var config = {};
|
|
|
|
get('/api/v1/mailserver/fts_config', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.setFtsConfig = function (enabled, callback) {
|
|
post('/api/v1/mailserver/fts_config', { 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.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', { allowlist: acl.allowlist, blocklist: acl.blocklist }, 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.listMailQueue = function (search, page, perPage, callback) {
|
|
var config = {
|
|
params: {
|
|
search: search,
|
|
page: page,
|
|
per_page: perPage
|
|
}
|
|
};
|
|
|
|
get('/api/v1/mailserver/queue', config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data.queue);
|
|
});
|
|
};
|
|
|
|
Client.prototype.delMailQueueItem = function (file, callback) {
|
|
del('/api/v1/mailserver/queue/' + file, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
callback(null, data.usage);
|
|
});
|
|
};
|
|
|
|
Client.prototype.resendMailQueueItem = function (file, callback) {
|
|
post('/api/v1/mailserver/queue/' + file + '/resend', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
callback(null, data.usage);
|
|
});
|
|
};
|
|
|
|
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 (options, callback) {
|
|
post('/api/v1/domains/sync_dns', options, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.taskId);
|
|
});
|
|
};
|
|
|
|
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.getAllMailboxes = function (callback) {
|
|
var that = this;
|
|
|
|
this.getDomains(function (error, domains) {
|
|
if (error) return callback(error);
|
|
|
|
var mailboxes = [];
|
|
async.eachLimit(domains, 5, function (domain, callback) {
|
|
that.listMailboxes(domain.domain, '', 1, 1000, function (error, result) {
|
|
if (error) return callback(error);
|
|
|
|
mailboxes = mailboxes.concat(result);
|
|
|
|
callback();
|
|
});
|
|
}, function (error) {
|
|
if (error) return callback(error);
|
|
|
|
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.listMailboxes = 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, ownerId, ownerType, callback) {
|
|
var data = {
|
|
name: name,
|
|
ownerId: ownerId,
|
|
ownerType: ownerType,
|
|
active: true,
|
|
storageQuota: 0,
|
|
messagesQuota: 0
|
|
};
|
|
|
|
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, data, callback) {
|
|
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,
|
|
active: true
|
|
};
|
|
|
|
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, active, callback) {
|
|
var data = {
|
|
members: members,
|
|
membersOnly: membersOnly,
|
|
active: active
|
|
};
|
|
|
|
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);
|
|
});
|
|
};
|
|
|
|
// Volumes
|
|
Client.prototype.getVolumes = function (callback) {
|
|
get('/api/v1/volumes', null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.volumes);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getVolume = function (volume, callback) {
|
|
get('/api/v1/volumes/' + volume, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 200) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getVolumeStatus = function (volume, callback) {
|
|
get('/api/v1/volumes/' + volume + '/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.addVolume = function (name, mountType, mountOptions, callback) {
|
|
var data = {
|
|
name: name,
|
|
mountType: mountType,
|
|
mountOptions: mountOptions
|
|
};
|
|
|
|
post('/api/v1/volumes', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null, data.id);
|
|
});
|
|
};
|
|
|
|
Client.prototype.updateVolume = function (volumeId, mountOptions, callback) {
|
|
var data = {
|
|
mountOptions: mountOptions
|
|
};
|
|
|
|
post('/api/v1/volumes/' + volumeId, data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback();
|
|
});
|
|
};
|
|
|
|
Client.prototype.remountVolume = function (volumeId, callback) {
|
|
post('/api/v1/volumes/' + volumeId + '/remount', {}, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 202) return callback(new ClientError(status, data));
|
|
|
|
callback();
|
|
});
|
|
};
|
|
|
|
Client.prototype.removeVolume = function (volume, callback) {
|
|
var config = {
|
|
data: {
|
|
},
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
}
|
|
};
|
|
|
|
del('/api/v1/volumes/' + volume, config, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 204) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
// 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';
|
|
|
|
window.open(this.getConfig().consoleServerOrigin + '/#/cloudron/' + subscription.cloudronId + '?email=' + subscription.emailEncoded, '_blank');
|
|
};
|
|
|
|
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._onAppstoreApps = function (callback) {
|
|
if (!this._fetchingAppstoreApps) { callback(); }
|
|
else this._fetchingAppstoreAppsListener.push(callback);
|
|
};
|
|
|
|
Client.prototype.getAppstoreApps = function (callback) {
|
|
var that = this;
|
|
|
|
callback = callback || function () {};
|
|
|
|
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) {
|
|
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.registerCloudronWithSetupToken = function (setupToken, callback) {
|
|
var data = {
|
|
setupToken: setupToken
|
|
};
|
|
|
|
post('/api/v1/appstore/register_cloudron_with_setup_token', data, null, function (error, data, status) {
|
|
if (error) return callback(error);
|
|
if (status !== 201) return callback(new ClientError(status, data));
|
|
|
|
callback(null);
|
|
});
|
|
};
|
|
|
|
Client.prototype.registerCloudron = function (email, password, totpToken, signup, callback) {
|
|
var data = {
|
|
email: email,
|
|
password: password,
|
|
signup: signup
|
|
};
|
|
|
|
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);
|
|
});
|
|
};
|
|
|
|
// ----------------------------------------------
|
|
// Eventlog helpers
|
|
// ----------------------------------------------
|
|
Client.prototype.eventLogDetails = function (eventLog, appIdContext) {
|
|
var ACTION_ACTIVATE = 'cloudron.activate';
|
|
var ACTION_PROVISION = 'cloudron.provision';
|
|
var ACTION_RESTORE = 'cloudron.restore';
|
|
|
|
var ACTION_APP_CLONE = 'app.clone';
|
|
var ACTION_APP_REPAIR = 'app.repair';
|
|
var ACTION_APP_CONFIGURE = 'app.configure';
|
|
var ACTION_APP_INSTALL = 'app.install';
|
|
var ACTION_APP_RESTORE = 'app.restore';
|
|
var ACTION_APP_IMPORT = 'app.import';
|
|
var ACTION_APP_UNINSTALL = 'app.uninstall';
|
|
var ACTION_APP_UPDATE = 'app.update';
|
|
var ACTION_APP_UPDATE_FINISH = 'app.update.finish';
|
|
var ACTION_APP_BACKUP = 'app.backup';
|
|
var ACTION_APP_BACKUP_FINISH = 'app.backup.finish';
|
|
var ACTION_APP_LOGIN = 'app.login';
|
|
var ACTION_APP_OOM = 'app.oom';
|
|
var ACTION_APP_UP = 'app.up';
|
|
var ACTION_APP_DOWN = 'app.down';
|
|
var ACTION_APP_START = 'app.start';
|
|
var ACTION_APP_STOP = 'app.stop';
|
|
var ACTION_APP_RESTART = 'app.restart';
|
|
|
|
var ACTION_ARCHIVES_ADD = 'archives.add';
|
|
var ACTION_ARCHIVES_DEL = 'archives.del';
|
|
|
|
var ACTION_BACKUP_FINISH = 'backup.finish';
|
|
var ACTION_BACKUP_START = 'backup.start';
|
|
var ACTION_BACKUP_CLEANUP_START = 'backup.cleanup.start';
|
|
var ACTION_BACKUP_CLEANUP_FINISH = 'backup.cleanup.finish';
|
|
|
|
var ACTION_BRANDING_AVATAR = 'branding.avatar';
|
|
var ACTION_BRANDING_NAME = 'branding.name';
|
|
var ACTION_BRANDING_FOOTER = 'branding.footer';
|
|
|
|
var ACTION_CERTIFICATE_NEW = 'certificate.new';
|
|
var ACTION_CERTIFICATE_RENEWAL = 'certificate.renew';
|
|
var ACTION_CERTIFICATE_CLEANUP = 'certificate.cleanup';
|
|
|
|
var ACTION_DASHBOARD_DOMAIN_UPDATE = 'dashboard.domain.update';
|
|
|
|
var ACTION_DIRECTORY_SERVER_CONFIGURE = 'directoryserver.configure';
|
|
|
|
var ACTION_DOMAIN_ADD = 'domain.add';
|
|
var ACTION_DOMAIN_UPDATE = 'domain.update';
|
|
var ACTION_DOMAIN_REMOVE = 'domain.remove';
|
|
|
|
var ACTION_EXTERNAL_LDAP_CONFIGURE = 'externalldap.configure';
|
|
|
|
var ACTION_GROUP_ADD = 'group.add';
|
|
var ACTION_GROUP_UPDATE = 'group.update';
|
|
var ACTION_GROUP_REMOVE = 'group.remove';
|
|
var ACTION_GROUP_MEMBERSHIP = 'group.membership';
|
|
|
|
var ACTION_INSTALL_FINISH = 'cloudron.install.finish';
|
|
|
|
var ACTION_START = 'cloudron.start';
|
|
var ACTION_SERVICE_CONFIGURE = 'service.configure';
|
|
var ACTION_SERVICE_REBUILD = 'service.rebuild';
|
|
var ACTION_SERVICE_RESTART = 'service.restart';
|
|
var ACTION_UPDATE = 'cloudron.update';
|
|
var ACTION_UPDATE_FINISH = 'cloudron.update.finish';
|
|
var ACTION_USER_ADD = 'user.add';
|
|
var ACTION_USER_LOGIN = 'user.login';
|
|
var ACTION_USER_LOGIN_GHOST = 'user.login.ghost';
|
|
var ACTION_USER_LOGOUT = 'user.logout';
|
|
var ACTION_USER_REMOVE = 'user.remove';
|
|
var ACTION_USER_UPDATE = 'user.update';
|
|
var ACTION_USER_TRANSFER = 'user.transfer';
|
|
|
|
var ACTION_USER_DIRECTORY_PROFILE_CONFIG_UPDATE = 'userdirectory.profileconfig.update';
|
|
|
|
var ACTION_MAIL_LOCATION = 'mail.location';
|
|
var ACTION_MAIL_ENABLED = 'mail.enabled';
|
|
var ACTION_MAIL_DISABLED = 'mail.disabled';
|
|
var ACTION_MAIL_MAILBOX_ADD = 'mail.box.add';
|
|
var ACTION_MAIL_MAILBOX_UPDATE = 'mail.box.update';
|
|
var ACTION_MAIL_MAILBOX_REMOVE = 'mail.box.remove';
|
|
var ACTION_MAIL_LIST_ADD = 'mail.list.add';
|
|
var ACTION_MAIL_LIST_UPDATE = 'mail.list.update';
|
|
var ACTION_MAIL_LIST_REMOVE = 'mail.list.remove';
|
|
|
|
var ACTION_SUPPORT_TICKET = 'support.ticket';
|
|
var ACTION_SUPPORT_SSH = 'support.ssh';
|
|
|
|
var ACTION_VOLUME_ADD = 'volume.add';
|
|
var ACTION_VOLUME_UPDATE = 'volume.update';
|
|
var ACTION_VOLUME_REMOVE = 'volume.remove';
|
|
|
|
var ACTION_DYNDNS_UPDATE = 'dyndns.update';
|
|
|
|
var data = eventLog.data;
|
|
var errorMessage = data.errorMessage;
|
|
var details, app;
|
|
|
|
function appName(pre, app, defaultValue) {
|
|
if (appIdContext) return defaultValue || '';
|
|
|
|
pre = pre ? (pre + ' ') : '';
|
|
|
|
return pre + (app.label || app.fqdn || app.subdomain) + ' (' + app.manifest.title + ') ';
|
|
}
|
|
|
|
function eventBy() {
|
|
if (eventLog.source && eventLog.source.username) return ' by ' + eventLog.source.username;
|
|
return '';
|
|
}
|
|
|
|
switch (eventLog.action) {
|
|
case ACTION_ACTIVATE:
|
|
return 'Cloudron was activated';
|
|
|
|
case ACTION_PROVISION:
|
|
return 'Cloudron was setup';
|
|
|
|
case ACTION_RESTORE:
|
|
return 'Cloudron was restored using backup at ' + data.remotePath;
|
|
|
|
case ACTION_APP_CONFIGURE: {
|
|
if (!data.app) return '';
|
|
app = data.app;
|
|
|
|
if ('accessRestriction' in data) { // since it can be null
|
|
return 'Access restriction ' + appName('of', app) + ' was changed';
|
|
} else if ('operators' in data) {
|
|
return 'Operators ' + appName('of', app) + ' was changed';
|
|
} else if (data.label) {
|
|
return `Label ${appName('of', app)} was set to ${data.label}`;
|
|
} else if (data.tags) {
|
|
return `Tags ${appName('of', app)} was set to ${data.tags.join(', ')}`;
|
|
} else if (data.icon) {
|
|
return 'Icon ' + appName('of', app) + ' was changed';
|
|
} else if (data.memoryLimit) {
|
|
return 'Memory limit ' + appName('of', app) + ' was set to ' + prettyBinarySize(data.memoryLimit);
|
|
} else if (data.cpuShares) { // replaced by cpuQuota in 8.0
|
|
return 'CPU shares ' + appName('of', app) + ' was set to ' + Math.round((data.cpuShares * 100)/1024) + '%';
|
|
} else if (data.cpuQuota) {
|
|
return 'CPU quota ' + appName('of', app) + ' was set to ' + data.cpuQuota + '%';
|
|
} else if (data.env) {
|
|
return 'Env vars ' + appName('of', app) + ' was changed';
|
|
} else if ('debugMode' in data) { // since it can be null
|
|
if (data.debugMode) {
|
|
return appName('', app, 'App') + ' was placed in repair mode';
|
|
} else {
|
|
return appName('', app, 'App') + ' was taken out of repair mode';
|
|
}
|
|
} else if ('enableBackup' in data) {
|
|
return 'Automatic backups ' + appName('of', app) + ' was ' + (data.enableBackup ? 'enabled' : 'disabled');
|
|
} else if ('enableAutomaticUpdate' in data) {
|
|
return 'Automatic updates ' + appName('of', app) + ' was ' + (data.enableAutomaticUpdate ? 'enabled' : 'disabled');
|
|
} else if ('reverseProxyConfig' in data) {
|
|
return 'Reverse proxy configuration ' + appName('of', app) + ' was updated';
|
|
} else if ('upstreamUri' in data) {
|
|
return 'Upstream URI ' + appName('of', app) + ' was updated';
|
|
} else if ('cert' in data) {
|
|
if (data.cert) {
|
|
return 'Custom certificate was set ' + appName('for', app);
|
|
} else {
|
|
return 'Certificate ' + appName('of', app) + ' was reset';
|
|
}
|
|
} else if (data.subdomain) {
|
|
if (data.fqdn !== data.app.fqdn) {
|
|
return 'Location ' + appName('of', app) + ' was changed to ' + data.fqdn;
|
|
} else if (!angular.equals(data.redirectDomains, data.app.redirectDomains)) {
|
|
var altFqdns = data.redirectDomains.map(function (a) { return a.fqdn; });
|
|
return 'Alternate domains ' + appName('of', app) + ' was ' + (altFqdns.length ? 'set to ' + altFqdns.join(', ') : 'reset');
|
|
} else if (!angular.equals(data.aliasDomains, data.app.aliasDomains)) {
|
|
var aliasDomains = data.aliasDomains.map(function (a) { return a.fqdn; });
|
|
return 'Alias domains ' + appName('of', app) + ' was ' + (aliasDomains.length ? 'set to ' + aliasDomains.join(', ') : 'reset');
|
|
} else if (!angular.equals(data.portBindings, data.app.portBindings)) {
|
|
return 'Port bindings ' + appName('of', app) + ' was changed';
|
|
}
|
|
} else if ('dataDir' in data) {
|
|
if (data.dataDir) {
|
|
return 'Data directory ' + appName('of', app) + ' was set ' + data.dataDir;
|
|
} else {
|
|
return 'Data directory ' + appName('of', app) + ' was reset';
|
|
}
|
|
} else if ('icon' in data) {
|
|
if (data.icon) {
|
|
return 'Icon ' + appName('of', app) + ' was set';
|
|
} else {
|
|
return 'Icon ' + appName('of', app) + ' was reset';
|
|
}
|
|
} else if ('mailboxName' in data) {
|
|
if (data.mailboxName) {
|
|
return `Mailbox ${appName('of', app)} was set to ${data.mailboxDisplayName || '' } ${data.mailboxName}@${data.mailboxDomain}`;
|
|
} else {
|
|
return 'Mailbox ' + appName('of', app) + ' was disabled';
|
|
}
|
|
}
|
|
|
|
return appName('', app, 'App ') + 'was re-configured';
|
|
}
|
|
|
|
case ACTION_APP_INSTALL:
|
|
if (!data.app) return '';
|
|
return data.app.manifest.title + ' (package v' + data.app.manifest.version + ') was installed ' + appName('at', data.app) + eventBy();
|
|
|
|
case ACTION_APP_RESTORE:
|
|
if (!data.app) return '';
|
|
details = appName('', data.app, 'App') + ' was restored';
|
|
// older versions (<3.5) did not have these fields
|
|
if (data.fromManifest) details += ' from version ' + data.fromManifest.version;
|
|
if (data.toManifest) details += ' to version ' + data.toManifest.version;
|
|
if (data.remotePath) details += ' using backup at ' + data.remotePath;
|
|
return details;
|
|
|
|
case ACTION_APP_IMPORT:
|
|
if (!data.app) return '';
|
|
details = appName('', data.app, 'App') + ' was imported';
|
|
if (data.toManifest) details += ' to version ' + data.toManifest.version;
|
|
if (data.remotePath) details += ' using backup at ' + data.remotePath;
|
|
return details;
|
|
|
|
case ACTION_APP_UNINSTALL:
|
|
if (!data.app) return '';
|
|
return appName('', data.app, 'App') + ' (package v' + data.app.manifest.version + ') was uninstalled';
|
|
|
|
case ACTION_APP_UPDATE:
|
|
if (!data.app) return '';
|
|
return 'Update ' + appName('of', data.app) + ' started from v' + data.fromManifest.version + ' to v' + data.toManifest.version;
|
|
|
|
case ACTION_APP_UPDATE_FINISH:
|
|
if (!data.app) return '';
|
|
return appName('', data.app, 'App') + ' was updated to v' + data.app.manifest.version;
|
|
|
|
case ACTION_APP_BACKUP:
|
|
if (!data.app) return '';
|
|
return 'Backup ' + appName('of', data.app) + ' started';
|
|
|
|
case ACTION_APP_BACKUP_FINISH:
|
|
if (!data.app) return '';
|
|
if (data.errorMessage) {
|
|
return 'Backup ' + appName('of', data.app) + ' failed: ' + data.errorMessage;
|
|
} else {
|
|
return 'Backup ' + appName('of', data.app) + ' succeeded with backup id ' + data.backupId + ' at ' + data.remotePath;
|
|
}
|
|
|
|
case ACTION_APP_CLONE:
|
|
if (appIdContext === data.oldAppId) {
|
|
return 'App was cloned to ' + data.newApp.fqdn + ' using backup at ' + data.remotePath;
|
|
} else if (appIdContext === data.appId) {
|
|
return 'App was cloned from ' + data.oldApp.fqdn + ' using backup at ' + data.remotePath;
|
|
} else {
|
|
return appName('', data.newApp, 'App') + ' was cloned ' + appName('from', data.oldApp) + ' using backup at ' + data.remotePath;
|
|
}
|
|
|
|
case ACTION_APP_REPAIR:
|
|
return appName('', data.app, 'App') + ' was re-configured'; // re-configure of email apps is more common?
|
|
|
|
case ACTION_APP_LOGIN: {
|
|
app = this.getCachedAppSync(data.appId);
|
|
if (!app) return '';
|
|
return 'App ' + app.fqdn + ' logged in';
|
|
}
|
|
|
|
case ACTION_APP_OOM:
|
|
if (!data.app) return '';
|
|
return appName('', data.app, 'App') + ' ran out of memory';
|
|
|
|
case ACTION_APP_DOWN:
|
|
if (!data.app) return '';
|
|
return appName('', data.app, 'App') + ' is down';
|
|
|
|
case ACTION_APP_UP:
|
|
if (!data.app) return '';
|
|
return appName('', data.app, 'App') + ' is back online';
|
|
|
|
case ACTION_APP_START:
|
|
if (!data.app) return '';
|
|
return appName('', data.app, 'App') + ' was started';
|
|
|
|
case ACTION_APP_STOP:
|
|
if (!data.app) return '';
|
|
return appName('', data.app, 'App') + ' was stopped';
|
|
|
|
case ACTION_APP_RESTART:
|
|
if (!data.app) return '';
|
|
return appName('', data.app, 'App') + ' was restarted';
|
|
|
|
case ACTION_ARCHIVES_ADD:
|
|
return 'Backup ' + data.backupId + ' added to archive';
|
|
|
|
case ACTION_ARCHIVES_DEL:
|
|
return 'Backup ' + data.backupId + ' deleted from archive';
|
|
|
|
case ACTION_BACKUP_START:
|
|
return 'Backup started';
|
|
|
|
case ACTION_BACKUP_FINISH:
|
|
if (!errorMessage) {
|
|
return 'Cloudron backup created at ' + data.remotePath;
|
|
} else {
|
|
return 'Cloudron backup errored with error: ' + errorMessage;
|
|
}
|
|
|
|
case ACTION_BACKUP_CLEANUP_START:
|
|
return 'Backup cleaner started';
|
|
|
|
case ACTION_BACKUP_CLEANUP_FINISH:
|
|
return data.errorMessage ? 'Backup cleaner errored: ' + data.errorMessage : 'Backup cleaner removed ' + (data.removedBoxBackupPaths ? data.removedBoxBackupPaths.length : '0') + ' backups';
|
|
|
|
case ACTION_BRANDING_AVATAR:
|
|
return 'Cloudron Avatar Changed';
|
|
|
|
case ACTION_BRANDING_NAME:
|
|
return 'Cloudron Name set to ' + data.name;
|
|
|
|
case ACTION_BRANDING_FOOTER:
|
|
return 'Cloudron Footer set to ' + data.footer;
|
|
|
|
case ACTION_CERTIFICATE_NEW:
|
|
return 'Certificate install for ' + data.domain + (errorMessage ? ' failed' : ' succeeded');
|
|
|
|
case ACTION_CERTIFICATE_RENEWAL:
|
|
return 'Certificate renewal for ' + data.domain + (errorMessage ? ' failed' : ' succeeded');
|
|
|
|
case ACTION_CERTIFICATE_CLEANUP:
|
|
return 'Certificate(s) of ' + data.domains.join(',') + ' was cleaned up since they expired 6 months ago';
|
|
|
|
case ACTION_DASHBOARD_DOMAIN_UPDATE:
|
|
return 'Dashboard domain set to ' + data.fqdn || (data.subdomain + '.' + data.domain);
|
|
|
|
case ACTION_DIRECTORY_SERVER_CONFIGURE:
|
|
if (data.fromEnabled !== data.toEnabled) {
|
|
return 'Directory server was ' + (data.toEnabled ? 'enabled' : 'disabled');
|
|
} else {
|
|
return 'Directory server configuration was changed';
|
|
}
|
|
|
|
case ACTION_DOMAIN_ADD:
|
|
return 'Domain ' + data.domain + ' with ' + data.provider + ' provider was added';
|
|
|
|
case ACTION_DOMAIN_UPDATE:
|
|
return 'Domain ' + data.domain + ' with ' + data.provider + ' provider was updated';
|
|
|
|
case ACTION_DOMAIN_REMOVE:
|
|
return 'Domain ' + data.domain + ' was removed';
|
|
|
|
case ACTION_EXTERNAL_LDAP_CONFIGURE:
|
|
if (data.config.provider === 'noop') {
|
|
return 'External Directory disabled';
|
|
} else {
|
|
return 'External Directory set to ' + data.config.url + ' (' + data.config.provider + ')';
|
|
}
|
|
|
|
case ACTION_GROUP_ADD:
|
|
return 'Group ' + data.name + ' was added';
|
|
|
|
case ACTION_GROUP_UPDATE:
|
|
return 'Group name changed from ' + data.oldName + ' to ' + data.group.name;
|
|
|
|
case ACTION_GROUP_REMOVE:
|
|
return 'Group ' + data.group.name + ' was removed';
|
|
|
|
case ACTION_GROUP_MEMBERSHIP:
|
|
return 'Group membership of ' + data.group.name + ' changed. Now was ' + data.userIds.length + ' member(s).';
|
|
|
|
case ACTION_INSTALL_FINISH:
|
|
return 'Cloudron version ' + data.version + ' installed';
|
|
|
|
case ACTION_MAIL_LOCATION:
|
|
return 'Mail server location was changed to ' + data.subdomain + (data.subdomain ? '.' : '') + data.domain;
|
|
|
|
case ACTION_MAIL_ENABLED:
|
|
return 'Mail was enabled for domain ' + data.domain;
|
|
|
|
case ACTION_MAIL_DISABLED:
|
|
return 'Mail was disabled for domain ' + data.domain;
|
|
|
|
case ACTION_MAIL_MAILBOX_ADD:
|
|
return 'Mailbox ' + data.name + '@' + data.domain + ' was added';
|
|
|
|
case ACTION_MAIL_MAILBOX_UPDATE:
|
|
if (data.aliases) {
|
|
return 'Mailbox aliases of ' + data.name + '@' + data.domain + ' was updated';
|
|
} else {
|
|
return 'Mailbox ' + data.name + '@' + data.domain + ' was updated';
|
|
}
|
|
|
|
case ACTION_MAIL_MAILBOX_REMOVE:
|
|
return 'Mailbox ' + data.name + '@' + data.domain + ' was removed';
|
|
|
|
case ACTION_MAIL_LIST_ADD:
|
|
return 'Mail list ' + data.name + '@' + data.domain + 'was added';
|
|
|
|
case ACTION_MAIL_LIST_UPDATE:
|
|
return 'Mail list ' + data.name + '@' + data.domain + ' was updated';
|
|
|
|
case ACTION_MAIL_LIST_REMOVE:
|
|
return 'Mail list ' + data.name + '@' + data.domain + ' was removed';
|
|
|
|
case ACTION_START:
|
|
return 'Cloudron started with version ' + data.version;
|
|
|
|
case ACTION_SERVICE_CONFIGURE:
|
|
return 'Service ' + data.id + ' was configured';
|
|
|
|
case ACTION_SERVICE_REBUILD:
|
|
return 'Service ' + data.id + ' was rebuilt';
|
|
|
|
case ACTION_SERVICE_RESTART:
|
|
return 'Service ' + data.id + ' was restarted';
|
|
|
|
case ACTION_UPDATE:
|
|
return 'Cloudron update to version ' + data.boxUpdateInfo.version + ' was started';
|
|
|
|
case ACTION_UPDATE_FINISH:
|
|
if (data.errorMessage) {
|
|
return 'Cloudron update errored. Error: ' + data.errorMessage;
|
|
} else {
|
|
return 'Cloudron updated to version ' + data.newVersion;
|
|
}
|
|
|
|
case ACTION_USER_ADD:
|
|
return 'User ' + data.email + (data.user.username ? ' (' + data.user.username + ')' : '') + ' was added';
|
|
|
|
case ACTION_USER_UPDATE:
|
|
return 'User ' + (data.user ? (data.user.email + (data.user.username ? ' (' + data.user.username + ')' : '')) : data.userId) + ' was updated';
|
|
|
|
case ACTION_USER_REMOVE:
|
|
return 'User ' + (data.user ? (data.user.email + (data.user.username ? ' (' + data.user.username + ')' : '')) : data.userId) + ' was removed';
|
|
|
|
case ACTION_USER_TRANSFER:
|
|
return 'Apps of ' + data.oldOwnerId + ' was transferred to ' + data.newOwnerId;
|
|
|
|
case ACTION_USER_LOGIN:
|
|
if (data.mailboxId) {
|
|
return 'User ' + (data.user ? data.user.username : data.userId) + ' logged in to mailbox ' + data.mailboxId;
|
|
} else if (data.appId) {
|
|
app = this.getCachedAppSync(data.appId);
|
|
return 'User ' + (data.user ? data.user.username : data.userId) + ' logged in to ' + (app ? app.fqdn : data.appId);
|
|
} else { // can happen with directoryserver
|
|
return 'User ' + (data.user ? data.user.username : data.userId) + ' authenticated';
|
|
}
|
|
|
|
case ACTION_USER_LOGIN_GHOST:
|
|
return 'User ' + (data.user ? data.user.username : data.userId) + ' was impersonated';
|
|
|
|
case ACTION_USER_LOGOUT:
|
|
return 'User ' + (data.user ? data.user.username : data.userId) + ' logged out';
|
|
|
|
case ACTION_USER_DIRECTORY_PROFILE_CONFIG_UPDATE:
|
|
return 'User directory profile config updated. Mandatory 2FA: ' + (data.config.mandatory2FA) + ' Lock profiles: ' + (data.config.lockUserProfiles);
|
|
|
|
case ACTION_DYNDNS_UPDATE: {
|
|
details = data.errorMessage ? 'Error updating DNS. ' : 'Updated DNS. ';
|
|
if (data.fromIpv4 !== data.toIpv4) details += 'From IPv4 ' + data.fromIpv4 + ' to ' + data.toIpv4 + '. ';
|
|
if (data.fromIpv6 !== data.toIpv6) details += 'From IPv6 ' + data.fromIpv6 + ' to ' + data.toIpv6 + '.';
|
|
if (data.errorMessage) details += ' ' + data.errorMessage;
|
|
return details;
|
|
}
|
|
|
|
case ACTION_SUPPORT_SSH:
|
|
return 'Remote Support was ' + (data.enable ? 'enabled' : 'disabled');
|
|
|
|
case ACTION_SUPPORT_TICKET:
|
|
return 'Support ticket was created';
|
|
|
|
case ACTION_VOLUME_ADD:
|
|
return 'Volume "' + data.volume.name + '" was added';
|
|
|
|
case ACTION_VOLUME_UPDATE:
|
|
return 'Volme "' + data.volume.name + '" was updated';
|
|
|
|
case ACTION_VOLUME_REMOVE:
|
|
return 'Volume "' + data.volume.name + '" was removed';
|
|
|
|
default: return eventLog.action;
|
|
}
|
|
};
|
|
|
|
Client.prototype.eventLogSource = function (eventLog) {
|
|
var source = eventLog.source;
|
|
var line = '';
|
|
|
|
line = source.username || source.userId || source.mailboxId || source.authType || 'system';
|
|
if (source.appId) {
|
|
var app = this.getCachedAppSync(source.appId);
|
|
line += ' - ' + (app ? app.fqdn : source.appId);
|
|
}
|
|
|
|
return line;
|
|
};
|
|
|
|
|
|
client = new Client();
|
|
return client;
|
|
}]);
|