Added a warning, if another user edits the same motion.
This commit is contained in:
parent
bd68997a5d
commit
349505ac3d
@ -1196,7 +1196,7 @@ img {
|
||||
border-color: #d6e9c6;
|
||||
}
|
||||
#messaging .warning {
|
||||
color: #8a6d3b;
|
||||
color: #725523;
|
||||
background-color: #fcf8e3;
|
||||
border-color: #faebcc;
|
||||
}
|
||||
|
@ -89,9 +89,15 @@ angular.module('OpenSlidesApp.core', [
|
||||
}
|
||||
};
|
||||
socket.onmessage = function (event) {
|
||||
_.forEach(Autoupdate.messageReceivers, function (receiver) {
|
||||
receiver(event.data);
|
||||
});
|
||||
var dataList = [];
|
||||
try {
|
||||
dataList = JSON.parse(event.data);
|
||||
_.forEach(Autoupdate.messageReceivers, function (receiver) {
|
||||
receiver(dataList);
|
||||
});
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
}
|
||||
// Check if the promise is not resolved yet.
|
||||
if (Autoupdate.firstMessageDeferred.promise.$$state.status === 0) {
|
||||
Autoupdate.firstMessageDeferred.resolve();
|
||||
@ -268,14 +274,7 @@ angular.module('OpenSlidesApp.core', [
|
||||
'dsEject',
|
||||
function (DS, autoupdate, dsEject) {
|
||||
// Handler for normal autoupdate messages.
|
||||
autoupdate.onMessage(function(json) {
|
||||
var dataList = [];
|
||||
try {
|
||||
dataList = JSON.parse(json);
|
||||
} catch(err) {
|
||||
console.error(json);
|
||||
}
|
||||
|
||||
autoupdate.onMessage(function(dataList) {
|
||||
var dataListByCollection = _.groupBy(dataList, 'collection');
|
||||
_.forEach(dataListByCollection, function (list, key) {
|
||||
var changedElements = [];
|
||||
@ -314,26 +313,108 @@ angular.module('OpenSlidesApp.core', [
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
])
|
||||
|
||||
.factory('Notify', [
|
||||
'autoupdate',
|
||||
'operator',
|
||||
function (autoupdate, operator) {
|
||||
var anonymousTrackId;
|
||||
|
||||
// Handler for notify messages.
|
||||
autoupdate.onMessage(function(json) {
|
||||
var dataList = [];
|
||||
try {
|
||||
dataList = JSON.parse(json);
|
||||
} catch(err) {
|
||||
console.error(json);
|
||||
}
|
||||
|
||||
autoupdate.onMessage(function(dataList) {
|
||||
var dataListByCollection = _.groupBy(dataList, 'collection');
|
||||
_.forEach(dataListByCollection, function (list, key) {
|
||||
_.forEach(list, function (data) {
|
||||
if (data.collection === 'notify') {
|
||||
// TODO: Add more code here.
|
||||
console.log(data);
|
||||
_.forEach(dataListByCollection.notify, function (notifyItem) {
|
||||
// Check, if this current user (or anonymous instance) has send this notify.
|
||||
if (notifyItem.senderUserId) {
|
||||
if (operator.user) { // User send to user
|
||||
notifyItem.sendBySelf = (notifyItem.senderUserId === operator.user.id);
|
||||
} else { // User send to anonymous
|
||||
notifyItem.sendBySelf = false;
|
||||
}
|
||||
} else {
|
||||
if (operator.user) { // Anonymous send to user
|
||||
notifyItem.sendBySelf = false;
|
||||
} else { // Anonymous send to anonymous
|
||||
notifyItem.sendBySelf = (notifyItem.anonymousTrackId === anonymousTrackId);
|
||||
}
|
||||
}
|
||||
// notify registered receivers.
|
||||
_.forEach(callbackReceivers[notifyItem.name], function (item) {
|
||||
item.fn(notifyItem);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
var callbackReceivers = {};
|
||||
/* Structure of callbackReceivers:
|
||||
* event_name_one: [ {id:0, fn:fn}, {id:3, fn:fn} ],
|
||||
* event_name_two: [ {id:2, fn:fn} ],
|
||||
* */
|
||||
var idCounter = 0;
|
||||
var eventNameRegex = new RegExp('^[a-zA-Z_-]+$');
|
||||
var externIdRegex = new RegExp('^[a-zA-Z_-]+\/[0-9]+$');
|
||||
return {
|
||||
registerCallback: function (eventName, fn) {
|
||||
if (!eventNameRegex.test(eventName)) {
|
||||
throw 'eventName should only consist of [a-zA-z_-]';
|
||||
} else if (typeof fn === 'function') {
|
||||
var id = idCounter++;
|
||||
|
||||
if (!callbackReceivers[eventName]) {
|
||||
callbackReceivers[eventName] = [];
|
||||
}
|
||||
callbackReceivers[eventName].push({
|
||||
id: id,
|
||||
fn: fn,
|
||||
});
|
||||
return eventName + '/' + id;
|
||||
} else {
|
||||
throw 'fn should be a function.';
|
||||
}
|
||||
},
|
||||
deregisterCallback: function (externId) {
|
||||
if (externIdRegex.test(externId)){
|
||||
var split = externId.split('/');
|
||||
var eventName = split[0];
|
||||
var id = parseInt(split[1]);
|
||||
callbackReceivers[eventName] = _.filter(callbackReceivers[eventName], function (item) {
|
||||
return item.id !== id;
|
||||
});
|
||||
} else {
|
||||
throw externId + ' is not a valid id';
|
||||
}
|
||||
},
|
||||
// variable length of parameters, just pass ids.
|
||||
deregisterCallbacks: function () {
|
||||
_.forEach(arguments, this.deregisterCallback);
|
||||
},
|
||||
notify: function(eventName, params, users, channels) {
|
||||
if (eventNameRegex.test(eventName)) {
|
||||
if (!params || typeof params !== 'object') {
|
||||
params = {};
|
||||
}
|
||||
|
||||
var notifyItem = {
|
||||
collection: 'notify',
|
||||
name: eventName,
|
||||
params: params,
|
||||
users: users,
|
||||
replyChannels: channels,
|
||||
};
|
||||
if (!operator.user) {
|
||||
if (!anonymousTrackId) {
|
||||
anonymousTrackId = Math.floor(Math.random()*1000000);
|
||||
}
|
||||
notifyItem.anonymousTrackId = anonymousTrackId;
|
||||
}
|
||||
autoupdate.send([notifyItem]);
|
||||
} else {
|
||||
throw 'eventName should only consist of [a-zA-z_-]';
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
@ -1227,7 +1308,8 @@ angular.module('OpenSlidesApp.core', [
|
||||
'Projector',
|
||||
'ProjectionDefault',
|
||||
'Tag',
|
||||
function (ChatMessage, Config, Countdown, ProjectorMessage, Projector, ProjectionDefault, Tag) {}
|
||||
'Notify', // For setting up the autoupdate callback
|
||||
function (ChatMessage, Config, Countdown, ProjectorMessage, Projector, ProjectionDefault, Tag, Notify) {}
|
||||
]);
|
||||
|
||||
}());
|
||||
|
@ -276,7 +276,6 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
.factory('MotionForm', [
|
||||
'gettextCatalog',
|
||||
'operator',
|
||||
'autoupdate',
|
||||
'Editor',
|
||||
'MotionComment',
|
||||
'Category',
|
||||
@ -288,18 +287,11 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
'Workflow',
|
||||
'Agenda',
|
||||
'AgendaTree',
|
||||
function (gettextCatalog, operator, autoupdate, Editor, MotionComment, Category, Config, Mediafile, MotionBlock, Tag, User, Workflow, Agenda, AgendaTree) {
|
||||
function (gettextCatalog, operator, Editor, MotionComment, Category, Config, Mediafile, MotionBlock,
|
||||
Tag, User, Workflow, Agenda, AgendaTree) {
|
||||
return {
|
||||
// ngDialog for motion form
|
||||
getDialog: function (motion) {
|
||||
//TODO: This is just a test implementation. Remove it later.
|
||||
autoupdate.send([{
|
||||
collection: 'notify',
|
||||
name: 'motion_edit_dialog_opened',
|
||||
//users: [4, 5, ],
|
||||
//replyChannels: ["daphne.response.StSjKMGYeq!PfqbSbiJNP", ],
|
||||
}]);
|
||||
//End of test implementation
|
||||
return {
|
||||
template: 'static/templates/motions/motion-form.html',
|
||||
controller: motion ? 'MotionUpdateCtrl' : 'MotionCreateCtrl',
|
||||
@ -1614,6 +1606,8 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
.controller('MotionUpdateCtrl', [
|
||||
'$scope',
|
||||
'$state',
|
||||
'operator',
|
||||
'gettextCatalog',
|
||||
'Motion',
|
||||
'Category',
|
||||
'Config',
|
||||
@ -1624,10 +1618,12 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
'Workflow',
|
||||
'Agenda',
|
||||
'AgendaUpdate',
|
||||
'Notify',
|
||||
'Messaging',
|
||||
'motionId',
|
||||
'ErrorMessage',
|
||||
function($scope, $state, Motion, Category, Config, Mediafile, MotionForm, Tag,
|
||||
User, Workflow, Agenda, AgendaUpdate, motionId, ErrorMessage) {
|
||||
function($scope, $state, operator, gettextCatalog, Motion, Category, Config, Mediafile, MotionForm,
|
||||
Tag, User, Workflow, Agenda, AgendaUpdate, Notify, Messaging, motionId, ErrorMessage) {
|
||||
Category.bindAll({}, $scope, 'categories');
|
||||
Mediafile.bindAll({}, $scope, 'mediafiles');
|
||||
Tag.bindAll({}, $scope, 'tags');
|
||||
@ -1682,7 +1678,97 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
}
|
||||
}
|
||||
|
||||
// save motion
|
||||
/* Notify for displaying a warning, if other users edit this motion too */
|
||||
var editorNames = [];
|
||||
var messagingId = 'motionEditDialogOtherUsersWarning';
|
||||
var addActiveEditor = function (editorName) {
|
||||
editorNames.push(editorName);
|
||||
updateActiveEditors();
|
||||
};
|
||||
var removeActiveEditor = function (editorName) {
|
||||
var firstIndex = _.indexOf(editorNames, editorName);
|
||||
editorNames.splice(firstIndex, 1);
|
||||
updateActiveEditors();
|
||||
};
|
||||
var updateActiveEditors = function () {
|
||||
if (editorNames.length === 0) {
|
||||
Messaging.deleteMessage(messagingId);
|
||||
} else {
|
||||
// This block is only for getting the message string together...
|
||||
var editorsWithoutAnonymous = _.filter(editorNames, function (name) {
|
||||
return name;
|
||||
});
|
||||
var text = gettextCatalog.getString('Warning') + ': ';
|
||||
if (editorsWithoutAnonymous.length === 0) { // Only anonymous
|
||||
// Singular vs. plural
|
||||
if (editorNames.length === 1) {
|
||||
text += gettextCatalog.getString('One anonymous users is also editing this motion.');
|
||||
} else {
|
||||
text += editorNames.length + ' ' + gettextCatalog.getString('anonymous users are also editing this motion.');
|
||||
}
|
||||
} else {
|
||||
// At least one named user. The max users to display is 5. Anonymous users doesn't get displayed
|
||||
// by name, but the amount of users is shown.
|
||||
text += _.slice(editorsWithoutAnonymous, 0, 5).join(', ');
|
||||
if (editorsWithoutAnonymous.length > 5) {
|
||||
// More than 5 users with names.
|
||||
text += ', ... [+' + (editorNames.length - 5) + ']';
|
||||
} else if (editorsWithoutAnonymous.length !== editorNames.length) {
|
||||
// Less than 5 users, so the difference is calculated different.
|
||||
text += ', ... [+' + (editorNames.length - editorsWithoutAnonymous.length) + ']';
|
||||
}
|
||||
// Singular vs. plural
|
||||
if (editorNames.length === 1) {
|
||||
text += ' ' + gettextCatalog.getString('is also editing this motion.');
|
||||
} else {
|
||||
text += ' ' + gettextCatalog.getString('are also editing this motion.');
|
||||
}
|
||||
}
|
||||
Messaging.createOrEditMessage(messagingId, text, 'warning');
|
||||
}
|
||||
};
|
||||
|
||||
var responseCallbackId = Notify.registerCallback('motion_dialog_open_response', function (notify) {
|
||||
if (!notify.sendBySelf && notify.params.motionId === motionId) {
|
||||
addActiveEditor(notify.params.name);
|
||||
}
|
||||
});
|
||||
var queryCallbackId = Notify.registerCallback('motion_dialog_open_query', function (notify) {
|
||||
if (!notify.sendBySelf && notify.params.motionId === motionId) {
|
||||
addActiveEditor(notify.params.name);
|
||||
if (notify.senderUserId) {
|
||||
Notify.notify('motion_dialog_open_response', {
|
||||
name: operator.user ? operator.user.short_name : '',
|
||||
motionId: motionId,
|
||||
}, [notify.senderUserId]);
|
||||
} else {
|
||||
Notify.notify('motion_dialog_open_response', {
|
||||
name: operator.user ? operator.user.short_name : '',
|
||||
motionId: motionId,
|
||||
}, null, [notify.senderReplyChannelName]);
|
||||
}
|
||||
}
|
||||
});
|
||||
var closeCallbackId = Notify.registerCallback('motion_dialog_closed', function (notify) {
|
||||
if (notify.params.motionId === motionId) {
|
||||
removeActiveEditor(notify.params.name);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
Notify.deregisterCallbacks(responseCallbackId, queryCallbackId, closeCallbackId);
|
||||
Messaging.deleteMessage(messagingId);
|
||||
Notify.notify('motion_dialog_closed', {
|
||||
name: operator.user ? operator.user.short_name : '',
|
||||
motionId: motionId
|
||||
});
|
||||
});
|
||||
Notify.notify('motion_dialog_open_query', {
|
||||
name: operator.user ? operator.user.short_name : '',
|
||||
motionId: motionId,
|
||||
});
|
||||
|
||||
// Save motion
|
||||
$scope.save = function (motion, gotoDetailView) {
|
||||
// inject the changed motion (copy) object back into DS store
|
||||
Motion.inject(motion);
|
||||
|
@ -115,6 +115,10 @@ def ws_receive_site(message):
|
||||
item['senderReplyChannelName'] = message.reply_channel.name
|
||||
item['senderUserId'] = message.user.id or 0
|
||||
|
||||
# Force the params to be a dict
|
||||
if not isinstance(item.get('params'), dict):
|
||||
item['params'] = {}
|
||||
|
||||
users = item.get('users')
|
||||
if isinstance(users, list):
|
||||
# Send this item only to all reply channels of some site users.
|
||||
|
Loading…
Reference in New Issue
Block a user