diff --git a/lib/commands/admin-rpc.js b/lib/commands/admin-rpc.js index b9ec845b3..56978a3c6 100644 --- a/lib/commands/admin-rpc.js +++ b/lib/commands/admin-rpc.js @@ -351,6 +351,10 @@ var instanceStatus = function (Env, Server, cb) { updateAvailable: Env.updateAvailable, instancePurpose: Env.instancePurpose, + + instanceDescription: Env.instanceDescription, + instanceJurisdiction: Env.instanceJurisdiction, + instanceName: Env.instanceName, }); }; diff --git a/lib/decrees.js b/lib/decrees.js index 5f599705e..1f506026d 100644 --- a/lib/decrees.js +++ b/lib/decrees.js @@ -41,6 +41,9 @@ PROVIDE_AGGREGATE_STATISTICS REMOVE_DONATE_BUTTON BLOCK_DAILY_CHECK +SET_INSTANCE_JURISDICTION +SET_INSTANCE_DESCRIPTION + NOT IMPLEMENTED: // RESTRICTED REGISTRATION @@ -176,6 +179,15 @@ commands.SET_SUPPORT_MAILBOX = makeGenericSetter('supportMailbox', function (arg // CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_PURPOSE', ["development"]]], console.log) commands.SET_INSTANCE_PURPOSE = makeGenericSetter('instancePurpose', args_isString); +// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_JURISDICTION', ['France']]], console.log) +commands.SET_INSTANCE_JURISDICTION = makeGenericSetter('instanceJurisdiction', args_isString); + +// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_NAME', ['My Personal CryptPad']]], console.log) +commands.SET_INSTANCE_NAME = makeGenericSetter('instanceDescription', args_isString); + +// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_DESCRIPTION', ['A personal instance, hosted for me and nobody else']]], console.log) +commands.SET_INSTANCE_DESCRIPTION = makeGenericSetter('instanceDescription', args_isString); + // Maintenance: Empty string or an object with a start and end time var isNumber = function (value) { return typeof(value) === "number" && !isNaN(value); diff --git a/lib/env.js b/lib/env.js index 9970bc4f9..1c171dc6a 100644 --- a/lib/env.js +++ b/lib/env.js @@ -121,6 +121,10 @@ module.exports.create = function (config) { provideAggregateStatistics: false, updateAvailable: undefined, + instanceName: '', + instanceDescription: '', + instanceJurisdiction: '', + myDomain: config.myDomain, mySubdomain: config.mySubdomain, // only exists for the accounts integration customLimits: {}, diff --git a/lib/stats.js b/lib/stats.js index 1dbbb2ad9..bdbf5c24a 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -1,6 +1,11 @@ /*jshint esversion: 6 */ const Stats = module.exports; +var truthyStringOrNothing = function (s) { + if (typeof(s) !== 'string' || !s) { return undefined; } + return s.trim() || undefined; +}; + Stats.instanceData = function (Env) { var data = { version: Env.version, @@ -55,6 +60,15 @@ Stats.instanceData = function (Env) { // how long do you retain inactive accounts? data.accountRetentionTime = Env.accountRetentionTime; + // does this instance have a name??? + data.instanceName = truthyStringOrNothing(Env.instanceName); + + // does this instance have a jurisdiction ??? + data.instanceJurisdiction = truthyStringOrNothing(Env.instanceJurisdiction); + + // does this instance have a description??? + data.instanceDescription = truthyStringOrNothing(Env.instanceDescription); + // how long do you retain archived data? //data.archiveRetentionTime = Env.archiveRetentionTime, } diff --git a/www/admin/app-admin.less b/www/admin/app-admin.less index f66eb75f7..482369a6e 100644 --- a/www/admin/app-admin.less +++ b/www/admin/app-admin.less @@ -33,8 +33,12 @@ margin-top: 5px; } } - .cp-admin-setlimit-form + button { - margin-top: 5px !important; + .cp-admin-setlimit-form, + .cp-admin-setjurisdiction-form, + .cp-admin-setdescription-form { + + button { + margin-top: 5px !important; + } } .cp-admin-getlimits { code { @@ -199,6 +203,12 @@ input.cp-admin-inval { border-color: red !important; } + input[type="text"], textarea { + &.cp-listing-info[disabled] { + border: 1px solid transparent !important; //1px solid transparent !imprortant;;//none !important; + } + } + .cp-admin-nopassword { .cp-admin-pw { display: none !important; diff --git a/www/admin/inner.js b/www/admin/inner.js index a80c8ca32..b0dfffa46 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -56,7 +56,7 @@ define([ 'cp-admin-archive', 'cp-admin-unarchive', 'cp-admin-registration', - 'cp-admin-email' + 'cp-admin-email', ], 'quota': [ // Msg.admin_cat_quota 'cp-admin-defaultlimit', @@ -92,6 +92,11 @@ define([ 'cp-admin-block-daily-check', //'cp-admin-provide-aggregate-statistics', 'cp-admin-list-my-instance', + + 'cp-admin-name', + 'cp-admin-description', + 'cp-admin-jurisdiction', + 'cp-admin-consent-to-contact', 'cp-admin-remove-donate-button', 'cp-admin-instance-purpose', @@ -264,7 +269,7 @@ define([ UI.log(archive ? Messages.archivedFromServer : Messages.restoredFromServer); $input.val(''); $pwInput.val(''); - $reason.val('') + $reason.val(''); }); }); }); @@ -325,6 +330,8 @@ define([ var key = data.key; var $div = makeBlock(key); + // XXX support disabling this checkboxes in certain conditions, ie. when telemetry is off + var labelKey = 'admin_' + keyToCamlCase(key) + 'Label'; var titleKey = 'admin_' + keyToCamlCase(key) + 'Title'; var $cbox = $(UI.createCheckbox('cp-admin-' + key, @@ -407,6 +414,150 @@ define([ return $div; }; + Messages.admin_jurisdictionHint = 'Jurisdiction hint'; // XXX + Messages.admin_jurisdictionTitle = 'Jurisdiction title'; // XXX + Messages.admin_jurisdictionButton = 'Jurisdiction button'; // XXX + Messages.admin_jurisdictionPlaceholder = 'Jurisdiction placeholder'; // XXX + + create['jurisdiction'] = function () { + var key = 'jurisdiction'; + var $div = makeBlock(key, true); // Msg.admin_jurisdictionHint, Msg.admin_jurisdictionTitle, Msg.admin_jurisdictionButton + var $button = $div.find('button').addClass('cp-listing-action'); + + var input = h('input.cp-listing-info', { + type: 'text', + value: APP.instanceStatus.instanceJurisdiction || '', + placeholder: Messages.admin_jurisdictionPlaceholder, + }); + var $input = $(input); + var innerDiv = h('div.cp-admin-setjurisdiction-form', input); + var spinner = UI.makeSpinner($(innerDiv)); + + $button.click(function () { + if (!$input.val()) { return; } + spinner.spin(); + $button.attr('disabled', 'disabled'); + sFrameChan.query('Q_ADMIN_RPC', { + cmd: 'ADMIN_DECREE', + data: ['SET_INSTANCE_JURISDICTION', [$input.val()]] // XXX not implemented + }, function (e, response) { + $button.removeAttr('disabled'); + if (e || response.error) { + UI.warn(Messages.error); + $input.val(''); + console.error(e, response); + spinner.hide(); + return; + } + spinner.done(); + UI.log(Messages.saved); + }); + }); + + $button.before(innerDiv); + + return $div; + }; + + Messages.admin_nameHint = 'instance name hint'; // XXX + Messages.admin_nameTitle = 'instance name title'; // XXX + Messages.admin_nameButton = 'instance name button'; // XXX + Messages.admin_namePlaceholder = 'instance name placeholder'; // XXX + + create['name'] = function () { + var key = 'name'; + var $div = makeBlock(key, true); + // Msg.admin_nameHint, Msg.admin_nameTitle, Msg.admin_nameButton + var $button = $div.find('button').addClass('cp-listing-action'); + + var input = h('input.cp-listing-info', { + type: 'text', + value: APP.instanceStatus.instanceName || '', + placeholder: Messages.admin_namePlaceholder, + style: 'margin-bottom: 5px;', + }); + var $input = $(input); + var innerDiv = h('div.cp-admin-setname-form', input); // XXX fix styles + var spinner = UI.makeSpinner($(innerDiv)); + + $button.click(function () { + if (!$input.val()) { return; } + spinner.spin(); + $button.attr('disabled', 'disabled'); + sFrameChan.query('Q_ADMIN_RPC', { + cmd: 'ADMIN_DECREE', + data: ['SET_INSTANCE_NAME', [$input.val()]] // XXX not implemented + }, function (e, response) { + $button.removeAttr('disabled'); + if (e || response.error) { + UI.warn(Messages.error); + $input.val(''); + console.error(e, response); + spinner.hide(); + return; + } + spinner.done(); + UI.log(Messages.saved); + }); + }); + + $button.before(innerDiv); + + return $div; + }; + + + Messages.admin_descriptionHint = 'Description hint'; // XXX + Messages.admin_descriptionTitle = 'Description title'; // XXX + Messages.admin_descriptionButton = 'Description button'; // XXX + Messages.admin_descriptionPlaceholder = 'Description placeholder'; // XXX + + create['description'] = function () { + var key = 'description'; + var $div = makeBlock(key, true); + + var textarea = h('textarea.cp-admin-description-text.cp-listing-info', { // XXX use something from UI elements? + placeholder: Messages.admin_descriptionPlaceholder, + }, APP.instanceStatus.instanceDescription || ''); + + var $button = $div.find('button'); + + $button.addClass('cp-listing-action'); + + var innerDiv = h('div.cp-admin-setdescription-form', { + //style: 'margin-bottom: 5px', // XXX LOL NO + }, [ + textarea, + ]); + $button.before(innerDiv); + + var $input = $(textarea); + var spinner = UI.makeSpinner($(innerDiv)); + + $button.click(function () { + if (!$input.val()) { return; } + spinner.spin(); + $button.attr('disabled', 'disabled'); + sFrameChan.query('Q_ADMIN_RPC', { + cmd: 'ADMIN_DECREE', + data: ['SET_INSTANCE_DESCRIPTION', [$input.val()]] // XXX + }, function (e, response) { + $button.removeAttr('disabled'); + if (e || response.error) { + UI.warn(Messages.error); + $input.val(''); + console.error(e, response); + spinner.hide(); + return; + } + spinner.done(); + UI.log(Messages.saved); + }); + }); + + return $div; + }; + var getPrettySize = UIElements.prettySize; create['defaultlimit'] = function () { @@ -1799,6 +1950,7 @@ define([ }, }); + // XXX disable this checkbox if server telemetry is disabled? create['list-my-instance'] = makeAdminCheckbox({ // Messages.admin_listMyInstanceTitle.admin_listMyInstanceHint.admin_listMyInstanceLabel key: 'list-my-instance', getState: function () { @@ -2034,6 +2186,19 @@ define([ if (!Array.isArray(data)) { return void cb('EINVAL'); } APP.instanceStatus = data[0]; console.log("Status", APP.instanceStatus); + + var isListed = Boolean(APP.instanceStatus.listMyInstance); + var $actions = $('.cp-listing-action'); + var $fields = $('.cp-listing-info'); + + if (isListed) { + $actions.removeAttr('disabled'); + $fields.removeAttr('disabled'); + } else { + $actions.attr('disabled', 'disabled'); + $fields.attr('disabled', 'disabled'); + } + cb(); }); };