From 171d00a943003281aaa266e1f26f60fe29974a72 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 11 Mar 2021 12:27:12 +0100 Subject: [PATCH] Broadcast deletion (manual and automatic) --- .../src/less2/include/notifications.less | 13 +++ www/admin/app-admin.less | 24 ++++++ www/admin/inner.js | 82 +++++++++++++++++-- www/common/outer/mailbox-handlers.js | 65 +++++++++++++++ www/common/outer/mailbox.js | 22 ++++- www/common/sframe-common-mailbox.js | 35 +++++++- www/common/sframe-common.js | 8 ++ 7 files changed, 237 insertions(+), 12 deletions(-) diff --git a/customize.dist/src/less2/include/notifications.less b/customize.dist/src/less2/include/notifications.less index 46209eb6a..133ee2d2a 100644 --- a/customize.dist/src/less2/include/notifications.less +++ b/customize.dist/src/less2/include/notifications.less @@ -17,6 +17,19 @@ .cp-notification { min-height: @notif-height; display: flex; + .cp-broadcast { + display: flex; + img { + width: 30px; + } + padding: 0 5px; + &.admin { + cursor: pointer; + &:hover { + background-color: @cp_dropdown-bg-hover; + } + } + } .cp-avatar { .avatar_main(30px); padding: 0 5px; diff --git a/www/admin/app-admin.less b/www/admin/app-admin.less index 2875c0a27..bf63e53c3 100644 --- a/www/admin/app-admin.less +++ b/www/admin/app-admin.less @@ -226,6 +226,30 @@ .cp-broadcast-preview { vertical-align: bottom !important; } + .cp-broadcast-delete { + width: 100%; + min-width: 600px; + .cp-notification { + display: flex; + align-items: center; + .cp-avatar, .cp-broadcast, .cp-notification-dismiss { + display: none; + } + p { + margin: 0 !important; + } + .cp-notification-content { + width: 100%; + padding: 10px; + } + .cp-clickable { + cursor: pointer; + &:hover { + background-color: @cp_dropdown-bg-hover; + } + } + } + } } } diff --git a/www/admin/inner.js b/www/admin/inner.js index b6d1988e5..42e3e4123 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -944,12 +944,17 @@ define([ Messages.broadcast_survey = 'survey'; // XXX Messages.broadcast_version = 'version'; // XXX Messages.broadcast_custom = 'custom'; // XXX + Messages.broadcast_delete = 'delete'; // XXX Messages.broadcast_newVersionReload = 'Force a worker reload on all clients'; // XXX Messages.broadcast_surveyURL = 'Survey URL'; Messages.broadcast_translations = 'Translations'; - Messages.broadcast_defaultLanguage = 'Default language'; + Messages.broadcast_defaultLanguage = 'Fallback to this language (optional)'; Messages.broadcast_start = 'Start time'; Messages.broadcast_end = 'End time'; + Messages.broadcast_preview = "Preview in a fake notification"; + Messages.broadcast_setLKH = "Mark as latest"; + Messages.broadcast_deleteBtn = "Delete for all"; + Messages.broadcast_reset = "Reset my visible messages"; var getBroadcastForm = function ($form, key) { $form.empty(); @@ -966,6 +971,7 @@ define([ var data = getData(); if (data === false) { return void UI.warn(Messages.error); } $button.prop('disabled', 'disabled'); + data.time = +new Date(); common.mailbox.sendTo('BROADCAST_'+key.toUpperCase(), data, {}, function (err) { $button.prop('disabled', ''); if (err) { return UI.warn(Messages.error); } @@ -997,7 +1003,7 @@ define([ UI.log(Messages.saved); }); }; - var preview = h('button.cp-broadcast-preview.btn.btn-secondary', Messages.share_linkOpen); + var preview = h('button.cp-broadcast-preview.btn.btn-secondary', Messages.broadcast_preview); $(preview).click(function () { onPreview(); }); @@ -1022,7 +1028,7 @@ define([ }; var addLang = function (l) { if ($container.find('.cp-broadcast-lang[data-lang="'+l+'"]').length) { return; } - var preview = h('button.btn.btn-secondary', Messages.share_linkOpen); + var preview = h('button.btn.btn-secondary', Messages.broadcast_preview); $(preview).click(function () { onPreview(l); }); @@ -1197,12 +1203,74 @@ define([ return; } + if (key === 'delete') { + (function () { + var table = h('table.cp-broadcast-delete'); + var $table = $(table); + common.mailbox.subscribe(["broadcast"], { + onMessage: function (data, el) { + if (Util.find(data, ['content', 'msg', 'type']) === 'BROADCAST_DELETE') { + var _uid = Util.find(data, ['content', 'msg', 'content', 'uid']); + var $button = $table.find('[data-uid="'+_uid+'"] td.delete button'); + $button.prop('disabled', 'disabled').text(Messages.deleted); + return; + } + var uid = Util.find(data, ['content', 'msg', 'uid']); + var time = Util.find(data, ['content', 'msg', 'content', 'time']); + var setLKHBtn = h('button.btn.btn-secondary', Messages.broadcast_setLKH); + var deleteBtn = h('button.btn.btn-danger', Messages.broadcast_deleteBtn); + $(setLKHBtn).click(function () { + // XXX + }); + var tr = h('tr', { 'data-uid': uid }, [ + h('td', 'ID: '+uid), + h('td', new Date(time || 0).toLocaleString()), + h('td', el), + h('td', setLKHBtn), + h('td.delete', deleteBtn), + ]); + + UI.confirmButton(deleteBtn, { + classes: 'btn-danger', + multiple: true + }, function () { + getData = function () { + if (!uid) { return false; } + return { uid: uid }; + }; + reset = function () { + $(deleteBtn).prop('disabled', 'disabled').text(Messages.deleted); + }; + send(); + }); + + $table.append(tr); + }, + history: true // won't receive new messages: not a "subscription" + }); + + var resetMine = h('button.btn.btn-primary', Messages.broadcast_reset); + UI.confirmButton(resetMine, {}, function () { + common.mailbox.reset('broadcast', function () { + // XXX + console.error(arguments); + }); + }); + + $form.append([ + resetMine, + table + ]); + })(); + return; + } + }; create['broadcast'] = function () { var key = 'broadcast'; var $div = makeBlock(key); - var form = h('div.cp-admin-broadcast-form') + var form = h('div.cp-admin-broadcast-form'); var $select = $(h('div.cp-dropdown-container')).appendTo($div); var $form = $(form).appendTo($div); @@ -1210,7 +1278,8 @@ define([ 'maintenance', 'survey', 'version', - 'custom' + 'custom', + 'delete' ]; categories = categories.map(function (key) { return { @@ -1400,8 +1469,7 @@ define([ var privateData = metadataMgr.getPrivateData(); common.setTabTitle(Messages.adminPage || 'Administration'); - if (!privateData.edPublic || !ApiConfig.adminKeys || !Array.isArray(ApiConfig.adminKeys) - || ApiConfig.adminKeys.indexOf(privateData.edPublic) === -1) { + if (!common.isAdmin()) { return void UI.errorLoadingScreen(Messages.admin_authError || '403 Forbidden'); } diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index 3a39e4ce7..f200ed387 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -686,6 +686,71 @@ define([ }; + // Broadcast + var broadcasts = {}; + handlers['BROADCAST_MAINTENANCE'] = function (ctx, box, data, cb) { + var msg = data.msg; + var content = msg.content; + if (content.end < (+new Date())) { + // Expired maintenance: dismiss + return void cb(true); + } + var uid = msg.uid; + broadcasts[uid] = { + type: box.type, + hash: data.hash + }; + cb(false); + }; + handlers['BROADCAST_VERSION'] = function (ctx, box, data, cb) { + var msg = data.msg; + var content = msg.content; + if (!box.ready) { + // This is an old version message: dismiss + return void cb(true); + } + if (content.reload) { + // We're going to force a disconnect, dismiss + // XXX + return void cb(true); + } + var uid = msg.uid; + broadcasts[uid] = { + type: box.type, + hash: data.hash + }; + cb(false); + }; + handlers['BROADCAST_SURVEY'] = function (ctx, box, data, cb) { + var msg = data.msg; + var uid = msg.uid; + broadcasts[uid] = { + type: box.type, + hash: data.hash + }; + cb(false); + }; + handlers['BROADCAST_CUSTOM'] = function (ctx, box, data, cb) { + var msg = data.msg; + var uid = msg.uid; + broadcasts[uid] = { + type: box.type, + hash: data.hash + }; + cb(false); + }; + handlers['BROADCAST_DELETE'] = function (ctx, box, data, cb) { + var msg = data.msg; + var content = msg.content; + var uid = content.uid; // uid of the message to delete + if (!broadcasts[uid]) { + // We don't have this message in memory, nothing to delete + return void cb(true); + } + cb(false, broadcasts[uid]); + delete broadcasts[uid]; + }; + return { add: function (ctx, box, data, cb) { /** diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js index 680eddd73..7b91938c9 100644 --- a/www/common/outer/mailbox.js +++ b/www/common/outer/mailbox.js @@ -464,6 +464,21 @@ proxy.mailboxes = { }); }; + var resetBox = function (ctx, cId, type, cb) { + var box = ctx.mailboxes && ctx.mailboxes[type]; + if (!box) { return void cb({error: 'ENOENT'}); } + + console.log(box); + if (type === 'broadcast') { + box.viewed = []; + box.lastKnownHash = ''; // XXX Use api/broadcast + return void cb(); + } + + box.lastKnownHash = ''; + box.viewed = []; + }; + var subscribe = function (ctx, data, cId, cb) { // Get existing notifications Object.keys(ctx.boxes).forEach(function (type) { @@ -491,19 +506,21 @@ proxy.mailboxes = { Mailbox.init = function (cfg, waitFor, emit) { var mailbox = {}; var store = cfg.store; + var mailboxes = store.proxy.mailboxes = store.proxy.mailboxes || {}; + var ctx = { Store: cfg.Store, store: store, pinPads: cfg.pinPads, updateMetadata: cfg.updateMetadata, updateDrive: cfg.updateDrive, + mailboxes: mailboxes, emit: emit, clients: [], boxes: {}, req: {} }; - var mailboxes = store.proxy.mailboxes = store.proxy.mailboxes || {}; initializeMailboxes(ctx, mailboxes); initializeHistory(ctx); @@ -580,6 +597,9 @@ proxy.mailboxes = { if (cmd === 'LOAD_HISTORY') { return void loadHistory(ctx, clientId, data, cb); } + if (cmd === 'RESET') { + return void resetBox(ctx, clientId, data, cb); + } }; return mailbox; diff --git a/www/common/sframe-common-mailbox.js b/www/common/sframe-common-mailbox.js index 174777449..3e711265c 100644 --- a/www/common/sframe-common-mailbox.js +++ b/www/common/sframe-common-mailbox.js @@ -1,13 +1,16 @@ define([ 'jquery', + '/api/config', '/common/common-util.js', '/common/common-hash.js', '/common/common-interface.js', '/common/common-ui-elements.js', '/common/notifications.js', '/common/hyperscript.js', + '/common/clipboard.js', '/customize/messages.js', -], function ($, Util, Hash, UI, UIElements, Notifications, h, Messages) { +], function ($, ApiConfig, Util, Hash, UI, UIElements, Notifications, h, + Clipboard, Messages) { var Mailbox = {}; Mailbox.create = function (Common) { @@ -56,7 +59,24 @@ define([ var notif; var avatar; var userData = Util.find(data, ['content', 'msg', 'content', 'user']); - if (userData && typeof(userData) === "object" && userData.profile) { + + if (Util.find(data, ['content', 'msg', 'type']) === 'BROADCAST_DELETE') { + return; + } + if (data.type === 'broadcast') { + var urlArgs = Util.find(ApiConfig, ['requireConf', 'urlArgs']) || ''; + var adminCls = Common.isAdmin() ? '.admin' : ''; + avatar = h('span.cp-broadcast'+adminCls, h('img', { + src: '/customize/CryptPad_logo.svg?' + urlArgs, + title: adminCls ? 'Copy UID' : '' // XXX + })); + if (adminCls) { + $(avatar).click(function () { + var success = Clipboard.copy(Util.find(data, ['content', 'msg', 'uid'])); + if (success) { UI.log(Messages.shareSuccess); } + }); + } + } else if (userData && typeof(userData) === "object" && userData.profile) { avatar = h('span.cp-avatar'); Common.displayAvatar($(avatar), userData.avatar, userData.displayName || userData.name); $(avatar).click(function (e) { @@ -160,7 +180,7 @@ define([ hash: data.content.hash, type: data.type }; - if (/^LOCAL|/.test(dataObj.hash)) { + if (/^LOCAL\|/.test(dataObj.hash)) { onViewed(dataObj); cb(); return; @@ -188,7 +208,7 @@ define([ cfg.onViewed(data); }); } - if (typeof(cfg.onMessage) === "function") { + if (typeof(cfg.onMessage) === "function" && !cfg.history) { onMessageHandlers.push(function (data, el) { var type = data.type; if (types.indexOf(type) === -1 && !(teams && /^team-/.test(type))) { return; } @@ -206,6 +226,13 @@ define([ }); }; + mailbox.reset = function (type, cb) { + if (!type) { return; } + execCommand('RESET', type, function (obj) { + cb(obj); + }); + }; + var historyState = false; var onHistory = function () {}; mailbox.getMoreHistory = function (type, count, lastKnownHash, cb) { diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index c46a0641d..1036f84d3 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -1,5 +1,6 @@ define([ 'jquery', + '/api/config', '/bower_components/nthen/index.js', '/customize/messages.js', '/common/sframe-chainpad-netflux-inner.js', @@ -26,6 +27,7 @@ define([ '/bower_components/localforage/dist/localforage.min.js' ], function ( $, + ApiConfig, nThen, Messages, CpNfInner, @@ -703,6 +705,12 @@ define([ }); }; + funcs.isAdmin = function () { + var privateData = ctx.metadataMgr.getPrivateData(); + return privateData.edPublic && Array.isArray(ApiConfig.adminKeys) && + ApiConfig.adminKeys.indexOf(privateData.edPublic) !== -1; + }; + funcs.mailbox = {}; Object.freeze(funcs);