mirror of https://github.com/xwiki-labs/cryptpad
Instance notification prototype
This commit is contained in:
parent
7ab529d4e9
commit
fee8a88169
|
@ -8,7 +8,7 @@
|
||||||
& {
|
& {
|
||||||
@alertify_padding-base: @variables_padding;
|
@alertify_padding-base: @variables_padding;
|
||||||
|
|
||||||
input:not(.form-control):not([type="checkbox"]), textarea, div.cp-textarea {
|
input:not(.numInput):not(.form-control):not([type="checkbox"]), textarea, div.cp-textarea {
|
||||||
// background-color: @alertify-input-fg;
|
// background-color: @alertify-input-fg;
|
||||||
color: @cp_forms-fg;
|
color: @cp_forms-fg;
|
||||||
background-color: @cp_forms-bg;
|
background-color: @cp_forms-bg;
|
||||||
|
|
|
@ -254,6 +254,11 @@ Channel.writePrivateMessage = function (Env, args, _cb, Server, netfluxId) {
|
||||||
var session = HK.getNetfluxSession(Env, netfluxId);
|
var session = HK.getNetfluxSession(Env, netfluxId);
|
||||||
var allowed = HK.listAllowedUsers(metadata);
|
var allowed = HK.listAllowedUsers(metadata);
|
||||||
|
|
||||||
|
// Special broadcast channel
|
||||||
|
if (channelId === '00000000000000000000000000000000') {
|
||||||
|
allowed = Env.admins;
|
||||||
|
}
|
||||||
|
|
||||||
if (HK.isUserSessionAllowed(allowed, session)) { return; }
|
if (HK.isUserSessionAllowed(allowed, session)) { return; }
|
||||||
|
|
||||||
w.abort();
|
w.abort();
|
||||||
|
|
|
@ -883,6 +883,10 @@ HK.onChannelMessage = function (Env, Server, channel, msgStruct, cb) {
|
||||||
// don't store messages if the channel id indicates that it's an ephemeral message
|
// don't store messages if the channel id indicates that it's an ephemeral message
|
||||||
if (!channel.id || channel.id.length === EPHEMERAL_CHANNEL_LENGTH) { return void cb(); }
|
if (!channel.id || channel.id.length === EPHEMERAL_CHANNEL_LENGTH) { return void cb(); }
|
||||||
|
|
||||||
|
if (channel.id === '00000000000000000000000000000000' && msgStruct[1] !== null) {
|
||||||
|
return void cb('ERESTRICTED_ADMIN');
|
||||||
|
}
|
||||||
|
|
||||||
const isCp = /^cp\|/.test(msgStruct[4]);
|
const isCp = /^cp\|/.test(msgStruct[4]);
|
||||||
let id;
|
let id;
|
||||||
if (isCp) {
|
if (isCp) {
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
|
|
||||||
.cp-admin-setlimit-form {
|
.cp-admin-setlimit-form, .cp-admin-broadcast-form {
|
||||||
label {
|
label {
|
||||||
font-weight: normal !important;
|
font-weight: normal !important;
|
||||||
}
|
}
|
||||||
|
@ -199,5 +199,30 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cp-admin-broadcast-form {
|
||||||
|
margin-top: 30px;
|
||||||
|
& > button:last-child {
|
||||||
|
margin-top: 30px !important;
|
||||||
|
}
|
||||||
|
.cp-broadcast-container {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
}
|
||||||
|
.cp-broadcast-lang {
|
||||||
|
margin: 30px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
align-items: baseline;
|
||||||
|
.cp-checkmark {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div.cp-broadcast-languages {
|
||||||
|
& > label.cp-checkmark:not(:last-child) {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,9 @@ define([
|
||||||
'/common/common-signing-keys.js',
|
'/common/common-signing-keys.js',
|
||||||
'/support/ui.js',
|
'/support/ui.js',
|
||||||
|
|
||||||
|
'/lib/datepicker/flatpickr.js',
|
||||||
|
|
||||||
|
'css!/lib/datepicker/flatpickr.min.css',
|
||||||
'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',
|
||||||
'less!/admin/app-admin.less',
|
'less!/admin/app-admin.less',
|
||||||
|
@ -31,7 +34,8 @@ define([
|
||||||
Util,
|
Util,
|
||||||
Hash,
|
Hash,
|
||||||
Keys,
|
Keys,
|
||||||
Support
|
Support,
|
||||||
|
Flatpickr
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var APP = {
|
var APP = {
|
||||||
|
@ -67,6 +71,9 @@ define([
|
||||||
'cp-admin-support-list',
|
'cp-admin-support-list',
|
||||||
'cp-admin-support-init'
|
'cp-admin-support-init'
|
||||||
],
|
],
|
||||||
|
'broadcast': [ // Msg.admin_cat_support
|
||||||
|
'cp-admin-broadcast'
|
||||||
|
],
|
||||||
'performance': [ // Msg.admin_cat_performance
|
'performance': [ // Msg.admin_cat_performance
|
||||||
'cp-admin-refresh-performance',
|
'cp-admin-refresh-performance',
|
||||||
'cp-admin-performance-profiling',
|
'cp-admin-performance-profiling',
|
||||||
|
@ -930,6 +937,279 @@ define([
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Messages.admin_cat_broadcast // XXX
|
||||||
|
// Messages.admin_broadcastHint // XXX
|
||||||
|
// Messages.admin_broadcastTitle // XXX
|
||||||
|
Messages.broadcast_maintenance = 'maintenance';// XXX
|
||||||
|
Messages.broadcast_survey = 'survey'; // XXX
|
||||||
|
Messages.broadcast_version = 'version'; // XXX
|
||||||
|
Messages.broadcast_custom = 'custom'; // 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_start = 'Start time';
|
||||||
|
Messages.broadcast_end = 'End time';
|
||||||
|
|
||||||
|
var getBroadcastForm = function ($form, key) {
|
||||||
|
$form.empty();
|
||||||
|
|
||||||
|
var getData = function () {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
var reset = function () {};
|
||||||
|
|
||||||
|
var button = h('button.btn.btn-primary', Messages.support_formButton);
|
||||||
|
var $button = $(button);
|
||||||
|
|
||||||
|
var send = function () {
|
||||||
|
var data = getData();
|
||||||
|
if (data === false) { return void UI.warn(Messages.error); }
|
||||||
|
$button.prop('disabled', 'disabled');
|
||||||
|
common.mailbox.sendTo('BROADCAST_'+key.toUpperCase(), data, {}, function (err) {
|
||||||
|
$button.prop('disabled', '');
|
||||||
|
if (err) { return UI.warn(Messages.error); }
|
||||||
|
reset();
|
||||||
|
UI.log(Messages.saved);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
$button.click(function () {
|
||||||
|
send();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (key === 'custom') {
|
||||||
|
(function () {
|
||||||
|
var container = h('div.cp-broadcast-container');
|
||||||
|
var $container = $(container);
|
||||||
|
var languages = Messages._languages;
|
||||||
|
var keys = Object.keys(languages).sort();
|
||||||
|
|
||||||
|
var onPreview = function (l) {
|
||||||
|
// XXX
|
||||||
|
};
|
||||||
|
|
||||||
|
var reorder = function () {
|
||||||
|
$container.find('.cp-broadcast-lang').each(function (i, el) {
|
||||||
|
var $el = $(el);
|
||||||
|
var l = $el.attr('data-lang');
|
||||||
|
$el.css('order', keys.indexOf(l));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var removeLang = function (l) {
|
||||||
|
$container.find('.cp-broadcast-lang[data-lang="'+l+'"]').remove();
|
||||||
|
};
|
||||||
|
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);
|
||||||
|
$(preview).click(function () {
|
||||||
|
onPreview(l);
|
||||||
|
});
|
||||||
|
var bcastDefault = Messages.broadcast_defaultLanguage;
|
||||||
|
$container.append(h('div.cp-broadcast-lang', { 'data-lang': l }, [
|
||||||
|
h('h4', languages[l]),
|
||||||
|
h('label', Messages.kanban_body),
|
||||||
|
h('textarea'),
|
||||||
|
UI.createRadio('broadcastDefault', null, bcastDefault, false, {
|
||||||
|
'data-lang': l,
|
||||||
|
label: {class: 'noTitle'}
|
||||||
|
}),
|
||||||
|
preview
|
||||||
|
]));
|
||||||
|
reorder();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var boxes = keys.map(function (l) {
|
||||||
|
var $cbox = $(UI.createCheckbox('cp-broadcast-custom-lang-'+l,
|
||||||
|
languages[l], false, { label: { class: 'noTitle' } }));
|
||||||
|
var $check = $cbox.find('input').on('change', function () {
|
||||||
|
var c = $check.is(':checked');
|
||||||
|
if (c) { return void addLang(l); }
|
||||||
|
removeLang(l);
|
||||||
|
});
|
||||||
|
if (l === 'en') {
|
||||||
|
setTimeout(function () {
|
||||||
|
$check.click();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return $cbox[0];
|
||||||
|
});
|
||||||
|
|
||||||
|
getData = function () {
|
||||||
|
var map = {};
|
||||||
|
var defaultLanguage;
|
||||||
|
var error = false;
|
||||||
|
$container.find('.cp-broadcast-lang').each(function (i, el) {
|
||||||
|
var $el = $(el);
|
||||||
|
var l = $el.attr('data-lang');
|
||||||
|
if (!l) { error = true; return; }
|
||||||
|
var text = $el.find('textarea').val();
|
||||||
|
if (!text.trim()) { error = true; return; }
|
||||||
|
if ($el.find('.cp-checkmark input').is(':checked')) {
|
||||||
|
defaultLanguage = l;
|
||||||
|
}
|
||||||
|
map[l] = text;
|
||||||
|
});
|
||||||
|
if (!Object.keys(map).length) {
|
||||||
|
console.error('You must select at least one language');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
console.error('One of the selected languages has no data');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
defaultLanguage: defaultLanguage,
|
||||||
|
content: map
|
||||||
|
};
|
||||||
|
};
|
||||||
|
reset = function () {
|
||||||
|
$container.find('.cp-broadcast-lang textarea').each(function (i, el) {
|
||||||
|
$(el).val('');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
$form.append([
|
||||||
|
h('label', Messages.broadcast_translations),
|
||||||
|
h('div.cp-broadcast-languages', boxes),
|
||||||
|
container,
|
||||||
|
button
|
||||||
|
]);
|
||||||
|
})();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (key === 'maintenance') {
|
||||||
|
(function () {
|
||||||
|
var start = h('input');
|
||||||
|
var end = h('input');
|
||||||
|
var $start = $(start);
|
||||||
|
var $end = $(end);
|
||||||
|
|
||||||
|
var endPickr = Flatpickr(end, {
|
||||||
|
enableTime: true,
|
||||||
|
minDate: new Date()
|
||||||
|
});
|
||||||
|
Flatpickr(start, {
|
||||||
|
enableTime: true,
|
||||||
|
minDate: new Date(),
|
||||||
|
onChange: function () {
|
||||||
|
endPickr.set('minDate', new Date($start.val()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
getData = function () {
|
||||||
|
var start = +new Date($start.val());
|
||||||
|
var end = +new Date($start.val());
|
||||||
|
if (isNaN(start) || isNaN(end)) {
|
||||||
|
console.error('Invalid dates');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
start: start,
|
||||||
|
end: end
|
||||||
|
};
|
||||||
|
};
|
||||||
|
reset = function () {
|
||||||
|
$start.val('');
|
||||||
|
$end.val('');
|
||||||
|
};
|
||||||
|
$form.append([
|
||||||
|
h('label', Messages.broadcast_start),
|
||||||
|
start,
|
||||||
|
h('label', Messages.broadcast_end),
|
||||||
|
end,
|
||||||
|
h('br'),
|
||||||
|
button
|
||||||
|
]);
|
||||||
|
})();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (key === 'version') {
|
||||||
|
(function () {
|
||||||
|
var $cbox = $(UI.createCheckbox('cp-admin-version-reload',
|
||||||
|
Messages.broadcast_newVersionReload,
|
||||||
|
false, { label: { class: 'noTitle' } }));
|
||||||
|
var $checkbox = $cbox.find('input');
|
||||||
|
getData = function () {
|
||||||
|
return {
|
||||||
|
reload: $checkbox.is(':checked')
|
||||||
|
};
|
||||||
|
};
|
||||||
|
reset = function () {
|
||||||
|
$checkbox[0].checked = false;
|
||||||
|
};
|
||||||
|
$form.append([
|
||||||
|
$cbox[0],
|
||||||
|
h('br'),
|
||||||
|
button
|
||||||
|
]);
|
||||||
|
})();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (key === 'survey') {
|
||||||
|
(function () {
|
||||||
|
var label = h('label', Messages.broadcast_surveyURL);
|
||||||
|
var input = h('input');
|
||||||
|
var $input = $(input);
|
||||||
|
getData = function () {
|
||||||
|
var url = $input.val();
|
||||||
|
if (!Util.isValidURL(url)) {
|
||||||
|
console.error('Invalid URL');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
url: url
|
||||||
|
};
|
||||||
|
};
|
||||||
|
reset = function () {
|
||||||
|
$input.val('');
|
||||||
|
};
|
||||||
|
$form.append([
|
||||||
|
label,
|
||||||
|
input,
|
||||||
|
h('br'),
|
||||||
|
button
|
||||||
|
]);
|
||||||
|
})();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
create['broadcast'] = function () {
|
||||||
|
var key = 'broadcast';
|
||||||
|
var $div = makeBlock(key);
|
||||||
|
|
||||||
|
var form = h('div.cp-admin-broadcast-form')
|
||||||
|
var $select = $(h('div.cp-dropdown-container')).appendTo($div);
|
||||||
|
var $form = $(form).appendTo($div);
|
||||||
|
|
||||||
|
var categories = [
|
||||||
|
'maintenance',
|
||||||
|
'survey',
|
||||||
|
'version',
|
||||||
|
'custom'
|
||||||
|
];
|
||||||
|
categories = categories.map(function (key) {
|
||||||
|
return {
|
||||||
|
tag: 'a',
|
||||||
|
content: h('span', Messages['broadcast_'+key]),
|
||||||
|
action: function () {
|
||||||
|
getBroadcastForm($form, key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
var dropdownCfg = {
|
||||||
|
text: Messages.support_category,
|
||||||
|
angleDown: 1,
|
||||||
|
options: categories,
|
||||||
|
container: $select,
|
||||||
|
isSelect: true
|
||||||
|
};
|
||||||
|
UIElements.createDropdown(dropdownCfg);
|
||||||
|
|
||||||
|
|
||||||
|
return $div;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
var onRefreshPerformance = Util.mkEvent();
|
var onRefreshPerformance = Util.mkEvent();
|
||||||
|
|
||||||
create['refresh-performance'] = function () {
|
create['refresh-performance'] = function () {
|
||||||
|
@ -1010,6 +1290,7 @@ define([
|
||||||
stats: 'fa fa-line-chart',
|
stats: 'fa fa-line-chart',
|
||||||
quota: 'fa fa-hdd-o',
|
quota: 'fa fa-hdd-o',
|
||||||
support: 'fa fa-life-ring',
|
support: 'fa fa-life-ring',
|
||||||
|
broadcast: 'fa fa-bullhorn',
|
||||||
performance: 'fa fa-heartbeat',
|
performance: 'fa fa-heartbeat',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -554,6 +554,16 @@
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Util.isValidURL = function (str) {
|
||||||
|
var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
|
||||||
|
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
|
||||||
|
'((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
|
||||||
|
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
|
||||||
|
'(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
|
||||||
|
'(\\#[-a-z\\d_]*)?$','i'); // fragment locator
|
||||||
|
return !!pattern.test(str);
|
||||||
|
};
|
||||||
|
|
||||||
var emoji_patt = /([\uD800-\uDBFF][\uDC00-\uDFFF])/;
|
var emoji_patt = /([\uD800-\uDBFF][\uDC00-\uDFFF])/;
|
||||||
var isEmoji = function (str) {
|
var isEmoji = function (str) {
|
||||||
return emoji_patt.test(str);
|
return emoji_patt.test(str);
|
||||||
|
|
|
@ -406,6 +406,87 @@ define([
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Messages.broadcast_newSurvey = "A new survey is available."; // XXX
|
||||||
|
handlers['BROADCAST_SURVEY'] = function (common, data) {
|
||||||
|
var content = data.content;
|
||||||
|
var msg = content.msg.content;
|
||||||
|
content.getFormatText = function () {
|
||||||
|
return Messages.broadcast_newSurvey;
|
||||||
|
};
|
||||||
|
content.handler = function () {
|
||||||
|
common.openUnsafeURL(msg.url);
|
||||||
|
// XXX dismiss on click?
|
||||||
|
};
|
||||||
|
if (!content.archived) {
|
||||||
|
content.dismissHandler = defaultDismiss(common, data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Messages.broadcast_newMaintenance = "A maintenance is planned between <b>{0}</b> and <b>{1}</b>"; // XXX
|
||||||
|
handlers['BROADCAST_MAINTENANCE'] = function (common, data) {
|
||||||
|
var content = data.content;
|
||||||
|
var msg = content.msg.content;
|
||||||
|
content.getFormatText = function () {
|
||||||
|
return Messages._getKey('broadcast_newMaintenance', [
|
||||||
|
new Date(msg.start).toLocaleString(),
|
||||||
|
new Date(msg.end).toLocaleString(),
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
if (!content.archived) {
|
||||||
|
content.dismissHandler = defaultDismiss(common, data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Messages.broadcast_newVersion = "A new version is available. Reload the page to discover the new features!"; // XXX
|
||||||
|
handlers['BROADCAST_VERSION'] = function (common, data) {
|
||||||
|
var content = data.content;
|
||||||
|
content.getFormatText = function () {
|
||||||
|
return Messages.broadcast_newVersion;
|
||||||
|
};
|
||||||
|
if (!content.archived) {
|
||||||
|
content.dismissHandler = defaultDismiss(common, data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Messages.broadcast_newCustom = "Message from the administrators"; // XXX
|
||||||
|
handlers['BROADCAST_CUSTOM'] = function (common, data) {
|
||||||
|
var content = data.content;
|
||||||
|
var msg = content.msg.content;
|
||||||
|
var text = msg.content;
|
||||||
|
var defaultL = msg.defaultLanguage;
|
||||||
|
// Check if our language is available
|
||||||
|
var toShow = text[Messages._languageUsed];
|
||||||
|
// Otherwise, fallback to the default language if it exists
|
||||||
|
if (!toShow && defaultL) { toShow = text[defaultL]; }
|
||||||
|
// No translation available, dismiss
|
||||||
|
if (!toShow) { defaultDismiss(common, data)(); }
|
||||||
|
|
||||||
|
var slice = toShow.length > 500;
|
||||||
|
toShow = Util.fixHTML(toShow);
|
||||||
|
|
||||||
|
content.getFormatText = function () {
|
||||||
|
// XXX Add a title to custom messages? Or use a generic key in the notification and only display the text in the alert?
|
||||||
|
if (slice) {
|
||||||
|
return toShow.slice(0, 500) + '...';
|
||||||
|
}
|
||||||
|
return toShow;
|
||||||
|
};
|
||||||
|
if (slice) {
|
||||||
|
content.handler = function () {
|
||||||
|
// XXX Allow markdown (sanitized)?
|
||||||
|
var content = h('div', [
|
||||||
|
h('h4', Messages.broadcast_newCustom),
|
||||||
|
h('div', toShow)
|
||||||
|
]);
|
||||||
|
UI.alert(content);
|
||||||
|
// XXX Dismiss on click?
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!content.archived) {
|
||||||
|
content.dismissHandler = defaultDismiss(common, data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// NOTE: don't forget to fixHTML everything returned by "getFormatText"
|
// NOTE: don't forget to fixHTML everything returned by "getFormatText"
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
define([
|
define([
|
||||||
|
'/api/config',
|
||||||
'/common/common-util.js',
|
'/common/common-util.js',
|
||||||
'/common/common-hash.js',
|
'/common/common-hash.js',
|
||||||
'/common/common-realtime.js',
|
'/common/common-realtime.js',
|
||||||
|
@ -7,17 +8,20 @@ define([
|
||||||
'/common/outer/mailbox-handlers.js',
|
'/common/outer/mailbox-handlers.js',
|
||||||
'/bower_components/chainpad-netflux/chainpad-netflux.js',
|
'/bower_components/chainpad-netflux/chainpad-netflux.js',
|
||||||
'/bower_components/chainpad-crypto/crypto.js',
|
'/bower_components/chainpad-crypto/crypto.js',
|
||||||
], function (Util, Hash, Realtime, Messaging, Notify, Handlers, CpNetflux, Crypto) {
|
], function (Config, Util, Hash, Realtime, Messaging, Notify, Handlers, CpNetflux, Crypto) {
|
||||||
var Mailbox = {};
|
var Mailbox = {};
|
||||||
|
|
||||||
var TYPES = [
|
var TYPES = [
|
||||||
'notifications',
|
'notifications',
|
||||||
'supportadmin',
|
'supportadmin',
|
||||||
'support'
|
'support',
|
||||||
|
'broadcast'
|
||||||
];
|
];
|
||||||
var BLOCKING_TYPES = [
|
var BLOCKING_TYPES = [
|
||||||
];
|
];
|
||||||
|
|
||||||
|
var BROADCAST_CHAN = '00000000000000000000000000000000';
|
||||||
|
|
||||||
var initializeMailboxes = function (ctx, mailboxes) {
|
var initializeMailboxes = function (ctx, mailboxes) {
|
||||||
if (!mailboxes['notifications']) {
|
if (!mailboxes['notifications']) {
|
||||||
mailboxes.notifications = {
|
mailboxes.notifications = {
|
||||||
|
@ -39,6 +43,16 @@ define([
|
||||||
if (res.error) { console.error(res); }
|
if (res.error) { console.error(res); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (!mailboxes['broadcast']) {
|
||||||
|
mailboxes.broadcast = {
|
||||||
|
channel: BROADCAST_CHAN,
|
||||||
|
lastKnownHash: '', // XXX load /api/brooadcast to set this hash
|
||||||
|
decrypted: true,
|
||||||
|
viewed: []
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// XXX update lastKnownHash from /api/broadcast
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -80,33 +94,49 @@ proxy.mailboxes = {
|
||||||
|
|
||||||
// Send a message to someone else
|
// Send a message to someone else
|
||||||
var sendTo = Mailbox.sendTo = function (ctx, type, msg, user, _cb) {
|
var sendTo = Mailbox.sendTo = function (ctx, type, msg, user, _cb) {
|
||||||
|
user = user || {};
|
||||||
var cb = _cb || function (obj) {
|
var cb = _cb || function (obj) {
|
||||||
if (obj && obj.error) {
|
if (obj && obj.error) {
|
||||||
console.error(obj.error);
|
console.error(obj.error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!Crypto.Mailbox) {
|
if (!Crypto.Mailbox) {
|
||||||
return void cb({error: "chainpad-crypto is outdated and doesn't support mailboxes."});
|
return void cb({error: "chainpad-crypto is outdated and doesn't support mailboxes."});
|
||||||
}
|
}
|
||||||
var keys = getMyKeys(ctx);
|
|
||||||
if (!keys) { return void cb({error: "missing asymmetric encryption keys"}); }
|
|
||||||
if (!user || !user.channel || !user.curvePublic) { return void cb({error: "no notification channel"}); }
|
|
||||||
|
|
||||||
var anonRpc = Util.find(ctx, [ 'store', 'anon_rpc', ]);
|
var anonRpc = Util.find(ctx, [ 'store', 'anon_rpc', ]);
|
||||||
if (!anonRpc) { return void cb({error: "anonymous rpc session not ready"}); }
|
if (!anonRpc) { return void cb({error: "anonymous rpc session not ready"}); }
|
||||||
|
|
||||||
var crypto = Crypto.Mailbox.createEncryptor(keys);
|
// Broadcast mailbox doesn't use encryption. Sending messages there is restricted
|
||||||
|
// to admins in the server directly
|
||||||
// Always send your data
|
var crypto = { encrypt: function (x) { return x; } };
|
||||||
if (typeof(msg) === "object" && !msg.user) {
|
var channel = BROADCAST_CHAN;
|
||||||
var myData = Messaging.createData(ctx.store.proxy, false);
|
var obj = {
|
||||||
msg.user = myData;
|
uid: Util.uid(), // add uid at the beginning to have a unique server hash
|
||||||
}
|
|
||||||
|
|
||||||
var text = JSON.stringify({
|
|
||||||
type: type,
|
type: type,
|
||||||
content: msg
|
content: msg
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (!/^BROADCAST/.test(type)) {
|
||||||
|
var keys = getMyKeys(ctx);
|
||||||
|
if (!keys) { return void cb({error: "missing asymmetric encryption keys"}); }
|
||||||
|
if (!user || !user.channel || !user.curvePublic) { return void cb({error: "no notification channel"}); }
|
||||||
|
channel = user.channel;
|
||||||
|
crypto = Crypto.Mailbox.createEncryptor(keys);
|
||||||
|
|
||||||
|
// Always send your data
|
||||||
|
if (typeof(msg) === "object" && !msg.user) {
|
||||||
|
var myData = Messaging.createData(ctx.store.proxy, false);
|
||||||
|
msg.user = myData;
|
||||||
|
}
|
||||||
|
obj = {
|
||||||
|
type: type,
|
||||||
|
content: msg
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var text = JSON.stringify(obj);
|
||||||
var ciphertext = crypto.encrypt(text, user.curvePublic);
|
var ciphertext = crypto.encrypt(text, user.curvePublic);
|
||||||
|
|
||||||
// If we've sent this message to one of our teams' mailbox, we may want to "dismiss" it
|
// If we've sent this message to one of our teams' mailbox, we may want to "dismiss" it
|
||||||
|
@ -121,7 +151,7 @@ proxy.mailboxes = {
|
||||||
}
|
}
|
||||||
|
|
||||||
anonRpc.send("WRITE_PRIVATE_MESSAGE", [
|
anonRpc.send("WRITE_PRIVATE_MESSAGE", [
|
||||||
user.channel,
|
channel,
|
||||||
ciphertext
|
ciphertext
|
||||||
], function (err /*, response */) {
|
], function (err /*, response */) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -239,8 +269,11 @@ proxy.mailboxes = {
|
||||||
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 = m.keys || getMyKeys(ctx);
|
var keys = m.keys || getMyKeys(ctx);
|
||||||
if (!keys) { return void console.error("missing asymmetric encryption keys"); }
|
if (!keys && !m.decrypted) { return void console.error("missing asymmetric encryption keys"); }
|
||||||
var crypto = Crypto.Mailbox.createEncryptor(keys);
|
var crypto = m.decrypted ? {
|
||||||
|
encrypt: function (x) { return x; },
|
||||||
|
decrypt: function (x) { return x; }
|
||||||
|
} : Crypto.Mailbox.createEncryptor(keys);
|
||||||
box.encryptor = crypto;
|
box.encryptor = crypto;
|
||||||
var cfg = {
|
var cfg = {
|
||||||
network: ctx.store.network,
|
network: ctx.store.network,
|
||||||
|
|
|
@ -106,7 +106,7 @@ define([
|
||||||
|
|
||||||
// Call the onMessage handlers
|
// Call the onMessage handlers
|
||||||
var isNotification = function (type) {
|
var isNotification = function (type) {
|
||||||
return type === "notifications" || /^team-/.test(type);
|
return type === "notifications" || /^team-/.test(type) || type === "broadcast";
|
||||||
};
|
};
|
||||||
var pushMessage = function (data, handler) {
|
var pushMessage = function (data, handler) {
|
||||||
var todo = function (f) {
|
var todo = function (f) {
|
||||||
|
|
|
@ -1081,7 +1081,7 @@ MessengerUI, Messages) {
|
||||||
$button.addClass('fa-bell');
|
$button.addClass('fa-bell');
|
||||||
};
|
};
|
||||||
|
|
||||||
Common.mailbox.subscribe(['notifications', 'team'], {
|
Common.mailbox.subscribe(['notifications', 'team', 'broadcast'], {
|
||||||
onMessage: function (data, el) {
|
onMessage: function (data, el) {
|
||||||
if (el) {
|
if (el) {
|
||||||
$(div).prepend(el);
|
$(div).prepend(el);
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -445,6 +445,9 @@ define([
|
||||||
};
|
};
|
||||||
ctx.FM = common.createFileManager(fmConfig);
|
ctx.FM = common.createFileManager(fmConfig);
|
||||||
|
|
||||||
|
ui.send = function (id, type, data, dest) {
|
||||||
|
return send(ctx, id, type, data, dest);
|
||||||
|
};
|
||||||
ui.sendForm = function (id, form, dest) {
|
ui.sendForm = function (id, form, dest) {
|
||||||
return sendForm(ctx, id, form, dest);
|
return sendForm(ctx, id, form, dest);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue