Merge pull request #674 from normanjaeckel/Fixes_for_1.4b2
Several template and bug fixes, some minor view behavior changes
This commit is contained in:
commit
b80a526ddc
@ -2,5 +2,5 @@ language: python
|
||||
python:
|
||||
- "2.6"
|
||||
- "2.7"
|
||||
install: "pip install -r requirements_development.txt --use-mirrors"
|
||||
install: "pip install -r requirements.txt --use-mirrors"
|
||||
script: "fab travis_ci"
|
||||
|
@ -136,7 +136,7 @@ III. Installation on GNU/Linux and MacOSX using the sources (for development)
|
||||
|
||||
4. Install all required python packages:
|
||||
|
||||
$ pip install -r requirements_development.txt
|
||||
$ pip install -r requirements.txt
|
||||
|
||||
5. Start OpenSlides server and open URL in your default browser:
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
<li>
|
||||
<a href="{% model_url motion %}">
|
||||
{% if motion.identifier %}
|
||||
[#{{ motion.identifier }}]
|
||||
[# {{ motion.identifier }}]
|
||||
{% else %}
|
||||
[---]
|
||||
{% endif %}
|
||||
@ -37,7 +37,7 @@
|
||||
<li>
|
||||
<a href="{% model_url motion %}">
|
||||
{% if motion.identifier %}
|
||||
[#{{ motion.identifier }}]
|
||||
[# {{ motion.identifier }}]
|
||||
{% else %}
|
||||
[---]
|
||||
{% endif %}
|
||||
|
@ -111,21 +111,19 @@ class Item(MPTTModel, SlideMixin):
|
||||
def __unicode__(self):
|
||||
return self.get_title()
|
||||
|
||||
def get_absolute_url(self, link='view'):
|
||||
def get_absolute_url(self, link='detail'):
|
||||
"""
|
||||
Return the URL to this item. By default it is the link to its
|
||||
view or the view of a related object.
|
||||
|
||||
The link can be:
|
||||
* view
|
||||
* edit
|
||||
* detail or view
|
||||
* update or edit
|
||||
* delete
|
||||
"""
|
||||
if link == 'view':
|
||||
if self.related_sid:
|
||||
return self.get_related_slide().get_absolute_url(link)
|
||||
if link == 'detail' or link == 'view':
|
||||
return reverse('item_view', args=[str(self.id)])
|
||||
if link == 'edit':
|
||||
if link == 'update' or link == 'edit':
|
||||
if self.related_sid:
|
||||
return self.get_related_slide().get_absolute_url(link)
|
||||
return reverse('item_edit', args=[str(self.id)])
|
||||
@ -139,7 +137,7 @@ class Item(MPTTModel, SlideMixin):
|
||||
# TODO: Rename it to 'get_related_object'
|
||||
object = get_slide_from_sid(self.related_sid, element=True)
|
||||
if object is None:
|
||||
self.title = 'Item for deleted slide: %s' % self.related_sid
|
||||
self.title = _('Item for deleted slide %s') % self.related_sid
|
||||
self.related_sid = None
|
||||
self.save()
|
||||
return self
|
||||
@ -256,7 +254,7 @@ class Item(MPTTModel, SlideMixin):
|
||||
dictionary contains a prefix, the speaker and its type. Types
|
||||
are old_speaker, actual_speaker and coming_speaker.
|
||||
"""
|
||||
speaker_query = Speaker.objects.filter(item=self)
|
||||
speaker_query = Speaker.objects.filter(item=self) # TODO: Why not self.speaker_set?
|
||||
list_of_speakers = []
|
||||
|
||||
# Parse old speakers
|
||||
@ -312,6 +310,16 @@ class Item(MPTTModel, SlideMixin):
|
||||
|
||||
return list_of_speakers
|
||||
|
||||
def get_next_speaker(self):
|
||||
"""
|
||||
Returns the speaker object of the person who is next.
|
||||
"""
|
||||
try:
|
||||
return self.speaker_set.filter(begin_time=None).order_by('weight')[0]
|
||||
except IndexError:
|
||||
# The list of speakers is empty.
|
||||
return None
|
||||
|
||||
|
||||
class SpeakerManager(models.Manager):
|
||||
def add(self, person, item):
|
||||
|
@ -23,54 +23,7 @@ table#agendatime td {
|
||||
}
|
||||
|
||||
/*** List of speakers ***/
|
||||
/* List of speakers - projector slide */
|
||||
ul#list_of_speakers {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
#list_of_speakers li {
|
||||
font-size: 130%;
|
||||
line-height: 150%;
|
||||
}
|
||||
#list_of_speakers .old_speaker {
|
||||
color: #9FA9B7;
|
||||
}
|
||||
#list_of_speakers .actual_speaker {
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
/* List of speakers - overlay */
|
||||
#overlay_list_of_speaker_box {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-radius: 0.4em;
|
||||
border: 0.1em solid #777777;
|
||||
background-color: #cccccc;
|
||||
opacity: 0.9;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
z-index: 2;
|
||||
width: 45%;
|
||||
min-width: 200px;
|
||||
}
|
||||
#overlay_list_of_speaker_box h3 {
|
||||
margin: 5px;
|
||||
}
|
||||
#overlay_list_of_speaker_box ul {
|
||||
margin: 5px;
|
||||
}
|
||||
#overlay_list_of_speaker_box li {
|
||||
font-size: 120%;
|
||||
line-height: 120%;
|
||||
}
|
||||
#overlay_list_of_speaker_box .old_speaker {
|
||||
color: #777777;
|
||||
}
|
||||
#overlay_list_of_speaker_box .actual_speaker {
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
/* List of speakers - agenda item view */
|
||||
/* List of speakers – agenda item view */
|
||||
div#complete_list_of_speakers li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
@ -1,6 +1,34 @@
|
||||
{% load i18n %}
|
||||
{% load tags %}
|
||||
|
||||
<style type="text/css">
|
||||
/* List of speakers – overlay */
|
||||
#overlay_list_of_speaker_box {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-radius: 0.4em;
|
||||
border: 0.1em solid #777777;
|
||||
background-color: #cccccc;
|
||||
opacity: 0.9;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
z-index: 2;
|
||||
width: 45%;
|
||||
min-width: 200px}
|
||||
#overlay_list_of_speaker_box h3 {
|
||||
margin: 5px}
|
||||
#overlay_list_of_speaker_box ul {
|
||||
margin: 5px}
|
||||
#overlay_list_of_speaker_box li {
|
||||
font-size: 120%;
|
||||
line-height: 120%}
|
||||
#overlay_list_of_speaker_box .old_speaker {
|
||||
color: #777777}
|
||||
#overlay_list_of_speaker_box .actual_speaker {
|
||||
margin-bottom: 0em}
|
||||
</style>
|
||||
|
||||
<div id="overlay_list_of_speaker_box">
|
||||
<h3>{% trans "List of speakers" %} {% if closed %}(<span class="closed">{% trans 'closed' %}</span>){% endif %}</h3>
|
||||
{% if list_of_speakers %}
|
||||
|
@ -2,5 +2,5 @@
|
||||
{% load tags %}
|
||||
|
||||
<span>
|
||||
{% trans "List of speakers" %}
|
||||
{% trans "List of speakers" %} <small class="grey">({% trans 'This overlay only appears on agenda slides if it is activated' %}.)</small>
|
||||
</span>
|
||||
|
@ -1,11 +1,13 @@
|
||||
{% load i18n %}
|
||||
{% load tags %}
|
||||
|
||||
|
||||
{% if perms.agenda.can_be_speaker %}
|
||||
<p><a href="{% url 'agenda_add_to_current_list_of_speakers' %}" class="btn"><i class="icon icon-speaker"></i> {% trans 'Put me on the current list of speakers' %}</a></p>
|
||||
{% endif %}
|
||||
|
||||
<p><a href="{% url 'agenda_current_list_of_speakers' %}" class="btn"><i class="icon icon-bell"></i> {% trans 'Go to current list of speakers' %}</a></p>
|
||||
|
||||
{% if perms.agenda.can_manage_agenda %}
|
||||
<hr>
|
||||
<a href="{% url 'agenda_current_list_of_speakers' %}" class="btn btn-mini"><i class="icon icon-bell"></i> {% trans 'Next speaker' %}</a>
|
||||
<a href="{% url 'agenda_next_on_current_list_of_speakers' %}" class="btn btn-mini"><i class="icon icon-bell"></i> {% trans 'Next speaker' %}</a>
|
||||
{% endif %}
|
||||
|
@ -4,7 +4,7 @@
|
||||
{% load tags %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block title %}{{ block.super }} – {{ item.title }}{% endblock %}
|
||||
{% block title %}{{ block.super }} – {{ item }}{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<link type="text/css" rel="stylesheet" media="all" href="{% static 'styles/agenda.css' %}" />
|
||||
@ -22,18 +22,6 @@
|
||||
<small class="pull-right">
|
||||
<div class="btn-toolbar">
|
||||
<a href="{% url 'item_overview' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a>
|
||||
{% if perms.agenda.can_manage_agenda %}
|
||||
<div class="btn-group">
|
||||
<a data-toggle="dropdown" href="#" class="btn btn-mini dropdown-toggle">
|
||||
{% trans 'More actions' %}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right">
|
||||
<li><a href="{% url 'item_edit' item.id %}"><i class="icon-pencil"></i> {% trans 'Edit item' %}</a></li>
|
||||
<li><a href="{% url 'item_delete' item.id %}"><i class="icon-remove"></i> {% trans 'Delete item' %}</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if perms.projector.can_manage_projector %}
|
||||
<a href="{% url 'projector_activate_slide' item.sid %}"
|
||||
class="activate_link btn btn-mini {% if item.active and not show_list %}btn-primary{% endif %}"
|
||||
@ -41,10 +29,28 @@
|
||||
<i class="icon icon-facetime-video {% if item.active and not show_list %}icon-white{% endif %}"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if perms.agenda.can_manage_agenda %}
|
||||
<div class="btn-group">
|
||||
<a data-toggle="dropdown" href="#" class="btn btn-mini dropdown-toggle">
|
||||
{% trans 'More actions' %}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right">
|
||||
<li><a href="{% model_url item 'update' %}"><i class="icon-pencil"></i> {% trans 'Edit item' %}</a></li>
|
||||
<li><a href="{% model_url item 'delete' %}"><i class="icon-remove"></i> {% trans 'Delete item' %}</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</small>
|
||||
</h1>
|
||||
<p>{{ item.text|safe|linebreaks }}</p>
|
||||
<p>
|
||||
{% if item.get_related_slide == item %}
|
||||
{{ item.text|safe|linebreaks }}
|
||||
{% else %}
|
||||
<a href="{% model_url item.get_related_slide %}">{% trans 'Goto' %} {% trans item.get_related_type %} {{ item.get_related_slide }}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% if perms.agenda.can_manage_agenda %}
|
||||
{% if item.comment %}
|
||||
|
@ -5,6 +5,23 @@
|
||||
|
||||
{% block title %}{{ block.super }} – {{ item }}{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<style type="text/css">
|
||||
/* List of speakers – projector slide */
|
||||
ul#list_of_speakers {
|
||||
list-style-type: none;
|
||||
padding: 0}
|
||||
#list_of_speakers li {
|
||||
font-size: 130%;
|
||||
line-height: 150%}
|
||||
#list_of_speakers .old_speaker {
|
||||
color: #9FA9B7}
|
||||
#list_of_speakers .actual_speaker {
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.5em}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ title }}</h1>
|
||||
<h2 style="margin-top: -10px;">
|
||||
@ -18,7 +35,7 @@
|
||||
{% if list_of_speakers %}
|
||||
<ul id="list_of_speakers">
|
||||
{% for speaker_dict in list_of_speakers %}
|
||||
<li class="{{speaker_dict.type}}"> {#o ld_speaker, actual_speaker, coming_speaker #}
|
||||
<li class="{{ speaker_dict.type }}"> {# old_speaker, actual_speaker, coming_speaker #}
|
||||
{% if speaker_dict.type == 'coming_speaker' %}
|
||||
{{ speaker_dict.prefix }}.
|
||||
{% endif %}
|
||||
|
@ -101,14 +101,18 @@ urlpatterns = patterns(
|
||||
name='agenda_speaker_change_order',
|
||||
),
|
||||
|
||||
url(r'^list_of_speakers/add/$',
|
||||
CurrentListOfSpeakersView.as_view(set_speaker=True),
|
||||
name='agenda_add_to_current_list_of_speakers',
|
||||
),
|
||||
|
||||
url(r'^list_of_speakers/$',
|
||||
CurrentListOfSpeakersView.as_view(),
|
||||
name='agenda_current_list_of_speakers',
|
||||
),
|
||||
|
||||
url(r'^list_of_speakers/add/$',
|
||||
CurrentListOfSpeakersView.as_view(set_speaker=True),
|
||||
name='agenda_add_to_current_list_of_speakers',
|
||||
),
|
||||
|
||||
url(r'^list_of_speakers/next/$',
|
||||
CurrentListOfSpeakersView.as_view(next_speaker=True),
|
||||
name='agenda_next_on_current_list_of_speakers',
|
||||
)
|
||||
)
|
||||
|
@ -436,9 +436,11 @@ class SpeakerChangeOrderView(SingleObjectMixin, RedirectView):
|
||||
|
||||
class CurrentListOfSpeakersView(RedirectView):
|
||||
"""
|
||||
Redirect to the current list of speakers and set the request.user on it.
|
||||
Redirect to the current list of speakers and set the request.user on it or
|
||||
begins speach of the next speaker.
|
||||
"""
|
||||
set_speaker = False
|
||||
next_speaker = False
|
||||
|
||||
def get_item(self):
|
||||
"""
|
||||
@ -455,16 +457,21 @@ class CurrentListOfSpeakersView(RedirectView):
|
||||
Returns the URL to the item_view if:
|
||||
|
||||
* the current slide is an item,
|
||||
* the user has the permission to see the item and
|
||||
* the user has the permission to see the item,
|
||||
* the user who wants to be a speaker has this permission and
|
||||
* the list of speakers of the item is not closed,
|
||||
|
||||
in other case, it returns the URL to the dashboard.
|
||||
|
||||
This method also adds the request.user to the list of speakers, if he
|
||||
has the right permissions and the list is not closed.
|
||||
|
||||
This method also begins the speach of the next speaker, if the flag
|
||||
next_speaker is given.
|
||||
"""
|
||||
item = self.get_item()
|
||||
request = self.request
|
||||
|
||||
if item is None:
|
||||
messages.error(request, _(
|
||||
'There is no list of speakers for the current slide. '
|
||||
@ -474,17 +481,32 @@ class CurrentListOfSpeakersView(RedirectView):
|
||||
if self.set_speaker:
|
||||
if item.speaker_list_closed:
|
||||
messages.error(request, _('The list of speakers is closed.'))
|
||||
return reverse('dashboard')
|
||||
|
||||
if self.request.user.has_perm('agenda.can_be_speaker'):
|
||||
try:
|
||||
Speaker.objects.add(self.request.user, item)
|
||||
except OpenSlidesError:
|
||||
messages.error(request, _('You are already on the list of speakers.'))
|
||||
reverse_to_dashboard = True
|
||||
else:
|
||||
messages.error(request, _('You can not put yourself on the list of speakers.'))
|
||||
if self.request.user.has_perm('agenda.can_be_speaker'):
|
||||
try:
|
||||
Speaker.objects.add(self.request.user, item)
|
||||
except OpenSlidesError:
|
||||
messages.error(request, _('You are already on the list of speakers.'))
|
||||
finally:
|
||||
reverse_to_dashboard = False
|
||||
else:
|
||||
messages.error(request, _('You can not put yourself on the list of speakers.'))
|
||||
reverse_to_dashboard = True
|
||||
else:
|
||||
reverse_to_dashboard = False
|
||||
|
||||
if not self.request.user.has_perm('agenda.can_see_agenda'):
|
||||
if self.next_speaker:
|
||||
next_speaker_object = item.get_next_speaker()
|
||||
if next_speaker_object:
|
||||
next_speaker_object.begin_speach()
|
||||
messages.success(request, _('%s is now speaking.') % next_speaker_object)
|
||||
else:
|
||||
messages.error(request, _('The list of speakers is empty.'))
|
||||
if not self.set_speaker:
|
||||
reverse_to_dashboard = True
|
||||
|
||||
if reverse_to_dashboard or not self.request.user.has_perm('agenda.can_see_agenda'):
|
||||
return reverse('dashboard')
|
||||
else:
|
||||
return reverse('item_view', args=[item.pk])
|
||||
|
@ -37,7 +37,7 @@ class AssignmentCandidate(models.Model):
|
||||
|
||||
|
||||
class Assignment(models.Model, SlideMixin):
|
||||
prefix = 'assignment'
|
||||
prefix = ugettext_noop('assignment')
|
||||
STATUS = (
|
||||
('sea', ugettext_lazy('Searching for candidates')),
|
||||
('vot', ugettext_lazy('Voting')),
|
||||
@ -226,10 +226,10 @@ class Assignment(models.Model, SlideMixin):
|
||||
data['template'] = 'projector/Assignment.html'
|
||||
return data
|
||||
|
||||
def get_absolute_url(self, link='view'):
|
||||
if link == 'view':
|
||||
def get_absolute_url(self, link='detail'):
|
||||
if link == 'detail' or link == 'view':
|
||||
return reverse('assignment_view', args=[str(self.id)])
|
||||
if link == 'edit':
|
||||
if link == 'update' or link == 'edit':
|
||||
return reverse('assignment_edit', args=[str(self.id)])
|
||||
if link == 'delete':
|
||||
return reverse('assignment_delete', args=[str(self.id)])
|
||||
|
@ -157,7 +157,7 @@ class MotionImportForm(CssClassMixin, forms.Form):
|
||||
csvfile = forms.FileField(
|
||||
widget=forms.FileInput(attrs={'size': '50'}),
|
||||
label=ugettext_lazy('CSV File'),
|
||||
help_text=ugettext_lazy('The file should be encoded in UTF-8.'))
|
||||
help_text=ugettext_lazy('The file has to be encoded in UTF-8.'))
|
||||
"""
|
||||
CSV filt with import data.
|
||||
"""
|
||||
|
@ -43,7 +43,7 @@ class Motion(SlideMixin, models.Model):
|
||||
This class is the main entry point to all other classes related to a motion.
|
||||
"""
|
||||
|
||||
prefix = 'motion'
|
||||
prefix = ugettext_noop('motion')
|
||||
"""
|
||||
Prefix for the slide system.
|
||||
"""
|
||||
@ -100,7 +100,7 @@ class Motion(SlideMixin, models.Model):
|
||||
"""
|
||||
Return a human readable name of this motion.
|
||||
"""
|
||||
return self.get_title()
|
||||
return self.active_version.title
|
||||
|
||||
# TODO: Use transaction
|
||||
def save(self, ignore_version_data=False, *args, **kwargs):
|
||||
@ -163,11 +163,11 @@ class Motion(SlideMixin, models.Model):
|
||||
"""
|
||||
Return an URL for this version.
|
||||
|
||||
The keyword argument 'link' can be 'detail', 'view', 'edit' or 'delete'.
|
||||
The keyword argument 'link' can be 'detail', 'view', 'edit', 'update' or 'delete'.
|
||||
"""
|
||||
if link == 'view' or link == 'detail':
|
||||
return reverse('motion_detail', args=[str(self.id)])
|
||||
if link == 'edit':
|
||||
if link == 'update' or link == 'edit':
|
||||
return reverse('motion_edit', args=[str(self.id)])
|
||||
if link == 'delete':
|
||||
return reverse('motion_delete', args=[str(self.id)])
|
||||
@ -349,6 +349,12 @@ class Motion(SlideMixin, models.Model):
|
||||
except IndexError:
|
||||
return self.new_version
|
||||
|
||||
def get_last_not_rejected_version(self):
|
||||
"""
|
||||
Returns the newest version of the motion, which is not rejected.
|
||||
"""
|
||||
return self.versions.filter(rejected=False).order_by('-version_number')[0]
|
||||
|
||||
@property
|
||||
def submitters(self):
|
||||
return sorted([object.person for object in self.submitter.all()],
|
||||
@ -452,11 +458,15 @@ class Motion(SlideMixin, models.Model):
|
||||
"""
|
||||
Return a title for the Agenda.
|
||||
"""
|
||||
return self.last_version.title # TODO: nutze active_version
|
||||
return self.active_version.title
|
||||
|
||||
## def get_agenda_title_supplement(self):
|
||||
## number = self.number or '<i>[%s]</i>' % ugettext('no number')
|
||||
## return '(%s %s)' % (ugettext('motion'), number)
|
||||
def get_agenda_title_supplement(self):
|
||||
"""
|
||||
Returns the supplement to the title for the agenda item.
|
||||
"""
|
||||
if self.identifier:
|
||||
return '(%s %s)' % (_('Motion'), self.identifier)
|
||||
return '(%s)' % _('Motion')
|
||||
|
||||
def get_allowed_actions(self, person):
|
||||
"""
|
||||
@ -672,11 +682,9 @@ class MotionLog(models.Model):
|
||||
Return a string, representing the log message.
|
||||
"""
|
||||
time = formats.date_format(self.time, 'DATETIME_FORMAT')
|
||||
return_message = '%s ' % time
|
||||
for message in self.message_list:
|
||||
return_message += _(message)
|
||||
return_message = '%s ' % time + ''.join(map(_, self.message_list))
|
||||
if self.person is not None:
|
||||
return_message += ' by %s' % self.person
|
||||
return_message += _(' by %s') % self.person
|
||||
return return_message
|
||||
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
{% else %}
|
||||
<i>[{% trans "no number" %}]</i>,
|
||||
{% endif %}
|
||||
{# TODO: show only for complex workflow #}
|
||||
{# TODO: show only for workflow with versioning #}
|
||||
{% trans "Version" %} {{ motion.version.version_number }}
|
||||
</small>
|
||||
<small class="pull-right">
|
||||
@ -57,19 +57,19 @@
|
||||
<div class="row-fluid">
|
||||
<div class="span8">
|
||||
{# TODO: show only for workflow with versioning #}
|
||||
{% if motion.version.version_number < motion.last_version.version_number %}
|
||||
{% if motion.version.version_number != motion.get_last_not_rejected_version.version_number %}
|
||||
<span class="label label-warning">
|
||||
<i class="icon-warning-sign icon-white"></i> {% trans "This is not the newest version." %}
|
||||
<i class="icon-warning-sign icon-white"></i> {% trans "This is not the last not rejected version." %}
|
||||
</span>
|
||||
<a href="{% model_url motion.last_version %}" class="btn btn-small">{% trans "Go to last version" %}
|
||||
(#{{ motion.last_version.version_number }})</a>
|
||||
<a href="{% model_url motion.get_last_not_rejected_version %}" class="btn btn-small">{% trans "Go to last not rejected version" %}
|
||||
(# {{ motion.get_last_not_rejected_version.version_number }})</a>
|
||||
{% endif %}
|
||||
{% if motion.version.version_number > motion.active_version.version_number %}
|
||||
{% if motion.version.version_number != motion.active_version.version_number %}
|
||||
<span class="label label-warning">
|
||||
<i class="icon-warning-sign icon-white"></i> {% trans "This version is not yet authorized." %}
|
||||
<i class="icon-warning-sign icon-white"></i> {% trans "This version is not authorized." %}
|
||||
</span>
|
||||
<a href="{% model_url motion.active_version %}" class="btn btn-small">{% trans "Go to last authorized version" %}
|
||||
(#{{ motion.active_version.version_number }})</a>
|
||||
(# {{ motion.active_version.version_number }})</a>
|
||||
{% endif %}
|
||||
|
||||
<!-- Text -->
|
||||
@ -198,7 +198,7 @@
|
||||
{% if perms.motion.can_manage_motion or poll.has_votes %}
|
||||
<li>{% trans "Vote" %}
|
||||
{% if perms.motion.can_manage_motion %}
|
||||
<a class="btn btn-mini" href="{% url 'motion_poll_edit' motion.id poll.id %}" title="{% trans 'Edit Vote' %}"><i class="icon-edit"></i></a>
|
||||
<a class="btn btn-mini" href="{% url 'motion_poll_edit' motion.id poll.id %}" title="{% trans 'Edit Vote' %}"><i class="icon-pencil"></i></a>
|
||||
<a class="btn btn-mini" href="{% url 'motion_poll_delete' motion.id poll.id %}" title="{% trans 'Delete Vote' %}"><i class="icon-remove"></i></a>
|
||||
{% endif %}
|
||||
<br>
|
||||
@ -220,7 +220,7 @@
|
||||
</li>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
<span style="margin-left:-25px;">-</span>
|
||||
<span style="margin-left:-25px;">–</span>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
{% if allowed_actions.create_poll %}
|
||||
@ -235,7 +235,7 @@
|
||||
{% if motion.category %}
|
||||
{{ motion.category }}
|
||||
{% else %}
|
||||
-
|
||||
–
|
||||
{% endif %}
|
||||
|
||||
<!-- Creation Time -->
|
||||
|
@ -23,8 +23,9 @@
|
||||
<li>
|
||||
{% trans 'Identifier, reason, submitter and category are optional and may be empty' %}.
|
||||
</li>
|
||||
<li>{% trans 'The first line (header) is ignored' %}.</li>
|
||||
<li>
|
||||
{% trans 'Required CSV file encoding: UTF-8.' %}
|
||||
{% trans 'Required CSV file encoding is UTF-8' %}.
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/OpenSlides/OpenSlides/wiki/CSV-Import">{% trans 'Use the CSV example file from OpenSlides Wiki.' %}</a>
|
||||
|
@ -50,8 +50,8 @@
|
||||
{% for motion in motion_list %}
|
||||
<tr class="{% if motion.active %}activeline{% endif %}">
|
||||
<td class="nobr">{{ motion.identifier|default:'' }}</td>
|
||||
<td><a href="{% model_url motion %}">{{ motion.title }}</a></td>
|
||||
<td class="optional">{% if motion.category %}{{ motion.category }}{% else %}-{% endif %}</td>
|
||||
<td><a href="{% model_url motion %}">{{ motion }}</a></td>
|
||||
<td class="optional">{% if motion.category %}{{ motion.category }}{% else %}–{% endif %}</td>
|
||||
<td><span class="label label-info">{% trans motion.state.name %}</span></td>
|
||||
<td class="optional">
|
||||
{% for submitter in motion.submitter.all %}
|
||||
|
@ -15,7 +15,7 @@
|
||||
</a>
|
||||
<a href="{% model_url motion %}">
|
||||
{% if motion.identifier %}
|
||||
[#{{ motion.identifier }}]
|
||||
[# {{ motion.identifier }}]
|
||||
{% else %}
|
||||
[---]
|
||||
{% endif %}
|
||||
|
@ -14,7 +14,7 @@
|
||||
</p>
|
||||
|
||||
<!-- poll results -->
|
||||
{% with motion.polls as polls %}
|
||||
{% with motion.polls.all as polls %}
|
||||
{% if polls.exists and polls.0.has_votes %}
|
||||
<p><b>{% trans "Poll result" %}:</b>
|
||||
{% for poll in polls %}
|
||||
@ -53,7 +53,7 @@
|
||||
|
||||
<h1>
|
||||
{% if motion.identifier %}
|
||||
{% trans "Motion No." %} {{ motion.identifier }}
|
||||
{% trans "Motion" %} {{ motion.identifier }}
|
||||
{% else %}
|
||||
{% trans "Motion" %} [---]
|
||||
{% endif %}
|
||||
|
@ -64,6 +64,8 @@ class GetVersionMixin(object):
|
||||
object.version = int(version_number)
|
||||
except MotionVersion.DoesNotExist:
|
||||
raise Http404('Version %s not found' % version_number)
|
||||
else:
|
||||
object.version = object.get_last_not_rejected_version()
|
||||
return object
|
||||
|
||||
|
||||
@ -227,6 +229,9 @@ class MotionDeleteView(DeleteView):
|
||||
"""Check if the request.user has the permission to delete the motion."""
|
||||
return self.get_object().get_allowed_actions(request.user)['delete']
|
||||
|
||||
def get_success_message(self):
|
||||
return _('%s was successfully deleted.') % _('Motion')
|
||||
|
||||
motion_delete = MotionDeleteView.as_view()
|
||||
|
||||
|
||||
@ -279,7 +284,7 @@ class VersionRejectView(GetVersionMixin, SingleObjectMixin, QuestionMixin, Redir
|
||||
|
||||
model = Motion
|
||||
question_url_name = 'motion_version_detail'
|
||||
success_url_name = 'motion_version_detail'
|
||||
success_url_name = 'motion_detail'
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
"""
|
||||
@ -307,6 +312,12 @@ class VersionRejectView(GetVersionMixin, SingleObjectMixin, QuestionMixin, Redir
|
||||
message_list=[ugettext_noop('Version %d rejected') % self.object.version.version_number],
|
||||
person=self.request.user)
|
||||
|
||||
def get_success_url_name_args(self):
|
||||
"""
|
||||
Returns the motion pk as argument for the success url name.
|
||||
"""
|
||||
return [self.object.pk]
|
||||
|
||||
version_reject = VersionRejectView.as_view()
|
||||
|
||||
|
||||
@ -505,7 +516,7 @@ class PollDeleteView(PollMixin, DeleteView):
|
||||
Write a log message, if the form is valid.
|
||||
"""
|
||||
super(PollDeleteView, self).case_yes()
|
||||
self.object.write_log([ugettext_noop('Poll deleted')], self.request.user)
|
||||
self.object.motion.write_log([ugettext_noop('Poll deleted')], self.request.user)
|
||||
|
||||
def get_redirect_url(self, **kwargs):
|
||||
"""
|
||||
|
@ -4,5 +4,5 @@ reportlab==2.7
|
||||
pillow==2.0.0
|
||||
qrcode==2.7
|
||||
tornado==3.0.1
|
||||
bleach==1.2.1
|
||||
bleach==1.2.2
|
||||
beautifulsoup4==4.1.3
|
||||
|
Loading…
Reference in New Issue
Block a user