Merge branch 'support' of github.com:xwiki-labs/cryptpad into notifications
This commit is contained in:
commit
cc92be85cb
@ -90,12 +90,21 @@
|
|||||||
button.btn {
|
button.btn {
|
||||||
@button-bg: @colortheme_sidebar-button-bg;
|
@button-bg: @colortheme_sidebar-button-bg;
|
||||||
@button-red-bg: @colortheme_sidebar-button-red-bg;
|
@button-red-bg: @colortheme_sidebar-button-red-bg;
|
||||||
|
@button-alt-bg: @colortheme_sidebar-button-alt-bg;
|
||||||
background-color: @button-bg;
|
background-color: @button-bg;
|
||||||
border-color: darken(@button-bg, 10%);
|
border-color: darken(@button-bg, 10%);
|
||||||
color: white;
|
color: white;
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: darken(@button-bg, 10%);
|
background-color: darken(@button-bg, 10%);
|
||||||
}
|
}
|
||||||
|
&.btn-secondary {
|
||||||
|
background-color: @button-alt-bg;
|
||||||
|
border-color: darken(@button-alt-bg, 10%);
|
||||||
|
color: black;
|
||||||
|
&:hover {
|
||||||
|
background-color: darken(@button-alt-bg, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
&.btn-danger {
|
&.btn-danger {
|
||||||
background-color: @button-red-bg;
|
background-color: @button-red-bg;
|
||||||
border-color: darken(@button-red-bg, 10%);
|
border-color: darken(@button-red-bg, 10%);
|
||||||
|
|||||||
69
customize.dist/src/less2/include/support.less
Normal file
69
customize.dist/src/less2/include/support.less
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
@import (reference) "./colortheme-all.less";
|
||||||
|
.support_main () {
|
||||||
|
@ticket-bg: #F7F7F7;
|
||||||
|
@msg-bg: #eee;
|
||||||
|
@fromme-bg: #ddd;
|
||||||
|
.cp-support-container {
|
||||||
|
.cp-support-list-ticket {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
background-color: @ticket-bg;
|
||||||
|
padding: 10px;
|
||||||
|
width: 1200px;
|
||||||
|
max-width: 90%;
|
||||||
|
margin: 5px auto;
|
||||||
|
.cp-support-list-message {
|
||||||
|
background-color: @msg-bg;
|
||||||
|
margin: 2px;
|
||||||
|
padding: 2px 5px;
|
||||||
|
.cp-support-fromme {
|
||||||
|
background-color: @fromme-bg;
|
||||||
|
}
|
||||||
|
.cp-support-showdata {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: @fromme-bg;
|
||||||
|
.cp-support-message-data {
|
||||||
|
display: none;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-support-message-time {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
margin-bottom: 0;
|
||||||
|
&.cp-support-message-content {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-support-list-actions {
|
||||||
|
order: 3;
|
||||||
|
.cp-support-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-support-form-container {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
&.cp-support-list-closed {
|
||||||
|
.cp-support-list-actions {
|
||||||
|
display: block !important;
|
||||||
|
.cp-support-answer, .cp-support-close {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.cp-support-hide {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-support-form-container {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,12 +1,13 @@
|
|||||||
|
/* jshint esversion: 6, node: true */
|
||||||
|
|
||||||
const Nacl = require('tweetnacl');
|
const Nacl = require('tweetnacl');
|
||||||
const Crypto = require('crypto');
|
|
||||||
|
|
||||||
const keyPair = Nacl.box.keyPair();
|
const keyPair = Nacl.box.keyPair();
|
||||||
console.log(keyPair);
|
console.log(keyPair);
|
||||||
|
|
||||||
console.log("You've just generated a new key pair for your support mailbox.");
|
console.log("You've just generated a new key pair for your support mailbox.");
|
||||||
|
|
||||||
console.log("The public key should first be added to your config.js file ('supportMailboxPublicKey'), then save and restart the server.")
|
console.log("The public key should first be added to your config.js file ('supportMailboxPublicKey'), then save and restart the server.");
|
||||||
console.log("Once restarted, administrators (specified with 'adminKeys' in config.js too) will be able to add the private key into their account. This can be done using the administration panel.");
|
console.log("Once restarted, administrators (specified with 'adminKeys' in config.js too) will be able to add the private key into their account. This can be done using the administration panel.");
|
||||||
console.log("You will have to send the private key to each administrator manually so that they can add it to their account.");
|
console.log("You will have to send the private key to each administrator manually so that they can add it to their account.");
|
||||||
console.log();
|
console.log();
|
||||||
@ -1,5 +1,6 @@
|
|||||||
@import (reference) '../../customize/src/less2/include/framework.less';
|
@import (reference) '../../customize/src/less2/include/framework.less';
|
||||||
@import (reference) '../../customize/src/less2/include/sidebar-layout.less';
|
@import (reference) '../../customize/src/less2/include/sidebar-layout.less';
|
||||||
|
@import (reference) '../../customize/src/less2/include/support.less';
|
||||||
|
|
||||||
&.cp-app-admin {
|
&.cp-app-admin {
|
||||||
|
|
||||||
@ -9,6 +10,11 @@
|
|||||||
@color: @colortheme_admin-color
|
@color: @colortheme_admin-color
|
||||||
);
|
);
|
||||||
.sidebar-layout_main();
|
.sidebar-layout_main();
|
||||||
|
.support_main();
|
||||||
|
|
||||||
|
.cp-hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
|
|||||||
@ -9,6 +9,8 @@ define([
|
|||||||
'/customize/messages.js',
|
'/customize/messages.js',
|
||||||
'/common/common-interface.js',
|
'/common/common-interface.js',
|
||||||
'/common/common-util.js',
|
'/common/common-util.js',
|
||||||
|
'/common/common-hash.js',
|
||||||
|
'/support/ui.js',
|
||||||
|
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||||
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
@ -23,7 +25,9 @@ define([
|
|||||||
h,
|
h,
|
||||||
Messages,
|
Messages,
|
||||||
UI,
|
UI,
|
||||||
Util
|
Util,
|
||||||
|
Hash,
|
||||||
|
Support
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var APP = {};
|
var APP = {};
|
||||||
@ -41,6 +45,10 @@ define([
|
|||||||
'cp-admin-active-pads',
|
'cp-admin-active-pads',
|
||||||
'cp-admin-registered',
|
'cp-admin-registered',
|
||||||
'cp-admin-disk-usage',
|
'cp-admin-disk-usage',
|
||||||
|
],
|
||||||
|
'support': [
|
||||||
|
'cp-admin-support-list',
|
||||||
|
'cp-admin-support-init'
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -94,7 +102,6 @@ define([
|
|||||||
sFrameChan.query('Q_ADMIN_RPC', {
|
sFrameChan.query('Q_ADMIN_RPC', {
|
||||||
cmd: 'ACTIVE_SESSIONS',
|
cmd: 'ACTIVE_SESSIONS',
|
||||||
}, function (e, data) {
|
}, function (e, data) {
|
||||||
console.log(e, data);
|
|
||||||
var total = data[0];
|
var total = data[0];
|
||||||
var ips = data[1];
|
var ips = data[1];
|
||||||
$div.append(h('pre', total + ' (' + ips + ')'));
|
$div.append(h('pre', total + ' (' + ips + ')'));
|
||||||
@ -160,6 +167,111 @@ define([
|
|||||||
return $div;
|
return $div;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var supportKey = ApiConfig.supportMailbox;
|
||||||
|
create['support-list'] = function () {
|
||||||
|
if (!supportKey || !APP.privateKey) { return; }
|
||||||
|
var $div = makeBlock('support-list');
|
||||||
|
$div.addClass('cp-support-container');
|
||||||
|
var hashesById = {};
|
||||||
|
|
||||||
|
// Register to the "support" mailbox
|
||||||
|
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;
|
||||||
|
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(Support.makeCloseMessage(common, content, hash));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (msg.type !== 'TICKET') { return; }
|
||||||
|
|
||||||
|
if (!$ticket.length) {
|
||||||
|
$ticket = Support.makeTicket($div, common, 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(Support.makeMessage(common, content, hash, true));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return $div;
|
||||||
|
};
|
||||||
|
|
||||||
|
var checkAdminKey = function (priv) {
|
||||||
|
if (!supportKey) { return; }
|
||||||
|
return Hash.checkBoxKeyPair(priv, supportKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
create['support-init'] = function () {
|
||||||
|
var $div = makeBlock('support-init');
|
||||||
|
if (!supportKey) {
|
||||||
|
$div.append(h('p', Messages.admin_supportInitHelp || "Your server is not configured to have a support mailbox. If you want a support mailbox to receive messages from your users, you should ask your server administrator to run the script located in './scripts/generate-admin-keys.js', store the public key in the 'config.js' file, and send you the private key.")); // XXX
|
||||||
|
return $div;
|
||||||
|
}
|
||||||
|
if (!APP.privateKey || !checkAdminKey(APP.privateKey)) {
|
||||||
|
$div.append(h('p', Messages.admin_supportInitPrivate || "Your CryptPad instance is configured to use a support mailbox but your account doesn't have the correct private key to access it. Please use the following form to add or update the private key to your account")); // XXX
|
||||||
|
|
||||||
|
var error = h('div.cp-admin-support-error');
|
||||||
|
var input = h('input.cp-admin-add-private-key');
|
||||||
|
var button = h('button.btn.btn-primary', Messages.admin_supportAddKey || 'add key'); // XXX
|
||||||
|
|
||||||
|
if (APP.privateKey && !checkAdminKey(APP.privateKey)) {
|
||||||
|
$(error).text(Messages.admin_supportAddError || 'invalid'); // XXX
|
||||||
|
}
|
||||||
|
|
||||||
|
$div.append(h('div', [
|
||||||
|
error,
|
||||||
|
input,
|
||||||
|
button
|
||||||
|
]));
|
||||||
|
|
||||||
|
$(button).click(function () {
|
||||||
|
var key = $(input).val();
|
||||||
|
if (!checkAdminKey(key)) {
|
||||||
|
$(input).val('');
|
||||||
|
return void $(error).text(Messages.admin_supportAddError || 'invalid'); // XXX
|
||||||
|
}
|
||||||
|
sFrameChan.query("Q_ADMIN_MAILBOX", key, function () {
|
||||||
|
console.log(key);
|
||||||
|
console.log(arguments);
|
||||||
|
APP.privateKey = key;
|
||||||
|
console.log('ok');
|
||||||
|
$('.cp-admin-support-init').hide();
|
||||||
|
APP.$rightside.append(create['support-list']()); // TODO: check?
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return $div;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
var hideCategories = function () {
|
var hideCategories = function () {
|
||||||
APP.$rightside.find('> div').hide();
|
APP.$rightside.find('> div').hide();
|
||||||
};
|
};
|
||||||
@ -180,6 +292,7 @@ define([
|
|||||||
var $category = $('<div>', {'class': 'cp-sidebarlayout-category'}).appendTo($categories);
|
var $category = $('<div>', {'class': 'cp-sidebarlayout-category'}).appendTo($categories);
|
||||||
if (key === 'general') { $category.append($('<span>', {'class': 'fa fa-user-o'})); }
|
if (key === 'general') { $category.append($('<span>', {'class': 'fa fa-user-o'})); }
|
||||||
if (key === 'stats') { $category.append($('<span>', {'class': 'fa fa-hdd-o'})); }
|
if (key === 'stats') { $category.append($('<span>', {'class': 'fa fa-hdd-o'})); }
|
||||||
|
if (key === 'support') { $category.append($('<span>', {'class': 'fa fa-life-ring'})); }
|
||||||
|
|
||||||
if (key === active) {
|
if (key === active) {
|
||||||
$category.addClass('cp-leftside-active');
|
$category.addClass('cp-leftside-active');
|
||||||
@ -236,6 +349,7 @@ define([
|
|||||||
return void UI.errorLoadingScreen(Messages.admin_authError || '403 Forbidden');
|
return void UI.errorLoadingScreen(Messages.admin_authError || '403 Forbidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
APP.privateKey = privateData.supportPrivateKey;
|
||||||
APP.origin = privateData.origin;
|
APP.origin = privateData.origin;
|
||||||
APP.readOnly = privateData.readOnly;
|
APP.readOnly = privateData.readOnly;
|
||||||
|
|
||||||
|
|||||||
@ -38,6 +38,9 @@ define([
|
|||||||
}).nThen(function (/*waitFor*/) {
|
}).nThen(function (/*waitFor*/) {
|
||||||
var addRpc = function (sframeChan, Cryptpad/*, Utils*/) {
|
var addRpc = function (sframeChan, Cryptpad/*, Utils*/) {
|
||||||
// Adding a new avatar from the profile: pin it and store it in the object
|
// Adding a new avatar from the profile: pin it and store it in the object
|
||||||
|
sframeChan.on('Q_ADMIN_MAILBOX', function (data, cb) {
|
||||||
|
Cryptpad.addAdminMailbox(data, cb);
|
||||||
|
});
|
||||||
sframeChan.on('Q_ADMIN_RPC', function (data, cb) {
|
sframeChan.on('Q_ADMIN_RPC', function (data, cb) {
|
||||||
Cryptpad.adminRpc(data, cb);
|
Cryptpad.adminRpc(data, cb);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -89,6 +89,18 @@ define([
|
|||||||
if (!publicKey) { return; }
|
if (!publicKey) { return; }
|
||||||
return uint8ArrayToHex(Hash.decodeBase64(publicKey).subarray(0,16));
|
return uint8ArrayToHex(Hash.decodeBase64(publicKey).subarray(0,16));
|
||||||
};
|
};
|
||||||
|
Hash.getBoxPublicFromSecret = function (priv) {
|
||||||
|
if (!priv) { return; }
|
||||||
|
var u8_priv = Hash.decodeBase64(priv);
|
||||||
|
var pair = Nacl.box.keyPair.fromSecretKey(u8_priv);
|
||||||
|
return Hash.encodeBase64(pair.publicKey);
|
||||||
|
};
|
||||||
|
Hash.checkBoxKeyPair = function (priv, pub) {
|
||||||
|
if (!pub || !priv) { return false; }
|
||||||
|
var u8_priv = Hash.decodeBase64(priv);
|
||||||
|
var pair = Nacl.box.keyPair.fromSecretKey(u8_priv);
|
||||||
|
return pub === Hash.encodeBase64(pair.publicKey);
|
||||||
|
};
|
||||||
|
|
||||||
Hash.createRandomHash = function (type, password) {
|
Hash.createRandomHash = function (type, password) {
|
||||||
var cryptor;
|
var cryptor;
|
||||||
|
|||||||
@ -620,6 +620,9 @@ define([
|
|||||||
common.adminRpc = function (data, cb) {
|
common.adminRpc = function (data, cb) {
|
||||||
postMessage("ADMIN_RPC", data, cb);
|
postMessage("ADMIN_RPC", data, cb);
|
||||||
};
|
};
|
||||||
|
common.addAdminMailbox = function (data, cb) {
|
||||||
|
postMessage("ADMIN_ADD_MAILBOX", data, cb);
|
||||||
|
};
|
||||||
|
|
||||||
// Network
|
// Network
|
||||||
common.onNetworkDisconnect = Util.mkEvent();
|
common.onNetworkDisconnect = Util.mkEvent();
|
||||||
|
|||||||
@ -479,7 +479,8 @@ define([
|
|||||||
thumbnails: disableThumbnails === false,
|
thumbnails: disableThumbnails === false,
|
||||||
isDriveOwned: Boolean(Util.find(store, ['driveMetadata', 'owners'])),
|
isDriveOwned: Boolean(Util.find(store, ['driveMetadata', 'owners'])),
|
||||||
support: Util.find(store.proxy, ['mailboxes', 'support', 'channel']),
|
support: Util.find(store.proxy, ['mailboxes', 'support', 'channel']),
|
||||||
pendingFriends: store.proxy.friends_pending || {}
|
pendingFriends: store.proxy.friends_pending || {},
|
||||||
|
supportPrivateKey: Util.find(store.proxy, ['mailboxes', 'supportadmin', 'keys', 'curvePrivate'])
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
cb(JSON.parse(JSON.stringify(metadata)));
|
cb(JSON.parse(JSON.stringify(metadata)));
|
||||||
@ -1060,6 +1061,26 @@ define([
|
|||||||
cb(res);
|
cb(res);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
Store.addAdminMailbox = function (clientId, data, cb) {
|
||||||
|
var priv = data;
|
||||||
|
var pub = Hash.getBoxPublicFromSecret(priv);
|
||||||
|
if (!priv || !pub) { return void cb({error: 'EINVAL'}); }
|
||||||
|
var channel = Hash.getChannelIdFromKey(pub);
|
||||||
|
var mailboxes = store.proxy.mailboxes = store.proxy.mailboxes || {};
|
||||||
|
var box = mailboxes.supportadmin = {
|
||||||
|
channel: channel,
|
||||||
|
viewed: [],
|
||||||
|
lastKnownHash: '',
|
||||||
|
keys: {
|
||||||
|
curvePublic: pub,
|
||||||
|
curvePrivate: priv
|
||||||
|
}
|
||||||
|
};
|
||||||
|
store.mailbox.open('supportadmin', box, function () {
|
||||||
|
console.log('ready');
|
||||||
|
});
|
||||||
|
onSync(cb);
|
||||||
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
/////////////////////// PAD //////////////////////////////////////
|
/////////////////////// PAD //////////////////////////////////////
|
||||||
|
|||||||
@ -10,6 +10,7 @@ define([
|
|||||||
|
|
||||||
var TYPES = [
|
var TYPES = [
|
||||||
'notifications',
|
'notifications',
|
||||||
|
'supportadmin',
|
||||||
'support'
|
'support'
|
||||||
];
|
];
|
||||||
var BLOCKING_TYPES = [
|
var BLOCKING_TYPES = [
|
||||||
@ -96,10 +97,10 @@ proxy.mailboxes = {
|
|||||||
network.join(user.channel).then(function (wc) {
|
network.join(user.channel).then(function (wc) {
|
||||||
wc.bcast(ciphertext).then(function () {
|
wc.bcast(ciphertext).then(function () {
|
||||||
cb();
|
cb();
|
||||||
wc.leave();
|
|
||||||
|
|
||||||
// If we've just sent a message to one of our mailboxes, we have to trigger the handler manually
|
// If we've just sent a message to one of our mailboxes, we have to trigger the handler manually
|
||||||
// (the server won't send back our message to us)
|
// (the server won't send back our message to us)
|
||||||
|
// If it isn't one of our mailboxes, we can close it now
|
||||||
var box;
|
var box;
|
||||||
if (Object.keys(ctx.boxes).some(function (t) {
|
if (Object.keys(ctx.boxes).some(function (t) {
|
||||||
var _box = ctx.boxes[t];
|
var _box = ctx.boxes[t];
|
||||||
@ -110,6 +111,8 @@ proxy.mailboxes = {
|
|||||||
})) {
|
})) {
|
||||||
var hash = ciphertext.slice(0, 64);
|
var hash = ciphertext.slice(0, 64);
|
||||||
box.onMessage(text, null, null, null, hash, user.curvePublic);
|
box.onMessage(text, null, null, null, hash, user.curvePublic);
|
||||||
|
} else {
|
||||||
|
wc.leave();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
@ -200,7 +203,7 @@ proxy.mailboxes = {
|
|||||||
if (!Crypto.Mailbox) {
|
if (!Crypto.Mailbox) {
|
||||||
return void console.error("chainpad-crypto is outdated and doesn't support mailboxes.");
|
return void console.error("chainpad-crypto is outdated and doesn't support mailboxes.");
|
||||||
}
|
}
|
||||||
var keys = getMyKeys(ctx);
|
var keys = m.keys || getMyKeys(ctx);
|
||||||
if (!keys) { return void console.error("missing asymmetric encryption keys"); }
|
if (!keys) { return void console.error("missing asymmetric encryption keys"); }
|
||||||
var crypto = Crypto.Mailbox.createEncryptor(keys);
|
var crypto = Crypto.Mailbox.createEncryptor(keys);
|
||||||
var cfg = {
|
var cfg = {
|
||||||
@ -364,6 +367,7 @@ proxy.mailboxes = {
|
|||||||
Object.keys(mailboxes).forEach(function (key) {
|
Object.keys(mailboxes).forEach(function (key) {
|
||||||
if (TYPES.indexOf(key) === -1) { return; }
|
if (TYPES.indexOf(key) === -1) { return; }
|
||||||
var m = mailboxes[key];
|
var m = mailboxes[key];
|
||||||
|
console.log(key, m);
|
||||||
|
|
||||||
if (BLOCKING_TYPES.indexOf(key) === -1) {
|
if (BLOCKING_TYPES.indexOf(key) === -1) {
|
||||||
openChannel(ctx, key, m, function () {
|
openChannel(ctx, key, m, function () {
|
||||||
@ -386,6 +390,11 @@ proxy.mailboxes = {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mailbox.open = function (key, m, cb) {
|
||||||
|
if (TYPES.indexOf(key) === -1) { return; }
|
||||||
|
openChannel(ctx, key, m, cb);
|
||||||
|
};
|
||||||
|
|
||||||
mailbox.dismiss = function (data, cb) {
|
mailbox.dismiss = function (data, cb) {
|
||||||
dismiss(ctx, data, '', cb);
|
dismiss(ctx, data, '', cb);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -84,6 +84,7 @@ define([
|
|||||||
DELETE_ACCOUNT: Store.deleteAccount,
|
DELETE_ACCOUNT: Store.deleteAccount,
|
||||||
// Admin
|
// Admin
|
||||||
ADMIN_RPC: Store.adminRpc,
|
ADMIN_RPC: Store.adminRpc,
|
||||||
|
ADMIN_ADD_MAILBOX: Store.addAdminMailbox,
|
||||||
};
|
};
|
||||||
|
|
||||||
Rpc.query = function (cmd, data, cb) {
|
Rpc.query = function (cmd, data, cb) {
|
||||||
|
|||||||
@ -123,6 +123,7 @@ define([
|
|||||||
|
|
||||||
var onMessage = function (data) {
|
var onMessage = function (data) {
|
||||||
// data = { type: 'type', content: {msg: 'msg', hash: 'hash'} }
|
// data = { type: 'type', content: {msg: 'msg', hash: 'hash'} }
|
||||||
|
console.log(data.type, data.content);
|
||||||
pushMessage(data);
|
pushMessage(data);
|
||||||
if (!history[data.type]) { history[data.type] = []; }
|
if (!history[data.type]) { history[data.type] = []; }
|
||||||
history[data.type].push(data.content);
|
history[data.type].push(data.content);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
@import (reference) '../../customize/src/less2/include/framework.less';
|
@import (reference) '../../customize/src/less2/include/framework.less';
|
||||||
@import (reference) '../../customize/src/less2/include/sidebar-layout.less';
|
@import (reference) '../../customize/src/less2/include/sidebar-layout.less';
|
||||||
|
@import (reference) '../../customize/src/less2/include/support.less';
|
||||||
|
|
||||||
&.cp-app-support {
|
&.cp-app-support {
|
||||||
.framework_min_main(
|
.framework_min_main(
|
||||||
@ -8,6 +9,7 @@
|
|||||||
@color: @colortheme_support-color
|
@color: @colortheme_support-color
|
||||||
);
|
);
|
||||||
.sidebar-layout_main();
|
.sidebar-layout_main();
|
||||||
|
.support_main();
|
||||||
|
|
||||||
.cp-hidden {
|
.cp-hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
|
|||||||
@ -9,8 +9,8 @@ define([
|
|||||||
'/common/common-hash.js',
|
'/common/common-hash.js',
|
||||||
'/customize/messages.js',
|
'/customize/messages.js',
|
||||||
'/common/hyperscript.js',
|
'/common/hyperscript.js',
|
||||||
|
'/support/ui.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
'/common/common-feedback.js',
|
|
||||||
|
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||||
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
@ -26,17 +26,15 @@ define([
|
|||||||
Hash,
|
Hash,
|
||||||
Messages,
|
Messages,
|
||||||
h,
|
h,
|
||||||
ApiConfig,
|
Support,
|
||||||
Feedback
|
ApiConfig
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var saveAs = window.saveAs;
|
|
||||||
var APP = window.APP = {};
|
var APP = window.APP = {};
|
||||||
|
|
||||||
var common;
|
var common;
|
||||||
var metadataMgr;
|
var metadataMgr;
|
||||||
var privateData;
|
var privateData;
|
||||||
var sframeChan;
|
|
||||||
|
|
||||||
var categories = {
|
var categories = {
|
||||||
'tickets': [
|
'tickets': [
|
||||||
@ -47,9 +45,9 @@ define([
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
var supportKey = ApiConfig.supportMailbox; // XXX curvePublic
|
var supportKey = ApiConfig.supportMailbox;
|
||||||
var supportChannel = Hash.getChannelIdFromKey(supportKey); // XXX
|
var supportChannel = Hash.getChannelIdFromKey(supportKey);
|
||||||
if (true || !supportKey || !supportChannel) {
|
if (!supportKey || !supportChannel) {
|
||||||
categories = {
|
categories = {
|
||||||
'tickets': [
|
'tickets': [
|
||||||
'cp-support-disabled'
|
'cp-support-disabled'
|
||||||
@ -75,138 +73,14 @@ define([
|
|||||||
return $div;
|
return $div;
|
||||||
};
|
};
|
||||||
|
|
||||||
var showError = function (form, msg) {
|
|
||||||
if (!msg) {
|
|
||||||
return void $(form).find('.cp-support-form-error').text('').hide();
|
|
||||||
}
|
|
||||||
$(form).find('.cp-support-form-error').text(msg).show();
|
|
||||||
};
|
|
||||||
|
|
||||||
var makeForm = function (cb, title) {
|
|
||||||
var button;
|
|
||||||
|
|
||||||
if (typeof(cb) === "function") {
|
|
||||||
button = h('button.btn.btn-primary.cp-support-list-send', Messages.support_send || 'Send'); // XXX
|
|
||||||
$(button).click(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
var content = [
|
|
||||||
h('hr'),
|
|
||||||
h('div.cp-support-form-error'),
|
|
||||||
h('label' + (title ? '.cp-hidden' : ''), Messages.support_formTitle || 'title...'), // XXX
|
|
||||||
h('input.cp-support-form-title' + (title ? '.cp-hidden' : ''), {
|
|
||||||
placeholder: Messages.support_formTitlePlaceholder || 'title here...', // XXX
|
|
||||||
value: title
|
|
||||||
}),
|
|
||||||
cb ? undefined : h('br'),
|
|
||||||
h('label', Messages.support_formMessage || 'content...'), // XXX
|
|
||||||
h('textarea.cp-support-form-msg', {
|
|
||||||
placeholder: Messages.support_formMessagePlaceholder || 'describe your problem here...' // XXX
|
|
||||||
}),
|
|
||||||
h('hr'),
|
|
||||||
button
|
|
||||||
];
|
|
||||||
|
|
||||||
return h('div.cp-support-form-container', content);
|
|
||||||
};
|
|
||||||
|
|
||||||
var sendForm = function (id, form) {
|
|
||||||
var user = metadataMgr.getUserData();
|
|
||||||
privateData = metadataMgr.getPrivateData();
|
|
||||||
|
|
||||||
var $title = $(form).find('.cp-support-form-title');
|
|
||||||
var $content = $(form).find('.cp-support-form-msg');
|
|
||||||
|
|
||||||
var title = $title.val();
|
|
||||||
if (!title) {
|
|
||||||
return void showError(form, Messages.support_formTitleError || 'title error'); // XXX
|
|
||||||
}
|
|
||||||
var content = $content.val();
|
|
||||||
if (!content) {
|
|
||||||
return void showError(form, Messages.support_formContentError || 'content error'); // XXX
|
|
||||||
}
|
|
||||||
// Success: hide any error
|
|
||||||
showError(form, null);
|
|
||||||
$content.val('');
|
|
||||||
$title.val('');
|
|
||||||
|
|
||||||
common.mailbox.sendTo('TICKET', {
|
|
||||||
sender: {
|
|
||||||
name: user.name,
|
|
||||||
channel: privateData.support,
|
|
||||||
curvePublic: user.curvePublic,
|
|
||||||
edPublic: privateData.edPublic
|
|
||||||
},
|
|
||||||
title: title,
|
|
||||||
message: content,
|
|
||||||
id: id
|
|
||||||
}, {
|
|
||||||
channel: supportChannel,
|
|
||||||
curvePublic: supportKey
|
|
||||||
});
|
|
||||||
common.mailbox.sendTo('TICKET', {
|
|
||||||
sender: {
|
|
||||||
name: user.name,
|
|
||||||
channel: privateData.support,
|
|
||||||
curvePublic: user.curvePublic,
|
|
||||||
edPublic: privateData.edPublic
|
|
||||||
},
|
|
||||||
title: title,
|
|
||||||
message: content,
|
|
||||||
id: id
|
|
||||||
}, {
|
|
||||||
channel: privateData.support,
|
|
||||||
curvePublic: user.curvePublic
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// List existing (open?) tickets
|
// List existing (open?) tickets
|
||||||
create['list'] = function () {
|
create['list'] = function () {
|
||||||
var key = 'list';
|
var key = 'list';
|
||||||
var $div = makeBlock(key);
|
var $div = makeBlock(key);
|
||||||
|
$div.addClass('cp-support-container');
|
||||||
var makeTicket = function (content) {
|
var hashesById = {};
|
||||||
var ticketTitle = content.id + ' - ' + content.title;
|
|
||||||
var answer = h('button.btn.btn-primary.cp-support-answer', Messages.support_answer || 'Answer'); // XXX
|
|
||||||
|
|
||||||
var $ticket = $(h('div.cp-support-list-ticket', {
|
|
||||||
'data-id': content.id
|
|
||||||
}, [
|
|
||||||
h('h2', ticketTitle),
|
|
||||||
h('div.cp-support-list-actions', answer)
|
|
||||||
]));
|
|
||||||
|
|
||||||
$(answer).click(function () {
|
|
||||||
$div.find('.cp-support-form-container').remove();
|
|
||||||
$div.find('.cp-support-answer').show();
|
|
||||||
$(answer).hide();
|
|
||||||
var form = makeForm(function () {
|
|
||||||
var sent = sendForm(content.id, form);
|
|
||||||
if (sent) {
|
|
||||||
$(answer).show();
|
|
||||||
$(form).remove();
|
|
||||||
}
|
|
||||||
}, content.title);
|
|
||||||
$ticket.append(form);
|
|
||||||
});
|
|
||||||
|
|
||||||
$div.append($ticket);
|
|
||||||
return $ticket;
|
|
||||||
};
|
|
||||||
|
|
||||||
var makeMessage = function (content, hash) {
|
|
||||||
// Check content.sender to see if it comes from us or from an admin
|
|
||||||
// XXX admins should send their personal public key?
|
|
||||||
var fromMe = content.sender && content.sender.edPublic === privateData.edPublic;
|
|
||||||
return h('div.cp-support-list-message', [
|
|
||||||
h('p.cp-support-message-from' + fromMe ? '.cp-support-fromme' : '',
|
|
||||||
//Messages._getKey('support_from', [content.sender.name])), // XXX
|
|
||||||
[h('b', 'From: '), content.sender.name]),
|
|
||||||
h('pre.cp-support-message-content', content.message)
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Register to the "support" mailbox
|
// Register to the "support" mailbox
|
||||||
common.mailbox.subscribe(['support'], {
|
common.mailbox.subscribe(['support'], {
|
||||||
@ -220,23 +94,39 @@ define([
|
|||||||
*/
|
*/
|
||||||
var msg = data.content.msg;
|
var msg = data.content.msg;
|
||||||
var hash = data.content.hash;
|
var hash = data.content.hash;
|
||||||
if (msg.type === 'CLOSE') {
|
|
||||||
// A ticket has been closed by the admins...
|
|
||||||
// TODO: add a "closed" class to the ticket in the UI
|
|
||||||
}
|
|
||||||
if (msg.type !== 'TICKET') { return; }
|
|
||||||
var content = msg.content;
|
var content = msg.content;
|
||||||
var id = content.id;
|
var id = content.id;
|
||||||
|
|
||||||
var $ticket = $div.find('.cp-support-list-ticket[data-id="'+id+'"]');
|
var $ticket = $div.find('.cp-support-list-ticket[data-id="'+id+'"]');
|
||||||
if (!$ticket.length) {
|
|
||||||
$ticket = makeTicket(content);
|
hashesById[id] = hashesById[id] || [];
|
||||||
|
if (hashesById[id].indexOf(hash) === -1) {
|
||||||
|
hashesById[id].push(data);
|
||||||
}
|
}
|
||||||
$ticket.append(makeMessage(content, hash));
|
|
||||||
},
|
if (msg.type === 'CLOSE') {
|
||||||
onViewed: function (data) {
|
// A ticket has been closed by the admins...
|
||||||
// Remove the ticket with this hash
|
if (!$ticket.length) { return; }
|
||||||
// If the ticket div is empty, remove the ticket div
|
$ticket.addClass('cp-support-list-closed');
|
||||||
|
$ticket.append(Support.makeCloseMessage(common, content, hash));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (msg.type !== 'TICKET') { return; }
|
||||||
|
|
||||||
|
if (!$ticket.length) {
|
||||||
|
$ticket = Support.makeTicket($div, common, 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(Support.makeMessage(common, content, hash, false));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return $div;
|
return $div;
|
||||||
@ -247,14 +137,20 @@ define([
|
|||||||
var key = 'form';
|
var key = 'form';
|
||||||
var $div = makeBlock(key, true);
|
var $div = makeBlock(key, true);
|
||||||
|
|
||||||
var form = makeForm();
|
var form = Support.makeForm();
|
||||||
|
|
||||||
$div.find('button').before(form);
|
$div.find('button').before(form);
|
||||||
|
|
||||||
var id = Util.uid();
|
var id = Util.uid();
|
||||||
|
|
||||||
$div.find('button').click(function () {
|
$div.find('button').click(function () {
|
||||||
var sent = sendForm(id, form);
|
var metadataMgr = common.getMetadataMgr();
|
||||||
|
var privateData = metadataMgr.getPrivateData();
|
||||||
|
var user = metadataMgr.getUserData();
|
||||||
|
var sent = Support.sendForm(common, id, form, {
|
||||||
|
channel: privateData.support,
|
||||||
|
curvePublic: user.curvePublic
|
||||||
|
});
|
||||||
if (sent) {
|
if (sent) {
|
||||||
$('.cp-sidebarlayout-category[data-category="tickets"]').click();
|
$('.cp-sidebarlayout-category[data-category="tickets"]').click();
|
||||||
}
|
}
|
||||||
@ -338,7 +234,7 @@ define([
|
|||||||
APP.$toolbar = $('#cp-toolbar');
|
APP.$toolbar = $('#cp-toolbar');
|
||||||
APP.$leftside = $('<div>', {id: 'cp-sidebarlayout-leftside'}).appendTo(APP.$container);
|
APP.$leftside = $('<div>', {id: 'cp-sidebarlayout-leftside'}).appendTo(APP.$container);
|
||||||
APP.$rightside = $('<div>', {id: 'cp-sidebarlayout-rightside'}).appendTo(APP.$container);
|
APP.$rightside = $('<div>', {id: 'cp-sidebarlayout-rightside'}).appendTo(APP.$container);
|
||||||
sFrameChan = common.getSframeChannel();
|
var sFrameChan = common.getSframeChannel();
|
||||||
sFrameChan.onReady(waitFor());
|
sFrameChan.onReady(waitFor());
|
||||||
}).nThen(function (/*waitFor*/) {
|
}).nThen(function (/*waitFor*/) {
|
||||||
createToolbar();
|
createToolbar();
|
||||||
|
|||||||
@ -36,8 +36,6 @@ define([
|
|||||||
};
|
};
|
||||||
window.addEventListener('message', onMsg);
|
window.addEventListener('message', onMsg);
|
||||||
}).nThen(function (/*waitFor*/) {
|
}).nThen(function (/*waitFor*/) {
|
||||||
var addRpc = function (sframeChan, Cryptpad, Utils) {
|
|
||||||
};
|
|
||||||
var category;
|
var category;
|
||||||
if (window.location.hash) {
|
if (window.location.hash) {
|
||||||
category = window.location.hash.slice(1);
|
category = window.location.hash.slice(1);
|
||||||
@ -48,7 +46,6 @@ define([
|
|||||||
};
|
};
|
||||||
SFCommonO.start({
|
SFCommonO.start({
|
||||||
noRealtime: true,
|
noRealtime: true,
|
||||||
addRpc: addRpc,
|
|
||||||
addData: addData
|
addData: addData
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
203
www/support/ui.js
Normal file
203
www/support/ui.js
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
define([
|
||||||
|
'jquery',
|
||||||
|
'/api/config',
|
||||||
|
'/common/hyperscript.js',
|
||||||
|
'/common/common-hash.js',
|
||||||
|
'/common/common-util.js',
|
||||||
|
'/customize/messages.js',
|
||||||
|
], function ($, ApiConfig, h, Hash, Util, Messages) {
|
||||||
|
|
||||||
|
var showError = function (form, msg) {
|
||||||
|
if (!msg) {
|
||||||
|
return void $(form).find('.cp-support-form-error').text('').hide();
|
||||||
|
}
|
||||||
|
$(form).find('.cp-support-form-error').text(msg).show();
|
||||||
|
};
|
||||||
|
|
||||||
|
var send = function (common, id, type, data, dest) {
|
||||||
|
var supportKey = ApiConfig.supportMailbox;
|
||||||
|
var supportChannel = Hash.getChannelIdFromKey(supportKey);
|
||||||
|
var metadataMgr = common.getMetadataMgr();
|
||||||
|
var user = metadataMgr.getUserData();
|
||||||
|
var privateData = metadataMgr.getPrivateData();
|
||||||
|
|
||||||
|
data = data || {};
|
||||||
|
|
||||||
|
data.sender = {
|
||||||
|
name: user.name,
|
||||||
|
channel: privateData.support,
|
||||||
|
curvePublic: user.curvePublic,
|
||||||
|
edPublic: privateData.edPublic
|
||||||
|
};
|
||||||
|
data.id = id;
|
||||||
|
data.time = +new Date();
|
||||||
|
|
||||||
|
// Send the message to the admin mailbox and to the user mailbox
|
||||||
|
common.mailbox.sendTo(type, data, {
|
||||||
|
channel: supportChannel,
|
||||||
|
curvePublic: supportKey
|
||||||
|
});
|
||||||
|
common.mailbox.sendTo(type, data, {
|
||||||
|
channel: dest.channel,
|
||||||
|
curvePublic: dest.curvePublic
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var sendForm = function (common, id, form, dest) {
|
||||||
|
var $title = $(form).find('.cp-support-form-title');
|
||||||
|
var $content = $(form).find('.cp-support-form-msg');
|
||||||
|
|
||||||
|
var title = $title.val();
|
||||||
|
if (!title) {
|
||||||
|
return void showError(form, Messages.support_formTitleError || 'title error'); // XXX
|
||||||
|
}
|
||||||
|
var content = $content.val();
|
||||||
|
if (!content) {
|
||||||
|
return void showError(form, Messages.support_formContentError || 'content error'); // XXX
|
||||||
|
}
|
||||||
|
// Success: hide any error
|
||||||
|
showError(form, null);
|
||||||
|
$content.val('');
|
||||||
|
$title.val('');
|
||||||
|
|
||||||
|
send(common, id, 'TICKET', {
|
||||||
|
title: title,
|
||||||
|
message: content,
|
||||||
|
}, dest);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var makeForm = function (cb, title) {
|
||||||
|
var button;
|
||||||
|
|
||||||
|
if (typeof(cb) === "function") {
|
||||||
|
button = h('button.btn.btn-primary.cp-support-list-send', Messages.support_send || 'Send'); // XXX
|
||||||
|
$(button).click(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
var cancel = title ? h('button.btn.btn-secondary', Messages.cancel) : undefined;
|
||||||
|
|
||||||
|
var content = [
|
||||||
|
h('hr'),
|
||||||
|
h('div.cp-support-form-error'),
|
||||||
|
h('label' + (title ? '.cp-hidden' : ''), Messages.support_formTitle || 'title...'), // XXX
|
||||||
|
h('input.cp-support-form-title' + (title ? '.cp-hidden' : ''), {
|
||||||
|
placeholder: Messages.support_formTitlePlaceholder || 'title here...', // XXX
|
||||||
|
value: title || ''
|
||||||
|
}),
|
||||||
|
cb ? undefined : h('br'),
|
||||||
|
h('label', Messages.support_formMessage || 'content...'), // XXX
|
||||||
|
h('textarea.cp-support-form-msg', {
|
||||||
|
placeholder: Messages.support_formMessagePlaceholder || 'describe your problem here...' // XXX
|
||||||
|
}),
|
||||||
|
h('hr'),
|
||||||
|
button,
|
||||||
|
cancel
|
||||||
|
];
|
||||||
|
|
||||||
|
var form = h('div.cp-support-form-container', content);
|
||||||
|
|
||||||
|
$(cancel).click(function () {
|
||||||
|
$(form).closest('.cp-support-list-ticket').find('.cp-support-list-actions').show();
|
||||||
|
$(form).remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
return form;
|
||||||
|
};
|
||||||
|
|
||||||
|
var makeTicket = function ($div, common, content, onHide) {
|
||||||
|
var ticketTitle = content.id + ' - ' + content.title;
|
||||||
|
var answer = h('button.btn.btn-primary.cp-support-answer', Messages.support_answer || 'Answer'); // XXX
|
||||||
|
var close = h('button.btn.btn-danger.cp-support-close', Messages.support_close || 'Close'); // XXX
|
||||||
|
var hide = h('button.btn.btn-danger.cp-support-hide', Messages.support_remove || 'Remove'); // XXX
|
||||||
|
|
||||||
|
var actions = h('div.cp-support-list-actions', [
|
||||||
|
answer,
|
||||||
|
close,
|
||||||
|
hide
|
||||||
|
]);
|
||||||
|
|
||||||
|
var $ticket = $(h('div.cp-support-list-ticket', {
|
||||||
|
'data-id': content.id
|
||||||
|
}, [
|
||||||
|
h('h2', ticketTitle),
|
||||||
|
actions
|
||||||
|
]));
|
||||||
|
|
||||||
|
$(close).click(function () {
|
||||||
|
send(common, content.id, 'CLOSE', {}, content.sender);
|
||||||
|
});
|
||||||
|
|
||||||
|
$(hide).click(function () {
|
||||||
|
if (typeof(onHide) !== "function") { return; }
|
||||||
|
onHide();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(answer).click(function () {
|
||||||
|
$ticket.find('.cp-support-form-container').remove();
|
||||||
|
$(actions).hide();
|
||||||
|
var form = makeForm(function () {
|
||||||
|
var sent = sendForm(common, content.id, form, content.sender);
|
||||||
|
if (sent) {
|
||||||
|
$(actions).show();
|
||||||
|
$(form).remove();
|
||||||
|
}
|
||||||
|
}, content.title);
|
||||||
|
$ticket.append(form);
|
||||||
|
});
|
||||||
|
|
||||||
|
$div.append($ticket);
|
||||||
|
return $ticket;
|
||||||
|
};
|
||||||
|
|
||||||
|
var makeMessage = function (common, content, hash, isAdmin) {
|
||||||
|
var metadataMgr = common.getMetadataMgr();
|
||||||
|
var privateData = metadataMgr.getPrivateData();
|
||||||
|
|
||||||
|
// Check content.sender to see if it comes from us or from an admin
|
||||||
|
// XXX admins should send their personal public key?
|
||||||
|
var fromMe = content.sender && content.sender.edPublic === privateData.edPublic;
|
||||||
|
|
||||||
|
var userData = h('div.cp-support-showdata', [
|
||||||
|
Messages.support_showData || 'Show/hide data', // XXX
|
||||||
|
h('pre.cp-support-message-data', JSON.stringify(content.sender, 0, 2))
|
||||||
|
]);
|
||||||
|
$(userData).click(function () {
|
||||||
|
$(userData).find('pre').toggle();
|
||||||
|
});
|
||||||
|
|
||||||
|
return h('div.cp-support-list-message', {
|
||||||
|
'data-hash': hash
|
||||||
|
}, [
|
||||||
|
h('div.cp-support-message-from' + (fromMe ? '.cp-support-fromme' : ''),
|
||||||
|
//Messages._getKey('support_from', [content.sender.name, new Date(content.time)])), // XXX
|
||||||
|
[h('b', 'From: '), content.sender.name, h('span.cp-support-message-time', content.time ? new Date(content.time).toLocaleString() : '')]),
|
||||||
|
h('pre.cp-support-message-content', content.message),
|
||||||
|
isAdmin ? userData : undefined,
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
var makeCloseMessage = function (common, content, hash) {
|
||||||
|
var metadataMgr = common.getMetadataMgr();
|
||||||
|
var privateData = metadataMgr.getPrivateData();
|
||||||
|
var fromMe = content.sender && content.sender.edPublic === privateData.edPublic;
|
||||||
|
|
||||||
|
return h('div.cp-support-list-message', {
|
||||||
|
'data-hash': hash
|
||||||
|
}, [
|
||||||
|
h('div.cp-support-message-from' + (fromMe ? '.cp-support-fromme' : ''),
|
||||||
|
//Messages._getKey('support_from', [content.sender.name, new Date(content.time)])), // XXX
|
||||||
|
[h('b', 'From: '), content.sender.name, h('span.cp-support-message-time', content.time ? new Date(content.time).toLocaleString() : '')]),
|
||||||
|
h('pre.cp-support-message-content', Messages.support_closed || 'Ticket closed...') // XXX
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
sendForm: sendForm,
|
||||||
|
makeForm: makeForm,
|
||||||
|
makeTicket: makeTicket,
|
||||||
|
makeMessage: makeMessage,
|
||||||
|
makeCloseMessage: makeCloseMessage
|
||||||
|
};
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user