|
|
|
@ -73,8 +73,9 @@ define([
|
|
|
|
|
'cp-admin-support-list',
|
|
|
|
|
'cp-admin-support-init'
|
|
|
|
|
],
|
|
|
|
|
'broadcast': [ // Msg.admin_cat_support
|
|
|
|
|
'cp-admin-broadcast-delete',
|
|
|
|
|
'broadcast': [ // Msg.admin_cat_broadcast
|
|
|
|
|
'cp-admin-maintenance',
|
|
|
|
|
'cp-admin-survey',
|
|
|
|
|
'cp-admin-broadcast',
|
|
|
|
|
],
|
|
|
|
|
'performance': [ // Msg.admin_cat_performance
|
|
|
|
@ -941,38 +942,174 @@ define([
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Messages.admin_cat_broadcast = "Broadcast"; // XXX
|
|
|
|
|
// Messages.admin_broadcastHint // XXX
|
|
|
|
|
// Messages.admin_broadcastTitle // XXX
|
|
|
|
|
|
|
|
|
|
//Messages.admin_broadcastDeleteHint // XXX
|
|
|
|
|
//Messages.admin_broadcastDeleteTitle // XXX
|
|
|
|
|
|
|
|
|
|
Messages.broadcast_new = "New message";
|
|
|
|
|
Messages.broadcast_maintenance = 'maintenance';// XXX
|
|
|
|
|
Messages.broadcast_survey = 'survey'; // XXX
|
|
|
|
|
Messages.broadcast_version = 'version'; // XXX
|
|
|
|
|
Messages.broadcast_custom = 'custom'; // XXX
|
|
|
|
|
Messages.broadcast_delete = 'delete'; // XXX
|
|
|
|
|
Messages.broadcast_newVersionReload = 'Force a worker reload on all clients'; // XXX
|
|
|
|
|
Messages.broadcast_surveyURL = 'Survey URL';
|
|
|
|
|
Messages.broadcast_translations = 'Translations';
|
|
|
|
|
Messages.broadcast_defaultLanguage = 'Fallback to this language (optional)';
|
|
|
|
|
|
|
|
|
|
Messages.admin_maintenanceTitle = "Maintenance"; // XXX
|
|
|
|
|
Messages.admin_maintenanceHint = "Plan, remove or update a maintenance. You can only have one active maintenance at a time."; // XXX
|
|
|
|
|
Messages.admin_maintenanceButton = "Plan maintenance"; // XXX
|
|
|
|
|
Messages.admin_maintenanceCancel = "Cancel planned maintenance"; // XXX
|
|
|
|
|
Messages.broadcast_start = 'Start time';
|
|
|
|
|
Messages.broadcast_end = 'End time';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Messages.admin_surveyTitle = "Survey"; // XXX
|
|
|
|
|
Messages.admin_surveyHint = "Add, update or remove the active survey accessible from the user menu"; // XXX
|
|
|
|
|
Messages.admin_surveyButton = "Apply survey"; // XXX
|
|
|
|
|
Messages.admin_surveyCancel = "Cancel active survey"; // XXX
|
|
|
|
|
Messages.admin_surveyActive = "View the active survey"; // XXX
|
|
|
|
|
Messages.broadcast_surveyURL = 'Survey URL';
|
|
|
|
|
|
|
|
|
|
Messages.admin_broadcastTitle = "Broadcast a message"; // XXX
|
|
|
|
|
Messages.admin_broadcastHint = "Send a message to all the existing and future users as a notification"; // XXX
|
|
|
|
|
Messages.admin_broadcastButton = "Send"; // XXX
|
|
|
|
|
Messages.admin_broadcastActive = "Active message"; // XXX
|
|
|
|
|
Messages.admin_broadcastCancel = "Delete active message"; // XXX
|
|
|
|
|
Messages.broadcast_translations = 'Translations';
|
|
|
|
|
Messages.broadcast_defaultLanguage = 'Fallback to this language';
|
|
|
|
|
Messages.broadcast_preview = "Preview in a fake notification";
|
|
|
|
|
Messages.broadcast_deleteBtn = "Delete for all";
|
|
|
|
|
Messages.broadcast_clear = "Clear all for everybody";
|
|
|
|
|
Messages.expired = "Expired";
|
|
|
|
|
Messages.broadcast_empty = "No active message";
|
|
|
|
|
Messages.broadcast_noFallback = "Don't fallback to a default language";
|
|
|
|
|
|
|
|
|
|
var onRefreshBroadcast = Util.mkEvent();
|
|
|
|
|
var broadcast = {
|
|
|
|
|
getData: function () { return false; },
|
|
|
|
|
reset: function () {},
|
|
|
|
|
handlers: {}
|
|
|
|
|
};
|
|
|
|
|
broadcast.handlers.custom = function ($form, button, send, preview, onPreview) {
|
|
|
|
|
|
|
|
|
|
var getApi = function (cb) {
|
|
|
|
|
return function () {
|
|
|
|
|
require(['/api/broadcast?'+ (+new Date())], function (Broadcast) {
|
|
|
|
|
cb(Broadcast);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Update the lastBroadcastHash in /api/broadcast if we can do it.
|
|
|
|
|
// To do so, find the last "BROADCAST_CUSTOM" in the current history and use the previous
|
|
|
|
|
// message's hash.
|
|
|
|
|
// If the last BROADCAST_CUSTOM has been deleted by an admin, we can use the most recent
|
|
|
|
|
// message's hash.
|
|
|
|
|
var checkLastBroadcastHash = function () {
|
|
|
|
|
var deleted = [];
|
|
|
|
|
|
|
|
|
|
require(['/api/broadcast?'+ (+new Date())], function (BCast) {
|
|
|
|
|
var hash = BCast.lastBroadcastHash || '1'; // Truthy value if no lastKnownHash
|
|
|
|
|
common.mailbox.getNotificationsHistory('broadcast', null, hash, function (e, msgs) {
|
|
|
|
|
if (e) { return void console.error(e); }
|
|
|
|
|
|
|
|
|
|
// No history, nothing to change
|
|
|
|
|
if (!Array.isArray(msgs)) { return; }
|
|
|
|
|
if (!msgs.length) { return; }
|
|
|
|
|
|
|
|
|
|
var lastHash;
|
|
|
|
|
var next = false;
|
|
|
|
|
|
|
|
|
|
// Start from the most recent messages until you find a CUSTOM message and
|
|
|
|
|
// check if it has been deleted
|
|
|
|
|
msgs.reverse().some(function (data) {
|
|
|
|
|
var c = data.content;
|
|
|
|
|
|
|
|
|
|
// This is the hash we want to keep
|
|
|
|
|
if (next) {
|
|
|
|
|
if (!c || !c.hash) { return; }
|
|
|
|
|
lastHash = c.hash;
|
|
|
|
|
next = false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// initialize with the most recent hash
|
|
|
|
|
if (!lastHash && c && c.hash) { lastHash = c.hash; }
|
|
|
|
|
|
|
|
|
|
var msg = c && c.msg;
|
|
|
|
|
if (!msg) { return; }
|
|
|
|
|
|
|
|
|
|
// Remember all deleted messages
|
|
|
|
|
if (msg.type === "BROADCAST_DELETE") {
|
|
|
|
|
deleted.push(Util.find(msg, ['content', 'uid']));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Only check custom messages
|
|
|
|
|
if (msg.type !== "BROADCAST_CUSTOM") { return; }
|
|
|
|
|
|
|
|
|
|
// If the most recent CUSTOM message has been deleted, it means we don't
|
|
|
|
|
// need to keep any message and we can continue with lastHash as the most
|
|
|
|
|
// recent broadcast message.
|
|
|
|
|
if (deleted.indexOf(msg.uid) !== -1) { return true; }
|
|
|
|
|
|
|
|
|
|
// We just found the oldest message we want to keep, move one iteration
|
|
|
|
|
// further into the loop to get the next message's hash.
|
|
|
|
|
// If this is the end of the loop, don't bump lastBroadcastHash at all.
|
|
|
|
|
next = true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// If we don't have to bump our lastBroadcastHash, abort
|
|
|
|
|
if (next) { return; }
|
|
|
|
|
|
|
|
|
|
// Otherwise, bump to lastHash
|
|
|
|
|
console.warn('Updating last broadcast hash to', lastHash);
|
|
|
|
|
sFrameChan.query('Q_ADMIN_RPC', {
|
|
|
|
|
cmd: 'ADMIN_DECREE',
|
|
|
|
|
data: ['SET_LAST_BROADCAST_HASH', [lastHash]]
|
|
|
|
|
}, function (e) {
|
|
|
|
|
if (e) {
|
|
|
|
|
console.error(e);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
console.log('lastBroadcastHash updated');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
create['broadcast'] = function () {
|
|
|
|
|
var key = 'broadcast';
|
|
|
|
|
var $div = makeBlock(key);
|
|
|
|
|
|
|
|
|
|
var form = h('div.cp-admin-broadcast-form');
|
|
|
|
|
var $form = $(form).appendTo($div);
|
|
|
|
|
|
|
|
|
|
var refresh = getApi(function (Broadcast) {
|
|
|
|
|
var button = h('button.btn.btn-primary', Messages.admin_broadcastButton);
|
|
|
|
|
var $button = $(button);
|
|
|
|
|
var removeButton = h('button.btn.btn-danger', Messages.admin_broadcastCancel);
|
|
|
|
|
var active = h('div.cp-broadcast-active', h('p', Messages.admin_broadcastActive));
|
|
|
|
|
var $active = $(active);
|
|
|
|
|
var activeUid;
|
|
|
|
|
var deleted = [];
|
|
|
|
|
|
|
|
|
|
// Render active message (if there is one)
|
|
|
|
|
require(['/api/broadcast?'+ (+new Date())], function (BCast) {
|
|
|
|
|
var hash = BCast.lastBroadcastHash || '1'; // Truthy value if no lastKnownHash
|
|
|
|
|
common.mailbox.getNotificationsHistory('broadcast', null, hash, function (e, msgs) {
|
|
|
|
|
if (e) { return void console.error(e); }
|
|
|
|
|
if (!Array.isArray(msgs)) { return; }
|
|
|
|
|
if (!msgs.length) {
|
|
|
|
|
$active.hide();
|
|
|
|
|
}
|
|
|
|
|
msgs.reverse().some(function (data) {
|
|
|
|
|
var c = data.content;
|
|
|
|
|
var msg = c && c.msg;
|
|
|
|
|
if (!msg) { return; }
|
|
|
|
|
if (msg.type === "BROADCAST_DELETE") {
|
|
|
|
|
deleted.push(Util.find(msg, ['content', 'uid']));
|
|
|
|
|
}
|
|
|
|
|
if (msg.type !== "BROADCAST_CUSTOM") { return; }
|
|
|
|
|
if (deleted.indexOf(msg.uid) !== -1) { return true; }
|
|
|
|
|
|
|
|
|
|
// We found an active custom message, show it
|
|
|
|
|
var el = common.mailbox.createElement(data);
|
|
|
|
|
var table = h('table.cp-broadcast-delete');
|
|
|
|
|
var $table = $(table);
|
|
|
|
|
var uid = Util.find(data, ['content', 'msg', 'uid']);
|
|
|
|
|
var time = Util.find(data, ['content', 'msg', 'content', 'time']);
|
|
|
|
|
var tr = h('tr', { 'data-uid': uid }, [
|
|
|
|
|
h('td', 'ID: '+uid),
|
|
|
|
|
h('td', new Date(time || 0).toLocaleString()),
|
|
|
|
|
h('td', el),
|
|
|
|
|
h('td.delete', removeButton),
|
|
|
|
|
]);
|
|
|
|
|
$table.append(tr);
|
|
|
|
|
$active.append(table);
|
|
|
|
|
activeUid = uid;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
if (!activeUid) { $active.hide(); }
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Custom message
|
|
|
|
|
var container = h('div.cp-broadcast-container');
|
|
|
|
|
var $container = $(container);
|
|
|
|
@ -988,22 +1125,36 @@ define([
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var noFallbackBtn = h('button.btn.btn-secondary.cp-broadcast-preview',
|
|
|
|
|
Messages.broadcast_noFallback);
|
|
|
|
|
var $noFallbackBtn = $(noFallbackBtn);
|
|
|
|
|
var checkFallbackBtn = function () {
|
|
|
|
|
// Remove a textarea
|
|
|
|
|
var removeLang = function (l) {
|
|
|
|
|
$container.find('.cp-broadcast-lang[data-lang="'+l+'"]').remove();
|
|
|
|
|
|
|
|
|
|
var hasDefault = $container.find('.cp-broadcast-lang .cp-checkmark input:checked').length;
|
|
|
|
|
if (hasDefault) {
|
|
|
|
|
$noFallbackBtn.css('visibility', '');
|
|
|
|
|
} else {
|
|
|
|
|
$noFallbackBtn.css('visibility', 'hidden');
|
|
|
|
|
if (!hasDefault) {
|
|
|
|
|
$container.find('.cp-broadcast-lang').first().find('.cp-checkmark input').prop('checked', 'checked');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Remove a textarea
|
|
|
|
|
var removeLang = function (l) {
|
|
|
|
|
$container.find('.cp-broadcast-lang[data-lang="'+l+'"]').remove();
|
|
|
|
|
checkFallbackBtn();
|
|
|
|
|
var getData = function () { return false; };
|
|
|
|
|
var onPreview = function (l) {
|
|
|
|
|
var data = getData();
|
|
|
|
|
if (data === false) { return void UI.warn(Messages.error); }
|
|
|
|
|
|
|
|
|
|
var msg = {
|
|
|
|
|
uid: Util.uid(),
|
|
|
|
|
type: 'BROADCAST_CUSTOM',
|
|
|
|
|
content: data
|
|
|
|
|
};
|
|
|
|
|
common.mailbox.onMessage({
|
|
|
|
|
lang: l,
|
|
|
|
|
type: 'broadcast',
|
|
|
|
|
content: {
|
|
|
|
|
msg: msg,
|
|
|
|
|
hash: 'LOCAL|' + JSON.stringify(msg).slice(0,58)
|
|
|
|
|
}
|
|
|
|
|
}, function () {
|
|
|
|
|
UI.log(Messages.saved);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Add a textarea
|
|
|
|
@ -1019,9 +1170,6 @@ define([
|
|
|
|
|
'data-lang': l,
|
|
|
|
|
label: {class: 'noTitle'}
|
|
|
|
|
});
|
|
|
|
|
$(radio).find('input').on('change', function () {
|
|
|
|
|
checkFallbackBtn();
|
|
|
|
|
});
|
|
|
|
|
$container.append(h('div.cp-broadcast-lang', { 'data-lang': l }, [
|
|
|
|
|
h('h4', languages[l]),
|
|
|
|
|
h('label', Messages.kanban_body),
|
|
|
|
@ -1029,7 +1177,6 @@ define([
|
|
|
|
|
radio,
|
|
|
|
|
preview
|
|
|
|
|
]));
|
|
|
|
|
checkFallbackBtn();
|
|
|
|
|
reorder();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -1051,7 +1198,7 @@ define([
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Extract form data
|
|
|
|
|
broadcast.getData = function () {
|
|
|
|
|
getData = function () {
|
|
|
|
|
var map = {};
|
|
|
|
|
var defaultLanguage;
|
|
|
|
|
var error = false;
|
|
|
|
@ -1079,33 +1226,85 @@ define([
|
|
|
|
|
content: map
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
// Clear all the textarea when sent
|
|
|
|
|
broadcast.reset = function () {
|
|
|
|
|
$container.find('.cp-broadcast-lang textarea').each(function (i, el) {
|
|
|
|
|
$(el).val('');
|
|
|
|
|
|
|
|
|
|
var send = function (data) {
|
|
|
|
|
$button.prop('disabled', 'disabled');
|
|
|
|
|
data.time = +new Date();
|
|
|
|
|
common.mailbox.sendTo('BROADCAST_CUSTOM', data, {}, function (err, data) {
|
|
|
|
|
if (err) {
|
|
|
|
|
$button.prop('disabled', '');
|
|
|
|
|
console.error(err);
|
|
|
|
|
return UI.warn(Messages.error);
|
|
|
|
|
}
|
|
|
|
|
UI.log(Messages.saved);
|
|
|
|
|
refresh();
|
|
|
|
|
|
|
|
|
|
checkLastBroadcastHash();
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// "Don't fallback to a default language" button
|
|
|
|
|
$noFallbackBtn.click(function () {
|
|
|
|
|
$container.find('.cp-checkmark input').prop('checked', false);
|
|
|
|
|
$noFallbackBtn.css('visibility', 'hidden');
|
|
|
|
|
$button.click(function () {
|
|
|
|
|
var data = getData();
|
|
|
|
|
if (data === false) { return void UI.warn(Messages.error); }
|
|
|
|
|
send(data);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
UI.confirmButton(removeButton, {
|
|
|
|
|
classes: 'btn-danger',
|
|
|
|
|
}, function () {
|
|
|
|
|
if (!activeUid) { return; }
|
|
|
|
|
common.mailbox.sendTo('BROADCAST_DELETE', {
|
|
|
|
|
uid: activeUid
|
|
|
|
|
}, {}, function (err, data) {
|
|
|
|
|
if (err) { return UI.warn(Messages.error); }
|
|
|
|
|
UI.log(Messages.saved);
|
|
|
|
|
refresh();
|
|
|
|
|
checkLastBroadcastHash();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Make the form
|
|
|
|
|
$form.append([
|
|
|
|
|
$form.empty().append([
|
|
|
|
|
active,
|
|
|
|
|
h('label', Messages.broadcast_translations),
|
|
|
|
|
h('div.cp-broadcast-languages', boxes),
|
|
|
|
|
container,
|
|
|
|
|
h('div.cp-broadcast-form-submit', [
|
|
|
|
|
noFallbackBtn,
|
|
|
|
|
h('br'),
|
|
|
|
|
button
|
|
|
|
|
])
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
refresh();
|
|
|
|
|
|
|
|
|
|
return $div;
|
|
|
|
|
};
|
|
|
|
|
broadcast.handlers.maintenance = function ($form, button, send, preview) {
|
|
|
|
|
// Maintenance message
|
|
|
|
|
|
|
|
|
|
create['maintenance'] = function () {
|
|
|
|
|
var key = 'maintenance';
|
|
|
|
|
var $div = makeBlock(key);
|
|
|
|
|
|
|
|
|
|
var form = h('div.cp-admin-broadcast-form');
|
|
|
|
|
var $form = $(form).appendTo($div);
|
|
|
|
|
|
|
|
|
|
var refresh = getApi(function (Broadcast) {
|
|
|
|
|
var button = h('button.btn.btn-primary', Messages.admin_maintenanceButton);
|
|
|
|
|
var $button = $(button);
|
|
|
|
|
var removeButton = h('button.btn.btn-danger', Messages.admin_maintenanceCancel);
|
|
|
|
|
var active;
|
|
|
|
|
|
|
|
|
|
if (Broadcast && Broadcast.maintenance) {
|
|
|
|
|
var m = Broadcast.maintenance;
|
|
|
|
|
if (m.start && m.end && m.end >= (+new Date())) {
|
|
|
|
|
active = h('div.cp-broadcast-active', [
|
|
|
|
|
UI.setHTML(h('p'), Messages._getKey('broadcast_maintenance', [
|
|
|
|
|
new Date(m.start).toLocaleString(),
|
|
|
|
|
new Date(m.end).toLocaleString(),
|
|
|
|
|
])),
|
|
|
|
|
removeButton
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Start and end date pickers
|
|
|
|
|
var start = h('input');
|
|
|
|
@ -1125,7 +1324,7 @@ define([
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Extract form data
|
|
|
|
|
broadcast.getData = function () {
|
|
|
|
|
var getData = function () {
|
|
|
|
|
var start = +new Date($start.val());
|
|
|
|
|
var end = +new Date($end.val());
|
|
|
|
|
if (isNaN(start) || isNaN(end)) {
|
|
|
|
@ -1138,349 +1337,137 @@ define([
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Clear when sent
|
|
|
|
|
broadcast.reset = function () {
|
|
|
|
|
$start.val('');
|
|
|
|
|
$end.val('');
|
|
|
|
|
};
|
|
|
|
|
$form.append([
|
|
|
|
|
h('label', Messages.broadcast_start),
|
|
|
|
|
start,
|
|
|
|
|
h('label', Messages.broadcast_end),
|
|
|
|
|
end,
|
|
|
|
|
h('br'),
|
|
|
|
|
h('div.cp-broadcast-form-submit', [
|
|
|
|
|
button,
|
|
|
|
|
preview
|
|
|
|
|
])
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
broadcast.handlers.version = function ($form, button, send, preview) {
|
|
|
|
|
// New version available message
|
|
|
|
|
|
|
|
|
|
// This checkbox can be used to trigger a fake "reconnect" event on the clients
|
|
|
|
|
// so that they can check api/config and reload the worker in case of a new version
|
|
|
|
|
var $cbox = $(UI.createCheckbox('cp-admin-version-reload',
|
|
|
|
|
Messages.broadcast_newVersionReload,
|
|
|
|
|
false, { label: { class: 'noTitle' } }));
|
|
|
|
|
var $checkbox = $cbox.find('input');
|
|
|
|
|
|
|
|
|
|
// Extract the data and make the form
|
|
|
|
|
broadcast.getData = function () {
|
|
|
|
|
return {
|
|
|
|
|
reload: $checkbox.is(':checked')
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
broadcast.reset = function () {
|
|
|
|
|
$checkbox[0].checked = false;
|
|
|
|
|
};
|
|
|
|
|
$form.append([
|
|
|
|
|
$cbox[0],
|
|
|
|
|
h('br'),
|
|
|
|
|
h('div.cp-broadcast-form-submit', [
|
|
|
|
|
button,
|
|
|
|
|
preview
|
|
|
|
|
])
|
|
|
|
|
]);
|
|
|
|
|
};
|
|
|
|
|
broadcast.handlers.survey = function ($form, button, send, preview) {
|
|
|
|
|
// New survey message
|
|
|
|
|
// TODO send different URLs for other languages?
|
|
|
|
|
var label = h('label', Messages.broadcast_surveyURL);
|
|
|
|
|
var input = h('input');
|
|
|
|
|
var $input = $(input);
|
|
|
|
|
broadcast.getData = function () {
|
|
|
|
|
var url = $input.val();
|
|
|
|
|
if (!Util.isValidURL(url)) {
|
|
|
|
|
console.error('Invalid URL');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
url: url
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
broadcast.reset = function () {
|
|
|
|
|
$input.val('');
|
|
|
|
|
};
|
|
|
|
|
$(button).off('click').click(function () {
|
|
|
|
|
var data = broadcast.getData();
|
|
|
|
|
var val = $input.val() || '';
|
|
|
|
|
|
|
|
|
|
// Invalid url: abort
|
|
|
|
|
// NOTE: empty strings are allowed to remove a surveyURL from the decrees
|
|
|
|
|
// XXX usability...
|
|
|
|
|
if (!data && val) { return void UI.warn(Messages.error); }
|
|
|
|
|
|
|
|
|
|
var url = data ? data.url : val;
|
|
|
|
|
|
|
|
|
|
var send = function (data) {
|
|
|
|
|
$button.prop('disabled', 'disabled');
|
|
|
|
|
sFrameChan.query('Q_ADMIN_RPC', {
|
|
|
|
|
cmd: 'ADMIN_DECREE',
|
|
|
|
|
data: ['SET_SURVEY_URL', [url]]
|
|
|
|
|
data: ['SET_MAINTENANCE', [data]]
|
|
|
|
|
}, function (e) {
|
|
|
|
|
if (e) {
|
|
|
|
|
UI.warn(Messages.error); console.error(e);
|
|
|
|
|
$button.prop('disabled', '');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!url) { return; }
|
|
|
|
|
send();
|
|
|
|
|
// Maintenance applied, send notification
|
|
|
|
|
common.mailbox.sendTo('BROADCAST_MAINTENANCE', {}, {}, function (err, data) {
|
|
|
|
|
refresh();
|
|
|
|
|
checkLastBroadcastHash();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
$form.append([
|
|
|
|
|
label,
|
|
|
|
|
input,
|
|
|
|
|
h('br'),
|
|
|
|
|
h('div.cp-broadcast-form-submit', [
|
|
|
|
|
button,
|
|
|
|
|
preview
|
|
|
|
|
])
|
|
|
|
|
]);
|
|
|
|
|
};
|
|
|
|
|
broadcast.handlers.delete = function ($form, button, send) {
|
|
|
|
|
require(['/api/broadcast?'+ (+new Date())], function (BCast) {
|
|
|
|
|
|
|
|
|
|
// Always display the messages from the instance "lastBroadcastHash"
|
|
|
|
|
var hash = BCast.lastBroadcastHash || '1'; // Truthy value if no lastKnownHash
|
|
|
|
|
common.mailbox.getNotificationsHistory('broadcast', null, hash, function (e, msgs) {
|
|
|
|
|
var table = h('table.cp-broadcast-delete');
|
|
|
|
|
var $table = $(table);
|
|
|
|
|
|
|
|
|
|
// Empty history
|
|
|
|
|
if (!msgs.length) {
|
|
|
|
|
$table.append(h('tr.empty', h('td', Messages.broadcast_empty)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build the table
|
|
|
|
|
msgs.forEach(function (data) {
|
|
|
|
|
var el = common.mailbox.createElement(data);
|
|
|
|
|
var t = Util.find(data, ['content', 'msg', 'type']);
|
|
|
|
|
|
|
|
|
|
// A "DELETE" message is here to disable a previous line
|
|
|
|
|
if (t === 'BROADCAST_DELETE') {
|
|
|
|
|
var _uid = Util.find(data, ['content', 'msg', 'content', 'uid']);
|
|
|
|
|
var $button = $table.find('[data-uid="'+_uid+'"] td.delete button');
|
|
|
|
|
$button.prop('disabled', 'disabled').text(Messages.deleted);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make the line
|
|
|
|
|
var uid = Util.find(data, ['content', 'msg', 'uid']);
|
|
|
|
|
var time = Util.find(data, ['content', 'msg', 'content', 'time']);
|
|
|
|
|
var deleteBtn = h('button.btn.btn-danger', Messages.broadcast_deleteBtn);
|
|
|
|
|
var tr = h('tr', { 'data-uid': uid }, [
|
|
|
|
|
h('td', 'ID: '+uid),
|
|
|
|
|
h('td', new Date(time || 0).toLocaleString()),
|
|
|
|
|
h('td', el),
|
|
|
|
|
h('td.delete', deleteBtn),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Auto-expire maintenance and survey messages
|
|
|
|
|
if (t === 'BROADCAST_MAINTENANCE') {
|
|
|
|
|
var end = Util.find(data, ['content', 'msg', 'content', 'end']);
|
|
|
|
|
if (end < +new Date()) {
|
|
|
|
|
$(deleteBtn).prop('disabled', 'disabled').text(Messages.expired);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (t === 'BROADCAST_VERSION') {
|
|
|
|
|
$(deleteBtn).prop('disabled', 'disabled').text(Messages.expired);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// "Delete this message" button
|
|
|
|
|
UI.confirmButton(deleteBtn, {
|
|
|
|
|
classes: 'btn-danger',
|
|
|
|
|
multiple: true
|
|
|
|
|
}, function () {
|
|
|
|
|
broadcast.getData = function () {
|
|
|
|
|
if (!uid) { return false; }
|
|
|
|
|
return { uid: uid };
|
|
|
|
|
};
|
|
|
|
|
broadcast.reset = function () {
|
|
|
|
|
$(deleteBtn).prop('disabled', 'disabled').text(Messages.deleted);
|
|
|
|
|
};
|
|
|
|
|
send();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$table.append(tr);
|
|
|
|
|
$button.click(function () {
|
|
|
|
|
var data = getData();
|
|
|
|
|
if (data === false) { return void UI.warn(Messages.error); }
|
|
|
|
|
send(data);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Clear all button: remove all the messages and bump lastBroadcastHash
|
|
|
|
|
var clearAll = h('button.btn.btn-danger', Messages.broadcast_clear);
|
|
|
|
|
UI.confirmButton(clearAll, {
|
|
|
|
|
UI.confirmButton(removeButton, {
|
|
|
|
|
classes: 'btn-danger',
|
|
|
|
|
multiple: true
|
|
|
|
|
}, function () {
|
|
|
|
|
broadcast.getData = function () {
|
|
|
|
|
return { all: true };
|
|
|
|
|
};
|
|
|
|
|
broadcast.reset = function () {};
|
|
|
|
|
|
|
|
|
|
// Send a message to all users telling them to wipe the broadcast mailbox
|
|
|
|
|
// and on success, send an admin decree to update /api/broadcast
|
|
|
|
|
send(function (err, obj) {
|
|
|
|
|
if (err) { return; }
|
|
|
|
|
if (!obj || !obj.hash) { return; }
|
|
|
|
|
/*
|
|
|
|
|
sFrameChan.query('Q_ADMIN_RPC', {
|
|
|
|
|
cmd: 'ADMIN_DECREE',
|
|
|
|
|
data: ['SET_LAST_BROADCAST_HASH', [obj.hash]]
|
|
|
|
|
}, function (e) {
|
|
|
|
|
if (e) {
|
|
|
|
|
UI.warn(Messages.error); console.error(e);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// On success, reload the "delete" tab
|
|
|
|
|
onRefreshBroadcast.fire();
|
|
|
|
|
});
|
|
|
|
|
*/
|
|
|
|
|
});
|
|
|
|
|
send("");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$form.append([
|
|
|
|
|
table,
|
|
|
|
|
msgs.length ? clearAll : undefined
|
|
|
|
|
$form.empty().append([
|
|
|
|
|
active,
|
|
|
|
|
h('label', Messages.broadcast_start),
|
|
|
|
|
start,
|
|
|
|
|
h('label', Messages.broadcast_end),
|
|
|
|
|
end,
|
|
|
|
|
h('br'),
|
|
|
|
|
h('div.cp-broadcast-form-submit', [
|
|
|
|
|
button
|
|
|
|
|
])
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
refresh();
|
|
|
|
|
|
|
|
|
|
return $div;
|
|
|
|
|
};
|
|
|
|
|
create['survey'] = function () {
|
|
|
|
|
var key = 'survey';
|
|
|
|
|
var $div = makeBlock(key);
|
|
|
|
|
|
|
|
|
|
var getBroadcastForm = function ($form, key) {
|
|
|
|
|
$form.empty();
|
|
|
|
|
var form = h('div.cp-admin-broadcast-form');
|
|
|
|
|
var $form = $(form).appendTo($div);
|
|
|
|
|
|
|
|
|
|
var button = h('button.btn.btn-primary', Messages.support_formButton);
|
|
|
|
|
var refresh = getApi(function (Broadcast) {
|
|
|
|
|
var button = h('button.btn.btn-primary', Messages.admin_surveyButton);
|
|
|
|
|
var $button = $(button);
|
|
|
|
|
|
|
|
|
|
var send = function (_cb) {
|
|
|
|
|
var cb = Util.once(_cb || function () {});
|
|
|
|
|
var data = broadcast.getData();
|
|
|
|
|
if (data === false) {
|
|
|
|
|
cb('NODATA');
|
|
|
|
|
return void UI.warn(Messages.error);
|
|
|
|
|
var removeButton = h('button.btn.btn-danger', Messages.admin_surveyCancel);
|
|
|
|
|
var active;
|
|
|
|
|
|
|
|
|
|
if (Broadcast && Broadcast.surveyURL) {
|
|
|
|
|
var a = h('a', {href: Broadcast.surveyURL}, Messages.admin_surveyActive);
|
|
|
|
|
$(a).click(function (e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
common.openUnsafeURL(Broadcast.surveyURL);
|
|
|
|
|
});
|
|
|
|
|
active = h('div.cp-broadcast-active', [
|
|
|
|
|
h('p', a),
|
|
|
|
|
removeButton
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
$button.prop('disabled', 'disabled');
|
|
|
|
|
data.time = +new Date();
|
|
|
|
|
common.mailbox.sendTo('BROADCAST_'+key.toUpperCase(), data, {}, function (err, data) {
|
|
|
|
|
$button.prop('disabled', '');
|
|
|
|
|
cb(err, data);
|
|
|
|
|
if (err) {
|
|
|
|
|
console.error(err);
|
|
|
|
|
return UI.warn(Messages.error);
|
|
|
|
|
|
|
|
|
|
// Survey form
|
|
|
|
|
var label = h('label', Messages.broadcast_surveyURL);
|
|
|
|
|
var input = h('input');
|
|
|
|
|
var $input = $(input);
|
|
|
|
|
|
|
|
|
|
// Extract form data
|
|
|
|
|
var getData = function () {
|
|
|
|
|
var url = $input.val();
|
|
|
|
|
if (!Util.isValidURL(url)) {
|
|
|
|
|
console.error('Invalid URL');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return url;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var send = function (data) {
|
|
|
|
|
$button.prop('disabled', 'disabled');
|
|
|
|
|
sFrameChan.query('Q_ADMIN_RPC', {
|
|
|
|
|
cmd: 'ADMIN_DECREE',
|
|
|
|
|
data: ['SET_LAST_BROADCAST_HASH', [data.hash]]
|
|
|
|
|
data: ['SET_SURVEY_URL', [data]]
|
|
|
|
|
}, function (e) {
|
|
|
|
|
if (e) {
|
|
|
|
|
$button.prop('disabled', '');
|
|
|
|
|
UI.warn(Messages.error); console.error(e);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// On success, reload the "delete" tab
|
|
|
|
|
onRefreshBroadcast.fire();
|
|
|
|
|
// Maintenance applied, send notification
|
|
|
|
|
common.mailbox.sendTo('BROADCAST_SURVEY', {}, {}, function (err, data) {
|
|
|
|
|
refresh();
|
|
|
|
|
checkLastBroadcastHash();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Only print success if there is no callback
|
|
|
|
|
if (!_cb) {
|
|
|
|
|
UI.log(Messages.saved);
|
|
|
|
|
// Clear the UI
|
|
|
|
|
broadcast.reset();
|
|
|
|
|
onRefreshBroadcast.fire();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
$button.click(function () {
|
|
|
|
|
send();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var onPreview = function (l) {
|
|
|
|
|
var data = broadcast.getData();
|
|
|
|
|
var data = getData();
|
|
|
|
|
if (data === false) { return void UI.warn(Messages.error); }
|
|
|
|
|
var msg = {
|
|
|
|
|
uid: Util.uid(),
|
|
|
|
|
type: 'BROADCAST_'+key.toUpperCase(),
|
|
|
|
|
content: data
|
|
|
|
|
};
|
|
|
|
|
common.mailbox.onMessage({
|
|
|
|
|
lang: l,
|
|
|
|
|
type: 'broadcast',
|
|
|
|
|
content: {
|
|
|
|
|
msg: msg,
|
|
|
|
|
hash: 'LOCAL|' + JSON.stringify(msg).slice(0,58)
|
|
|
|
|
}
|
|
|
|
|
}, function () {
|
|
|
|
|
UI.log(Messages.saved);
|
|
|
|
|
send(data);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
var preview = h('button.cp-broadcast-preview.btn.btn-secondary', Messages.broadcast_preview);
|
|
|
|
|
$(preview).click(function () {
|
|
|
|
|
onPreview();
|
|
|
|
|
UI.confirmButton(removeButton, {
|
|
|
|
|
classes: 'btn-danger',
|
|
|
|
|
}, function () {
|
|
|
|
|
send("");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var handler = broadcast.handlers[key];
|
|
|
|
|
if (!handler) { return; } // XXX
|
|
|
|
|
handler($form, button, send, preview, onPreview);
|
|
|
|
|
};
|
|
|
|
|
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',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// The "version" message only works if the instance is using a manual /api/config
|
|
|
|
|
// This is a custom setup for which our team won't provide support and is NOT
|
|
|
|
|
// recommended unless you know exactly what you're doing.
|
|
|
|
|
if (!AppConfig.customApiConfig) { categories.splice(2,1); }
|
|
|
|
|
|
|
|
|
|
categories = categories.map(function (key) {
|
|
|
|
|
return {
|
|
|
|
|
tag: 'a',
|
|
|
|
|
content: h('span', Messages['broadcast_'+key]),
|
|
|
|
|
action: function () {
|
|
|
|
|
getBroadcastForm($form, key);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
$form.empty().append([
|
|
|
|
|
active,
|
|
|
|
|
label,
|
|
|
|
|
input,
|
|
|
|
|
h('br'),
|
|
|
|
|
h('div.cp-broadcast-form-submit', [
|
|
|
|
|
button
|
|
|
|
|
])
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
var dropdownCfg = {
|
|
|
|
|
text: Messages.broadcast_new,
|
|
|
|
|
angleDown: 1,
|
|
|
|
|
options: categories,
|
|
|
|
|
container: $select,
|
|
|
|
|
isSelect: true,
|
|
|
|
|
buttonCls: 'btn btn-default'
|
|
|
|
|
};
|
|
|
|
|
UIElements.createDropdown(dropdownCfg);
|
|
|
|
|
|
|
|
|
|
refresh();
|
|
|
|
|
|
|
|
|
|
return $div;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
create['broadcast-delete'] = function () {
|
|
|
|
|
var key = 'broadcast-delete';
|
|
|
|
|
var $div = makeBlock(key);
|
|
|
|
|
|
|
|
|
|
var form = h('div.cp-admin-broadcast-form');
|
|
|
|
|
var $form = $(form).appendTo($div);
|
|
|
|
|
getBroadcastForm($form, 'delete');
|
|
|
|
|
onRefreshBroadcast.reg(function () {
|
|
|
|
|
getBroadcastForm($form, 'delete');
|
|
|
|
|
});
|
|
|
|
|
return $div;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var onRefreshPerformance = Util.mkEvent();
|
|
|
|
|
|
|
|
|
|
create['refresh-performance'] = function () {
|
|
|
|
|