Merge branch 'broadcast' into calendar
commit
67f0ab2484
20
CHANGELOG.md
20
CHANGELOG.md
|
@ -1,3 +1,23 @@
|
|||
# WIP
|
||||
|
||||
* OnlyOffice
|
||||
* inform OnlyOffice of userlist changes
|
||||
* rename doc and slide editors
|
||||
* handle different lock formats for docs and slides
|
||||
* relative to sheets
|
||||
* handle some cursor logic outside of sheets
|
||||
* handle locks when integrating remote checkpoints in strict mode
|
||||
* OnlyOffice renamed buttons in slides and docs and we need to hardcode CSS that hides them by their randomly generated IDs
|
||||
* support CryptPad cursor colors in OnlyOffice by adding opacity value
|
||||
* use the appropriate APIs to detect if the document is modified
|
||||
* display users cursor colors in the toolbar next to their name
|
||||
* handle errors when migrating in embed mode
|
||||
* change the method we use to lock the whole sheet since OnlyOffice changed their internal API's behaviour
|
||||
* bad channel IDs stored in your drive or accessed via bad links (corrupted somehow)
|
||||
* don't try to join invalid channels
|
||||
* don't try to get their metadata
|
||||
* prompt premium users to cancel their subscriptions before deleting their accounts
|
||||
|
||||
# 4.3.1
|
||||
|
||||
This minor release addresses some bugs discovered after deploying and tagging 4.3.0
|
||||
|
|
|
@ -12,6 +12,17 @@ Data.getMetadataRaw = function (Env, channel /* channelName */, _cb) {
|
|||
if (channel.length !== HK.STANDARD_CHANNEL_LENGTH &&
|
||||
channel.length !== HK.ADMIN_CHANNEL_LENGTH) { return cb("INVALID_CHAN_LENGTH"); }
|
||||
|
||||
// return synthetic metadata for admin broadcast channels as a safety net
|
||||
// in case anybody manages to write metadata
|
||||
/*
|
||||
if (channel.length === HK.ADMIN_CHANNEL_LENGTH) { // XXX
|
||||
return void cb(void 0, {
|
||||
channel: channel,
|
||||
creation: +new Date(),
|
||||
owners: Env.admins,
|
||||
});
|
||||
} */
|
||||
|
||||
var cached = Env.metadata_cache[channel];
|
||||
if (HK.isMetadataMessage(cached)) {
|
||||
Env.checkCache(channel);
|
||||
|
@ -141,7 +152,7 @@ Data.setMetadata = function (Env, safeKey, data, cb, Server) {
|
|||
const metadata_cache = Env.metadata_cache;
|
||||
|
||||
// update the cached metadata
|
||||
metadata_cache[channel] = metadata;
|
||||
metadata_cache[channel] = metadata; // XXX guard against malicious takeover of the broadcast channel
|
||||
|
||||
// it's easy to check if the channel is restricted
|
||||
const isRestricted = metadata.restricted;
|
||||
|
|
|
@ -27,6 +27,7 @@ DISABLE_INTEGRATED_EVICTION
|
|||
// BROADCAST
|
||||
SET_LAST_BROADCAST_HASH
|
||||
SET_SURVEY_URL
|
||||
SET_MAINTENANCE
|
||||
|
||||
NOT IMPLEMENTED:
|
||||
|
||||
|
@ -129,10 +130,10 @@ var args_isString = function (args) {
|
|||
return Array.isArray(args) && typeof(args[0]) === "string";
|
||||
};
|
||||
var args_isMaintenance = function (args) {
|
||||
return Array.isArray(args) && args[0] && args[0].end && args[0].start;
|
||||
return Array.isArray(args) && args[0] && args[0].end && args[0].start; // XXX we could validate that these are numbers && !isNaN
|
||||
};
|
||||
|
||||
var makeBroadcastSetter = function (attr) {
|
||||
var makeBroadcastSetter = function (attr) { // XXX could pass extra validation here?
|
||||
return function (Env, args) {
|
||||
if (!args_isString(args) && !args_isMaintenance(args)) {
|
||||
throw new Error('INVALID_ARGS');
|
||||
|
@ -149,7 +150,7 @@ var makeBroadcastSetter = function (attr) {
|
|||
commands.SET_LAST_BROADCAST_HASH = makeBroadcastSetter('lastBroadcastHash');
|
||||
|
||||
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_SURVEY_URL', [url]]], console.log)
|
||||
commands.SET_SURVEY_URL = makeBroadcastSetter('surveyURL');
|
||||
commands.SET_SURVEY_URL = makeBroadcastSetter('surveyURL'); // XXX anticipate language-specific surveys
|
||||
|
||||
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_MAINTENANCE', [{start: +Date, end: +Date}]]], console.log)
|
||||
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_MAINTENANCE', [""]]], console.log)
|
||||
|
|
|
@ -113,8 +113,7 @@ var setHeaders = (function () {
|
|||
|
||||
// Don't set CSP headers on /api/config because they aren't necessary and they cause problems
|
||||
// when duplicated by NGINX in production environments
|
||||
// XXX /api/broadcast too?
|
||||
if (/^\/api\/config/.test(req.url)) { return; }
|
||||
if (/^\/api\/(broadcast|config)/.test(req.url)) { return; }
|
||||
// targeted CSP, generic policies, maybe custom headers
|
||||
const h = [
|
||||
/^\/common\/onlyoffice\/.*\/index\.html.*/,
|
||||
|
@ -273,7 +272,7 @@ var serveConfig = (function () {
|
|||
};
|
||||
}());
|
||||
|
||||
var serveBroadcast = (function () {
|
||||
var serveBroadcast = (function () { // XXX deduplicate
|
||||
var cacheString = function () {
|
||||
return (Env.FRESH_KEY? '-' + Env.FRESH_KEY: '') + (Env.DEV_MODE? '-' + (+new Date()): '');
|
||||
};
|
||||
|
@ -284,7 +283,7 @@ var serveBroadcast = (function () {
|
|||
maintenance = undefined;
|
||||
}
|
||||
return [
|
||||
'define(function(){',
|
||||
'define(function(){', // XXX maybe this could just be JSON
|
||||
'return ' + JSON.stringify({
|
||||
lastBroadcastHash: Env.lastBroadcastHash,
|
||||
surveyURL: Env.surveyURL,
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
a {
|
||||
color: @cryptpad_color_link;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.cp-admin-setlimit-form, .cp-admin-broadcast-form {
|
||||
label {
|
||||
|
|
|
@ -970,6 +970,7 @@ define([
|
|||
var getApi = function (cb) {
|
||||
return function () {
|
||||
require(['/api/broadcast?'+ (+new Date())], function (Broadcast) {
|
||||
// XXX require.s.contexts._ can be used to erase old loaded objects
|
||||
cb(Broadcast);
|
||||
});
|
||||
};
|
||||
|
@ -1060,7 +1061,7 @@ define([
|
|||
var form = h('div.cp-admin-broadcast-form');
|
||||
var $form = $(form).appendTo($div);
|
||||
|
||||
var refresh = getApi(function (Broadcast) {
|
||||
var refresh = getApi(function (/* Broadcast */) { // XXX unused argument
|
||||
var button = h('button.btn.btn-primary', Messages.admin_broadcastButton);
|
||||
var $button = $(button);
|
||||
var removeButton = h('button.btn.btn-danger', Messages.admin_broadcastCancel);
|
||||
|
@ -1219,7 +1220,7 @@ define([
|
|||
}
|
||||
if (error) {
|
||||
console.error('One of the selected languages has no data');
|
||||
return false;
|
||||
return false; // XXX better error handling?
|
||||
}
|
||||
return {
|
||||
defaultLanguage: defaultLanguage,
|
||||
|
@ -1229,8 +1230,8 @@ define([
|
|||
|
||||
var send = function (data) {
|
||||
$button.prop('disabled', 'disabled');
|
||||
data.time = +new Date();
|
||||
common.mailbox.sendTo('BROADCAST_CUSTOM', data, {}, function (err, data) {
|
||||
data.time = +new Date(); // XXX not used anymore?
|
||||
common.mailbox.sendTo('BROADCAST_CUSTOM', data, {}, function (err /*, data */) { // XXX unused argument
|
||||
if (err) {
|
||||
$button.prop('disabled', '');
|
||||
console.error(err);
|
||||
|
@ -1249,13 +1250,13 @@ define([
|
|||
send(data);
|
||||
});
|
||||
|
||||
UI.confirmButton(removeButton, {
|
||||
UI.confirmButton(removeButton, { // XXX table jank
|
||||
classes: 'btn-danger',
|
||||
}, function () {
|
||||
if (!activeUid) { return; }
|
||||
common.mailbox.sendTo('BROADCAST_DELETE', {
|
||||
uid: activeUid
|
||||
}, {}, function (err, data) {
|
||||
}, {}, function (err /* , data */) { // XXX unused argument
|
||||
if (err) { return UI.warn(Messages.error); }
|
||||
UI.log(Messages.saved);
|
||||
refresh();
|
||||
|
@ -1311,7 +1312,8 @@ define([
|
|||
var end = h('input');
|
||||
var $start = $(start);
|
||||
var $end = $(end);
|
||||
var endPickr = Flatpickr(end, {
|
||||
// XXX new Date().toLocaleString('fr-fr', {month: 'long'}).replace(/./, c => c.toUpperCase())
|
||||
var endPickr = Flatpickr(end, { // XXX translations?
|
||||
enableTime: true,
|
||||
minDate: new Date()
|
||||
});
|
||||
|
@ -1349,7 +1351,7 @@ define([
|
|||
return;
|
||||
}
|
||||
// Maintenance applied, send notification
|
||||
common.mailbox.sendTo('BROADCAST_MAINTENANCE', {}, {}, function (err, data) {
|
||||
common.mailbox.sendTo('BROADCAST_MAINTENANCE', {}, {}, function (/* err, data */) { // XXX unused arguments
|
||||
refresh();
|
||||
checkLastBroadcastHash();
|
||||
});
|
||||
|
@ -1411,7 +1413,7 @@ define([
|
|||
common.openUnsafeURL(Broadcast.surveyURL);
|
||||
});
|
||||
active = h('div.cp-broadcast-active', [
|
||||
h('p', a),
|
||||
h('p', a), // XXX spacing around this element is really cramped
|
||||
removeButton
|
||||
]);
|
||||
}
|
||||
|
@ -1445,7 +1447,7 @@ define([
|
|||
// Maintenance applied, send notification
|
||||
common.mailbox.sendTo('BROADCAST_SURVEY', {
|
||||
url: data
|
||||
}, {}, function (err, data) {
|
||||
}, {}, function (/* err, data */) { // XXX unused arguments
|
||||
refresh();
|
||||
checkLastBroadcastHash();
|
||||
});
|
||||
|
|
|
@ -162,7 +162,7 @@ define(function() {
|
|||
// making it much faster to open new tabs.
|
||||
config.disableWorkers = false;
|
||||
|
||||
//config.surveyURL = "";
|
||||
//config.surveyURL = ""; // XXX remove this?
|
||||
|
||||
// Teams are always loaded during the initial loading screen (for the first tab only if
|
||||
// SharedWorkers are available). Allowing users to be members of multiple teams can
|
||||
|
|
|
@ -1409,7 +1409,7 @@ define([
|
|||
// Migration required but read-only: continue...
|
||||
if (readOnly) {
|
||||
setEditable(true);
|
||||
getEditor().setViewModeDisconnect();
|
||||
try { getEditor().asc_setRestriction(true); } catch (e) {}
|
||||
} else {
|
||||
// No changes after the cp: migrate now
|
||||
onMigrateRdy.fire();
|
||||
|
@ -1434,12 +1434,9 @@ define([
|
|||
return;
|
||||
}
|
||||
|
||||
if (lock) {
|
||||
getEditor().setViewModeDisconnect();
|
||||
} else if (readOnly) {
|
||||
try {
|
||||
getEditor().asc_setRestriction(true);
|
||||
} catch (e) {}
|
||||
if (lock || readOnly) {
|
||||
try { getEditor().asc_setRestriction(true); } catch (e) {}
|
||||
//getEditor().setViewModeDisconnect(); // can't be used anymore, display an OO error popup
|
||||
} else {
|
||||
setEditable(true);
|
||||
deleteOfflineLocks();
|
||||
|
@ -1459,7 +1456,6 @@ define([
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (isLockedModal.modal && force) {
|
||||
isLockedModal.modal.closeModal();
|
||||
delete isLockedModal.modal;
|
||||
|
@ -1469,7 +1465,8 @@ define([
|
|||
}
|
||||
|
||||
if (APP.template) {
|
||||
getEditor().setViewModeDisconnect();
|
||||
try { getEditor().asc_setRestriction(true); } catch (e) {}
|
||||
//getEditor().setViewModeDisconnect();
|
||||
UI.removeLoadingScreen();
|
||||
makeCheckpoint(true);
|
||||
return;
|
||||
|
@ -1483,7 +1480,7 @@ define([
|
|||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (APP.migrate && !readOnly) {
|
||||
if (lock && !readOnly) {
|
||||
onMigrateRdy.fire();
|
||||
}
|
||||
|
||||
|
@ -2065,7 +2062,7 @@ define([
|
|||
UI.removeModals();
|
||||
UI.confirm(Messages.oo_uploaded, function (yes) {
|
||||
try {
|
||||
getEditor().setViewModeDisconnect();
|
||||
getEditor().asc_setRestriction(true);
|
||||
} catch (e) {}
|
||||
if (!yes) { return; }
|
||||
common.gotoURL();
|
||||
|
@ -2232,7 +2229,9 @@ define([
|
|||
APP.history = true;
|
||||
APP.template = true;
|
||||
var editor = getEditor();
|
||||
if (editor) { editor.setViewModeDisconnect(); }
|
||||
if (editor) {
|
||||
try { getEditor().asc_setRestriction(true); } catch (e) {}
|
||||
}
|
||||
var content = parsed.content;
|
||||
|
||||
// Get checkpoint
|
||||
|
@ -2372,7 +2371,7 @@ define([
|
|||
var setHistoryMode = function (bool) {
|
||||
if (bool) {
|
||||
APP.history = true;
|
||||
getEditor().setViewModeDisconnect();
|
||||
try { getEditor().asc_setRestriction(true); } catch (e) {}
|
||||
return;
|
||||
}
|
||||
// Cancel button: redraw from lastCp
|
||||
|
@ -2579,7 +2578,11 @@ define([
|
|||
APP.onLocal();
|
||||
} else {
|
||||
msg = h('div.alert.alert-warning.cp-burn-after-reading', Messages.oo_sheetMigration_anonymousEditor);
|
||||
$(APP.helpMenu.menu).after(msg);
|
||||
if (APP.helpMenu) {
|
||||
$(APP.helpMenu.menu).after(msg);
|
||||
} else {
|
||||
$('#cp-app-oo-editor').prepend(msg);
|
||||
}
|
||||
readOnly = true;
|
||||
}
|
||||
} else if (content && content.version <= 3) { // V2 or V3
|
||||
|
@ -2591,7 +2594,11 @@ define([
|
|||
APP.onLocal();
|
||||
} else {
|
||||
msg = h('div.alert.alert-warning.cp-burn-after-reading', Messages.oo_sheetMigration_anonymousEditor);
|
||||
$(APP.helpMenu.menu).after(msg);
|
||||
if (APP.helpMenu) {
|
||||
$(APP.helpMenu.menu).after(msg);
|
||||
} else {
|
||||
$('#cp-app-oo-editor').prepend(msg);
|
||||
}
|
||||
readOnly = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3178,7 +3178,7 @@ define([
|
|||
});
|
||||
};
|
||||
|
||||
Store.newVersionReload = function () {
|
||||
Store.newVersionReload = function () { // XXX not used anymore?
|
||||
broadcast([], "NETWORK_RECONNECT");
|
||||
};
|
||||
Store.disconnect = function () {
|
||||
|
|
|
@ -687,7 +687,7 @@ define([
|
|||
|
||||
|
||||
// Broadcast
|
||||
var broadcasts = {};
|
||||
//var broadcasts = {}; // XXX defined but never used ?
|
||||
handlers['BROADCAST_MAINTENANCE'] = function (ctx, box, data, cb) {
|
||||
var msg = data.msg;
|
||||
var uid = msg.uid;
|
||||
|
@ -708,7 +708,7 @@ define([
|
|||
var dismiss = !content.url;
|
||||
cb(dismiss, old);
|
||||
};
|
||||
var activeCustom
|
||||
var activeCustom;
|
||||
handlers['BROADCAST_CUSTOM'] = function (ctx, box, data, cb) {
|
||||
var msg = data.msg;
|
||||
var uid = msg.uid;
|
||||
|
|
|
@ -341,7 +341,7 @@ proxy.mailboxes = {
|
|||
};
|
||||
var notify = box.ready;
|
||||
Handlers.add(ctx, box, message, function (dismissed, toDismiss, setAsLKH) {
|
||||
if (setAsLKH) {
|
||||
if (setAsLKH) { // XXX confirm whether this if is used?
|
||||
// Update LKH
|
||||
box.data.lastKnownHash = hash;
|
||||
box.data.viewed = [];
|
||||
|
|
|
@ -1382,15 +1382,15 @@ define([
|
|||
|
||||
// Viewer to editor
|
||||
if (user.role === "VIEWER" && data.data.role !== "VIEWER") {
|
||||
changeEditRights(ctx, teamId, user, true, function (err) {
|
||||
return void cb({error: err});
|
||||
changeEditRights(ctx, teamId, user, true, function (obj) {
|
||||
return void cb(obj);
|
||||
});
|
||||
}
|
||||
|
||||
// Editor to viewer
|
||||
if (user.role !== "VIEWER" && data.data.role === "VIEWER") {
|
||||
changeEditRights(ctx, teamId, user, false, function (err) {
|
||||
return void cb({error: err});
|
||||
changeEditRights(ctx, teamId, user, false, function (obj) {
|
||||
return void cb(obj);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1032,7 +1032,7 @@ MessengerUI, Messages) {
|
|||
Messages.broadcast_maintenance = "A maintenance is planned between <b>{0}</b> and <b>{1}</b>"; // XXX
|
||||
var createMaintenance = function (toolbar, config) {
|
||||
var $notif = toolbar.$top.find('.'+MAINTENANCE_CLS);
|
||||
var button = h('button.cp-maintenance-wrench.fa.fa-wrench');
|
||||
var button = h('button.cp-maintenance-wrench.fa.fa-wrench'); // XXX might need some color contrast
|
||||
$notif.append(button);
|
||||
|
||||
|
||||
|
|
|
@ -445,7 +445,7 @@ define([
|
|||
};
|
||||
ctx.FM = common.createFileManager(fmConfig);
|
||||
|
||||
ui.send = function (id, type, data, dest) {
|
||||
ui.send = function (id, type, data, dest) { // XXX confirm that this is actually used
|
||||
return send(ctx, id, type, data, dest);
|
||||
};
|
||||
ui.sendForm = function (id, form, dest) {
|
||||
|
|
Loading…
Reference in New Issue