From a6ccf3149eac95383b5008ce60f7d78762679e06 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 16 Feb 2022 06:26:13 +0100 Subject: [PATCH 01/45] Translated using Weblate (Japanese) Currently translated at 100.0% (1427 of 1427 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index f99d4ef96..281d52255 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -1422,5 +1422,10 @@ "form_conditional_addAnd": "「かつ」の条件を追加", "form_conditional_add": "「あるいは」の条件を追加", "form_condition_isnot": "等しくない", - "form_condition_is": "等しい" + "form_condition_is": "等しい", + "form_template_poll": "スケジュールの投票のテンプレート", + "bounce_danger": "クリックしたリンクは、ウェブページではなく、悪質かもしれないコードやデータに結びついています。\n\n(\"{0}\")\n\nセキュリティー上の理由で、CryptPadはこのデータをブロックしています。OKをクリックするとタブが閉じます。", + "bounce_confirm": "このページから退出しようとしています: {0}\n\n次のページを開いてよろしいですか?:{1}", + "form_condition_hasnot": "含まない", + "form_condition_has": "含む" } From f1fc2d2ad94a251c2275f5e92efd879a35ab93b5 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 18 Feb 2022 18:45:52 +0530 Subject: [PATCH 02/45] WIP provide a reason when archiving or resoring a file through the admin panel --- lib/commands/admin-rpc.js | 28 ++++++++++++++++++++++++++-- www/admin/inner.js | 21 +++++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/lib/commands/admin-rpc.js b/lib/commands/admin-rpc.js index 59750571e..b9ec845b3 100644 --- a/lib/commands/admin-rpc.js +++ b/lib/commands/admin-rpc.js @@ -155,7 +155,17 @@ var flushCache = function (Env, Server, cb) { // CryptPad_AsyncStore.rpc.send('ADMIN', ['ARCHIVE_DOCUMENT', documentID], console.log) var archiveDocument = function (Env, Server, cb, data) { - var id = Array.isArray(data) && data[1]; + if (!Array.isArray(data)) { return void cb("EINVAL"); } + var args = data[1]; + + var id, reason; + if (typeof(args) === 'string') { + id = args; + } else if (args && typeof(args) === 'object') { + id = args.id; + reason = args.reason; + } + if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); } switch (id.length) { @@ -164,6 +174,7 @@ var archiveDocument = function (Env, Server, cb, data) { return void Env.msgStore.archiveChannel(id, Util.both(cb, function (err) { Env.Log.info("ARCHIVAL_CHANNEL_BY_ADMIN_RPC", { channelId: id, + reason: reason, status: err? String(err): "SUCCESS", }); })); @@ -171,6 +182,7 @@ var archiveDocument = function (Env, Server, cb, data) { return void Env.blobStore.archive.blob(id, Util.both(cb, function (err) { Env.Log.info("ARCHIVAL_BLOB_BY_ADMIN_RPC", { id: id, + reason: reason, status: err? String(err): "SUCCESS", }); })); @@ -184,7 +196,17 @@ var archiveDocument = function (Env, Server, cb, data) { }; var restoreArchivedDocument = function (Env, Server, cb, data) { - var id = Array.isArray(data) && data[1]; + if (!Array.isArray(data)) { return void cb("EINVAL"); } + var args = data[1]; + + var id, reason; + if (typeof(args) === 'string') { + id = args; + } else if (args && typeof(args) === 'object') { + id = args.id; + reason = args.reason; + } + if (typeof(id) !== 'string' || id.length < 32) { return void cb("EINVAL"); } switch (id.length) { @@ -192,6 +214,7 @@ var restoreArchivedDocument = function (Env, Server, cb, data) { return void Env.msgStore.restoreArchivedChannel(id, Util.both(cb, function (err) { Env.Log.info("RESTORATION_CHANNEL_BY_ADMIN_RPC", { id: id, + reason: reason, status: err? String(err): 'SUCCESS', }); })); @@ -201,6 +224,7 @@ var restoreArchivedDocument = function (Env, Server, cb, data) { return void Env.blobStore.restore.blob(id, Util.both(cb, function (err) { Env.Log.info("RESTORATION_BLOB_BY_ADMIN_RPC", { id: id, + reason: reason, status: err? String(err): 'SUCCESS', }); })); diff --git a/www/admin/inner.js b/www/admin/inner.js index 83143a546..a80c8ca32 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -146,6 +146,8 @@ define([ return $div; }; + Messages.admin_archiveReason = "// XXX REASON"; // XXX + var archiveForm = function (archive, $div, $button) { var label = h('label', { for: 'cp-admin-archive' }, Messages.admin_archiveInput); var input = h('input#cp-admin-archive', { @@ -159,6 +161,14 @@ define([ id: 'cp-admin-archive-pw', placeholder: Messages.login_password }); + var input3 = h('input', { + id: 'cp-admin-archive-reason', + placeholder: Messages.admin_archiveReason, + }); + var label3 = h('label', { + for: 'cp-admin-archive-reason', + }, Messages.admin_archiveReason); + var $pw = $(input2); $pw.addClass('cp-admin-pw'); var $pwInput = $pw.find('input'); @@ -168,7 +178,9 @@ define([ label, input, label2, - input2 + input2, + label3, + input3, ])); $div.addClass('cp-admin-nopassword'); @@ -234,9 +246,13 @@ define([ } }), true); }).nThen(function () { + var $reason = $(input3); sFrameChan.query('Q_ADMIN_RPC', { cmd: archive ? 'ARCHIVE_DOCUMENT' : 'RESTORE_ARCHIVED_DOCUMENT', - data: channel + data: { + id: channel, + reason: $reason.val(), // XXX + }, }, function (err, obj) { var e = err || (obj && obj.error); clicked = false; @@ -248,6 +264,7 @@ define([ UI.log(archive ? Messages.archivedFromServer : Messages.restoredFromServer); $input.val(''); $pwInput.val(''); + $reason.val('') }); }); }); From 6c56785e1508c82fb8ba7e4215f510ffb77ad4b7 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 21 Feb 2022 11:34:33 +0530 Subject: [PATCH 03/45] fix incorrect config snippet in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08183cd6f..d348ebe64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -135,7 +135,7 @@ Our team has limited resources, so we've chosen to introduce the new (and **expe To enable the use of the OnlyOffice Document and Presentation editor for everyone on your instance, edit your [customize/application_config.js](https://docs.cryptpad.fr/en/admin_guide/customization.html#application-config) file to include `AppConfig.enableEarlyAccess = true;`. -If you wish to avoid a rush of support tickets from your users by limiting early access to users with custom quota increases, add another line like so `Constants.earlyAccessApps = ['doc', 'presentation'];`. +If you wish to avoid a rush of support tickets from your users by limiting early access to users with custom quota increases, add another line like so `AppConfig.premiumTypes = ['doc', 'presentation'];`. As these editors become more stable we plan to enable them by default on third-party instances. Keep in mind, these editors may be unstable and users may lose their work. Our team will fix bugs given sufficient information to reproduce them, but we will not take the time to help you recover lost data unless you have taken a support contract with us. From aaafc648f69bc96ddd7cb209cef3bdadf6b0a133 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 22 Feb 2022 17:33:28 +0530 Subject: [PATCH 04/45] guard against malformed DOM queries in forms that include polls and fix display of escaped HTML in poll option titles --- www/form/inner.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/form/inner.js b/www/form/inner.js index bceb1219b..a0084057f 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -706,7 +706,7 @@ define([ } var day = _date && allDays[_date.getDay()]; return h('div.cp-poll-cell.cp-form-poll-option', { - title: Util.fixHTML(data) + title: data, }, [ opts.type === 'day' ? h('span.cp-form-weekday', day) : undefined, opts.type === 'day' ? h('span.cp-form-weekday-separator', ' - ') : undefined, @@ -865,7 +865,7 @@ define([ if (totalMax.value) { $total.find('[data-id]').removeClass('cp-poll-best'); totalMax.data.forEach(function (k) { - $total.find('[data-id="'+k+'"]').addClass('cp-poll-best'); + $total.find('[data-id="'+ (k.replace(/"/g, '\\"')) + '"]').addClass('cp-poll-best'); }); } }; From 1202b7a6911aa46ed19ed232e128e8a64012c38e Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 24 Feb 2022 15:28:24 +0530 Subject: [PATCH 05/45] WIP configure instance name, jurisdiction, and description on admin panel --- lib/commands/admin-rpc.js | 4 + lib/decrees.js | 12 +++ lib/env.js | 4 + lib/stats.js | 14 ++++ www/admin/app-admin.less | 14 +++- www/admin/inner.js | 169 +++++++++++++++++++++++++++++++++++++- 6 files changed, 213 insertions(+), 4 deletions(-) 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(); }); }; From 7c3d56345319186e4727baa076f05764a59b9018 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 24 Feb 2022 15:37:05 +0530 Subject: [PATCH 06/45] WIP support for customized and translated legal info --- customize.dist/pages.js | 49 ++++++++++++---- www/checkup/main.js | 70 ++++++++++++++++++++++- www/common/application_config_internal.js | 26 +++++++++ www/common/common-ui-elements.js | 23 +++++++- 4 files changed, 155 insertions(+), 13 deletions(-) diff --git a/customize.dist/pages.js b/customize.dist/pages.js index ea52b00f8..2012fc103 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -102,27 +102,54 @@ define([ return h('a', attrs, text); }; - var imprintUrl = AppConfig.imprint && (typeof(AppConfig.imprint) === "boolean" ? - '/imprint.html' : AppConfig.imprint); - Pages.versionString = "v4.13.0"; + var customURLs = Pages.customURLs = {}; + (function () { + var defaultURLs = { + //imprint: '/imprint.html', // XXX cryptpad.org/default-imprint.html? + //privacy: '/privacy.html', // XXX cryptpad.org/default-privacy.html? + terms: '/terms.html', // XXX cryptpad.org/default-terms.html? + //roadmap: '/roadmap.html', // XXX cryptpad.org/default-roadmap.html? + source: 'https://github.com/xwiki-labs/cryptpad', + }; + var l = Msg._getLanguage(); + ['imprint', 'privacy', 'terms', 'roadmap', 'source'].forEach(function (k) { + var value = AppConfig[k]; + if (value === false) { return; } + if (value === true) { + customURLs[k] = defaultURLs[k]; + return; + } + + if (!value) { return; } + if (typeof(value) === 'string') { + customURLs[k] = value; + return; + } + if (typeof(value) === 'object') { + customURLs[k] = value[l] || value['default']; + } + }); + }()); + + Msg.footer_source = 'Source code'; // XXX // used for the about menu - Pages.imprintLink = AppConfig.imprint ? footLink(imprintUrl, 'imprint') : undefined; - Pages.privacyLink = footLink(AppConfig.privacy, 'privacy'); - Pages.githubLink = footLink('https://github.com/xwiki-labs/cryptpad', null, 'GitHub'); + Pages.imprintLink = footLink(customURLs.imprint, 'imprint'); + Pages.privacyLink = footLink(customURLs.privacy, 'privacy'); + Pages.termsLink = footLink(customURLs.terms, 'footer_tos'); + Pages.sourceLink = footLink(customURLs.source, 'footer_source'); Pages.docsLink = footLink('https://docs.cryptpad.fr', 'docs_link'); - Pages.roadmapLink = footLink(AppConfig.roadmap, 'footer_roadmap'); + Pages.roadmapLink = footLink(customURLs.roadmap, 'footer_roadmap'); Pages.infopageFooter = function () { - var terms = footLink('/terms.html', 'footer_tos'); // FIXME this should be configurable like the other legal pages var legalFooter; // only display the legal part of the footer if it has content - if (terms || Pages.privacyLink || Pages.imprintLink) { + if (Pages.termsLink || Pages.privacyLink || Pages.imprintLink) { legalFooter = footerCol('footer_legal', [ - terms, + Pages.termsLink, Pages.privacyLink, Pages.imprintLink, ]); @@ -145,7 +172,7 @@ define([ footLink('/what-is-cryptpad.html', 'topbar_whatIsCryptpad'), Pages.docsLink, footLink('/features.html', Pages.areSubscriptionsAllowed()? 'pricing': 'features'), // Messages.pricing, Messages.features - Pages.githubLink, + Pages.sourceLink, footLink('https://opencollective.com/cryptpad/contribute/', 'footer_donate'), ]), footerCol('footer_aboutUs', [ diff --git a/www/checkup/main.js b/www/checkup/main.js index e7d952dbb..c1c6cdf2a 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -392,7 +392,6 @@ define([ assert(function (cb, msg) { msg.innerText = "Missing HTTP headers required for .xlsx export from sheets. "; - var url = cacheBuster(sheetURL); var expect = { 'cross-origin-resource-policy': 'cross-origin', 'cross-origin-embedder-policy': 'require-corp', @@ -1114,6 +1113,75 @@ define([ }); }); + var POLICY_ADVISORY = " It's advised that you either provide one or disable registration."; + var isValidInfoURL = function (url) { + // XXX check that it's an absolute URL ???? + if (!url || typeof(url) !== 'string') { return false; } + try { + var parsed = new URL(url, ApiConfig.httpUnsafeOrigin); + // check that the URL parsed and that they haven't simply linked to + // '/' or '.' or something silly like that. + return ![ + ApiConfig.httpUnsafeOrigin, + ApiConfig.httpUnsafeOrigin + '/', + ].includes(parsed.href); + } catch (err) { + return false; + } + }; + + // XXX check if they provide terms of service + assert(function (cb, msg) { + if (ApiConfig.restrictRegistration) { return void cb(true); } + + var url = Pages.customURLs.terms; + setWarningClass(msg); + msg.appendChild(h('span', [ + 'No terms of service specified.', // XXX + POLICY_ADVISORY, + ])); + cb(isValidInfoURL(url) || url); // XXX + }); + + // XXX check if they provide legal data + assert(function (cb, msg) { + if (ApiConfig.restrictRegistration) { return void cb(true); } + + var url = Pages.customURLs.imprint; + setWarningClass(msg); + msg.appendChild(h('span', [ + 'No legal data provided.', // XXX + POLICY_ADVISORY, + ])); + cb(isValidInfoURL(url) || url); // XXX + }); + + // XXX check if they provide a privacy policy + assert(function (cb, msg) { + if (ApiConfig.restrictRegistration) { return void cb(true); } + + var url = Pages.customURLs.privacy; + setWarningClass(msg); + msg.appendChild(h('span', [ + 'No privacy policy provided.', // XXX + POLICY_ADVISORY, + ])); + cb(isValidInfoURL(url) || url); // XXX + }); + + // XXX check if they provide a link to source code + assert(function (cb, msg) { + if (ApiConfig.restrictRegistration) { return void cb(true); } + + var url = Pages.customURLs.source; + setWarningClass(msg); + msg.appendChild(h('span', [ + 'No source code link provided.', // XXX + POLICY_ADVISORY, + ])); + cb(isValidInfoURL(url) || url); // XXX + }); + var serverToken; Tools.common_xhr('/', function (xhr) { serverToken = xhr.getResponseHeader('server'); diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index 3360e4f15..1943cbd29 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -35,6 +35,9 @@ define(function() { //'doc', 'presentation' ]; + // XXX + // AppConfig.premiumTypes = ['doc', 'presentation']; + /* CryptPad is available is multiple languages, but only English and French are maintained * by the developers. The other languages may be outdated, and any missing string for a langauge * will use the english version instead. You can customize the langauges you want to be available @@ -65,6 +68,29 @@ define(function() { */ //AppConfig.roadmap = 'https://cryptpad.fr/kanban/#/2/kanban/view/PLM0C3tFWvYhd+EPzXrbT+NxB76Z5DtZhAA5W5hG9wo/'; + // XXX +/* +AppConfig.imprint, AppConfig.privacy, AppConfig.terms, AppConfig.source, and AppConfig.roadmap can each be configured in one of three manners: + +// to prevent the display of privacy policy entirely: +AppConfig.privacy = false; + +// to display the default privacy policy: +AppConfig.privacy = true; + +// to display translated versions of the privacy policy depending on +// the user's configured or inferred language +AppConfig.privacy = { + 'default': '...', // displayed if there is no exact match + 'en': '/privacy.en.html', + 'fr': '/privacy.fr.html', +}; + + +*/ + AppConfig.source = 'https://github.com/xwiki-labs/cryptpad/'; // XXX + + /* Cryptpad apps use a common API to display notifications to users * by default, notifications are hidden after 5 seconds * You can change their duration here (measured in milliseconds) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 4b39b6aa2..38fee4c29 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1637,6 +1637,11 @@ define([ return $container; }; + Messages.info_termsFlavour = "XXX terms flavour"; // XXX + Messages.info_imprintFlavour = "XXX imprint flavour"; // XXX + Messages.info_roadmapFlavour = "XXX roadmap flavour"; // XXX + Messages.info_sourceFlavour = "XXX source flavour"; // XXX + UIElements.displayInfoMenu = function (Common, metadataMgr) { //var padType = metadataMgr.getMetadata().type; var priv = metadataMgr.getPrivateData(); @@ -1647,9 +1652,10 @@ define([ var template = function (line, link) { if (!line || !link) { return; } - var p = $('

').html(line)[0]; + var p = $('

').html(line)[0]; // XXX var sub = link.cloneNode(true); +// XXX use URL if you need to? /* This is a hack to make relative URLs point to the main domain instead of the sandbox domain. It will break if the admins have specified some less common URL formats for their customizable links, such as if they've @@ -1669,6 +1675,17 @@ define([ var faqLine = template(Messages.help_genericMore, Pages.docsLink); + // XXX terms + var termsLine = template(Messages.info_termsFlavour, Pages.termsLink); + + // XXX imprint + var imprintLine = template(Messages.info_imprintFlavour, Pages.imprintLink); + + // XXX roadmap + var roadmapLine = template(Messages.info_roadmapFlavour, Pages.roadmapLink); + + var sourceLine = template(Messages.info_sourceFlavour, Pages.sourceLink); + var content = h('div.cp-info-menu-container', [ h('div.logo-block', [ h('img', { @@ -1680,7 +1697,11 @@ define([ h('hr'), legalLine, privacyLine, + termsLine, // XXX + imprintLine, // XXX faqLine, + roadmapLine, // XXX + sourceLine, // XXX ]); $(content).find('a').attr('target', '_blank'); From 2134ec02b689b89d1c3576e93eb791365bbdef00 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 24 Feb 2022 18:06:46 +0530 Subject: [PATCH 07/45] prompt users to include useful information in support tickets --- www/support/app-support.less | 20 ++++++++++------- www/support/ui.js | 42 +++++++++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/www/support/app-support.less b/www/support/app-support.less index d4719956c..c364d84e7 100644 --- a/www/support/app-support.less +++ b/www/support/app-support.less @@ -7,6 +7,10 @@ .sidebar-layout_main(); .support_main(); + .cp-dropdown-container { + margin-bottom: 0px !important; + } + .cp-hidden { display: none !important; } @@ -14,14 +18,14 @@ display: flex; flex-flow: column; - .cp-support-form-attachments { - .fa { - cursor: pointer; - } - &> span { - padding: 10px; - } - } + .cp-support-form-attachments { + .fa { + cursor: pointer; + } + &> span { + padding: 10px; + } + } .cp-support-language-list { .cp-support-language { diff --git a/www/support/ui.js b/www/support/ui.js index 2f97ec412..6683ca6ad 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -8,7 +8,8 @@ define([ '/common/clipboard.js', '/common/common-ui-elements.js', '/customize/messages.js', -], function ($, ApiConfig, h, UI, Hash, Util, Clipboard, UIElements, Messages) { + '/customize/pages.js', +], function ($, ApiConfig, h, UI, Hash, Util, Clipboard, UIElements, Messages, Pages) { var getDebuggingData = function (ctx, data) { var common = ctx.common; @@ -145,19 +146,22 @@ define([ return true; }; + Messages.support_cat_abuse = "Abuse"; // XXX + Messages.support_cat_terms = "Terms violation"; // XXX + var makeCategoryDropdown = function (ctx, container, onChange, all) { var categories = [ 'account', // Msg.support_cat_account 'data', // Msg.support_cat_data 'bug', // Msg.support_cat_bug - // TODO report + 'abuse', // Msg.support_cat_abuse + Pages.customURLs.terms? 'terms': undefined, // Msg.support_cat_terms 'other' // Msg.support_cat_other ]; if (all) { categories.push('all'); } // Msg.support_cat_all - - categories = categories.map(function (key) { + if (!key) { return; } return { tag: 'a', content: h('span', Messages['support_cat_'+key]), @@ -178,6 +182,16 @@ define([ return $select; }; + Messages.support_warning_prompt = "We may require additional information depending on the nature of your issue. Choose the most relevant category for suggestions."; + + Messages.support_warning_account = "CryptPad administrators are unable to identify accounts, teams, folders, and files by their names. Please provide their identifiers if your issue relates to one of these features."; // XXX + Messages.support_warning_data = 'What data was lost? Is it entirely gone or only corrupted? Is it backed up? Can you provide a link to the content or at least its document id?'; // XXX + Messages.support_warning_bug = "Describe the bug in as much detail as possible. In which browser did you first notice the problem? In which other browser does it first occur, if any? Can you provide a list of all the extensions you've installed?"; // XXX + Messages.support_warning_report = 'Give us a link to the reported content, some context about its contents, and where it is being distributed.'; // XXX + Messages.support_warning_terms = 'Reports of content or behaviour which violate our terms of service should include links to any related content and descriptions of how they violate the terms. If possible, a description of the context in which you discovered the behaviour may help us prevent future violations.'; // XXX + Messages.support_warning_abuse = "If you have experienced targeted abuse on the platform, please provide a description of what occurred and indicate any evidence that might help us prevent this abuse in the future."; + Messages.support_warning_other = "What is the nature of your query? Providing as much relevant information as possible in your first message may make it easier for us to address your issue quickly."; // XXX + var makeForm = function (ctx, cb, title) { var button; @@ -193,18 +207,36 @@ define([ value: '' }); var catContainer = h('div.cp-dropdown-container' + (title ? '.cp-hidden': '')); + var notice = h('div.alert.alert-info', Messages.support_warning_prompt); makeCategoryDropdown(ctx, catContainer, function (key) { $(category).val(key); + console.log(key); + var warning = Messages['support_warning_' + key] || ''; + if (key === 'terms') { + // XXX AppConfig.terms or Pages.termsLink + notice.innerHTML = ''; + //notice.appendChild(UI.setHTML(h('span'), Messages.support_ + var content = UI.setHTML(h('span'), Messages.support_warning_terms); + var link = content.querySelector('a'); + link.href = Pages.customURLs.terms; + notice.appendChild(content); + return; + } + + notice.innerText = warning; + // TODO add a hint suggesting relevant information to include for the chosen category }); var attachments, addAttachment; + var content = [ h('hr'), category, catContainer, - h('br'), + notice, + //h('br'), h('input.cp-support-form-title' + (title ? '.cp-hidden' : ''), { placeholder: Messages.support_formTitle, type: 'text', From 6a2ec4ae7e24814125e5a6c429713fa09d009287 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Feb 2022 13:14:59 +0530 Subject: [PATCH 08/45] consider profile links unsafe --- www/profile/inner.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/www/profile/inner.js b/www/profile/inner.js index 8f7b8cf08..230bcc88e 100644 --- a/www/profile/inner.js +++ b/www/profile/inner.js @@ -135,6 +135,14 @@ define([ rel: 'noreferrer noopener' }).appendTo($block).hide(); + APP.$link.click(function (ev) { + ev.preventDefault(); + ev.stopPropagation(); + var href = $(this).attr('href').trim(); + if (!href) { return; } + common.openUnsafeURL(href); + }); + APP.$linkEdit = $(); if (APP.readOnly) { return; } From 84b0e2bd451a8fc45f133a8fe21107cc02de9bb3 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Feb 2022 13:19:44 +0530 Subject: [PATCH 09/45] slight optimization in reordering ticket on the admin panel --- www/admin/inner.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/www/admin/inner.js b/www/admin/inner.js index 83143a546..6d3a4115f 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -908,19 +908,21 @@ define([ }; var _reorder = function () { - var orderAnswered = Object.keys(hashesById).filter(function (id) { + var hashKeys = Object.keys(hashesById); + + var orderAnswered = hashKeys.filter(function (id) { var d = getTicketData(id); return d && d.lastAdmin && !d.closed; }).sort(sort); - var orderPremium = Object.keys(hashesById).filter(function (id) { + var orderPremium = hashKeys.filter(function (id) { var d = getTicketData(id); return d && d.premium && !d.lastAdmin && !d.closed; }).sort(sort); - var orderNormal = Object.keys(hashesById).filter(function (id) { + var orderNormal = hashKeys.filter(function (id) { var d = getTicketData(id); return d && !d.premium && !d.lastAdmin && !d.closed; }).sort(sort); - var orderClosed = Object.keys(hashesById).filter(function (id) { + var orderClosed = hashKeys.filter(function (id) { var d = getTicketData(id); return d && d.closed; }).sort(sort); From f31ebf7f2eef280a745d16b9bcf71eba0ec8de59 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Feb 2022 14:27:49 +0530 Subject: [PATCH 10/45] fully drop support for browsers lacking promises --- www/common/boot2.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/common/boot2.js b/www/common/boot2.js index 097d76489..925fb030c 100644 --- a/www/common/boot2.js +++ b/www/common/boot2.js @@ -86,11 +86,11 @@ define([ } } catch (e) { console.error(e); failStore(); } - require([document.querySelector('script[data-bootload]').getAttribute('data-bootload')]); if (typeof(Promise) !== 'function') { - setTimeout(function () { + return void setTimeout(function () { var s = "Internet Explorer is not supported anymore, including by Microsoft.\n\nMost of CryptPad's collaborative functionality requires a modern browser to work.\n\nWe recommend Mozilla Firefox."; window.alert(s); }); } + require([document.querySelector('script[data-bootload]').getAttribute('data-bootload')]); }); From 4344f4410b63349f249a4a47136741cf47e32086 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Feb 2022 15:47:28 +0530 Subject: [PATCH 11/45] handle links in forms --- www/form/inner.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/www/form/inner.js b/www/form/inner.js index a0084057f..5bcb642fd 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -986,6 +986,12 @@ define([ }); }); + var linkClickHandler = function (ev) { + ev.preventDefault(); + var href = ($(this).attr('href') || '').trim(); + if (!href) { return; } + APP.common.openUnsafeURL(href); + }; var STATIC_TYPES = { md: { @@ -999,6 +1005,8 @@ define([ }, opts.text); var $tag = $(tag); DiffMd.apply(DiffMd.render(opts.text || ''), $tag, APP.common); + $tag.find('a').click(linkClickHandler); + var cursorGetter; return { tag: tag, @@ -2904,6 +2912,7 @@ define([ if (content.answers.msg) { var $desc = $(description); DiffMd.apply(DiffMd.render(content.answers.msg), $desc, APP.common); + $desc.find('a').click(linkClickHandler); } var actions = h('div.cp-form-submit-actions', [ From 70f50711bfcf57eb565f84a222889b1a464b9031 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Feb 2022 16:02:06 +0530 Subject: [PATCH 12/45] abort loading several pages if embedded --- www/debug/main.js | 3 +++ www/login/main.js | 1 + www/register/main.js | 1 + 3 files changed, 5 insertions(+) diff --git a/www/debug/main.js b/www/debug/main.js index 6f855e1db..124ea39f9 100644 --- a/www/debug/main.js +++ b/www/debug/main.js @@ -13,6 +13,9 @@ define([ '/common/common-interface.js', ], function (nThen, ApiConfig, $, RequireConfig, SFCommonO, Cryptpad, Util, Hash, Realtime, Constants, UI) { + if (window.top !== window) { + return void window.alert(`If you are seeing this message then somebody might be trying to compromise your CryptPad account. Please contact the CryptPad development team.`); + } window.Cryptpad = { Common: Cryptpad, diff --git a/www/login/main.js b/www/login/main.js index df0be1733..1a27343fc 100644 --- a/www/login/main.js +++ b/www/login/main.js @@ -10,6 +10,7 @@ define([ 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', ], function ($, Cryptpad, Login, UI, Realtime, Feedback, LocalStore /*, Test */) { + if (window.top !== window) { return; } $(function () { var $checkImport = $('#import-recent'); if (LocalStore.isLoggedIn()) { diff --git a/www/register/main.js b/www/register/main.js index 301306f70..8edbaab92 100644 --- a/www/register/main.js +++ b/www/register/main.js @@ -14,6 +14,7 @@ define([ 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', ], function ($, Login, Cryptpad, /*Test,*/ Cred, UI, Util, Realtime, Constants, Feedback, LocalStore, h) { + if (window.top !== window) { return; } var Messages = Cryptpad.Messages; $(function () { if (LocalStore.isLoggedIn()) { From 1e2a05907472280f0227e84639131fde610d1a1e Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Feb 2022 16:09:52 +0530 Subject: [PATCH 13/45] lint compliance --- www/checkup/main.js | 1 - 1 file changed, 1 deletion(-) diff --git a/www/checkup/main.js b/www/checkup/main.js index e7d952dbb..2c227df5d 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -392,7 +392,6 @@ define([ assert(function (cb, msg) { msg.innerText = "Missing HTTP headers required for .xlsx export from sheets. "; - var url = cacheBuster(sheetURL); var expect = { 'cross-origin-resource-policy': 'cross-origin', 'cross-origin-embedder-policy': 'require-corp', From 5f757fd21fcda7cf778829f700e16753f1bd086e Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 28 Feb 2022 14:34:57 +0530 Subject: [PATCH 14/45] possible fix for pads being duplicated in team drives --- www/common/outer/async-store.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 729793039..0f6db4db3 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1172,7 +1172,7 @@ define([ var sendTo = []; var inMyDrive; getAllStores().forEach(function (s) { - if (data.teamId && s.id !== data.teamId) { return; } + if (data.teamId && Number(s.id) !== data.teamId) { return; } if (storeLocally && s.id) { return; } // If this is an edit link but we don't have edit rights, this entry is not useful @@ -1189,7 +1189,7 @@ define([ // we need to make a copy of this pad in our drive. We're going to check // if the pad is stored in our MAIN drive. // We only need to check this if the current manager is the target (data.teamId) - if (data.teamId === s.id) { + if (data.teamId === Number(s.id)) { inMyDrive = res.some(function (obj) { return !obj.fId; }); From 4019ec0880749e7d7d9646710afb419bac46abd8 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 28 Feb 2022 11:57:39 +0100 Subject: [PATCH 15/45] Fix 'store in cryptdrive' --- www/common/common-ui-elements.js | 4 +++- www/common/cryptpad-common.js | 3 +++ www/common/sframe-common-outer.js | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 4b39b6aa2..dcf0809ec 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -808,7 +808,9 @@ define([ h('span.cp-toolbar-name.cp-toolbar-drawer-element', Messages.toolbar_storeInDrive) ])).click(common.prepareFeedback(type)).click(function () { $(button).hide(); - common.getSframeChannel().query("Q_AUTOSTORE_STORE", null, function (err, obj) { + common.getSframeChannel().query("Q_AUTOSTORE_STORE", { + forceOwnDrive: true, + }, function (err, obj) { var error = err || (obj && obj.error); if (error) { $(button).show(); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index a0d584ea5..d32d06eac 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -974,6 +974,9 @@ define([ data.forceSave = 1; //delete common.initialTeam; } + if (data.forceOwnDrive) { + data.teamId = -1; + } if (common.initialPath) { if (!data.path) { data.path = Array.isArray(common.initialPath) ? common.initialPath diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 7351a2485..91d11c20d 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -1181,7 +1181,8 @@ define([ title: currentTitle, channel: secret.channel, path: initialPathInDrive, // Where to store the pad if we don't have it in our drive - forceSave: true + forceSave: true, + forceOwnDrive: obj && obj.forceOwnDrive }; setPadTitle(data, cb); }); From f9de03440443666a2b40fe3f3b8a39e9a0edfa67 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 28 Feb 2022 17:46:51 +0530 Subject: [PATCH 16/45] correctly detect when a pad is already stored in your personal drive to avoid creating duplicates --- www/common/outer/async-store.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 0f6db4db3..b59456fd0 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1189,10 +1189,12 @@ define([ // we need to make a copy of this pad in our drive. We're going to check // if the pad is stored in our MAIN drive. // We only need to check this if the current manager is the target (data.teamId) - if (data.teamId === Number(s.id)) { - inMyDrive = res.some(function (obj) { - return !obj.fId; - }); + if ((!s.id && !data.teamId) || Number(s.id) === data.teamId) { + if (!inMyDrive) { + inMyDrive = res.some(function (obj) { + return !obj.fId; + }); + } } Array.prototype.push.apply(allData, res); From ac7409f7efe23ba358f15e86a925b9ec4806e401 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 28 Feb 2022 14:19:16 +0100 Subject: [PATCH 17/45] Fix other duplicate pad issue --- www/common/outer/async-store.js | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index b59456fd0..2726e9c83 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1170,11 +1170,8 @@ define([ // If it is stored, update its data, otherwise ask the user if they want to store it var allData = []; var sendTo = []; - var inMyDrive; + var inTargetDrive; getAllStores().forEach(function (s) { - if (data.teamId && Number(s.id) !== data.teamId) { return; } - if (storeLocally && s.id) { return; } - // If this is an edit link but we don't have edit rights, this entry is not useful if (h.mode === "edit" && s.id && !s.secondaryKey) { return; @@ -1185,15 +1182,10 @@ define([ sendTo.push(s.id); } - // If we've just accepted ownership for a pad stored in a shared folder, - // we need to make a copy of this pad in our drive. We're going to check - // if the pad is stored in our MAIN drive. - // We only need to check this if the current manager is the target (data.teamId) + // Check if the pad is already stored in the specified drive (data.teamId) if ((!s.id && !data.teamId) || Number(s.id) === data.teamId) { - if (!inMyDrive) { - inMyDrive = res.some(function (obj) { - return !obj.fId; - }); + if (!inTargetDrive) { + inTargetDrive = res.length; } } @@ -1233,7 +1225,7 @@ define([ }); // Add the pad if it does not exist in our drive - if (!contains || (data.forceSave && !inMyDrive)) { + if (!contains || (data.forceSave && !inTargetDrive)) { var autoStore = Util.find(store.proxy, ['settings', 'general', 'autostore']); if (autoStore !== 1 && !data.forceSave && !data.path) { // send event to inner to display the corner popup @@ -1260,7 +1252,8 @@ define([ }, cb); // Let inner know that dropped files shouldn't trigger the popup postMessage(clientId, "AUTOSTORE_DISPLAY_POPUP", { - stored: true + stored: true, + inMyDrive: !contains && data.teamId // display "store in cryptdrive" entry }); return; } @@ -1275,7 +1268,7 @@ define([ // Let inner know that dropped files shouldn't trigger the popup postMessage(clientId, "AUTOSTORE_DISPLAY_POPUP", { stored: true, - inMyDrive: inMyDrive + inMyDrive: true }); nThen(function (waitFor) { sendTo.forEach(function (teamId) { From afa799867a28b8baa5cac925f50dec7dd8131785 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 28 Feb 2022 14:31:10 +0100 Subject: [PATCH 18/45] Fix 'store in cryptdrive' displayed when creating a pad from the drive --- www/common/outer/async-store.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 2726e9c83..e2073835d 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1170,7 +1170,7 @@ define([ // If it is stored, update its data, otherwise ask the user if they want to store it var allData = []; var sendTo = []; - var inTargetDrive; + var inTargetDrive, inMyDrive; getAllStores().forEach(function (s) { // If this is an edit link but we don't have edit rights, this entry is not useful if (h.mode === "edit" && s.id && !s.secondaryKey) { @@ -1189,6 +1189,8 @@ define([ } } + if (!s.id) { inMyDrive = res.length; } + Array.prototype.push.apply(allData, res); }); var contains = allData.length !== 0; @@ -1253,7 +1255,7 @@ define([ // Let inner know that dropped files shouldn't trigger the popup postMessage(clientId, "AUTOSTORE_DISPLAY_POPUP", { stored: true, - inMyDrive: !contains && data.teamId // display "store in cryptdrive" entry + inMyDrive: inMyDrive || (!contains && !data.teamId) // display "store in cryptdrive" entry }); return; } @@ -1268,7 +1270,7 @@ define([ // Let inner know that dropped files shouldn't trigger the popup postMessage(clientId, "AUTOSTORE_DISPLAY_POPUP", { stored: true, - inMyDrive: true + inMyDrive: inMyDrive }); nThen(function (waitFor) { sendTo.forEach(function (teamId) { From df0881ffb1d8b87212d157e453d0c9b41825c7e6 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 28 Feb 2022 19:21:29 +0530 Subject: [PATCH 19/45] lint compliance --- www/common/outer/async-store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index e2073835d..0856572bc 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1159,7 +1159,7 @@ define([ expire = data.expire; } - var storeLocally = data.teamId === -1; + //var storeLocally = data.teamId === -1; if (data.teamId === -1) { data.teamId = undefined; } // If a teamId is provided, it means we want to store the pad in a specific From a102f306ed1435d4388b2b7dada57024d4da8b05 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 1 Mar 2022 14:43:47 +0100 Subject: [PATCH 20/45] Translated using Weblate (French) Currently translated at 99.8% (1436 of 1438 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fr/ --- www/common/translations/messages.fr.json | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index 74195430e..5a7f8e22b 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -964,7 +964,7 @@ "todo_move": "Votre liste de tâches est désormais dans le kanban {0} dans votre Drive.", "settings_safeLinkDefault": "Les liens sécurisés sont désormais activés par défaut. Veuillez utiliser le menu Partager pour copier les liens plutôt que la barre d'adresse de votre navigateur.", "support_languagesPreamble": "L'équipe de support parle les langues suivantes :", - "info_privacyFlavour": "Description de la confidentialité de vos données.", + "info_privacyFlavour": "Déclaration de confidentialité pour cette instance", "user_about": "À propos de CryptPad", "info_imprintFlavour": "Informations légales sur les administrateurs de cette instance.", "support_cat_all": "Tout", @@ -1427,5 +1427,14 @@ "form_exportSheet": "Exporter vers Tableur", "form_answerChoice": "Veuillez choisir comment vous souhaitez répondre à ce formulaire :", "bounce_danger": "Le lien sur lequel vous avez cliqué ne mène pas à une page web mais à du code ou des données qui pourraient être dangereuses.\n\n(\"{0}\")\n\nCryptPad bloque ce type de lien pour des raisons de sécurité. En cliquant sur OK, vous fermerez cet onglet.", - "bounce_confirm": "Vous êtes sur le point de quitter : {0}\n\nÊtes vous sûr de vouloir visiter \"{1}\" ?" + "bounce_confirm": "Vous êtes sur le point de quitter : {0}\n\nÊtes vous sûr de vouloir visiter \"{1}\" ?", + "info_sourceFlavour": "Code source de CryptPad", + "info_termsFlavour": "Conditions d'utilisation pour cette instance", + "footer_source": "Code source", + "admin_jurisdictionHint": "Le pays où les données chiffrées de cette instance sont hébergées", + "admin_descriptionHint": "Le texte descriptif affiché pour cette instance dans la liste des instances publiques sur cryptpad.org", + "admin_descriptionTitle": "Description de l'instance", + "admin_nameHint": "Le nom affiché pour cette instance dans la liste des instances publiques sur cryptpad.org", + "admin_nameTitle": "Nom de l'instance", + "admin_archiveNote": "Note" } From d3145f0667fe62ee607e758d3b6d18059c1bad6f Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 1 Mar 2022 14:43:47 +0100 Subject: [PATCH 21/45] Translated using Weblate (English) Currently translated at 99.9% (1437 of 1438 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1438 of 1438 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1437 of 1437 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1437 of 1437 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1436 of 1436 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1435 of 1435 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1434 of 1434 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1433 of 1433 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1432 of 1432 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1431 of 1431 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1430 of 1430 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1429 of 1429 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1428 of 1428 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 11b05dc6f..1ac415d7c 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -967,9 +967,9 @@ "slide_textCol": "Text color", "support_languagesPreamble": "The support team speaks the following languages:", "settings_safeLinkDefault": "Safe Links are now turned on by default. Please use the Share menu to copy links rather than your browser's address bar.", - "info_imprintFlavour": "Legal information about the administrators of this instance.", + "info_imprintFlavour": "Legal information about the administrators of this instance", "user_about": "About CryptPad", - "info_privacyFlavour": "Our privacy policy describes how we treat your data.", + "info_privacyFlavour": "Privacy policy for this instance", "support_cat_account": "User account", "support_cat_data": "Loss of content", "support_cat_bug": "Bug report", @@ -1427,5 +1427,16 @@ "form_exportSheet": "Export to Sheet", "form_answerChoice": "Please choose how you would like to answer this form:", "bounce_confirm": "You are about to leave: {0}\n\nAre you sure you want to visit \"{1}\"?", - "bounce_danger": "The link you clicked does not lead to a web-page but to some code or data that could be malicious.\n\n(\"{0}\")\n\nCryptPad blocks these for security reasons. Clicking OK will close this tab." + "bounce_danger": "The link you clicked does not lead to a web-page but to some code or data that could be malicious.\n\n(\"{0}\")\n\nCryptPad blocks these for security reasons. Clicking OK will close this tab.", + "admin_archiveNote": "Note", + "admin_nameTitle": "Instance name", + "admin_nameHint": "The name displayed for this instance in the list of public instances on cryptpad.org", + "ui_saved": "{0} saved", + "admin_descriptionTitle": "Instance description", + "admin_descriptionHint": "The descriptive text displayed for this instance in the list of public instances on cryptpad.org", + "admin_jurisdictionTitle": "Hosting location", + "admin_jurisdictionHint": "The country where this instance's encrypted data is hosted", + "footer_source": "Source code", + "info_termsFlavour": "Terms of service for this instance", + "info_sourceFlavour": "Source code for CryptPad" } From 0d871d2f7ea1c1b517d8513e7ab7506e5136eed4 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 1 Mar 2022 14:43:48 +0100 Subject: [PATCH 22/45] Translated using Weblate (Spanish) Currently translated at 45.3% (647 of 1427 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/es/ --- www/common/translations/messages.es.json | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.es.json b/www/common/translations/messages.es.json index 00d2b357b..2c793dace 100644 --- a/www/common/translations/messages.es.json +++ b/www/common/translations/messages.es.json @@ -669,5 +669,24 @@ "footer_product": "Producto", "admin_flushCacheDone": "Vaciado de caché exitoso", "admin_flushCacheButton": "Vaciar caché", - "admin_flushCacheHint": "Obligar a usuarios a descargar los recursos más nuevos para el cliente (sólo si su servidor está en modo actualizado o “fresh mode”)" + "admin_flushCacheHint": "Obligar a usuarios a descargar los recursos más nuevos para el cliente (sólo si su servidor está en modo actualizado o “fresh mode”)", + "profile_friendRequestSent": "Pedido de contacto pendiente...", + "profile_info": "Otros usuarios pueden encontrar su perfil haciendo clic en su nombre en la lista de usuarios de los documentos.", + "profile_addLink": "Añade un enlace a su sitio web", + "profile_editDescription": "Edita su descripción", + "profile_addDescription": "Añadir una descripción", + "notifications_empty": "No hay notificaciones disponibles", + "friendRequest_notification": "{0} le envió una solicitud de contacto", + "friendRequest_received": "{0} quiere ser tu contato", + "friendRequest_accepted": "{0} aceptó su solicitud de contacto", + "friendRequest_declined": "{0} rechazó su solicitud de contacto", + "friendRequest_decline": "Declinar", + "friendRequest_accept": "Aceptar (Enter)", + "friendRequest_later": "Decidir después", + "drive_activeOld": "Documentos menos recientes", + "drive_active28Days": "Últimas 4 semanas", + "drive_active7Days": "Últimos 7 dias", + "drive_active1Day": "Últimas 24 horas", + "settings_codeSpellcheckLabel": "Habilite la verificación ortográfica en el editor de código", + "settings_codeSpellcheckTitle": "Corrección ortográfica" } From 5813b8a322aed5d80e2d0d30a193c73f8618cc42 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 1 Mar 2022 14:51:51 +0100 Subject: [PATCH 23/45] Translated using Weblate (English) Currently translated at 99.8% (1436 of 1438 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 1ac415d7c..c49843f25 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -558,7 +558,7 @@ "four04_pageNotFound": "We couldn't find the page you were looking for.", "header_logoTitle": "Go to your CryptDrive", "header_homeTitle": "Go to CryptPad homepage", - "help_genericMore": "Learn more about how CryptPad can work for you by reading our Documentation.", + "help_genericMore": "Learn more about how CryptPad can work for you by reading our Documentation", "edit": "edit", "view": "view", "feedback_about": "If you're reading this, you were probably curious why CryptPad is requesting web pages when you perform certain actions.", @@ -967,7 +967,7 @@ "slide_textCol": "Text color", "support_languagesPreamble": "The support team speaks the following languages:", "settings_safeLinkDefault": "Safe Links are now turned on by default. Please use the Share menu to copy links rather than your browser's address bar.", - "info_imprintFlavour": "Legal information about the administrators of this instance", + "info_imprintFlavour": "Legal information about the administrators of this instance", "user_about": "About CryptPad", "info_privacyFlavour": "Privacy policy for this instance", "support_cat_account": "User account", From 31a55a43896b2c1bf35cb272cfe4ad6759290091 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 1 Mar 2022 21:08:31 +0530 Subject: [PATCH 24/45] WIP adjustments for new translation keys --- www/admin/inner.js | 63 +++++++++++--------------------- www/common/common-ui-elements.js | 25 ++----------- www/support/ui.js | 2 +- 3 files changed, 27 insertions(+), 63 deletions(-) diff --git a/www/admin/inner.js b/www/admin/inner.js index b0dfffa46..be0ff68af 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -53,14 +53,18 @@ define([ 'general': [ // Msg.admin_cat_general 'cp-admin-flush-cache', 'cp-admin-update-limit', - 'cp-admin-archive', - 'cp-admin-unarchive', 'cp-admin-registration', 'cp-admin-email', + + 'cp-admin-name', + 'cp-admin-description', + 'cp-admin-jurisdiction', ], 'quota': [ // Msg.admin_cat_quota 'cp-admin-defaultlimit', 'cp-admin-setlimit', + 'cp-admin-archive', + 'cp-admin-unarchive', 'cp-admin-getquota', 'cp-admin-getlimits', ], @@ -93,10 +97,6 @@ define([ //'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', @@ -151,8 +151,6 @@ define([ return $div; }; - Messages.admin_archiveReason = "// XXX REASON"; // XXX - var archiveForm = function (archive, $div, $button) { var label = h('label', { for: 'cp-admin-archive' }, Messages.admin_archiveInput); var input = h('input#cp-admin-archive', { @@ -168,11 +166,10 @@ define([ }); var input3 = h('input', { id: 'cp-admin-archive-reason', - placeholder: Messages.admin_archiveReason, }); var label3 = h('label', { for: 'cp-admin-archive-reason', - }, Messages.admin_archiveReason); + }, Messages.admin_archiveNote); var $pw = $(input2); $pw.addClass('cp-admin-pw'); @@ -377,8 +374,8 @@ define([ create['email'] = function () { var key = 'email'; - var $div = makeBlock(key, true); // Msg.admin_emailHint, Msg.admin_emailTitle, Msg.admin_emailButton - var $button = $div.find('button'); + var $div = makeBlock(key, true); // Msg.admin_emailHint, Msg.admin_emailTitle, Msg.admin_emailButton // XXX drop 'emailButton' + var $button = $div.find('button').text(Messages.settings_save); var input = h('input', { type: 'email', @@ -414,15 +411,10 @@ 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 $button = $div.find('button').addClass('cp-listing-action').text(Messages.settings_save); var input = h('input.cp-listing-info', { type: 'text', @@ -434,12 +426,12 @@ define([ var spinner = UI.makeSpinner($(innerDiv)); $button.click(function () { - if (!$input.val()) { return; } + if (!$input.val()) { return; } // XXX spinner.spin(); $button.attr('disabled', 'disabled'); sFrameChan.query('Q_ADMIN_RPC', { cmd: 'ADMIN_DECREE', - data: ['SET_INSTANCE_JURISDICTION', [$input.val()]] // XXX not implemented + data: ['SET_INSTANCE_JURISDICTION', [$input.val()]] // XXX }, function (e, response) { $button.removeAttr('disabled'); if (e || response.error) { @@ -450,7 +442,7 @@ define([ return; } spinner.done(); - UI.log(Messages.saved); + UI.log(Messages._getKey('ui_saved', [Messages.admin_jurisdictionTitle])); }); }); @@ -459,21 +451,16 @@ define([ 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 $button = $div.find('button').addClass('cp-listing-action').text(Messages.settings_save); var input = h('input.cp-listing-info', { type: 'text', - value: APP.instanceStatus.instanceName || '', - placeholder: Messages.admin_namePlaceholder, + value: APP.instanceStatus.instanceName || ApiConfig.httpUnsafeOrigin || '', + placeholder: ApiConfig.httpUnsafeOrigin, //Messages.admin_namePlaceholder, // XXX style: 'margin-bottom: 5px;', }); var $input = $(input); @@ -481,7 +468,7 @@ define([ var spinner = UI.makeSpinner($(innerDiv)); $button.click(function () { - if (!$input.val()) { return; } + if (!$input.val()) { return; } // XXX spinner.spin(); $button.attr('disabled', 'disabled'); sFrameChan.query('Q_ADMIN_RPC', { @@ -497,7 +484,7 @@ define([ return; } spinner.done(); - UI.log(Messages.saved); + UI.log(Messages._getKey('ui_saved', [Messages.admin_nameTitle])); }); }); @@ -506,21 +493,15 @@ define([ 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, + placeholder: Messages.home_host || '', // XXX }, APP.instanceStatus.instanceDescription || ''); - var $button = $div.find('button'); + var $button = $div.find('button').text(Messages.settings_save); $button.addClass('cp-listing-action'); @@ -535,7 +516,7 @@ define([ var spinner = UI.makeSpinner($(innerDiv)); $button.click(function () { - if (!$input.val()) { return; } + if (!$input.val()) { return; } // XXX spinner.spin(); $button.attr('disabled', 'disabled'); sFrameChan.query('Q_ADMIN_RPC', { @@ -551,7 +532,7 @@ define([ return; } spinner.done(); - UI.log(Messages.saved); + UI.log(Messages._getKey('ui_saved', [Messages.admin_descriptionTitle])); }); }); diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index d7b401fa2..01e19f0ef 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1639,11 +1639,6 @@ define([ return $container; }; - Messages.info_termsFlavour = "XXX terms flavour"; // XXX - Messages.info_imprintFlavour = "XXX imprint flavour"; // XXX - Messages.info_roadmapFlavour = "XXX roadmap flavour"; // XXX - Messages.info_sourceFlavour = "XXX source flavour"; // XXX - UIElements.displayInfoMenu = function (Common, metadataMgr) { //var padType = metadataMgr.getMetadata().type; var priv = metadataMgr.getPrivateData(); @@ -1674,18 +1669,8 @@ define([ var legalLine = template(Messages.info_imprintFlavour, Pages.imprintLink); var privacyLine = template(Messages.info_privacyFlavour, Pages.privacyLink); - var faqLine = template(Messages.help_genericMore, Pages.docsLink); - - // XXX terms var termsLine = template(Messages.info_termsFlavour, Pages.termsLink); - - // XXX imprint - var imprintLine = template(Messages.info_imprintFlavour, Pages.imprintLink); - - // XXX roadmap - var roadmapLine = template(Messages.info_roadmapFlavour, Pages.roadmapLink); - var sourceLine = template(Messages.info_sourceFlavour, Pages.sourceLink); var content = h('div.cp-info-menu-container', [ @@ -1697,13 +1682,11 @@ define([ h('span', Pages.versionString) ]), h('hr'), - legalLine, - privacyLine, - termsLine, // XXX - imprintLine, // XXX faqLine, - roadmapLine, // XXX - sourceLine, // XXX + termsLine, + privacyLine, + legalLine, + sourceLine, ]); $(content).find('a').attr('target', '_blank'); diff --git a/www/support/ui.js b/www/support/ui.js index 6683ca6ad..2d1e13017 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -182,7 +182,7 @@ define([ return $select; }; - Messages.support_warning_prompt = "We may require additional information depending on the nature of your issue. Choose the most relevant category for suggestions."; + Messages.support_warning_prompt = "We may require additional information depending on the nature of your issue. Choose the most relevant category for suggestions."; // XXX Messages.support_warning_account = "CryptPad administrators are unable to identify accounts, teams, folders, and files by their names. Please provide their identifiers if your issue relates to one of these features."; // XXX Messages.support_warning_data = 'What data was lost? Is it entirely gone or only corrupted? Is it backed up? Can you provide a link to the content or at least its document id?'; // XXX From 3a704f2e5a734ff0845604c19b8bf43f2d2ec978 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 2 Mar 2022 12:27:55 +0530 Subject: [PATCH 25/45] WIP support pager translations --- www/support/ui.js | 79 +++++++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/www/support/ui.js b/www/support/ui.js index 2d1e13017..f402471d0 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -95,6 +95,9 @@ define([ } }; + //Messages.support_formCategoryError = "Error: category is empty"; // XXX (existing key) + Messages.support_formCategoryError = "Please select a ticket category from the dropdown menu"; // XXX + var sendForm = function (ctx, id, form, dest) { var $form = $(form); var $cat = $form.find('.cp-support-form-category'); @@ -104,15 +107,10 @@ define([ var $attachments = $form.find('.cp-support-attachments'); var category = $cat.val().trim(); - /* - // || ($form.closest('.cp-support-list-ticket').data('cat') || "").trim(); - // Messages.support_formCategoryError = "Error: category is empty"; // TODO ensure this is translated before use - if (!category) { console.log($cat); return void UI.alert(Messages.support_formCategoryError); } - */ var title = $title.val().trim(); if (!title) { @@ -146,16 +144,17 @@ define([ return true; }; - Messages.support_cat_abuse = "Abuse"; // XXX - Messages.support_cat_terms = "Terms violation"; // XXX + Messages.support_cat_drives = "Drive or team"; // XXX + Messages.support_cat_document = "Document"; // XXX + Messages.support_cat_abuse = "Report abuse"; // XXX var makeCategoryDropdown = function (ctx, container, onChange, all) { var categories = [ 'account', // Msg.support_cat_account - 'data', // Msg.support_cat_data + 'drives', // Msg.support_cat_drives + 'document', // Msg.support_cat_document, + Pages.customURLs.terms? 'abuse': undefined, // Msg.support_cat_abuse 'bug', // Msg.support_cat_bug - 'abuse', // Msg.support_cat_abuse - Pages.customURLs.terms? 'terms': undefined, // Msg.support_cat_terms 'other' // Msg.support_cat_other ]; if (all) { categories.push('all'); } // Msg.support_cat_all @@ -182,15 +181,28 @@ define([ return $select; }; - Messages.support_warning_prompt = "We may require additional information depending on the nature of your issue. Choose the most relevant category for suggestions."; // XXX + Messages.support_warning_prompt = "Please choose the most relevant category for your issue, this helps administrators triage and provides further suggestions for what information to provide"; // XXX + + Messages.support_warning_account = "Please note that administrators are not able to reset passwords. If you have lost the credentials to your account but are still logged in, you can migrate your data to a new account"; // XXX + + Messages.support_warning_drives = "Note that administrators are not able to identify folders and documents by name. For shared folders, please provide a document identifier (does not provide access to the content)"; // XXX + + Messages.support_warning_document = "Please specify which type of document is causing the issue and provide a document identifier (does not provide access to the content)"; // XXX + + Messages.support_warning_bug = "Please specify in which browser the issue occurs and if any extensions are installed. Please provide as much detail as possible about the issue and the steps necessary to reproduce it"; // XXX + + Messages.support_warning_abuse = "Please report content that violates the Terms of Service. Please provide links to the offending documents or user profiles and describe how they are violating the terms. Any additional information on the context in which you discovered the content or behaviour may help administrators prevent future violations"; // XXX - Messages.support_warning_account = "CryptPad administrators are unable to identify accounts, teams, folders, and files by their names. Please provide their identifiers if your issue relates to one of these features."; // XXX - Messages.support_warning_data = 'What data was lost? Is it entirely gone or only corrupted? Is it backed up? Can you provide a link to the content or at least its document id?'; // XXX - Messages.support_warning_bug = "Describe the bug in as much detail as possible. In which browser did you first notice the problem? In which other browser does it first occur, if any? Can you provide a list of all the extensions you've installed?"; // XXX - Messages.support_warning_report = 'Give us a link to the reported content, some context about its contents, and where it is being distributed.'; // XXX - Messages.support_warning_terms = 'Reports of content or behaviour which violate our terms of service should include links to any related content and descriptions of how they violate the terms. If possible, a description of the context in which you discovered the behaviour may help us prevent future violations.'; // XXX - Messages.support_warning_abuse = "If you have experienced targeted abuse on the platform, please provide a description of what occurred and indicate any evidence that might help us prevent this abuse in the future."; - Messages.support_warning_other = "What is the nature of your query? Providing as much relevant information as possible in your first message may make it easier for us to address your issue quickly."; // XXX + Messages.support_warning_other = "What is the nature of your query? Please provide as much relevant information as possible to make it easier for us to address your issue quickly"; // XXX + + var documentIdDocs = Pages.localizeDocsLink('https://docs.cryptpad.fr/en/user_guide/apps/general.html#properties'); + + var warningLinks = { + account: documentIdDocs, + document: documentIdDocs, + drives: documentIdDocs, + abuse: Pages.customURLs.terms, + }; var makeForm = function (ctx, cb, title) { var button; @@ -208,24 +220,31 @@ define([ }); var catContainer = h('div.cp-dropdown-container' + (title ? '.cp-hidden': '')); var notice = h('div.alert.alert-info', Messages.support_warning_prompt); + var clickHandler = function (ev) { + ev.preventDefault(); + var $link = $(this); + var href = $link.attr('href'); + if (!href) { return; } + ctx.common.openUnsafeURL(href); + }; + makeCategoryDropdown(ctx, catContainer, function (key) { $(category).val(key); console.log(key); var warning = Messages['support_warning_' + key] || ''; - if (key === 'terms') { - // XXX AppConfig.terms or Pages.termsLink - notice.innerHTML = ''; - //notice.appendChild(UI.setHTML(h('span'), Messages.support_ - var content = UI.setHTML(h('span'), Messages.support_warning_terms); - var link = content.querySelector('a'); - link.href = Pages.customURLs.terms; - notice.appendChild(content); + var warningLink = warningLinks[key]; + if (!warningLink) { + notice.innerText = warning; return; } - - notice.innerText = warning; - - // TODO add a hint suggesting relevant information to include for the chosen category + notice.innerHTML = ''; + var content = UI.setHTML(h('span'), warning); + var link = content.querySelector('a'); + if (link) { + link.href = warningLink; + link.onclick = clickHandler; + } + notice.appendChild(content); }); var attachments, addAttachment; From 93ae6b4546310ced191a12116684cb11d6718248 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 2 Mar 2022 15:06:47 +0100 Subject: [PATCH 26/45] Translated using Weblate (English) Currently translated at 99.8% (1446 of 1448 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 99.8% (1445 of 1447 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 99.8% (1444 of 1446 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 99.8% (1443 of 1445 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 99.8% (1442 of 1444 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 99.8% (1441 of 1443 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 99.8% (1440 of 1442 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 99.8% (1439 of 1441 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 99.8% (1438 of 1440 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 99.8% (1437 of 1439 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index c49843f25..f73abfdcf 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1438,5 +1438,15 @@ "admin_jurisdictionHint": "The country where this instance's encrypted data is hosted", "footer_source": "Source code", "info_termsFlavour": "Terms of service for this instance", - "info_sourceFlavour": "Source code for CryptPad" + "info_sourceFlavour": "Source code for CryptPad", + "support_warning_prompt": "Please choose the most relevant category for your issue. This helps administrators triage and provides further suggestions for what information to provide", + "support_warning_account": "Please note that administrators are not able to reset passwords. If you have lost the credentials to your account but are still logged in, you can migrate your data to a new account", + "support_warning_drives": "Note that administrators are not able to identify folders and documents by name. For shared folders, please provide a document identifier", + "support_warning_document": "Please specify which type of document is causing the issue and provide a document identifier or a link", + "support_warning_bug": "Please specify in which browser the issue occurs and if any extensions are installed. Please provide as much detail as possible about the issue and the steps necessary to reproduce it", + "support_warning_abuse": "Please report content that violates the Terms of Service. Please provide links to the offending documents or user profiles and describe how they are violating the terms. Any additional information on the context in which you discovered the content or behaviour may help administrators prevent future violations", + "support_warning_other": "What is the nature of your query? Please provide as much relevant information as possible to make it easier for us to address your issue quickly", + "support_cat_drives": "Drive or team", + "support_cat_document": "Document", + "support_cat_abuse": "Report abuse" } From b78c8db859a3023a447f23cd3dfe11b18476cc88 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 2 Mar 2022 20:33:24 +0530 Subject: [PATCH 27/45] remove hardcoded translations from support page --- www/support/ui.js | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/www/support/ui.js b/www/support/ui.js index f402471d0..b1ee309a6 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -95,8 +95,6 @@ define([ } }; - //Messages.support_formCategoryError = "Error: category is empty"; // XXX (existing key) - Messages.support_formCategoryError = "Please select a ticket category from the dropdown menu"; // XXX var sendForm = function (ctx, id, form, dest) { var $form = $(form); @@ -107,10 +105,13 @@ define([ var $attachments = $form.find('.cp-support-attachments'); var category = $cat.val().trim(); +/* +Messages.support_formCategoryError = "Please select a ticket category from the dropdown menu"; // TODO if (!category) { console.log($cat); return void UI.alert(Messages.support_formCategoryError); } +*/ var title = $title.val().trim(); if (!title) { @@ -144,10 +145,6 @@ define([ return true; }; - Messages.support_cat_drives = "Drive or team"; // XXX - Messages.support_cat_document = "Document"; // XXX - Messages.support_cat_abuse = "Report abuse"; // XXX - var makeCategoryDropdown = function (ctx, container, onChange, all) { var categories = [ 'account', // Msg.support_cat_account @@ -181,20 +178,6 @@ define([ return $select; }; - Messages.support_warning_prompt = "Please choose the most relevant category for your issue, this helps administrators triage and provides further suggestions for what information to provide"; // XXX - - Messages.support_warning_account = "Please note that administrators are not able to reset passwords. If you have lost the credentials to your account but are still logged in, you can migrate your data to a new account"; // XXX - - Messages.support_warning_drives = "Note that administrators are not able to identify folders and documents by name. For shared folders, please provide a document identifier (does not provide access to the content)"; // XXX - - Messages.support_warning_document = "Please specify which type of document is causing the issue and provide a document identifier (does not provide access to the content)"; // XXX - - Messages.support_warning_bug = "Please specify in which browser the issue occurs and if any extensions are installed. Please provide as much detail as possible about the issue and the steps necessary to reproduce it"; // XXX - - Messages.support_warning_abuse = "Please report content that violates the Terms of Service. Please provide links to the offending documents or user profiles and describe how they are violating the terms. Any additional information on the context in which you discovered the content or behaviour may help administrators prevent future violations"; // XXX - - Messages.support_warning_other = "What is the nature of your query? Please provide as much relevant information as possible to make it easier for us to address your issue quickly"; // XXX - var documentIdDocs = Pages.localizeDocsLink('https://docs.cryptpad.fr/en/user_guide/apps/general.html#properties'); var warningLinks = { From 2b89eb474a3098860b3f5bcf0f2ccd3bd8491479 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 4 Mar 2022 06:59:56 +0100 Subject: [PATCH 28/45] Translated using Weblate (Spanish) Currently translated at 46.2% (670 of 1448 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/es/ --- www/common/translations/messages.es.json | 40 ++++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/www/common/translations/messages.es.json b/www/common/translations/messages.es.json index 2c793dace..b98caa759 100644 --- a/www/common/translations/messages.es.json +++ b/www/common/translations/messages.es.json @@ -32,7 +32,7 @@ "exportPrompt": "¿Cómo te gustaría llamar a este archivo?", "changeNamePrompt": "Cambiar tu nombre (dejar vacío para ser anónimo): ", "clickToEdit": "Haz clic para cambiar", - "forgetPrompt": "Pulsar OK eliminará este documento del almacenamiento local (localStorage), ¿estás seguro?", + "forgetPrompt": "Pulsar OK moverá este documento a tu papelera. ¿Estás seguro?", "shareButton": "Compartir", "shareSuccess": "URL copiada al portapapeles", "presentButtonTitle": "Entrar en el modo presentación", @@ -66,13 +66,13 @@ "user_displayName": "Nombre visible", "user_accountName": "Nombre de cuenta", "newButton": "Nuevo", - "newButtonTitle": "Nuevo documento", + "newButtonTitle": "Crear un nuevo documento", "cancel": "Cancelar", "poll_publish_button": "Publicar", "poll_create_user": "Añadir usuario", "poll_create_option": "Añadir opción", "poll_commit": "Validar", - "fm_rootName": "Documentos", + "fm_rootName": "Drive", "fm_trashName": "Papelera", "fm_filesDataName": "Todos los archivos", "fm_templateName": "Plantilla", @@ -132,7 +132,7 @@ "settings_backup": "Copia de seguridad", "settings_restore": "Recuperar datos", "settings_reset": "Quita todos los documentos de tu CryptDrive", - "settings_resetPrompt": "Esta acción eliminará todos tus documentos.
¿Seguro que quieres continuar?
Introduce “I love CryptPad” para confirmar.", + "settings_resetPrompt": "Esta acción eliminará todos los documentos de tu Drive.
¿Seguro que quieres continuar?
Introduce “I love CryptPad” para confirmar.", "settings_resetDone": "¡Tu drive ahora está vacio!", "settings_resetTips": "Consejos en CryptDrive", "settings_resetTipsButton": "Restaurar consejos", @@ -142,7 +142,7 @@ "privacy": "Política de privacidad", "contact": "Contacto", "terms": "Términos de Servicio", - "movedToTrash": "Este pad fue movido a la papelera.
Acceder a mi Drive", + "movedToTrash": "Este documento fue movido a la papelera.
Acceder a mi Drive", "fm_newFile": "Nuevo documento", "fm_type": "Tipo", "fm_categoryError": "No se pudo abrir la categoría seleccionada, mostrando la raíz.", @@ -159,7 +159,7 @@ "printOptions": "Opciones de impresión", "printSlideNumber": "Mostrar el número de diapositiva", "printDate": "Mostrar la fecha", - "printTitle": "Mostrar el título", + "printTitle": "Mostrar el título del documento", "printCSS": "CSS personalizado:", "settings_importTitle": "Importar documentos recientes locales en CryptDrive", "settings_import": "Importar", @@ -203,8 +203,8 @@ "formattedGB": "{0} GB", "formattedKB": "{0} KB", "pinLimitReached": "Has llegado al límite de espacio", - "pinLimitNotPinned": "Has llegado al límite de espacio.
Este pad no estará presente en tu CryptDrive.", - "pinLimitDrive": "Has llegado al límite de espacio.
No puedes crear nuevos pads.", + "pinLimitNotPinned": "Has llegado al límite de espacio.
Este documento no estará presente en tu CryptDrive.", + "pinLimitDrive": "Has llegado al límite de espacio.
No puedes crear nuevos documentos.", "printTransition": "Activar transiciones", "settings_logoutEverywhereTitle": "Cerrar sesiones remotas", "settings_logoutEverywhere": "Cerrar todas las otras sesiones", @@ -227,7 +227,7 @@ "poll_locked": "Cerrado", "poll_unlocked": "Abierto", "common_connectionLost": "Conexión perdida
El documento está ahora en modo sólo lectura hasta que la conexión vuelva.", - "pinLimitReachedAlert": "Has llegado a tu límite de espacio. Los nuevos pads no serán guardados en tu CryptDrive.
Puedes eliminar pads de tu CryptDrive o suscribirte a una oferta premium para obtener más espacio.", + "pinLimitReachedAlert": "Has llegado a tu límite de espacio. Los nuevos documentos no serán guardados en tu CryptDrive.
Puedes eliminar documentos de tu CryptDrive o suscribirte a una oferta premium para obtener más espacio.", "fm_info_trash": "Vacía tu papelera para liberar espacio en tu CryptDrive.", "upload_mustLogin": "Tienes que estar conectado para subir archivos", "uploadButton": "Subir", @@ -302,10 +302,10 @@ "main_catch_phrase": "Paquete de colaboración
de extremo a extremo encriptado y de código abierto", "padNotPinned": "Este documento expirará tras 3 meses de inactividad, {0}ingresar{1} o {2}registrarse{3}para conservarlo.", "anonymousStoreDisabled": "El administrador de esta instancia de CryptPad ha deshabilitado al almacenamiento para usuarios anónimos. Debes iniciar sesión para poder usar CryptDrive.", - "expiredError": "Este pad ha expirado y ya no está disponible.", + "expiredError": "Este documento ha expirado y ya no está disponible.", "deletedError": "Este documento ha sido borrado y ya no se encuentra disponible.", - "inactiveError": "Esta nota ha sido eliminada por inactividad. Presione Esc para crear una nueva nota.", - "chainpadError": "Ha ocurrido un error crítico al actualizar su contenido. Esta página esta en modo de sólo lectura, para asegurarse que no perderá su trabajo.
HitEscpara continuar y ver esta nota, o recargar para editar nuevamente.", + "inactiveError": "Este documento ha sido eliminado por inactividad. Presione Esc para crear un nuev documento.", + "chainpadError": "Ha ocurrido un error crítico al actualizar su contenido. Esta página esta en modo de sólo lectura, para asegurarse que no perderá su trabajo.
HitEscpara continuar y ver este documento, o recargar para editar nuevamente.", "invalidHashError": "El documento que has solicitado tiene una URL invalida.", "errorCopy": " Aún puedes acceder esta versión en modo lectura persionando Esc.", "errorRedirectToHome": "PresionaEscpara ser redirigido a tu Cryptdrive.", @@ -323,17 +323,17 @@ "template_import": "Importar una plantilla", "template_empty": "No hay plantillas disponibles", "propertiesButton": "Propiedades", - "propertiesButtonTitle": "Obtener las propiedades de esta nota", + "propertiesButtonTitle": "Obtener las propiedades de este documento", "printButtonTitle2": "Imprimir el documento o exportar como archivo PDF", "printBackground": "Usar una imagen de fondo", "printBackgroundButton": "Elija una imagen", "printBackgroundValue": "Fondo de pantalla actual{0}", "printBackgroundRemove": "Eliminar este fondo de pantalla", "tags_title": "Etiquetas (sólo para tí)", - "tags_add": "Actualizar las etiquetas para los pads seleccionados", + "tags_add": "Actualizar las etiquetas para los documentos seleccionados", "tags_notShared": "Tus etiquetas no están compartidas con otros usuarios", "tags_duplicate": "Duplicar etiquetas: {0}", - "tags_noentry": "No puedes etiquetar una nota eliminada!", + "tags_noentry": "No puedes etiquetar un documento eliminado!", "slide_invalidLess": "Estilo personalizado no válido", "ok": "OK", "show_help_button": "Mostrar ayuda", @@ -457,17 +457,17 @@ "settings_ownDriveTitle": "Actualizar Cuenta", "settings_ownDriveHint": "Las cuentas más antiguas no tienen acceso a las funcionalidades más recientes. Una actualización gratuita habilitará las funcionalidades actuales y prepará su CryptDrive para las próximas actualizaciones.", "settings_ownDriveButton": "Actualiza tu cuenta", - "padNotPinnedVariable": "Este pad caducará después de {4} días de inactividad, {0} inicie sesión {1} o {2} registre {3} para preservarlo.", + "padNotPinnedVariable": "Este documento caducará después de {4} días de inactividad, {0} inicie sesión {1} o {2} registre {3} para preservarlo.", "register_emailWarning0": "Parece que envió su correo electrónico como su nombre de usuario.", "register_emailWarning1": "Puedes hacerlo si usted quiere, pero no se enviara a nuestros servidores.", "register_emailWarning2": "No podrá restablecer su contraseña utilizando su correo electrónico como puede hacerlo con muchos otros servicios.", "register_emailWarning3": "Si de todos modos entiende y desea utilizar su correo electrónico para su nombre de usuario, haga clic en Aceptar.", "settings_autostoreHint": " Automático Todos los documentos que visita se almacenan en su CryptDrive.
Manual (preguntar siempre) Si aún no ha guardado un docuemento, se le preguntará si desea para almacenarlos en su CryptDrive.
Manual (nunca preguntar) Los Documentos no se almacenan automáticamente en su CryptDrive. La opción para almacenarlos estará oculta.", - "settings_driveDuplicateTitle": "Documentos de propiedad duplicadas", - "settings_driveDuplicateHint": "Cuando mueve sus propias Pads a una carpeta compartida, se guarda una copia en su CryptDrive para asegurarse de que conserva su control sobre ella. Puedes ocultar archivos duplicados. Solo la versión compartida será visible, a menos que se elimine, en cuyo caso el original se mostrará en su ubicación anterior.", + "settings_driveDuplicateTitle": "Documentos propios duplicados", + "settings_driveDuplicateHint": "Cuando mueve sus documentos propios a una carpeta compartida, se guarda una copia en su CryptDrive para asegurarse de que conserva su control sobre ella. Puedes ocultar archivos duplicados. Solo la versión compartida será visible, a menos que se elimine, en cuyo caso el original se mostrará en su ubicación anterior.", "settings_padWidthHint": "Cambia entre el modo de página (por defecto) que limita el ancho del editor de texto, y el uso del ancho total de la pantalla.", - "settings_padSpellcheckHint": "Esta opción le permite habilitar la corrección ortográfica en los Pads de texto enriquecido. Los errores ortográficos estarán subrayados en rojo y tendrá que mantener presionada la tecla Ctrl o Meta mientras hace clic derecho para ver las opciones correctas.", - "settings_padSpellcheckLabel": "Habilite el corrector ortográfico en el Pad de texto enriquecido", + "settings_padSpellcheckHint": "Esta opción le permite habilitar la corrección ortográfica en los documentos de texto enriquecido. Los errores ortográficos estarán subrayados en rojo y tendrá que mantener presionada la tecla Ctrl o Meta mientras hace clic derecho con el ratón para ver las opciones correctas.", + "settings_padSpellcheckLabel": "Habilite el corrector ortográfico en el documento de texto enriquecido", "settings_ownDriveConfirm": "La actualización de su cuenta puede llevar algún tiempo. Deberá volver a iniciar sesión en todos sus dispositivos. ¿Estás seguro?", "settings_ownDrivePending": "Su cuenta se está actualizando. No cierre ni vuelva a cargar esta página hasta que se haya completado el proceso.", "settings_changePasswordTitle": "Cambiar tu contraseña", From 755228e43c5967a647ebfe90d75b2d352dcb714e Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 4 Mar 2022 17:34:06 +0530 Subject: [PATCH 29/45] empty the 'note' field when setting a custom quota on the admin panel --- www/admin/inner.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/admin/inner.js b/www/admin/inner.js index 83143a546..98213b384 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -517,11 +517,11 @@ define([ note, h('nav', [set, remove]) ]); + var $note = $(note); var getValues = function () { var key = $key.val(); var _limit = parseInt($(limit).val()); - var _note = $(note).val(); if (key.length !== 44) { try { var u = Keys.parseUser(key); @@ -535,6 +535,7 @@ define([ if (isNaN(_limit) || _limit < 0) { return void UI.warn(Messages.admin_invalLimit); } + var _note = ($note.val() || "").trim(); return { key: key, data: { @@ -585,6 +586,7 @@ define([ } APP.refreshLimits(); $key.val(''); + $note.val(''); }); }); From b65730b853036b181041f010cd52980624c6ba88 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 7 Mar 2022 18:42:00 +0530 Subject: [PATCH 30/45] allow admins to enable configurable disk I/O profiling --- lib/commands/admin-rpc.js | 3 ++ lib/decrees.js | 12 +++++ lib/env.js | 13 +++++ lib/hk-util.js | 6 ++- lib/storage/blob.js | 2 + lib/storage/block.js | 2 + server.js | 7 +++ www/admin/inner.js | 104 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 148 insertions(+), 1 deletion(-) diff --git a/lib/commands/admin-rpc.js b/lib/commands/admin-rpc.js index 59750571e..3fc87bce5 100644 --- a/lib/commands/admin-rpc.js +++ b/lib/commands/admin-rpc.js @@ -315,6 +315,9 @@ var instanceStatus = function (Env, Server, cb) { disableIntegratedEviction: Env.disableIntegratedEviction, disableIntegratedTasks: Env.disableIntegratedTasks, + enableProfiling: Env.enableProfiling, + profilingWindow: Env.profilingWindow, + maxUploadSize: Env.maxUploadSize, premiumUploadSize: Env.premiumUploadSize, diff --git a/lib/decrees.js b/lib/decrees.js index 5f599705e..371a4f8d7 100644 --- a/lib/decrees.js +++ b/lib/decrees.js @@ -24,6 +24,8 @@ SET_PREMIUM_UPLOAD_SIZE // BACKGROUND PROCESSES DISABLE_INTEGRATED_TASKS DISABLE_INTEGRATED_EVICTION +ENABLE_PROFILING +SET_PROFILING_WINDOW // BROADCAST SET_LAST_BROADCAST_HASH @@ -143,6 +145,16 @@ var makeIntegerSetter = function (attr) { return makeGenericSetter(attr, args_isInteger); }; +var arg_isPositiveInteger = function (args) { + return Array.isArray(args) && isInteger(args[0]) && args[0] > 0; +}; + +// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['ENABLE_PROFILING', [true]]], console.log) +commands.ENABLE_PROFILING = makeBooleanSetter('enableProfiling'); + +// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_PROFILING_WINDOW', [10000]]], console.log) +commands.SET_PROFILING_WINDOW = makeGenericSetter('profilingWindow', arg_isPositiveInteger); + // CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_MAX_UPLOAD_SIZE', [50 * 1024 * 1024]]], console.log) commands.SET_MAX_UPLOAD_SIZE = makeIntegerSetter('maxUploadSize'); diff --git a/lib/env.js b/lib/env.js index 9970bc4f9..656855396 100644 --- a/lib/env.js +++ b/lib/env.js @@ -54,6 +54,10 @@ module.exports.create = function (config) { launchTime: +new Date(), + enableProfiling: false, + profilingWindow: 10000, + bytesWritten: 0, + inactiveTime: config.inactiveTime, archiveRetentionTime: config.archiveRetentionTime, accountRetentionTime: config.accountRetentionTime, @@ -222,6 +226,15 @@ module.exports.create = function (config) { return typeof(config[key]) === 'string'? config[key]: def; }; + Env.incrementBytesWritten = function (n) { + if (!Env.enableProfiling) { return; } + if (!n || typeof(n) !== 'number' || n < 0) { return; } + Env.bytesWritten += n; + setTimeout(function () { + Env.bytesWritten -= n; + }, Env.profilingWindow); + }; + paths.pin = keyOrDefaultString('pinPath', './pins'); paths.block = keyOrDefaultString('blockPath', './block'); paths.data = keyOrDefaultString('filePath', './datastore'); diff --git a/lib/hk-util.js b/lib/hk-util.js index 276ac3e6f..a95eb19a6 100644 --- a/lib/hk-util.js +++ b/lib/hk-util.js @@ -380,10 +380,14 @@ const storeMessage = function (Env, channel, msg, isCp, optionalMessageHash, cb) // Message stored, call back cb(); - index.size += msgBin.length; + var msgLength = msgBin.length; + index.size += msgLength; // handle the next element in the queue next(); + + // keep track of how many bytes are written + Env.incrementBytesWritten(msgLength); })); }); }); diff --git a/lib/storage/blob.js b/lib/storage/blob.js index e5c7a2fce..a48f669af 100644 --- a/lib/storage/blob.js +++ b/lib/storage/blob.js @@ -131,11 +131,13 @@ var upload = function (Env, safeKey, content, cb) { blobstage.write(dec); session.currentUploadSize += len; cb(void 0, dec.length); + Env.incrementBytesWritten(len); }); } else { session.blobstage.write(dec); session.currentUploadSize += len; cb(void 0, dec.length); + Env.incrementBytesWritten(len); } }; diff --git a/lib/storage/block.js b/lib/storage/block.js index 1078f6d2e..90228c6bc 100644 --- a/lib/storage/block.js +++ b/lib/storage/block.js @@ -49,6 +49,7 @@ Block.archive = function (Env, publicKey, _cb) { return void cb('E_INVALID_BLOCK_ARCHIVAL_PATH'); } + // TODO Env.incrementBytesWritten Fse.move(currentPath, archivePath, { overwrite: true, }, cb); @@ -83,6 +84,7 @@ Block.write = function (Env, publicKey, buffer, _cb) { })); }).nThen(function () { Fs.writeFile(path, buffer, { encoding: 'binary' }, cb); + Env.incrementBytesWritten(buffer && buffer.length); }); }; diff --git a/server.js b/server.js index 73f63a3e1..204cd5f6e 100644 --- a/server.js +++ b/server.js @@ -284,6 +284,13 @@ var send404 = function (res, path) { send404(res); }); }; +app.get('/api/profiling', function (req, res, next) { + if (!Env.enableProfiling) { return void send404(res); } + res.setHeader('Content-Type', 'text/javascript'); + res.send(JSON.stringify({ + bytesWritten: Env.bytesWritten, + })); +}); app.use(function (req, res, next) { res.status(404); diff --git a/www/admin/inner.js b/www/admin/inner.js index 98213b384..59e410b55 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -66,6 +66,7 @@ define([ ], 'stats': [ // Msg.admin_cat_stats 'cp-admin-refresh-stats', + 'cp-admin-uptime', 'cp-admin-active-sessions', 'cp-admin-active-pads', 'cp-admin-open-files', @@ -85,6 +86,8 @@ define([ 'performance': [ // Msg.admin_cat_performance 'cp-admin-refresh-performance', 'cp-admin-performance-profiling', + 'cp-admin-enable-disk-measurements', + 'cp-admin-bytes-written', ], 'network': [ // Msg.admin_cat_network 'cp-admin-update-available', @@ -644,6 +647,29 @@ define([ return $div; }; + Messages.admin_uptimeTitle = 'Launch time'; + Messages.admin_uptimeHint = 'Date and time at which the server was launched'; + + create['uptime'] = function () { + var key = 'uptime'; + var $div = makeBlock(key); // Msg.admin_activeSessionsHint, .admin_activeSessionsTitle + var pre = h('pre'); + + var set = function () { + var uptime = APP.instanceStatus.launchTime; + if (typeof(uptime) !== 'number') { return; } + pre.innerText = new Date(uptime); + }; + + set(); + + $div.append(pre); + onRefreshStats.reg(function () { + set(); + }); + return $div; + }; + create['active-sessions'] = function () { var key = 'active-sessions'; var $div = makeBlock(key); // Msg.admin_activeSessionsHint, .admin_activeSessionsTitle @@ -1739,6 +1765,84 @@ define([ return $div; }; + Messages.admin_enableDiskMeasurementsTitle = "Measure disk performance"; // XXX + Messages.admin_enableDiskMeasurementsHint = "If enabled, a JSON endpoint will be exposed under /api/profiling which keeps a running measurement of disk I/O within a configurable window. This setting can impact server performance and may reveal data you'd rather keep hidden. It is recommended that you leave it disabled unless you know what you are doing."; // XXX + + create['enable-disk-measurements'] = makeAdminCheckbox({ + key: 'enable-disk-measurements', + getState: function () { + return APP.instanceStatus.enableProfiling; + }, + query: function (val, setState) { + sFrameChan.query('Q_ADMIN_RPC', { + cmd: 'ADMIN_DECREE', + data: ['ENABLE_PROFILING', [val]] + }, function (e, response) { + if (e || response.error) { + UI.warn(Messages.error); + console.error(e, response); + } + APP.updateStatus(function () { + setState(APP.instanceStatus.enableProfiling); + }); + }); + }, + }); + + Messages.admin_bytesWrittenTitle = "Disk performance measurement window"; + Messages.admin_bytesWrittenHint = "If you have enabled disk performance measurements then the duration of the window can be configured below."; // XXX + Messages.admin_bytesWrittenDuration = "Duration of the window in milliseconds: {0}"; // XXX + Messages.admin_defaultDuration = "admin_defaultDuration"; // XXX + Messages.admin_setDuration = "Set duration"; // XXX + + var isPositiveInteger = function (n) { + return n && typeof(n) === 'number' && n % 1 === 0 && n > 0; + }; + + create['bytes-written'] = function () { + var key = 'bytes-written'; + var $div = makeBlock(key); + + var duration = APP.instanceStatus.profilingWindow; + if (!isPositiveInteger(duration)) { duration = 10000; } + var newDuration = h('input', {type: 'number', min: 0, value: duration}); + var set = h('button.btn.btn-primary', Messages.admin_setDuration); + $div.append(h('div', [ + h('span.cp-admin-bytes-written-duration', Messages._getKey('admin_bytesWrittenDuration', [duration])), + h('div.cp-admin-setlimit-form', [ + newDuration, + h('nav', [set]) + ]) + ])); + + UI.confirmButton(set, { + classes: 'btn-primary', + multiple: true, + validate: function () { + var l = parseInt($(newDuration).val()); + if (isNaN(l)) { return false; } + return true; + } + }, function () { + var d = parseInt($(newDuration).val()); + if (!isPositiveInteger(d)) { return void UI.warn(Messages.error); } + + var data = [d]; + sFrameChan.query('Q_ADMIN_RPC', { + cmd: 'ADMIN_DECREE', + data: ['SET_PROFILING_WINDOW', data] + }, function (e, response) { + if (e || response.error) { + UI.warn(Messages.error); + return void console.error(e, response); + } + $div.find('.cp-admin-bytes-written-duration').text(Messages._getKey('admin_limit', [d])); + }); + }); + + 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); From c86ffead3cd7116694a77e06b7ab7df22e4672a3 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 7 Mar 2022 15:24:44 +0100 Subject: [PATCH 31/45] Fix duplicate pads in teams --- www/common/outer/async-store.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 0856572bc..5d8eac183 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1161,6 +1161,7 @@ define([ //var storeLocally = data.teamId === -1; if (data.teamId === -1) { data.teamId = undefined; } + if (data.teamId) { data.teamId = Number(data.teamId); } // If a teamId is provided, it means we want to store the pad in a specific // team drive. In this case, we just need to check if the pad is already From 46e9c6bc05c5263b359294486b860dc4885e3304 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 8 Mar 2022 10:41:15 +0530 Subject: [PATCH 32/45] lint compliance --- www/admin/inner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/admin/inner.js b/www/admin/inner.js index 84ff8f5ea..99d640940 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -267,7 +267,7 @@ define([ UI.log(archive ? Messages.archivedFromServer : Messages.restoredFromServer); $input.val(''); $pwInput.val(''); - $reason.val('') + $reason.val(''); }); }); }); From ef398de4a1cdd90e2ffcf870962ef9ff9f9422c8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 8 Mar 2022 11:03:32 +0530 Subject: [PATCH 33/45] disable measurement --- lib/storage/blob.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/storage/blob.js b/lib/storage/blob.js index a48f669af..4b17dc85c 100644 --- a/lib/storage/blob.js +++ b/lib/storage/blob.js @@ -131,13 +131,13 @@ var upload = function (Env, safeKey, content, cb) { blobstage.write(dec); session.currentUploadSize += len; cb(void 0, dec.length); - Env.incrementBytesWritten(len); + //Env.incrementBytesWritten(len); }); } else { session.blobstage.write(dec); session.currentUploadSize += len; cb(void 0, dec.length); - Env.incrementBytesWritten(len); + //Env.incrementBytesWritten(len); } }; From c111364024d33faf408f2111e10f9e6fed82b92a Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 8 Mar 2022 18:20:11 +0530 Subject: [PATCH 34/45] add two new tests to diagnose unavailability of uploaded blocks and blobs --- lib/api.js | 5 +++++ lib/storage/blob.js | 4 ++++ www/checkup/main.js | 48 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/lib/api.js b/lib/api.js index 277d085fa..9a317be86 100644 --- a/lib/api.js +++ b/lib/api.js @@ -4,6 +4,8 @@ const NetfluxSrv = require('chainpad-server'); const Decrees = require("./decrees"); const nThen = require("nthen"); +const Fs = require("fs"); +const Path = require("path"); module.exports.create = function (Env) { var log = Env.Log; @@ -19,6 +21,9 @@ nThen(function (w) { console.error(err); } })); +}).nThen(function (w) { + var fullPath = Path.join(Env.paths.block, 'placeholder.txt'); + Fs.writeFile(fullPath, 'PLACEHOLDER\n', w()); }).nThen(function () { // asynchronously create a historyKeeper and RPC together require('./historyKeeper.js').create(Env, function (err, historyKeeper) { diff --git a/lib/storage/blob.js b/lib/storage/blob.js index 4b17dc85c..7cf13dd59 100644 --- a/lib/storage/blob.js +++ b/lib/storage/blob.js @@ -495,6 +495,10 @@ BlobStore.create = function (config, _cb) { Fse.mkdirp(Path.join(Env.archivePath, Env.blobPath), w(function (e) { if (e) { CB(e); } })); + }).nThen(function (w) { + // XXX make a placeholder file in the root of the blob path + var fullPath = Path.join(Env.blobPath, 'placeholder.txt'); + Fse.writeFile(fullPath, 'PLACEHOLDER\n', w()); }).nThen(function () { var methods = { isFileId: isValidId, diff --git a/www/checkup/main.js b/www/checkup/main.js index 2c227df5d..e58976a8a 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -1113,6 +1113,54 @@ define([ }); }); + assert(function (cb, msg) { + var path = '/blob/placeholder.txt'; + var fullPath; + try { + fullPath = new URL(path, ApiConfig.fileHost || ApiConfig.httpUnsafeOrigin).href; + } catch (err) { + fullPath = path; + } + + msg.appendChild(h('span', [ + "A placeholder file was expected to be available at ", + code(fullPath), + ", but it was not found.", + " This commonly indicates a mismatch between the API server's ", + code('blobPath'), + " value and the path that the webserver or reverse proxy is attempting to serve.", + " This misconfiguration will cause errors with uploaded files and CryptPad's office editors (sheet, presentation, document).", + ])); + + Tools.common_xhr(fullPath, xhr => { + cb(xhr.status === 200 || xhr.status); + }); + }); + + assert(function (cb, msg) { + var path = '/block/placeholder.txt'; + var fullPath; + try { + fullPath = new URL(path, ApiConfig.fileHost || ApiConfig.httpUnsafeOrigin).href; + } catch (err) { + fullPath = path; + } + + msg.appendChild(h('span', [ + "A placeholder file was expected to be available at ", + code(fullPath), + ", but it was not found.", + " This commonly indicates a mismatch between the API server's ", + code('blockPath'), + " value and the path that the webserver or reverse proxy is attempting to serve.", + " This misconfiguration will cause errors with login, registration, and password change.", + ])); + + Tools.common_xhr(fullPath, xhr => { + cb(xhr.status === 200 || xhr.status); + }); + }); + var serverToken; Tools.common_xhr('/', function (xhr) { serverToken = xhr.getResponseHeader('server'); From 5de0e4891805005cd2f39518f40a1a73d8252a11 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 8 Mar 2022 16:04:56 +0100 Subject: [PATCH 35/45] Translated using Weblate (French) Currently translated at 100.0% (1448 of 1448 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fr/ --- www/common/translations/messages.fr.json | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index 5a7f8e22b..59746600b 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -1436,5 +1436,17 @@ "admin_descriptionTitle": "Description de l'instance", "admin_nameHint": "Le nom affiché pour cette instance dans la liste des instances publiques sur cryptpad.org", "admin_nameTitle": "Nom de l'instance", - "admin_archiveNote": "Note" + "admin_archiveNote": "Note", + "support_cat_abuse": "Signaler un abus", + "support_cat_document": "Document", + "support_cat_drives": "Drive ou équipe", + "support_warning_other": "Quelle est la nature de votre demande ? Veuillez fournir autant d'informations pertinentes que possible afin de nous permettre de traiter rapidement votre problème", + "support_warning_abuse": "Merci de signaler les contenus qui ne respectent pas les Conditions d'utilisation. Veuillez fournir des liens vers les documents ou les profils d'utilisateurs incriminés et décrire en quoi ils enfreignent les conditions. Toute information supplémentaire sur le contexte dans lequel vous avez découvert le contenu ou le comportement peut aider les administrateurs à prévenir de futures violations", + "support_warning_bug": "Veuillez préciser dans quel navigateur le problème se produit et si des extensions sont installées. Veuillez fournir autant de détails que possible sur le problème et les étapes nécessaires pour le reproduire", + "support_warning_document": "Veuillez préciser quel type de document est à l'origine du problème et fournir la référence du document ou un lien", + "support_warning_drives": "Veuillez noter que les administrateurs ne sont pas en mesure d'identifier des dossiers ou documents à partir de leur nom. Pour les dossiers partagés, veuillez fournir la référence du dossier", + "support_warning_account": "Veuillez noter que les administrateurs ne sont pas en mesure de réinitialiser les mots de passe. Si vous avez perdu vos identifiants mais que vous êtes encore connecté, vous pouvez transférer vos données vers un nouveau compte", + "support_warning_prompt": "Merci de choisir la catégorie la plus pertinente pour qualifier votre problème, ceci aide les administrateurs à faire le tri et fournit des suggestions sur les informations à fournir", + "admin_jurisdictionTitle": "Pays d'hébergement", + "ui_saved": "{0} enregistré" } From 69a0116e44e3ab21c58e7ef42dd0cb777cdb340e Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 9 Mar 2022 15:42:09 +0100 Subject: [PATCH 36/45] Fix drive download issues with OnlyOffice documents --- www/common/onlyoffice/inner.js | 4 +++- www/common/onlyoffice/ooiframe.js | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/www/common/onlyoffice/inner.js b/www/common/onlyoffice/inner.js index 547ef6c9d..d6024feb0 100644 --- a/www/common/onlyoffice/inner.js +++ b/www/common/onlyoffice/inner.js @@ -1804,6 +1804,7 @@ define([ } if (APP.isDownload) { + delete APP.isDownload; var bin = getContent(); if (!supportsXLSX()) { return void sframeChan.event('EV_OOIFRAME_DONE', bin, {raw: true}); @@ -2008,6 +2009,7 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null var blobUrl = (typeof mediasData[data.src] === 'undefined') ? "" : mediasData[data.src].blobUrl; if (blobUrl) { + delete downloadImages[name]; debug("CryptPad Image already loaded " + blobUrl); return void callback(blobUrl); } @@ -2556,7 +2558,7 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null type:'text/javascript', src: '/common/onlyoffice/'+version+'web-apps/apps/api/documents/api.js' }); - $('#cp-app-oo-editor').append(s); + $('#cp-app-oo-editor').empty().append(h('div#cp-app-oo-placeholder-a')).append(s); var hashes = content.hashes || {}; var idx = sortCpIndex(hashes); diff --git a/www/common/onlyoffice/ooiframe.js b/www/common/onlyoffice/ooiframe.js index 23c6424e3..c05c559fe 100644 --- a/www/common/onlyoffice/ooiframe.js +++ b/www/common/onlyoffice/ooiframe.js @@ -15,15 +15,17 @@ define([ var create = function (config) { // Loaded in load #2 var sframeChan; + var Util = config.modules.Utils.Util; + var _onReadyEvt = Util.mkEvent(true); var refresh = function (data, cb) { if (currentCb) { queue.push({data: data, cb: cb}); return; } if (!ready) { - ready = function () { + _onReadyEvt.reg(function () { refresh(data, cb); - }; + }); return; } currentCb = cb; @@ -152,10 +154,8 @@ define([ sframeChan.onReady(function () { if (ready === true) { return; } - if (typeof ready === "function") { - ready(); - } ready = true; + _onReadyEvt.fire(); }); }); }); From 4e571e0e8ec3d6f25d1ca5a6de3d3b4f2f5df571 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 10 Mar 2022 16:08:13 +0530 Subject: [PATCH 37/45] final cleanup before merging support-categories --- customize.dist/pages.js | 10 ++- scripts/translations/lint-translations.js | 4 +- www/admin/app-admin.less | 5 ++ www/admin/inner.js | 62 +++++++++-------- www/common/application_config_internal.js | 81 ++++++++++++++--------- www/support/ui.js | 4 +- 6 files changed, 98 insertions(+), 68 deletions(-) diff --git a/customize.dist/pages.js b/customize.dist/pages.js index 2012fc103..b438e4a58 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -107,10 +107,10 @@ define([ var customURLs = Pages.customURLs = {}; (function () { var defaultURLs = { - //imprint: '/imprint.html', // XXX cryptpad.org/default-imprint.html? - //privacy: '/privacy.html', // XXX cryptpad.org/default-privacy.html? - terms: '/terms.html', // XXX cryptpad.org/default-terms.html? - //roadmap: '/roadmap.html', // XXX cryptpad.org/default-roadmap.html? + //imprint: '/imprint.html', + //privacy: '/privacy.html', + terms: '/terms.html', + //roadmap: '/roadmap.html', source: 'https://github.com/xwiki-labs/cryptpad', }; var l = Msg._getLanguage(); @@ -133,8 +133,6 @@ define([ }); }()); - Msg.footer_source = 'Source code'; // XXX - // used for the about menu Pages.imprintLink = footLink(customURLs.imprint, 'imprint'); Pages.privacyLink = footLink(customURLs.privacy, 'privacy'); diff --git a/scripts/translations/lint-translations.js b/scripts/translations/lint-translations.js index 4eaab86b5..62ee8c60a 100644 --- a/scripts/translations/lint-translations.js +++ b/scripts/translations/lint-translations.js @@ -78,8 +78,8 @@ var processLang = function (map, lang, primary) { }); var weirdCapitalization; - s.replace(/cryptpad(\.fr)*/gi, function (brand) { - if (['CryptPad', 'cryptpad.fr'].includes(brand)) { return; } + s.replace(/cryptpad(\.fr|\.org)*/gi, function (brand) { + if (['CryptPad', 'cryptpad.fr', 'cryptpad.org'].includes(brand)) { return; } weirdCapitalization = true; }); diff --git a/www/admin/app-admin.less b/www/admin/app-admin.less index 482369a6e..4f0737cef 100644 --- a/www/admin/app-admin.less +++ b/www/admin/app-admin.less @@ -21,6 +21,11 @@ text-decoration: underline; } + .alert.alert-info.cp-admin-bigger-alert { + font-size: 16px; + } + + .cp-admin-setlimit-form, .cp-admin-broadcast-form { label { font-weight: normal !important; diff --git a/www/admin/inner.js b/www/admin/inner.js index a7688be43..1bef66b1d 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -56,6 +56,8 @@ define([ 'cp-admin-registration', 'cp-admin-email', + 'cp-admin-instance-info-notice', + 'cp-admin-name', 'cp-admin-description', 'cp-admin-jurisdiction', @@ -256,7 +258,7 @@ define([ cmd: archive ? 'ARCHIVE_DOCUMENT' : 'RESTORE_ARCHIVED_DOCUMENT', data: { id: channel, - reason: $reason.val(), // XXX + reason: $reason.val(), }, }, function (err, obj) { var e = err || (obj && obj.error); @@ -269,7 +271,8 @@ define([ UI.log(archive ? Messages.archivedFromServer : Messages.restoredFromServer); $input.val(''); $pwInput.val(''); - $reason.val(''); + // disabled because it's actually pretty annoying to re-enter this each time if you are archiving many files + //$reason.val(''); }); }); }); @@ -330,8 +333,6 @@ 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, @@ -375,9 +376,10 @@ define([ }, }); + // XXX remove emailButton create['email'] = function () { var key = 'email'; - var $div = makeBlock(key, true); // Msg.admin_emailHint, Msg.admin_emailTitle, Msg.admin_emailButton // XXX drop 'emailButton' + var $div = makeBlock(key, true); // Msg.admin_emailHint, Msg.admin_emailTitle var $button = $div.find('button').text(Messages.settings_save); var input = h('input', { @@ -429,12 +431,11 @@ define([ var spinner = UI.makeSpinner($(innerDiv)); $button.click(function () { - if (!$input.val()) { return; } // XXX spinner.spin(); $button.attr('disabled', 'disabled'); sFrameChan.query('Q_ADMIN_RPC', { cmd: 'ADMIN_DECREE', - data: ['SET_INSTANCE_JURISDICTION', [$input.val()]] // XXX + data: ['SET_INSTANCE_JURISDICTION', [$input.val().trim()]] }, function (e, response) { $button.removeAttr('disabled'); if (e || response.error) { @@ -454,6 +455,19 @@ define([ return $div; }; + Messages.admin_infoNotice1 = "The following fields describe your instance. Data entered will only be included in your server's telemetry if you opt in to inclusion in the list of public CryptPad instances."; // XXX + Messages.admin_infoNotice2 = "See the 'Network' tab for more details."; // XXX + + create['instance-info-notice'] = function () { + return $(h('div.cp-admin-instance-info-notice.cp-sidebarlayout-element', + h('div.alert.alert-info.cp-admin-bigger-alert', [ + Messages.admin_infoNotice1, + ' ', + Messages.admin_infoNotice2, + ]) + )); + }; + create['name'] = function () { var key = 'name'; var $div = makeBlock(key, true); @@ -463,20 +477,19 @@ define([ var input = h('input.cp-listing-info', { type: 'text', value: APP.instanceStatus.instanceName || ApiConfig.httpUnsafeOrigin || '', - placeholder: ApiConfig.httpUnsafeOrigin, //Messages.admin_namePlaceholder, // XXX + placeholder: ApiConfig.httpUnsafeOrigin, style: 'margin-bottom: 5px;', }); var $input = $(input); - var innerDiv = h('div.cp-admin-setname-form', input); // XXX fix styles + var innerDiv = h('div.cp-admin-setname-form', input); var spinner = UI.makeSpinner($(innerDiv)); $button.click(function () { - if (!$input.val()) { return; } // XXX spinner.spin(); $button.attr('disabled', 'disabled'); sFrameChan.query('Q_ADMIN_RPC', { cmd: 'ADMIN_DECREE', - data: ['SET_INSTANCE_NAME', [$input.val()]] // XXX not implemented + data: ['SET_INSTANCE_NAME', [$input.val().trim()]] }, function (e, response) { $button.removeAttr('disabled'); if (e || response.error) { @@ -498,19 +511,17 @@ define([ create['description'] = function () { var key = 'description'; - var $div = makeBlock(key, true); + var $div = makeBlock(key, true); // Msg.admin_descriptionHint - var textarea = h('textarea.cp-admin-description-text.cp-listing-info', { // XXX use something from UI elements? - placeholder: Messages.home_host || '', // XXX + var textarea = h('textarea.cp-admin-description-text.cp-listing-info', { + placeholder: Messages.home_host || '', }, APP.instanceStatus.instanceDescription || ''); var $button = $div.find('button').text(Messages.settings_save); $button.addClass('cp-listing-action'); - var innerDiv = h('div.cp-admin-setdescription-form', { - //style: 'margin-bottom: 5px', // XXX LOL NO - }, [ + var innerDiv = h('div.cp-admin-setdescription-form', [ textarea, ]); $button.before(innerDiv); @@ -519,12 +530,11 @@ define([ var spinner = UI.makeSpinner($(innerDiv)); $button.click(function () { - if (!$input.val()) { return; } // XXX spinner.spin(); $button.attr('disabled', 'disabled'); sFrameChan.query('Q_ADMIN_RPC', { cmd: 'ADMIN_DECREE', - data: ['SET_INSTANCE_DESCRIPTION', [$input.val()]] // XXX + data: ['SET_INSTANCE_DESCRIPTION', [$input.val().trim()]] }, function (e, response) { $button.removeAttr('disabled'); if (e || response.error) { @@ -1915,9 +1925,9 @@ define([ }; Messages.admin_enableDiskMeasurementsTitle = "Measure disk performance"; // XXX - Messages.admin_enableDiskMeasurementsHint = "If enabled, a JSON endpoint will be exposed under /api/profiling which keeps a running measurement of disk I/O within a configurable window. This setting can impact server performance and may reveal data you'd rather keep hidden. It is recommended that you leave it disabled unless you know what you are doing."; // XXX + Messages.admin_enableDiskMeasurementsHint = "If enabled, a JSON endpoint will be exposed under /api/profiling which keeps a running measurement of disk I/O within a configurable window (set below). This setting can impact server performance and may reveal data you'd rather keep hidden. It is recommended that you leave it disabled unless you know what you are doing."; // XXX - create['enable-disk-measurements'] = makeAdminCheckbox({ + create['enable-disk-measurements'] = makeAdminCheckbox({ // Msg.admin_enableDiskMeasurementsTitle.admin_enableDiskMeasurementsHint key: 'enable-disk-measurements', getState: function () { return APP.instanceStatus.enableProfiling; @@ -1938,10 +1948,10 @@ define([ }, }); - Messages.admin_bytesWrittenTitle = "Disk performance measurement window"; + Messages.admin_bytesWrittenTitle = "Disk performance measurement window"; // XXX Messages.admin_bytesWrittenHint = "If you have enabled disk performance measurements then the duration of the window can be configured below."; // XXX Messages.admin_bytesWrittenDuration = "Duration of the window in milliseconds: {0}"; // XXX - Messages.admin_defaultDuration = "admin_defaultDuration"; // XXX + //Messages.admin_defaultDuration = "admin_defaultDuration"; // XXX Messages.admin_setDuration = "Set duration"; // XXX var isPositiveInteger = function (n) { @@ -1985,7 +1995,7 @@ define([ UI.warn(Messages.error); return void console.error(e, response); } - $div.find('.cp-admin-bytes-written-duration').text(Messages._getKey('admin_limit', [d])); + $div.find('.cp-admin-bytes-written-duration').text(Messages._getKey('admin_bytesWrittenDuration', [d])); }); }); @@ -2037,7 +2047,6 @@ 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 () { @@ -2274,6 +2283,7 @@ define([ 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'); @@ -2285,7 +2295,7 @@ define([ $actions.attr('disabled', 'disabled'); $fields.attr('disabled', 'disabled'); } - +*/ cb(); }); }; diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index 1943cbd29..0dde18da3 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -48,48 +48,63 @@ define(function() { */ //AppConfig.availableLanguages = ['en', 'fr', 'de']; + /* + * AppConfig.imprint, AppConfig.privacy, AppConfig.terms, AppConfig.source, and AppConfig.roadmap + * define values used in at least one of the static pages' footer or the 'About CryptPad' menu. + * + * They can each be configured in one of three manners: + * + * 1. set their value to `false` to cause them not to be displayed, even if a default value exists + * example: + * AppConfig.privacy = false; + * 2. set their value to `true` to use the default value if it exists. + * example: + * AppConfig.privacy = true; + * 3. set their value to an object which maps language codes or a default setting to the relevant URL (as a string) + * example: + * AppConfig.privacy = { + * "default": 'https://example.com/privacy.html', + * "en": 'https://example.com/privacy.en.html', // in case English is not your default language + * "fr": 'https://example.com/privacy.fr.html', // another language + * "de": 'https://example.com/privacy.de.html', // you get the idea? + * }; + * + */ + /* You can display a link to the imprint (legal notice) of your website in the static pages - * footer. To do so, you can either set the following value to `true` and create an imprint.html page - * in the `customize` directory. You can also set it to an absolute URL if your imprint page already exists. + * footer. Since this is different for each individual or organization there is + * no default value. + * + * See the comments above for a description of possible configurations. */ AppConfig.imprint = false; - // AppConfig.imprint = true; - // AppConfig.imprint = 'https://xwiki.com/en/company/legal-notice'; /* You can display a link to your own privacy policy in the static pages footer. - * To do so, set the following value to the absolute URL of your privacy policy. + * Since this is different for each individual or organization there is no default value. + * See the comments above for a description of possible configurations. */ - // AppConfig.privacy = 'https://xwiki.com/en/company/PrivacyPolicy'; + AppConfig.privacy = false; - /* We (the project's developers) include the ability to display a 'Roadmap' in static pages footer. - * This is disabled by default. - * We use this to publish the project's development roadmap, but you can use it however you like. - * To do so, set the following value to an absolute URL. + /* You can display a link to your instances's terms of service in the static pages footer. + * Since this is different for each individual or organization there is no default value. + * + * See the comments above for a description of possible configurations. */ - //AppConfig.roadmap = 'https://cryptpad.fr/kanban/#/2/kanban/view/PLM0C3tFWvYhd+EPzXrbT+NxB76Z5DtZhAA5W5hG9wo/'; - - // XXX -/* -AppConfig.imprint, AppConfig.privacy, AppConfig.terms, AppConfig.source, and AppConfig.roadmap can each be configured in one of three manners: - -// to prevent the display of privacy policy entirely: -AppConfig.privacy = false; - -// to display the default privacy policy: -AppConfig.privacy = true; - -// to display translated versions of the privacy policy depending on -// the user's configured or inferred language -AppConfig.privacy = { - 'default': '...', // displayed if there is no exact match - 'en': '/privacy.en.html', - 'fr': '/privacy.fr.html', -}; - - -*/ - AppConfig.source = 'https://github.com/xwiki-labs/cryptpad/'; // XXX + AppConfig.terms = false; + + /* The terms of CryptPad's license require that its source code be made available + * to anyone who uses the software. If you have not made any modifications to the platform + * then it is sufficient to leave this as-is. If you have made changes, customize + * this value to a software repository which includes the source code including your modifications. + * + * See the comments above for a description of possible configurations. + */ + AppConfig.source = true; + /* If you wish to communicate your organization's roadmap to your users you may use the setting below. + * Since this is different for each individual or organization there is no default value. + */ + AppConfig.roadmap = false; /* Cryptpad apps use a common API to display notifications to users * by default, notifications are hidden after 5 seconds diff --git a/www/support/ui.js b/www/support/ui.js index b1ee309a6..ac935cc29 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -147,6 +147,7 @@ Messages.support_formCategoryError = "Please select a ticket category from the d var makeCategoryDropdown = function (ctx, container, onChange, all) { var categories = [ + // Msg.support_cat_data is left included because old tickets may still use it 'account', // Msg.support_cat_account 'drives', // Msg.support_cat_drives 'document', // Msg.support_cat_document, @@ -213,7 +214,8 @@ Messages.support_formCategoryError = "Please select a ticket category from the d makeCategoryDropdown(ctx, catContainer, function (key) { $(category).val(key); - console.log(key); + //console.log(key); + // Msg.support_warning_abuse.support_warning_account.support_warning_bug.support_warning_document.support_warning_drives.support_warning_other var warning = Messages['support_warning_' + key] || ''; var warningLink = warningLinks[key]; if (!warningLink) { From 14f6d65c7a4d0838930706ddb6bd32c08f9ba464 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 10 Mar 2022 18:30:08 +0530 Subject: [PATCH 38/45] don't show a checkbox for the terms of service if they don't exist --- customize.dist/pages/register.js | 14 +++++++++----- www/register/main.js | 14 +++++++++++--- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/customize.dist/pages/register.js b/customize.dist/pages/register.js index cf05defa5..1bd26ff47 100644 --- a/customize.dist/pages/register.js +++ b/customize.dist/pages/register.js @@ -10,13 +10,14 @@ define([ var urlArgs = Config.requireConf.urlArgs; var tos = $(UI.createCheckbox('accept-terms')).find('.cp-checkmark-label').append(Msg.register_acceptTerms).parent()[0]; + + var termsLink = Pages.customURLs.terms; $(tos).find('a').attr({ - href: '/terms.html', + href: termsLink, // '/terms.html', target: '_blank', tabindex: '-1', }); - var frame = function (content) { return [ h('div#cp-main', [ @@ -38,6 +39,11 @@ define([ ]); } + var termsCheck; + if (termsLink) { + termsCheck = h('div.checkbox-container', tos); + } + return frame([ h('div.row.cp-register-det', [ h('div#data.hidden.col-md-6', [ @@ -72,9 +78,7 @@ define([ h('div.checkbox-container', [ UI.createCheckbox('import-recent', Msg.register_importRecent, true) ]), - h('div.checkbox-container', [ - tos, - ]), + termsCheck, h('button#register', Msg.login_register) ]) ]), diff --git a/www/register/main.js b/www/register/main.js index 8edbaab92..fa26f38b4 100644 --- a/www/register/main.js +++ b/www/register/main.js @@ -11,9 +11,10 @@ define([ '/common/common-feedback.js', '/common/outer/local-store.js', '/common/hyperscript.js', + '/customize/pages.js', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', -], function ($, Login, Cryptpad, /*Test,*/ Cred, UI, Util, Realtime, Constants, Feedback, LocalStore, h) { +], function ($, Login, Cryptpad, /*Test,*/ Cred, UI, Util, Realtime, Constants, Feedback, LocalStore, h, Pages) { if (window.top !== window) { return; } var Messages = Cryptpad.Messages; $(function () { @@ -58,7 +59,14 @@ define([ var confirmPassword = $confirm.val(); var shouldImport = $checkImport[0].checked; - var doesAccept = $checkAcceptTerms[0].checked; + var doesAccept; + try { + // if this throws there's either a horrible bug (which someone will report) + // or the instance admins did not configure a terms page. + doesAccept = $checkAcceptTerms[0].checked; + } catch (err) { + console.error(err); + } if (Cred.isEmail(uname) && !I_REALLY_WANT_TO_USE_MY_EMAIL_FOR_MY_USERNAME) { var emailWarning = [ @@ -94,7 +102,7 @@ define([ return void UI.alert(Messages.register_passwordsDontMatch); } - if (!doesAccept) { // do they accept the terms of service? + if (Pages.customURLs.terms && !doesAccept) { // do they accept the terms of service? (if they exist) return void UI.alert(Messages.register_mustAcceptTerms); } From 2299cc85f96e9425a6ae9885a2e53fa406361ead Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 11 Mar 2022 13:06:31 +0530 Subject: [PATCH 39/45] apply even spacing in home page footer ...depending on whether legal column is displayed --- customize.dist/pages.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/customize.dist/pages.js b/customize.dist/pages.js index b438e4a58..8080968b1 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -73,12 +73,13 @@ define([ return select; }; - var footerCol = function (title, L, literal) { - return h('div.col-sm-3', [ + var footerCol = function (title, L, n) { + n = n || 3; + return h('div.col-sm-' + n, [ h('ul.list-unstyled', [ h('li.footer-title', { 'data-localization': title, - }, title? Msg[title]: literal ) + }, Msg[title]) ].concat(L.map(function (l) { return h('li', [ l ]); })) @@ -153,10 +154,12 @@ define([ ]); } + var n = legalFooter ? 3: 4; + return h('footer', [ h('div.container', [ h('div.row', [ - h('div.col-sm-3', [ + h('div.col-sm-' + n, [ h('div.cp-logo-foot', [ h('img', { src: '/customize/CryptPad_logo.svg', @@ -165,21 +168,21 @@ define([ }), h('span.logo-font', 'CryptPad') ]) - ], ''), + ]), footerCol('footer_product', [ footLink('/what-is-cryptpad.html', 'topbar_whatIsCryptpad'), Pages.docsLink, footLink('/features.html', Pages.areSubscriptionsAllowed()? 'pricing': 'features'), // Messages.pricing, Messages.features Pages.sourceLink, footLink('https://opencollective.com/cryptpad/contribute/', 'footer_donate'), - ]), + ], n), footerCol('footer_aboutUs', [ footLink('https://blog.cryptpad.fr/', 'blog'), footLink('/contact.html', 'contact'), footLink('https://github.com/xwiki-labs/cryptpad/wiki/Contributors', 'footer_team'), footLink('http://www.xwiki.com', null, 'XWiki SAS'), Pages.roadmapLink, - ]), + ], n), legalFooter, ]) ]), From 4b9e2bf26e5c9e7884ef2895c0a9654dac15110d Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 11 Mar 2022 13:12:27 +0530 Subject: [PATCH 40/45] link to existing terms page for backwards compatibility --- www/common/application_config_internal.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index 0dde18da3..67d1d92cd 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -86,11 +86,12 @@ define(function() { AppConfig.privacy = false; /* You can display a link to your instances's terms of service in the static pages footer. - * Since this is different for each individual or organization there is no default value. + * A default is included for backwards compatibility, but we recommend replacing this + * with your own terms. * * See the comments above for a description of possible configurations. */ - AppConfig.terms = false; + AppConfig.terms = true; /* The terms of CryptPad's license require that its source code be made available * to anyone who uses the software. If you have not made any modifications to the platform From 027fb8b4bb278e6b5fff291af639d9c21abe02ea Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 11 Mar 2022 13:26:29 +0530 Subject: [PATCH 41/45] don't prompt users with plans to upgrade on the support page --- www/support/inner.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/www/support/inner.js b/www/support/inner.js index a193a2f77..fd6a25662 100644 --- a/www/support/inner.js +++ b/www/support/inner.js @@ -169,6 +169,10 @@ define([ create['subscribe'] = function () { if (!Pages.areSubscriptionsAllowed()) { return; } + try { + if (common.getMetadataMgr().getPrivateData().plan) { return; } + } catch (err) {} + var url = Pages.accounts.upgradeURL; var accountsLink = h('a', { href: url, From c715334616cda31a9dfe41598e318745753f6e60 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 11 Mar 2022 13:49:34 +0530 Subject: [PATCH 42/45] stub a test on the checkup page --- www/checkup/main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/checkup/main.js b/www/checkup/main.js index d730d34c0..5e3d0ccfd 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -1159,6 +1159,7 @@ define([ // check if they provide legal data assert(function (cb, msg) { + if (true) { return void cb(true); } // XXX stubbed while we determine whether this is necessary if (ApiConfig.restrictRegistration) { return void cb(true); } var url = Pages.customURLs.imprint; From 1d93d4c45a6fa6e25f20f6d6a79eb5eb23b3e3b0 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 11 Mar 2022 19:17:53 +0530 Subject: [PATCH 43/45] fix category notice display logic --- www/support/ui.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/www/support/ui.js b/www/support/ui.js index ac935cc29..3e69660a4 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -188,7 +188,7 @@ Messages.support_formCategoryError = "Please select a ticket category from the d abuse: Pages.customURLs.terms, }; - var makeForm = function (ctx, cb, title) { + var makeForm = function (ctx, cb, title, hideNotice) { var button; if (typeof(cb) === "function") { @@ -203,7 +203,11 @@ Messages.support_formCategoryError = "Please select a ticket category from the d value: '' }); var catContainer = h('div.cp-dropdown-container' + (title ? '.cp-hidden': '')); - var notice = h('div.alert.alert-info', Messages.support_warning_prompt); + var notice; + if (!(hideNotice || ctx.isAdmin)) { + notice = h('div.alert.alert-info', Messages.support_warning_prompt); + } + var clickHandler = function (ev) { ev.preventDefault(); var $link = $(this); @@ -214,6 +218,7 @@ Messages.support_formCategoryError = "Please select a ticket category from the d makeCategoryDropdown(ctx, catContainer, function (key) { $(category).val(key); + if (!notice) { return; } //console.log(key); // Msg.support_warning_abuse.support_warning_account.support_warning_bug.support_warning_document.support_warning_drives.support_warning_other var warning = Messages['support_warning_' + key] || ''; @@ -373,13 +378,14 @@ Messages.support_formCategoryError = "Please select a ticket category from the d $(answer).click(function () { $ticket.find('.cp-support-form-container').remove(); $(actions).hide(); + var hideNotice = true; var form = makeForm(ctx, function () { var sent = sendForm(ctx, content.id, form, content.sender); if (sent) { $(actions).css('display', ''); $(form).remove(); } - }, content.title); + }, content.title, hideNotice); $ticket.append(form); }); @@ -507,8 +513,8 @@ Messages.support_formCategoryError = "Please select a ticket category from the d ui.sendForm = function (id, form, dest) { return sendForm(ctx, id, form, dest); }; - ui.makeForm = function (cb, title) { - return makeForm(ctx, cb, title); + ui.makeForm = function (cb, title, hideNotice) { + return makeForm(ctx, cb, title, hideNotice); }; ui.makeCategoryDropdown = function (container, onChange, all) { return makeCategoryDropdown(ctx, container, onChange, all); From 5a5f102a49e34b15e9e40301648b00d01aff24d1 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 11 Mar 2022 19:27:07 +0530 Subject: [PATCH 44/45] even faster admin-support redraw --- www/admin/inner.js | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/www/admin/inner.js b/www/admin/inner.js index 7aa6841eb..b9acc0607 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -1095,26 +1095,30 @@ define([ }; var _reorder = function () { - var hashKeys = Object.keys(hashesById); + var orderAnswered = []; + var orderPremium = []; + var orderNormal = []; + var orderClosed = []; - var orderAnswered = hashKeys.filter(function (id) { + Object.keys(hashesById).forEach(function (id) { var d = getTicketData(id); - return d && d.lastAdmin && !d.closed; - }).sort(sort); - var orderPremium = hashKeys.filter(function (id) { - var d = getTicketData(id); - return d && d.premium && !d.lastAdmin && !d.closed; - }).sort(sort); - var orderNormal = hashKeys.filter(function (id) { - var d = getTicketData(id); - return d && !d.premium && !d.lastAdmin && !d.closed; - }).sort(sort); - var orderClosed = hashKeys.filter(function (id) { - var d = getTicketData(id); - return d && d.closed; - }).sort(sort); + if (!d) { return; } + if (d.closed) { + return void orderClosed.push(id); + } + if (d.lastAdmin /* && !d.closed */) { + return void orderAnswered.push(id); + } + if (d.premium /* && !d.lastAdmin && !d.closed */) { + return void orderPremium.push(id); + } + orderNormal.push(id); + //if (!d.premium && !d.lastAdmin && !d.closed) { return void orderNormal.push(id); } + }); + var cols = [$col1, $col2, $col3, $col4]; [orderPremium, orderNormal, orderAnswered, orderClosed].forEach(function (list, j) { + list.sort(sort); list.forEach(function (id, i) { var $t = $div.find('[data-id="'+id+'"]'); var d = getTicketData(id); From 0a499d2fcf0774fb7bea3d66ef6c984b07bf406b Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 11 Mar 2022 18:07:07 +0100 Subject: [PATCH 45/45] Translated using Weblate (German) Currently translated at 100.0% (1448 of 1448 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/de/ --- www/common/translations/messages.de.json | 27 +++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index f914f256f..b0b93efb8 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -967,8 +967,8 @@ "slide_textCol": "Textfarbe", "support_languagesPreamble": "Das Support-Team spricht die folgenden Sprachen:", "settings_safeLinkDefault": "Sichere Links sind nun standardmäßig aktiviert. Bitte verwende zum Kopieren von Links das Menü Teilen und nicht die Adressleiste des Browsers.", - "info_imprintFlavour": "Rechtliche Informationen über die Administratoren dieses Servers.", - "info_privacyFlavour": "Unsere Datenschutzerklärung beschreibt, wie wir deine Daten verarbeiten.", + "info_imprintFlavour": "Rechtliche Informationen über die Administratoren dieses Servers", + "info_privacyFlavour": "Datenschutzerklärung für diese Instanz", "user_about": "Über CryptPad", "support_cat_all": "Alle", "support_cat_other": "Anderes", @@ -1427,5 +1427,26 @@ "form_exportSheet": "In Tabelle exportieren", "form_answerChoice": "Bitte wähle aus, wie du dieses Formular beantworten möchtest:", "bounce_danger": "Der Link, den du angeklickt hast, führt nicht zu einer Webseite, sondern zu einem Code oder Daten, die bösartig sein könnten.\n\n(\"{0}\")\n\nCryptPad blockiert solche Links aus Sicherheitsgründen. Klicke auf OK, um diesen Tab zu schließen.", - "bounce_confirm": "Du bist dabei zu verlassen: {0}\n\nBist du sicher, dass du \"{1}\" besuchen möchtest?" + "bounce_confirm": "Du bist dabei zu verlassen: {0}\n\nBist du sicher, dass du \"{1}\" besuchen möchtest?", + "info_sourceFlavour": "Quellcode von CryptPad", + "footer_source": "Quellcode", + "admin_jurisdictionHint": "Das Land, in dem die verschlüsselten Daten dieser Instanz gespeichert werden", + "admin_jurisdictionTitle": "Server-Standort", + "admin_archiveNote": "Notiz", + "support_warning_account": "Bitte beachte, dass Administratoren keine Passwörter zurücksetzen können. Wenn du die Zugangsdaten zu deinem Account verloren hast, aber noch eingeloggt bist, kannst du deine Daten in einen neuen Account importieren.", + "support_warning_prompt": "Bitte wähle die für dein Anliegen am besten geeignete Kategorie aus. Dies hilft den Administratoren bei der Bearbeitung und liefert weitere Vorschläge, welche Informationen bereitgestellt werden sollten.", + "support_warning_other": "Worum geht es bei deiner Anfrage? Bitte gib so viele relevante Informationen wie möglich an, damit wir dein Anliegen schnell bearbeiten können.", + "support_warning_abuse": "Bitte melde Inhalte, die gegen die Nutzungsbedingungen verstoßen. Bitte gib Links zu den betreffenden Dokumenten oder Nutzerprofilen an und beschreibe, wie sie gegen die Nutzungsbedingungen verstoßen. Jede zusätzliche Information über den Kontext, in dem du den Inhalt oder das Verhalten entdeckt hast, kann den Administratoren helfen, zukünftige Verstöße zu verhindern.", + "support_warning_bug": "Bitte gib an, in welchem Browser die Probleme auftreten und ob Erweiterungen installiert sind. Bitte beschreibe das Problem so detailliert wie möglich und gib die Schritte an, die zur Reproduktion des Problems notwendig sind.", + "support_warning_document": "Bitte gib an, bei welchem Dokumententyp es Probleme gibt, sowie die Kennung des Dokuments oder einen Link.", + "support_warning_drives": "Beachte, dass Administratoren nicht in der Lage sind, Ordner und Dokumente anhand ihres Namens zu identifizieren. Wenn es um einen geteilten Ordner geht, gib bitte die dazugehörige Kennung des Dokuments an.", + "info_termsFlavour": "Nutzungsbedingungen für diese Instanz", + "admin_descriptionHint": "Die Beschreibung wird in der Liste öffentlicher Instanzen auf cryptpad.org angezeigt", + "admin_descriptionTitle": "Beschreibung der Instanz", + "admin_nameHint": "Der Name wird in der Liste öffentlicher Instanzen auf cryptpad.org angezeigt", + "admin_nameTitle": "Name der Instanz", + "support_cat_abuse": "Missbrauch melden", + "support_cat_document": "Dokument", + "support_cat_drives": "Drive oder Team", + "ui_saved": "{0} gespeichert" }