Merge branch 'admin-network-pane' into staging
commit
0a7e692989
|
@ -122,28 +122,6 @@ module.exports = {
|
|||
],
|
||||
*/
|
||||
|
||||
/* We're very proud that CryptPad is available to the public as free software!
|
||||
* We do, however, still need to pay our bills as we develop the platform.
|
||||
*
|
||||
* By default CryptPad will prompt users to consider donating to
|
||||
* our OpenCollective campaign. We publish the state of our finances periodically
|
||||
* so you can decide for yourself whether our expenses are reasonable.
|
||||
*
|
||||
* You can disable any solicitations for donations by setting 'removeDonateButton' to true,
|
||||
* but we'd appreciate it if you didn't!
|
||||
*/
|
||||
//removeDonateButton: false,
|
||||
|
||||
/*
|
||||
* By default, CryptPad contacts one of our servers once a day.
|
||||
* This check-in will also send some very basic information about your instance including its
|
||||
* version and the adminEmail so we can reach you if we are aware of a serious problem.
|
||||
* We will never sell it or send you marketing mail.
|
||||
*
|
||||
* If you want to block this check-in and remain set 'blockDailyCheck' to true.
|
||||
*/
|
||||
//blockDailyCheck: false,
|
||||
|
||||
/* =====================
|
||||
* STORAGE
|
||||
* ===================== */
|
||||
|
|
|
@ -10,6 +10,7 @@ module.exports.create = function (Env) {
|
|||
|
||||
nThen(function (w) {
|
||||
Decrees.load(Env, w(function (err) {
|
||||
Env.flushCache();
|
||||
if (err) {
|
||||
log.error('DECREES_LOADING', {
|
||||
error: err.code || err,
|
||||
|
|
|
@ -317,6 +317,15 @@ var instanceStatus = function (Env, Server, cb) {
|
|||
|
||||
maxUploadSize: Env.maxUploadSize,
|
||||
premiumUploadSize: Env.premiumUploadSize,
|
||||
|
||||
consentToContact: Env.consentToContact,
|
||||
listMyInstance: Env.listMyInstance,
|
||||
provideAggregateStatistics: Env.provideAggregateStatistics,
|
||||
|
||||
removeDonateButton: Env.removeDonateButton,
|
||||
blockDailyCheck: Env.blockDailyCheck,
|
||||
|
||||
updateAvailable: Env.updateAvailable,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ const Quota = module.exports;
|
|||
|
||||
//const Util = require("../common-util");
|
||||
const Keys = require("../keys");
|
||||
const Package = require('../../package.json');
|
||||
const Https = require("https");
|
||||
const Util = require("../common-util");
|
||||
const Stats = require("../stats");
|
||||
|
||||
var validLimitFields = ['limit', 'plan', 'note', 'users', 'origin'];
|
||||
|
||||
|
@ -51,24 +51,66 @@ Quota.applyCustomLimits = function (Env) {
|
|||
// console.log(Env.limits);
|
||||
};
|
||||
|
||||
/*
|
||||
Env = {
|
||||
myDomain,
|
||||
mySubdomain,
|
||||
adminEmail,
|
||||
Package.version,
|
||||
|
||||
var isRemoteVersionNewer = function (local, remote) {
|
||||
try {
|
||||
local = local.split('.').map(Number);
|
||||
remote = remote.split('.').map(Number);
|
||||
for (var i = 0; i < 3; i++) {
|
||||
if (remote[i] < local[i]) { return false; }
|
||||
if (remote[i] > local[i]) { return true; }
|
||||
}
|
||||
} catch (err) {
|
||||
// if anything goes wrong just fall through and return false
|
||||
// false negatives are better than false positives
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/*
|
||||
var Assert = require("assert");
|
||||
[
|
||||
// remote versions
|
||||
['4.5.0', '4.5.0', false], // equal semver should not prompt
|
||||
['4.5.0', '4.5.1', true], // patch versions should prompt
|
||||
['4.5.0', '4.6.0', true], // minor versions should prompt
|
||||
['4.5.0', '5.0.0', true], // major versions should prompt
|
||||
// local
|
||||
['5.3.1', '4.9.0', false], // newer major should not prompt
|
||||
['4.7.0', '4.6.0', false], // newer minor should not prompt
|
||||
['4.7.0', '4.6.1', false], // newer patch should not prompt if other values are greater
|
||||
].forEach(function (x) {
|
||||
var result = isRemoteVersionNewer(x[0], x[1]);
|
||||
Assert.equal(result, x[2]);
|
||||
});
|
||||
*/
|
||||
|
||||
// check if the remote endpoint reported an available server version
|
||||
// which is newer than your current version (Env.version)
|
||||
// if so, set Env.updateAvailable to the URL of its release notes
|
||||
var checkUpdateAvailability = function (Env, json) {
|
||||
if (!(json && typeof(json.updateAvailable) === 'string' && typeof(json.version) === 'string')) { return; }
|
||||
// expects {updateAvailable: 'https://github.com/xwiki-labs/cryptpad/releases/4.7.0', version: '4.7.0'}
|
||||
// the version string is provided explicitly even though it could be parsed from GitHub's URL
|
||||
// this will allow old instances to understand responses of arbitrary URLs
|
||||
// as long as we keep using semver for 'version'
|
||||
if (!isRemoteVersionNewer(Env.version, json.version)) {
|
||||
Env.updateAvailable = undefined;
|
||||
return;
|
||||
}
|
||||
Env.updateAvailable = json.updateAvailable;
|
||||
Env.Log.info('AN_UPDATE_IS_AVAILABLE', {
|
||||
version: json.version,
|
||||
updateAvailable: json.updateAvaiable,
|
||||
});
|
||||
};
|
||||
|
||||
var queryAccountServer = function (Env, cb) {
|
||||
var done = Util.once(Util.mkAsync(cb));
|
||||
|
||||
var body = JSON.stringify({
|
||||
domain: Env.myDomain,
|
||||
subdomain: Env.mySubdomain || null,
|
||||
adminEmail: Env.adminEmail,
|
||||
version: Package.version
|
||||
});
|
||||
var rawBody = Stats.instanceData(Env);
|
||||
Env.Log.info("SERVER_TELEMETRY", rawBody);
|
||||
var body = JSON.stringify(rawBody);
|
||||
|
||||
var options = {
|
||||
host: 'accounts.cryptpad.fr',
|
||||
path: '/api/getauthorized',
|
||||
|
@ -92,6 +134,7 @@ var queryAccountServer = function (Env, cb) {
|
|||
response.on('end', function () {
|
||||
try {
|
||||
var json = JSON.parse(str);
|
||||
checkUpdateAvailability(Env, json);
|
||||
// don't overwrite the limits with junk data
|
||||
if (json && json.message === 'EINVAL') { return void cb(); }
|
||||
done(void 0, json);
|
||||
|
|
|
@ -34,6 +34,13 @@ SET_MAINTENANCE
|
|||
SET_ADMIN_EMAIL
|
||||
SET_SUPPORT_MAILBOX
|
||||
|
||||
// COMMUNITY PARTICIPATION AND GOVERNANCE
|
||||
CONSENT_TO_CONTACT
|
||||
LIST_MY_INSTANCE
|
||||
PROVIDE_AGGREGATE_STATISTICS
|
||||
REMOVE_DONATE_BUTTON
|
||||
BLOCK_DAILY_CHECK
|
||||
|
||||
NOT IMPLEMENTED:
|
||||
|
||||
// RESTRICTED REGISTRATION
|
||||
|
@ -89,6 +96,21 @@ commands.DISABLE_INTEGRATED_EVICTION = makeBooleanSetter('disableIntegratedEvict
|
|||
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['DISABLE_INTEGRATED_TASKS', [true]]], console.log)
|
||||
commands.DISABLE_INTEGRATED_TASKS = makeBooleanSetter('disableIntegratedTasks');
|
||||
|
||||
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['CONSENT_TO_CONTACT', [true]]], console.log)
|
||||
commands.CONSENT_TO_CONTACT = makeBooleanSetter('consentToContact');
|
||||
|
||||
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['LIST_MY_INSTANCE', [true]]], console.log)
|
||||
commands.LIST_MY_INSTANCE = makeBooleanSetter('listMyInstance');
|
||||
|
||||
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['PROVIDE_AGGREGATE_STATISTICS', [true]]], console.log)
|
||||
commands.PROVIDE_AGGREGATE_STATISTICS = makeBooleanSetter('provideAggregateStatistics');
|
||||
|
||||
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['REMOVE_DONATE_BUTTON', [true]]], console.log)
|
||||
commands.REMOVE_DONATE_BUTTON = makeBooleanSetter('removeDonateButton');
|
||||
|
||||
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['BLOCK_DAILY_CHECK', [true]]], console.log)
|
||||
commands.BLOCK_DAILY_CHECK = makeBooleanSetter('blockDailyCheck');
|
||||
|
||||
/*
|
||||
var isNonNegativeNumber = function (n) {
|
||||
return !(typeof(n) !== 'number' || isNaN(n) || n < 0);
|
||||
|
|
18
lib/env.js
18
lib/env.js
|
@ -10,10 +10,21 @@ const Core = require("./commands/core");
|
|||
|
||||
const Quota = require("./commands/quota");
|
||||
const Util = require("./common-util");
|
||||
const Package = require("../package.json");
|
||||
|
||||
var canonicalizeOrigin = function (s) {
|
||||
if (typeof(s) === 'undefined') { return; }
|
||||
return (s || '').trim().replace(/\/+$/, '');
|
||||
};
|
||||
|
||||
module.exports.create = function (config) {
|
||||
|
||||
const Env = {
|
||||
version: Package.version,
|
||||
|
||||
httpUnsafeOrigin: canonicalizeOrigin(config.httpUnsafeOrigin),
|
||||
httpSafeOrigin: canonicalizeOrigin(config.httpSafeOrigin),
|
||||
removeDonateButton: config.removeDonateButton,
|
||||
|
||||
OFFLINE_MODE: false,
|
||||
FRESH_KEY: '',
|
||||
FRESH_MODE: true,
|
||||
|
@ -97,6 +108,11 @@ module.exports.create = function (config) {
|
|||
allowSubscriptions: config.allowSubscriptions === true,
|
||||
blockDailyCheck: config.blockDailyCheck === true,
|
||||
|
||||
consentToContact: false,
|
||||
listMyInstance: false,
|
||||
provideAggregateStatistics: false,
|
||||
updateAvailable: undefined,
|
||||
|
||||
myDomain: config.myDomain,
|
||||
mySubdomain: config.mySubdomain, // only exists for the accounts integration
|
||||
customLimits: {},
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*jshint esversion: 6 */
|
||||
const Stats = module.exports;
|
||||
|
||||
Stats.instanceData = function (Env) {
|
||||
var data = {
|
||||
version: Env.version,
|
||||
|
||||
domain: Env.myDomain,
|
||||
subdomain: Env.mySubdomain,
|
||||
|
||||
httpUnsafeOrigin: Env.httpUnsafeOrigin,
|
||||
httpSafeOrigin: Env.httpSafeOrigin,
|
||||
|
||||
adminEmail: Env.adminEmail,
|
||||
consentToContact: Boolean(Env.consentToContact),
|
||||
};
|
||||
|
||||
/* We reserve the right to choose not to include instances
|
||||
in our public directory at our discretion.
|
||||
|
||||
The following details will be included in your telemetry
|
||||
as factors that may contribute to that decision.
|
||||
|
||||
These values are publicly available via /api/config
|
||||
posting them to our server just makes it easier for us.
|
||||
*/
|
||||
if (Env.listMyInstance) {
|
||||
// clearly indicate that you want to be listed
|
||||
data.listMyInstance = Env.listMyInstance;
|
||||
|
||||
// you should have enabled your admin panel
|
||||
data.adminKeys = Env.admins.length > 0;
|
||||
|
||||
// we expect that you enable your support mailbox
|
||||
data.supportMailbox = Boolean(Env.supportMailbox);
|
||||
|
||||
// do you allow registration?
|
||||
data.restrictRegistration = Boolean(Env.restrictRegistration);
|
||||
|
||||
// have you removed the donate button?
|
||||
data.removeDonateButton = Boolean(Env.removeDonateButton);
|
||||
|
||||
// after how long do you consider a document to be inactive?
|
||||
data.inactiveTime = Env.inactiveTime;
|
||||
|
||||
// how much storage do you offer to registered users?
|
||||
data.defaultStorageLimit = Env.defaultStorageLimit;
|
||||
|
||||
// what size file upload do you permit
|
||||
data.maxUploadSize = Env.maxUploadSize;
|
||||
|
||||
// how long do you retain inactive accounts?
|
||||
data.accountRetentionTime = Env.accountRetentionTime;
|
||||
|
||||
// how long do you retain archived data?
|
||||
//data.archiveRetentionTime = Env.archiveRetentionTime,
|
||||
}
|
||||
|
||||
// we won't consider instances for public listings
|
||||
// unless they opt to provide more info about themselves
|
||||
if (!Env.provideAggregateStatistics) { return data; }
|
||||
|
||||
return data;
|
||||
};
|
||||
|
46
server.js
46
server.js
|
@ -4,7 +4,6 @@
|
|||
var Express = require('express');
|
||||
var Http = require('http');
|
||||
var Fs = require('fs');
|
||||
var Package = require('./package.json');
|
||||
var Path = require("path");
|
||||
var nThen = require("nthen");
|
||||
var Util = require("./lib/common-util");
|
||||
|
@ -16,10 +15,6 @@ var Env = require("./lib/env").create(config);
|
|||
|
||||
var app = Express();
|
||||
|
||||
var canonicalizeOrigin = function (s) {
|
||||
return (s || '').trim().replace(/\/+$/, '');
|
||||
};
|
||||
|
||||
var fancyURL = function (domain, path) {
|
||||
try {
|
||||
if (domain && path) { return new URL(path, domain).href; }
|
||||
|
@ -30,15 +25,10 @@ var fancyURL = function (domain, path) {
|
|||
|
||||
(function () {
|
||||
// you absolutely must provide an 'httpUnsafeOrigin'
|
||||
if (typeof(config.httpUnsafeOrigin) !== 'string') {
|
||||
if (typeof(Env.httpUnsafeOrigin) !== 'string') {
|
||||
throw new Error("No 'httpUnsafeOrigin' provided");
|
||||
}
|
||||
|
||||
config.httpUnsafeOrigin = canonicalizeOrigin(config.httpUnsafeOrigin);
|
||||
if (typeof(config.httpSafeOrigin) === 'string') {
|
||||
config.httpSafeOrigin = canonicalizeOrigin(config.httpSafeOrigin);
|
||||
}
|
||||
|
||||
// fall back to listening on a local address
|
||||
// if httpAddress is not a string
|
||||
if (typeof(config.httpAddress) !== 'string') {
|
||||
|
@ -50,7 +40,7 @@ var fancyURL = function (domain, path) {
|
|||
config.httpPort = 3000;
|
||||
}
|
||||
|
||||
if (typeof(config.httpSafeOrigin) !== 'string') {
|
||||
if (typeof(Env.httpSafeOrigin) !== 'string') {
|
||||
Env.NO_SANDBOX = true;
|
||||
if (typeof(config.httpSafePort) !== 'number') {
|
||||
config.httpSafePort = config.httpPort + 1;
|
||||
|
@ -76,7 +66,7 @@ var setHeaders = (function () {
|
|||
}
|
||||
|
||||
// next define the base Content Security Policy (CSP) headers
|
||||
if (typeof(config.contentSecurity) === 'string') {
|
||||
if (typeof(config.contentSecurity) === 'string') { // XXX deprecate this
|
||||
headers['Content-Security-Policy'] = config.contentSecurity;
|
||||
if (!/;$/.test(headers['Content-Security-Policy'])) { headers['Content-Security-Policy'] += ';' }
|
||||
if (headers['Content-Security-Policy'].indexOf('frame-ancestors') === -1) {
|
||||
|
@ -87,14 +77,14 @@ var setHeaders = (function () {
|
|||
}
|
||||
} else {
|
||||
// use the default CSP headers constructed with your domain
|
||||
headers['Content-Security-Policy'] = Default.contentSecurity(config.httpUnsafeOrigin);
|
||||
headers['Content-Security-Policy'] = Default.contentSecurity(Env.httpUnsafeOrigin);
|
||||
}
|
||||
|
||||
const padHeaders = Util.clone(headers);
|
||||
if (typeof(config.padContentSecurity) === 'string') {
|
||||
padHeaders['Content-Security-Policy'] = config.padContentSecurity;
|
||||
} else {
|
||||
padHeaders['Content-Security-Policy'] = Default.padContentSecurity(config.httpUnsafeOrigin);
|
||||
padHeaders['Content-Security-Policy'] = Default.padContentSecurity(Env.httpUnsafeOrigin);
|
||||
}
|
||||
if (Object.keys(headers).length) {
|
||||
return function (req, res) {
|
||||
|
@ -151,7 +141,7 @@ app.head(/^\/common\/feedback\.html/, function (req, res, next) {
|
|||
|
||||
app.use('/blob', function (req, res, next) {
|
||||
if (req.method === 'HEAD') {
|
||||
Express.static(Path.join(__dirname, (config.blobPath || './blob')), {
|
||||
Express.static(Path.join(__dirname, Env.paths.blob), {
|
||||
setHeaders: function (res, path, stat) {
|
||||
res.set('Access-Control-Allow-Origin', '*');
|
||||
res.set('Access-Control-Allow-Headers', 'Content-Length');
|
||||
|
@ -191,13 +181,13 @@ var mainPagePattern = new RegExp('^\/(' + mainPages.join('|') + ').html$');
|
|||
app.get(mainPagePattern, Express.static(__dirname + '/customize'));
|
||||
app.get(mainPagePattern, Express.static(__dirname + '/customize.dist'));
|
||||
|
||||
app.use("/blob", Express.static(Path.join(__dirname, (config.blobPath || './blob')), {
|
||||
app.use("/blob", Express.static(Path.join(__dirname, Env.paths.blob), {
|
||||
maxAge: Env.DEV_MODE? "0d": "365d"
|
||||
}));
|
||||
app.use("/datastore", Express.static(Path.join(__dirname, (config.filePath || './datastore')), {
|
||||
app.use("/datastore", Express.static(Path.join(__dirname, Env.paths.data), {
|
||||
maxAge: "0d"
|
||||
}));
|
||||
app.use("/block", Express.static(Path.join(__dirname, (config.blockPath || '/block')), {
|
||||
app.use("/block", Express.static(Path.join(__dirname, Env.paths.block), {
|
||||
maxAge: "0d",
|
||||
}));
|
||||
|
||||
|
@ -252,12 +242,12 @@ var serveConfig = makeRouteCache(function (host) {
|
|||
'var obj = ' + JSON.stringify({
|
||||
requireConf: {
|
||||
waitSeconds: 600,
|
||||
urlArgs: 'ver=' + Package.version + cacheString(),
|
||||
urlArgs: 'ver=' + Env.version + cacheString(),
|
||||
},
|
||||
removeDonateButton: (config.removeDonateButton === true),
|
||||
allowSubscriptions: (config.allowSubscriptions === true),
|
||||
removeDonateButton: (Env.removeDonateButton === true),
|
||||
allowSubscriptions: (Env.allowSubscriptions === true),
|
||||
websocketPath: config.externalWebsocketURL,
|
||||
httpUnsafeOrigin: config.httpUnsafeOrigin,
|
||||
httpUnsafeOrigin: Env.httpUnsafeOrigin,
|
||||
adminEmail: Env.adminEmail,
|
||||
adminKeys: Env.admins,
|
||||
inactiveTime: Env.inactiveTime,
|
||||
|
@ -265,10 +255,10 @@ var serveConfig = makeRouteCache(function (host) {
|
|||
defaultStorageLimit: Env.defaultStorageLimit,
|
||||
maxUploadSize: Env.maxUploadSize,
|
||||
premiumUploadSize: Env.premiumUploadSize,
|
||||
restrictRegistration: Env.restrictRegistration, // FIXME see the race condition in env.js
|
||||
restrictRegistration: Env.restrictRegistration,
|
||||
}, null, '\t'),
|
||||
'obj.httpSafeOrigin = ' + (function () {
|
||||
if (config.httpSafeOrigin) { return '"' + config.httpSafeOrigin + '"'; }
|
||||
if (Env.httpSafeOrigin) { return '"' + Env.httpSafeOrigin + '"'; }
|
||||
if (config.httpSafePort) {
|
||||
return "(function () { return window.location.origin.replace(/\:[0-9]+$/, ':" +
|
||||
config.httpSafePort + "'); }())";
|
||||
|
@ -332,16 +322,16 @@ nThen(function (w) {
|
|||
var ps = port === 80? '': ':' + port;
|
||||
|
||||
var roughAddress = 'http://' + hostName + ps;
|
||||
var betterAddress = fancyURL(config.httpUnsafeOrigin);
|
||||
var betterAddress = fancyURL(Env.httpUnsafeOrigin);
|
||||
|
||||
if (betterAddress) {
|
||||
console.log('Serving content for %s via %s.\n', betterAddress, roughAddress);
|
||||
} else {
|
||||
console.log('Serving content via %s.\n', roughAddress);
|
||||
}
|
||||
if (!Array.isArray(config.adminKeys)) {
|
||||
if (!Env.admins.length) {
|
||||
console.log("Your instance is not correctly configured for safe use in production.\nSee %s for more information.\n",
|
||||
fancyURL(config.httpUnsafeOrigin, '/checkup/') || 'https://your-domain.com/checkup/'
|
||||
fancyURL(Env.httpUnsafeOrigin, '/checkup/') || 'https://your-domain.com/checkup/'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -85,15 +85,27 @@ define([
|
|||
'performance': [ // Msg.admin_cat_performance
|
||||
'cp-admin-refresh-performance',
|
||||
'cp-admin-performance-profiling',
|
||||
]
|
||||
],
|
||||
'network': [ // Msg.admin_cat_network
|
||||
'cp-admin-update-available',
|
||||
'cp-admin-checkup',
|
||||
'cp-admin-block-daily-check',
|
||||
//'cp-admin-provide-aggregate-statistics',
|
||||
'cp-admin-list-my-instance',
|
||||
'cp-admin-consent-to-contact',
|
||||
'cp-admin-remove-donate-button',
|
||||
],
|
||||
};
|
||||
|
||||
var create = {};
|
||||
|
||||
var keyToCamlCase = function (key) {
|
||||
return key.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); });
|
||||
};
|
||||
|
||||
var makeBlock = function (key, addButton) { // Title, Hint, maybeButton
|
||||
// Convert to camlCase for translation keys
|
||||
var safeKey = key.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); });
|
||||
|
||||
var safeKey = keyToCamlCase(key);
|
||||
var $div = $('<div>', {'class': 'cp-admin-' + key + ' cp-sidebarlayout-element'});
|
||||
$('<label>').text(Messages['admin_'+safeKey+'Title'] || key).appendTo($div);
|
||||
$('<span>', {'class': 'cp-sidebarlayout-description'})
|
||||
|
@ -260,7 +272,7 @@ define([
|
|||
var $div = makeBlock(key); // Msg.admin_registrationHint, .admin_registrationTitle, .admin_registrationButton
|
||||
|
||||
var state = APP.instanceStatus.restrictRegistration;
|
||||
var $cbox = $(UI.createCheckbox('cp-settings-userfeedback',
|
||||
var $cbox = $(UI.createCheckbox('cp-settings-' + key,
|
||||
Messages.admin_registrationTitle,
|
||||
state, { label: { class: 'noTitle' } }));
|
||||
var spinner = UI.makeSpinner($cbox);
|
||||
|
@ -289,6 +301,55 @@ define([
|
|||
return $div;
|
||||
};
|
||||
|
||||
var makeAdminCheckbox = function (data) {
|
||||
return function () {
|
||||
var state = data.getState();
|
||||
var key = data.key;
|
||||
var $div = makeBlock(key);
|
||||
|
||||
var labelKey = 'admin_' + keyToCamlCase(key) + 'Label';
|
||||
var titleKey = 'admin_' + keyToCamlCase(key) + 'Title';
|
||||
var $cbox = $(UI.createCheckbox('cp-admin-' + key,
|
||||
Messages[labelKey] || Messages[titleKey],
|
||||
state, { label: { class: 'noTitle' } }));
|
||||
var spinner = UI.makeSpinner($cbox);
|
||||
var $checkbox = $cbox.find('input').on('change', function() {
|
||||
spinner.spin();
|
||||
var val = $checkbox.is(':checked') || false;
|
||||
$checkbox.attr('disabled', 'disabled');
|
||||
data.query(val, function (state) {
|
||||
spinner.done();
|
||||
$checkbox[0].checked = state;
|
||||
$checkbox.removeAttr('disabled');
|
||||
});
|
||||
});
|
||||
$cbox.appendTo($div);
|
||||
return $div;
|
||||
};
|
||||
};
|
||||
|
||||
// Msg.admin_registrationHint, .admin_registrationTitle, .admin_registrationButton
|
||||
create['registration'] = makeAdminCheckbox({
|
||||
key: 'registration',
|
||||
getState: function () {
|
||||
return APP.instanceStatus.restrictRegistration;
|
||||
},
|
||||
query: function (val, setState) {
|
||||
sFrameChan.query('Q_ADMIN_RPC', {
|
||||
cmd: 'ADMIN_DECREE',
|
||||
data: ['RESTRICT_REGISTRATION', [val]]
|
||||
}, function (e, response) {
|
||||
if (e || response.error) {
|
||||
UI.warn(Messages.error);
|
||||
console.error(e, response);
|
||||
}
|
||||
APP.updateStatus(function () {
|
||||
setState(APP.instanceStatus.restrictRegistration);
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
create['email'] = function () {
|
||||
var key = 'email';
|
||||
var $div = makeBlock(key, true); // Msg.admin_emailHint, Msg.admin_emailTitle, Msg.admin_emailButton
|
||||
|
@ -1663,6 +1724,135 @@ define([
|
|||
return $div;
|
||||
};
|
||||
|
||||
create['update-available'] = function () { // Messages.admin_updateAvailableTitle.admin_updateAvailableHint.admin_updateAvailableLabel.admin_updateAvailableButton
|
||||
if (!APP.instanceStatus.updateAvailable) { return; }
|
||||
var $div = makeBlock('update-available', true);
|
||||
|
||||
var updateURL = 'https://github.com/xwiki-labs/cryptpad/releases/latest';
|
||||
if (typeof(APP.instanceStatus.updateAvailable) === 'string') {
|
||||
updateURL = APP.instanceStatus.updateAvailable;
|
||||
}
|
||||
|
||||
$div.find('button').click(function () {
|
||||
common.openURL(updateURL);
|
||||
});
|
||||
|
||||
return $div;
|
||||
};
|
||||
|
||||
create['checkup'] = function () {
|
||||
var $div = makeBlock('checkup', true); // Messages.admin_checkupButton.admin_checkupHint.admin_checkupTitle
|
||||
$div.find('button').click(function () {
|
||||
common.openURL('/checkup/');
|
||||
});
|
||||
return $div;
|
||||
};
|
||||
|
||||
create['consent-to-contact'] = makeAdminCheckbox({ // Messages.admin_consentToContactTitle.admin_consentToContactHint.admin_consentToContactLabel
|
||||
key: 'consent-to-contact',
|
||||
getState: function () {
|
||||
return APP.instanceStatus.consentToContact;
|
||||
},
|
||||
query: function (val, setState) {
|
||||
sFrameChan.query('Q_ADMIN_RPC', {
|
||||
cmd: 'ADMIN_DECREE',
|
||||
data: ['CONSENT_TO_CONTACT', [val]]
|
||||
}, function (e, response) {
|
||||
if (e || response.error) {
|
||||
UI.warn(Messages.error);
|
||||
console.error(e, response);
|
||||
}
|
||||
APP.updateStatus(function () {
|
||||
setState(APP.instanceStatus.consentToContact);
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
create['list-my-instance'] = makeAdminCheckbox({ // Messages.admin_listMyInstanceTitle.admin_listMyInstanceHint.admin_listMyInstanceLabel
|
||||
key: 'list-my-instance',
|
||||
getState: function () {
|
||||
return APP.instanceStatus.listMyInstance;
|
||||
},
|
||||
query: function (val, setState) {
|
||||
sFrameChan.query('Q_ADMIN_RPC', {
|
||||
cmd: 'ADMIN_DECREE',
|
||||
data: ['LIST_MY_INSTANCE', [val]]
|
||||
}, function (e, response) {
|
||||
if (e || response.error) {
|
||||
UI.warn(Messages.error);
|
||||
console.error(e, response);
|
||||
}
|
||||
APP.updateStatus(function () {
|
||||
setState(APP.instanceStatus.listMyInstance);
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
create['provide-aggregate-statistics'] = makeAdminCheckbox({ // Messages.admin_provideAggregateStatisticsTitle.admin_provideAggregateStatisticsHint.admin_provideAggregateStatisticsLabel
|
||||
key: 'provide-aggregate-statistics',
|
||||
getState: function () {
|
||||
return APP.instanceStatus.provideAggregateStatistics;
|
||||
},
|
||||
query: function (val, setState) {
|
||||
sFrameChan.query('Q_ADMIN_RPC', {
|
||||
cmd: 'ADMIN_DECREE',
|
||||
data: ['PROVIDE_AGGREGATE_STATISTICS', [val]]
|
||||
}, function (e, response) {
|
||||
if (e || response.error) {
|
||||
UI.warn(Messages.error);
|
||||
console.error(e, response);
|
||||
}
|
||||
APP.updateStatus(function () {
|
||||
setState(APP.instanceStatus.provideAggregateStatistics);
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
create['remove-donate-button'] = makeAdminCheckbox({ // Messages.admin_removeDonateButtonTitle.admin_removeDonateButtonHint.admin_removeDonateButtonLabel
|
||||
key: 'remove-donate-button',
|
||||
getState: function () {
|
||||
return APP.instanceStatus.removeDonateButton;
|
||||
},
|
||||
query: function (val, setState) {
|
||||
sFrameChan.query('Q_ADMIN_RPC', {
|
||||
cmd: 'ADMIN_DECREE',
|
||||
data: ['REMOVE_DONATE_BUTTON', [val]]
|
||||
}, function (e, response) {
|
||||
if (e || response.error) {
|
||||
UI.warn(Messages.error);
|
||||
console.error(e, response);
|
||||
}
|
||||
APP.updateStatus(function () {
|
||||
setState(APP.instanceStatus.removeDonateButton);
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
create['block-daily-check'] = makeAdminCheckbox({ // Messages.admin_blockDailyCheckTitle.admin_blockDailyCheckHint.admin_blockDailyCheckLabel
|
||||
key: 'block-daily-check',
|
||||
getState: function () {
|
||||
return APP.instanceStatus.blockDailyCheck;
|
||||
},
|
||||
query: function (val, setState) {
|
||||
sFrameChan.query('Q_ADMIN_RPC', {
|
||||
cmd: 'ADMIN_DECREE',
|
||||
data: ['BLOCK_DAILY_CHECK', [val]]
|
||||
}, function (e, response) {
|
||||
if (e || response.error) {
|
||||
UI.warn(Messages.error);
|
||||
console.error(e, response);
|
||||
}
|
||||
APP.updateStatus(function () {
|
||||
setState(APP.instanceStatus.blockDailyCheck);
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
var hideCategories = function () {
|
||||
APP.$rightside.find('> div').hide();
|
||||
};
|
||||
|
@ -1680,6 +1870,7 @@ define([
|
|||
support: 'fa fa-life-ring',
|
||||
broadcast: 'fa fa-bullhorn',
|
||||
performance: 'fa fa-heartbeat',
|
||||
network: 'fa fa-sitemap', // or fa-university ?
|
||||
};
|
||||
|
||||
var createLeftside = function () {
|
||||
|
|
Loading…
Reference in New Issue