New support: migration from the legacy system
This commit is contained in:
parent
de825af47a
commit
d0d3496904
5 changed files with 223 additions and 105 deletions
|
@ -253,6 +253,9 @@ define([
|
|||
sidebar.openCategory = name => {
|
||||
$(`.cp-sidebarlayout-category[data-category="${name}"]`).click();
|
||||
};
|
||||
sidebar.deleteCategory = name => {
|
||||
$(`.cp-sidebarlayout-category[data-category="${name}"]`).remove();
|
||||
};
|
||||
|
||||
sidebar.disableItem = (key) => {
|
||||
$(items[key]).remove();
|
||||
|
|
|
@ -18,7 +18,7 @@ define([
|
|||
|
||||
var TYPES = [
|
||||
'notifications',
|
||||
'supportadmin',
|
||||
//'supportadmin',
|
||||
'support',
|
||||
'supportteam',
|
||||
'broadcast'
|
||||
|
@ -397,6 +397,7 @@ proxy.mailboxes = {
|
|||
}
|
||||
msg.ctime = time || 0;
|
||||
box.content[hash] = msg;
|
||||
if (opts.dump) { return; }
|
||||
showMessage(ctx, type, message, null, function (obj) {
|
||||
if (!obj || !obj.msg || !notify) { return; }
|
||||
Notify.system(undefined, obj.msg);
|
||||
|
@ -450,7 +451,7 @@ proxy.mailboxes = {
|
|||
});
|
||||
box.ready = true;
|
||||
// Continue
|
||||
onReady();
|
||||
onReady(box.content);
|
||||
};
|
||||
box.cpNf = CpNetflux.start(cfg);
|
||||
};
|
||||
|
|
|
@ -165,7 +165,8 @@ define([
|
|||
author: data.name,
|
||||
supportKey: supportKey, // Store current support key
|
||||
lastAdmin: true,
|
||||
authorKey: data.curvePublic
|
||||
authorKey: data.curvePublic,
|
||||
notifications: data.notifications // Ticket created as admin, add user chan
|
||||
};
|
||||
}).nThen((waitFor) => {
|
||||
if (isAdmin) { return; }
|
||||
|
@ -588,6 +589,77 @@ define([
|
|||
});
|
||||
};
|
||||
|
||||
var clearLegacy = function (ctx, data, cId, cb) {
|
||||
let proxy = ctx.store.proxy;
|
||||
ctx.store.mailbox.close('supportadmin', function () {
|
||||
delete proxy.mailboxes.supportadmin;
|
||||
ctx.Store.onSync(null, function () {
|
||||
cb({done: true});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var dumpLegacy = function (ctx, data, cId, cb) {
|
||||
let proxy = ctx.store.proxy;
|
||||
let _legacy = Util.find(proxy, ['mailboxes', 'supportadmin']);
|
||||
if (!_legacy) { return void cb({error: 'ENOENT'}); }
|
||||
let legacy = Util.clone(_legacy);
|
||||
legacy.lastKnownHash = undefined;
|
||||
legacy.viewed = [];
|
||||
ctx.store.mailbox.open('supportadmin', legacy, function (contentByHash) {
|
||||
ctx.store.mailbox.close('supportadmin', function () {});
|
||||
cb(contentByHash);
|
||||
}, true, { // Opts
|
||||
dump: true
|
||||
});
|
||||
};
|
||||
var getLegacy = function (ctx, data, cId, cb) {
|
||||
let proxy = ctx.store.proxy;
|
||||
let legacy = Util.find(proxy, ['mailboxes', 'supportadmin']);
|
||||
if (!legacy) { return void cb({error: 'ENOENT'}); }
|
||||
ctx.store.mailbox.open('supportadmin', legacy, function (contentByHash) {
|
||||
ctx.store.mailbox.close('supportadmin', function () {});
|
||||
cb(contentByHash);
|
||||
}, true, { // Opts
|
||||
dump: true
|
||||
});
|
||||
};
|
||||
var restoreLegacy = function (ctx, data, cId, cb) {
|
||||
let proxy = ctx.store.proxy;
|
||||
let legacy = Util.find(proxy, ['mailboxes', 'supportadmin']);
|
||||
if (!legacy) { return void cb({error: 'ENOENT'}); }
|
||||
if (!ctx.adminRdyEvt) { return void cb({ error: 'EFORBIDDEN' }); }
|
||||
let messages = data.messages;
|
||||
let hashes = data.hashes;
|
||||
let first = messages[0];
|
||||
if (!first) { return void cb({error: 'EINVAL'}); }
|
||||
ctx.adminRdyEvt.reg(() => {
|
||||
let ticketData = {
|
||||
name: Util.find(first, ['sender', 'name']),
|
||||
notifications: Util.find(first, ['sender', 'notifications']),
|
||||
curvePublic: Util.find(first, ['sender', 'curvePublic']),
|
||||
channel: Hash.createChannelId(),
|
||||
title: first.title,
|
||||
time: first.time,
|
||||
ticket: {
|
||||
legacy: true,
|
||||
title: first.title,
|
||||
sender: first.sender,
|
||||
messages: messages
|
||||
}
|
||||
};
|
||||
makeTicket(ctx, ticketData, true, obj => {
|
||||
if (obj && obj.error) { return void cb(obj); }
|
||||
hashes.forEach(hash => {
|
||||
legacy.viewed.push(hash);
|
||||
});
|
||||
ctx.Store.onSync(null, function () {
|
||||
cb({done: true});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Mailbox events
|
||||
|
||||
var notifyClient = function (ctx, admin, type, channel) {
|
||||
|
@ -1115,6 +1187,18 @@ define([
|
|||
if (cmd === 'MOVE_TICKET_ADMIN') {
|
||||
return void moveTicketAdmin(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'GET_LEGACY') {
|
||||
return void getLegacy(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'DUMP_LEGACY') {
|
||||
return void dumpLegacy(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'CLEAR_LEGACY') {
|
||||
return void clearLegacy(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'RESTORE_LEGACY') {
|
||||
return void restoreLegacy(ctx, data, clientId, cb);
|
||||
}
|
||||
// Admin commands
|
||||
if (cmd === 'GET_PRIVATE_KEY') {
|
||||
return void getAdminKey(ctx, data, clientId, cb);
|
||||
|
|
|
@ -18,6 +18,8 @@ define([
|
|||
'/common/inner/sidebar-layout.js',
|
||||
'/support/ui.js',
|
||||
|
||||
'/components/file-saver/FileSaver.min.js',
|
||||
|
||||
'css!/components/components-font-awesome/css/font-awesome.min.css',
|
||||
'less!/moderation/app-moderation.less',
|
||||
], function (
|
||||
|
@ -38,6 +40,7 @@ define([
|
|||
)
|
||||
{
|
||||
var APP = {};
|
||||
var saveAs = window.saveAs;
|
||||
|
||||
var common;
|
||||
var sframeChan;
|
||||
|
@ -131,13 +134,20 @@ define([
|
|||
}
|
||||
var $ticket = $(ticket);
|
||||
obj.forEach(function (msg) {
|
||||
if (!data.notifications) {
|
||||
// Only add notifications channel if this is coming from the other user
|
||||
if (!data.notifications && msg.sender.drive) {
|
||||
data.notifications = Util.find(msg, ['sender', 'notifications']);
|
||||
}
|
||||
if (msg.close) {
|
||||
$ticket.addClass('cp-support-list-closed');
|
||||
return $ticket.append(APP.support.makeCloseMessage(msg));
|
||||
}
|
||||
if (msg.legacy && msg.messages) {
|
||||
msg.messages.forEach(c => {
|
||||
$ticket.append(APP.support.makeMessage(c));
|
||||
});
|
||||
return;
|
||||
}
|
||||
$ticket.append(APP.support.makeMessage(msg));
|
||||
});
|
||||
if (!open.includes(channel)) { open.push(channel); }
|
||||
|
@ -386,62 +396,137 @@ define([
|
|||
// XXX
|
||||
Messages.support_legacyTitle = "View old support data";
|
||||
Messages.support_legacyHint = "View tickets from the legacy system. You'll be able to recreate thse tickets on the new support system.";
|
||||
Messages.support_legacyButton = "Start";
|
||||
Messages.support_legacyButton = "Get active";
|
||||
Messages.support_legacyDump = "Export all";
|
||||
Messages.support_legacyClear = "Delete from my account";
|
||||
sidebar.addItem('legacy', cb => {
|
||||
if (!APP.privateKey) { return void cb(false); }
|
||||
|
||||
let start = blocks.button('primary', 'fa-paper-plane', Messages.support_legacyButton);
|
||||
let dump = blocks.button('secondary', 'fa-database', Messages.support_legacyDump);
|
||||
let clean = blocks.button('danger', 'fa-trash-o', Messages.support_legacyClear);
|
||||
let content = h('div.cp-support-container');
|
||||
let nav = blocks.nav([start, clean]);
|
||||
let nav = blocks.nav([start, dump, clean]);
|
||||
|
||||
UI.confirmButton(clean, { classes: 'btn-danger' }, function () {
|
||||
// XXX TODO remove my supportadmin mailbox
|
||||
console.error('NOT IMPLEMENTED');
|
||||
let sortLegacyTickets = contentByHash => {
|
||||
let all = {};
|
||||
Object.keys(contentByHash).forEach(key => {
|
||||
let data = contentByHash[key];
|
||||
let content = data.content;
|
||||
let id = content.id;
|
||||
content.hash = key;
|
||||
if (data.ctime) { content.time = data.ctime; }
|
||||
if (content.sender && content.sender.curvePublic !== data.author) { return; }
|
||||
all[id] = all[id] || [];
|
||||
all[id].push(content);
|
||||
all[id].sort((c1, c2) => {
|
||||
return c1.time - c2.time;
|
||||
});
|
||||
});
|
||||
// sort
|
||||
let sorted = Object.keys(all).sort((t1, t2) => {
|
||||
let a = t1[0];
|
||||
let b = t2[0];
|
||||
return (a.time || 0) - (b.time || 0);
|
||||
});
|
||||
return sorted.map(id => {
|
||||
return all[id];
|
||||
});
|
||||
};
|
||||
UI.confirmButton(dump, { classes: 'btn-secondary' }, function () {
|
||||
APP.module.execCommand('DUMP_LEGACY', {}, contentByHash => {
|
||||
// group by ticket id
|
||||
let sorted = sortLegacyTickets(contentByHash);
|
||||
let dump = '';
|
||||
sorted.forEach((t,i) => {
|
||||
if (!Array.isArray(t) || !t.length) { return; }
|
||||
let first = t[0];
|
||||
if (i) { dump += '\n\n'; }
|
||||
dump += `================================
|
||||
================================
|
||||
ID: #${first.id}
|
||||
Title: ${first.title}
|
||||
User: ${first.sender.name}
|
||||
Date: ${new Date(first.time).toISOString()}`;
|
||||
t.forEach(msg => {
|
||||
if (!msg.message) {
|
||||
dump += `
|
||||
--------------------------------
|
||||
CLOSED: ${new Date(msg.time).toISOString()}`;
|
||||
return;
|
||||
}
|
||||
dump += `
|
||||
--------------------------------
|
||||
From: ${msg.sender.name}
|
||||
Date: ${new Date(msg.time).toISOString()}
|
||||
---
|
||||
${msg.message}
|
||||
---
|
||||
Attachments:${JSON.stringify(msg.attachments, 0, 2)}`;
|
||||
});
|
||||
});
|
||||
saveAs(new Blob([dump], {type: 'text/plain'}), "cryptpad-support-dump.txt");
|
||||
});
|
||||
});
|
||||
UI.confirmButton(clean, { classes: 'btn-danger' }, function () {
|
||||
APP.module.execCommand('CLEAR_LEGACY', {}, () => {
|
||||
delete APP.privateKey;
|
||||
sidebar.deleteCategory('legacy');
|
||||
sidebar.openCategory('open');
|
||||
});
|
||||
});
|
||||
|
||||
let run = () => {
|
||||
let $div = $(content);
|
||||
$div.empty();
|
||||
common.mailbox.subscribe(['supportadmin'], {
|
||||
onMessage: function (data) {
|
||||
/*
|
||||
Get ID of the ticket
|
||||
If we already have a div for this ID
|
||||
Push the message to the end of the ticket
|
||||
If it's a new ticket ID
|
||||
Make a new div for this ID
|
||||
*/
|
||||
var msg = data.content.msg;
|
||||
var hash = data.content.hash;
|
||||
var content = msg.content;
|
||||
console.error(content, msg, hash);
|
||||
var id = content.id;
|
||||
var $ticket = $div.find('.cp-support-list-ticket[data-id="'+id+'"]');
|
||||
APP.module.execCommand('GET_LEGACY', {}, contentByHash => {
|
||||
// group by ticket id
|
||||
let sorted = sortLegacyTickets(contentByHash);
|
||||
sorted.forEach(ticket => {
|
||||
if (!Array.isArray(ticket) || !ticket.length) { return; }
|
||||
ticket.forEach(content => {
|
||||
var id = content.id;
|
||||
var $ticket = $div.find('.cp-support-list-ticket[data-id="'+id+'"]');
|
||||
|
||||
if (msg.type === 'CLOSE') {
|
||||
// A ticket has been closed by the admins...
|
||||
if (!$ticket.length) { return; }
|
||||
$ticket.addClass('cp-support-list-closed');
|
||||
$ticket.append(APP.support.makeCloseMessage(content, hash));
|
||||
return;
|
||||
}
|
||||
if (msg.type !== 'TICKET') { return; }
|
||||
$ticket.removeClass('cp-support-list-closed');
|
||||
if (!content.message) {
|
||||
// A ticket has been closed by the admins...
|
||||
if (!$ticket.length) { return; }
|
||||
$ticket.hide();
|
||||
$ticket.append(APP.support.makeCloseMessage(content));
|
||||
return;
|
||||
}
|
||||
$ticket.show();
|
||||
|
||||
if (!$ticket.length) {
|
||||
$ticket = APP.support.makeTicket({id, content});
|
||||
$div.append($ticket);
|
||||
}
|
||||
$ticket.append(APP.support.makeMessage(content));
|
||||
$ticket.find('.cp-support-showdata').attr('onclick', `showData();`);
|
||||
$ticket.find('.cp-support-showdata button').attr('onclick', `copyData();`);
|
||||
}
|
||||
const onMove = function () {
|
||||
let hashes = [];
|
||||
let messages = [];
|
||||
ticket.forEach(content => {
|
||||
hashes.push(content.hash);
|
||||
let clone = Util.clone(content);
|
||||
delete clone.hash;
|
||||
messages.push(clone);
|
||||
});
|
||||
APP.module.execCommand('RESTORE_LEGACY', {
|
||||
messages, hashes
|
||||
}, obj => {
|
||||
if (obj && obj.error) {
|
||||
console.error(obj.error);
|
||||
return void UI.warn(Messages.error);
|
||||
}
|
||||
});
|
||||
};
|
||||
if (!$ticket.length) {
|
||||
$ticket = APP.support.makeTicket({id, content, onMove});
|
||||
$div.append($ticket);
|
||||
}
|
||||
$ticket.append(APP.support.makeMessage(content));
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
Util.onClickEnter($(start), run);
|
||||
|
||||
|
||||
|
||||
let div = blocks.form([content], nav);
|
||||
cb(div);
|
||||
});
|
||||
|
|
|
@ -47,7 +47,6 @@ define([
|
|||
var categories = {
|
||||
'tickets': [ // Msg.support_cat_tickets
|
||||
'cp-support-list',
|
||||
'cp-support-listnew',
|
||||
],
|
||||
'new': [ // Msg.support_cat_new
|
||||
'cp-support-subscribe',
|
||||
|
@ -92,71 +91,11 @@ define([
|
|||
return $div;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// List existing (open?) tickets
|
||||
create['list'] = function () {
|
||||
var key = 'list';
|
||||
var $div = makeBlock(key); // Msg.support_listHint, .support_listTitle
|
||||
$div.addClass('cp-support-container');
|
||||
var hashesById = {};
|
||||
|
||||
// Register to the "support" mailbox
|
||||
common.mailbox.subscribe(['support'], {
|
||||
onMessage: function (data) {
|
||||
/*
|
||||
Get ID of the ticket
|
||||
If we already have a div for this ID
|
||||
Push the message to the end of the ticket
|
||||
If it's a new ticket ID
|
||||
Make a new div for this ID
|
||||
*/
|
||||
var msg = data.content.msg;
|
||||
var hash = data.content.hash;
|
||||
var content = msg.content;
|
||||
var id = content.id;
|
||||
var $ticket = $div.find('.cp-support-list-ticket[data-id="'+id+'"]');
|
||||
|
||||
hashesById[id] = hashesById[id] || [];
|
||||
if (hashesById[id].indexOf(hash) === -1) {
|
||||
hashesById[id].push(data);
|
||||
}
|
||||
|
||||
if (msg.type === 'CLOSE') {
|
||||
// A ticket has been closed by the admins...
|
||||
if (!$ticket.length) { return; }
|
||||
$ticket.addClass('cp-support-list-closed');
|
||||
$ticket.append(APP.support.makeCloseMessage(content, hash));
|
||||
return;
|
||||
}
|
||||
if (msg.type !== 'TICKET') { return; }
|
||||
$ticket.removeClass('cp-support-list-closed');
|
||||
|
||||
if (!$ticket.length) {
|
||||
$ticket = APP.support.makeTicket($div, content, function () {
|
||||
var error = false;
|
||||
hashesById[id].forEach(function (d) {
|
||||
common.mailbox.dismiss(d, function (err) {
|
||||
if (err) {
|
||||
error = true;
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
if (!error) { $ticket.remove(); }
|
||||
});
|
||||
}
|
||||
$ticket.append(APP.support.makeMessage(content, hash));
|
||||
}
|
||||
});
|
||||
return $div;
|
||||
};
|
||||
|
||||
var events = {
|
||||
'UPDATE_TICKET': Util.mkEvent()
|
||||
};
|
||||
create['listnew'] = function () {
|
||||
var key = 'listnew';
|
||||
create['list'] = function () {
|
||||
var key = 'list';
|
||||
var $div = makeBlock(key); // Msg.support_listHint, .support_listTitle
|
||||
var list = h('div.cp-support-container');
|
||||
var $list = $(list);
|
||||
|
@ -226,6 +165,12 @@ define([
|
|||
$ticket.addClass('cp-support-list-closed');
|
||||
return $ticket.append(APP.support.makeCloseMessage(msg));
|
||||
}
|
||||
if (msg.legacy && msg.messages) {
|
||||
msg.messages.forEach(c => {
|
||||
$ticket.append(APP.support.makeMessage(c));
|
||||
});
|
||||
return;
|
||||
}
|
||||
$ticket.append(APP.support.makeMessage(msg));
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue