Merge pull request #1777 from emanuelschuetze/fix1662
Sort list of speakers (Fixes#1662)
This commit is contained in:
commit
db22d1f7dc
@ -181,16 +181,22 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
|
|||||||
|
|
||||||
.controller('ItemDetailCtrl', [
|
.controller('ItemDetailCtrl', [
|
||||||
'$scope',
|
'$scope',
|
||||||
|
'$filter',
|
||||||
'$http',
|
'$http',
|
||||||
'Agenda',
|
'Agenda',
|
||||||
'User',
|
'User',
|
||||||
'item',
|
'item',
|
||||||
function ($scope, $http, Agenda, User, item) {
|
function ($scope, $filter, $http, Agenda, User, item) {
|
||||||
Agenda.bindOne(item.id, $scope, 'item');
|
Agenda.bindOne(item.id, $scope, 'item');
|
||||||
User.bindAll({}, $scope, 'users');
|
User.bindAll({}, $scope, 'users');
|
||||||
$scope.speaker = {};
|
$scope.speaker = {};
|
||||||
$scope.alert = {};
|
$scope.alert = {};
|
||||||
|
$scope.speakers = $filter('orderBy')(item.speakers, 'weight');
|
||||||
|
$scope.$watch(function () {
|
||||||
|
return Agenda.lastModified();
|
||||||
|
}, function () {
|
||||||
|
$scope.speakers = $filter('orderBy')(item.speakers, 'weight');
|
||||||
|
});
|
||||||
// close/open list of speakers of current item
|
// close/open list of speakers of current item
|
||||||
$scope.closeList = function (listClosed) {
|
$scope.closeList = function (listClosed) {
|
||||||
item.speaker_list_closed = listClosed;
|
item.speaker_list_closed = listClosed;
|
||||||
@ -201,6 +207,7 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
|
|||||||
$http.post('/rest/agenda/item/' + item.id + '/manage_speaker/', {'user': userId})
|
$http.post('/rest/agenda/item/' + item.id + '/manage_speaker/', {'user': userId})
|
||||||
.success(function(data){
|
.success(function(data){
|
||||||
$scope.alert.show = false;
|
$scope.alert.show = false;
|
||||||
|
$scope.speakers = item.speakers;
|
||||||
})
|
})
|
||||||
.error(function(data){
|
.error(function(data){
|
||||||
$scope.alert = { type: 'danger', msg: data.detail, show: true };
|
$scope.alert = { type: 'danger', msg: data.detail, show: true };
|
||||||
@ -211,9 +218,13 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
|
|||||||
$http.delete('/rest/agenda/item/' + item.id + '/manage_speaker/',
|
$http.delete('/rest/agenda/item/' + item.id + '/manage_speaker/',
|
||||||
{headers: {'Content-Type': 'application/json'},
|
{headers: {'Content-Type': 'application/json'},
|
||||||
data: JSON.stringify({speaker: speakerId})})
|
data: JSON.stringify({speaker: speakerId})})
|
||||||
|
.success(function(data){
|
||||||
|
$scope.speakers = item.speakers;
|
||||||
|
})
|
||||||
.error(function(data){
|
.error(function(data){
|
||||||
$scope.alert = { type: 'danger', msg: data.detail, show: true };
|
$scope.alert = { type: 'danger', msg: data.detail, show: true };
|
||||||
});
|
});
|
||||||
|
$scope.speakers = item.speakers;
|
||||||
};
|
};
|
||||||
// begin speech of selected/next speaker
|
// begin speech of selected/next speaker
|
||||||
$scope.beginSpeech = function (speakerId) {
|
$scope.beginSpeech = function (speakerId) {
|
||||||
@ -234,6 +245,18 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
|
|||||||
$scope.alert = { type: 'danger', msg: data.detail, show: true };
|
$scope.alert = { type: 'danger', msg: data.detail, show: true };
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
// save reordered list of speakers
|
||||||
|
$scope.treeOptions = {
|
||||||
|
dropped: function (event) {
|
||||||
|
var sortedSpeakers = [];
|
||||||
|
var nextSpeakers = $filter('filter')($scope.speakers, {'begin_time': null});
|
||||||
|
angular.forEach(nextSpeakers, function (speaker) {
|
||||||
|
sortedSpeakers.push(speaker.id);
|
||||||
|
});
|
||||||
|
$http.post('/rest/agenda/item/' + item.id + '/sort_speakers/',
|
||||||
|
{speakers: sortedSpeakers});
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -65,20 +65,26 @@
|
|||||||
</strong>
|
</strong>
|
||||||
|
|
||||||
<h3 translate>Next speakers:</h3>
|
<h3 translate>Next speakers:</h3>
|
||||||
<ol>
|
<div class="row">
|
||||||
<li ng-repeat="speaker in item.speakers | filter: {begin_time: null}">
|
<div ui-tree="treeOptions" class="col-sm-6">
|
||||||
{{ speaker.user.get_full_name() }}
|
<ol ui-tree-nodes="" ng-model="speakers">
|
||||||
<button os-perms="agenda.can_manage" ng-click="removeSpeaker(speaker.id)"
|
<li ng-repeat="speaker in speakers | filter: {begin_time: null}" ui-tree-node>
|
||||||
class="btn btn-default btn-xs">
|
<i ui-tree-handle="" class="fa fa-arrows-v"></i>
|
||||||
<i class="fa fa-times"></i>
|
{{ $index + 1 }}.
|
||||||
</button>
|
{{ speaker.user.get_full_name() }}
|
||||||
<button os-perms="agenda.can_manage" ng-click="beginSpeech(speaker.id)"
|
<button os-perms="agenda.can_manage" ng-click="removeSpeaker(speaker.id)"
|
||||||
class="btn btn-default btn-xs">
|
class="btn btn-default btn-xs">
|
||||||
<i class="fa fa-play"></i>
|
<i class="fa fa-times"></i>
|
||||||
</button>
|
</button>
|
||||||
</ol>
|
<button os-perms="agenda.can_manage" ng-click="beginSpeech(speaker.id)"
|
||||||
|
class="btn btn-default btn-xs">
|
||||||
|
<i class="fa fa-play"></i>
|
||||||
|
</button>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group spacer">
|
||||||
<alert ng-show="alert.show" type="{{ alert.type }}" ng-click="alert={}" close="alert={}">
|
<alert ng-show="alert.show" type="{{ alert.type }}" ng-click="alert={}" close="alert={}">
|
||||||
{{alert.msg}}
|
{{alert.msg}}
|
||||||
</alert>
|
</alert>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from cgi import escape
|
from cgi import escape
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.db import transaction
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.translation import ugettext_lazy
|
from django.utils.translation import ugettext_lazy
|
||||||
from reportlab.platypus import Paragraph
|
from reportlab.platypus import Paragraph
|
||||||
@ -48,7 +49,7 @@ class ItemViewSet(ListModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericV
|
|||||||
result = (self.request.user.has_perm('agenda.can_see') and
|
result = (self.request.user.has_perm('agenda.can_see') and
|
||||||
self.request.user.has_perm('agenda.can_see_hidden_items') and
|
self.request.user.has_perm('agenda.can_see_hidden_items') and
|
||||||
self.request.user.has_perm('agenda.can_manage'))
|
self.request.user.has_perm('agenda.can_manage'))
|
||||||
elif self.action in ('speak', 'numbering'):
|
elif self.action in ('speak', 'sort_speakers', 'numbering'):
|
||||||
result = (self.request.user.has_perm('agenda.can_see') and
|
result = (self.request.user.has_perm('agenda.can_see') and
|
||||||
self.request.user.has_perm('agenda.can_manage'))
|
self.request.user.has_perm('agenda.can_manage'))
|
||||||
else:
|
else:
|
||||||
@ -195,6 +196,44 @@ class ItemViewSet(ListModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericV
|
|||||||
# Initiate response.
|
# Initiate response.
|
||||||
return Response({'detail': message})
|
return Response({'detail': message})
|
||||||
|
|
||||||
|
@detail_route(methods=['POST'])
|
||||||
|
def sort_speakers(self, request, pk=None):
|
||||||
|
"""
|
||||||
|
Special view endpoint to sort the list of speakers.
|
||||||
|
|
||||||
|
Expects a list of IDs of the speakers.
|
||||||
|
"""
|
||||||
|
# Retrieve item.
|
||||||
|
item = self.get_object()
|
||||||
|
|
||||||
|
# Check data
|
||||||
|
speaker_ids = request.data.get('speakers')
|
||||||
|
if not isinstance(speaker_ids, list):
|
||||||
|
raise ValidationError(
|
||||||
|
{'detail': _('Invalid data.')})
|
||||||
|
|
||||||
|
# Get all speakers
|
||||||
|
speakers = {}
|
||||||
|
for speaker in item.speakers.filter(begin_time=None):
|
||||||
|
speakers[speaker.pk] = speaker
|
||||||
|
|
||||||
|
# Check and sort speakers
|
||||||
|
valid_speakers = []
|
||||||
|
for speaker_id in speaker_ids:
|
||||||
|
if not isinstance(speaker_id, int) or speakers.get(speaker_id) is None:
|
||||||
|
raise ValidationError(
|
||||||
|
{'detail': _('Invalid data.')})
|
||||||
|
valid_speakers.append(speakers[speaker_id])
|
||||||
|
weight = 0
|
||||||
|
with transaction.atomic():
|
||||||
|
for speaker in valid_speakers:
|
||||||
|
speaker.weight = weight
|
||||||
|
speaker.save()
|
||||||
|
weight += 1
|
||||||
|
|
||||||
|
# Initiate response.
|
||||||
|
return Response({'detail': _('List of speakers successfully sorted.')})
|
||||||
|
|
||||||
@list_route(methods=['get', 'put'])
|
@list_route(methods=['get', 'put'])
|
||||||
def tree(self, request):
|
def tree(self, request):
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user