16 changed files with 504 additions and 158 deletions
Split View
Diff Options
-
9customize.dist/src/less2/include/sidebar-layout.less
-
69customize.dist/src/less2/include/support.less
-
5scripts/generate-admin-keys.js
-
6www/admin/app-admin.less
-
118www/admin/inner.js
-
3www/admin/main.js
-
12www/common/common-hash.js
-
3www/common/cryptpad-common.js
-
23www/common/outer/async-store.js
-
13www/common/outer/mailbox.js
-
1www/common/outer/store-rpc.js
-
2www/common/sframe-common-mailbox.js
-
2www/support/app-support.less
-
190www/support/inner.js
-
3www/support/main.js
-
203www/support/ui.js
@ -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 Crypto = require('crypto'); |
|||
|
|||
const keyPair = Nacl.box.keyPair(); |
|||
console.log(keyPair); |
|||
|
|||
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("You will have to send the private key to each administrator manually so that they can add it to their account."); |
|||
console.log(); |
|||
@ -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 |
|||
}; |
|||
}); |
|||
Write
Preview
Loading…
Cancel
Save