Merge branch 'master' of github.com:OpenSlides/OpenSlides

This commit is contained in:
Oskar Hahn 2013-03-15 02:16:26 +01:00
commit c46ec570bf
14 changed files with 288 additions and 112 deletions

View File

@ -49,9 +49,9 @@ class Motion(SlideMixin, models.Model):
related_name="active_version")
"""Points to a specific version.
Used be the permitted-version-system to deside witch version is the active
Version. Could also be used to only choose a specific version as a default
version. Like the Sighted versions on Wikipedia.
Used be the permitted-version-system to deside which version is the active
version. Could also be used to only choose a specific version as a default
version. Like the sighted versions on Wikipedia.
"""
state = models.ForeignKey('State', null=True) # TODO: Check whether null=True is necessary.
@ -574,7 +574,7 @@ class Category(models.Model):
name = models.CharField(max_length=255, verbose_name=ugettext_lazy("Category name"))
"""Name of the category."""
prefix = models.CharField(blank=True, max_length=32, verbose_name=ugettext_lazy("Category prefix"))
prefix = models.CharField(blank=True, max_length=32, verbose_name=ugettext_lazy("Prefix"))
"""Prefix of the category.
Used to build the identifier of a motion.
@ -589,6 +589,8 @@ class Category(models.Model):
if link == 'delete':
return reverse('motion_category_delete', args=[str(self.id)])
class Meta:
ordering = ['prefix']
## class Comment(models.Model):
## motion_version = models.ForeignKey(MotionVersion)

View File

@ -0,0 +1,41 @@
/**
* OpenSlides motion style
*
* :copyright: 2013 by OpenSlides team, see AUTHORS.
* :license: GNU GPL, see LICENSE for more details.
*/
/* motion version diff table */
table.diff, .diff_row {
font-size: 12px;
width: 100%;
border: 0px;
}
table.diff[rules][rules="groups"] > colgroup, table[rules][rules="groups"] > tfoot, table[rules][rules="groups"] > thead, table[rules][rules="groups"] > tbody {
border: none;
}
table.diff td {
padding: 0 !important;
border: none;
}
.diff_header {
background-color:#e0e0e0;
}
td.diff_header {
text-align:right;
display: none;
}
.diff_next {
background-color:#c0c0c0;
display: none;
}
.diff_add {
background-color:#aaffaa;
}
.diff_chg {
background-color:#ffff77;
}
.diff_sub {
background-color:#ffaaaa;
}

View File

@ -5,7 +5,7 @@
{% block title %}
{{ block.super }}
{% if motion %}
{% if category %}
{% trans "Edit category" %}
{% else %}
{% trans "New category" %}
@ -14,7 +14,7 @@
{% block content %}
<h1>
{% if motion %}
{% if category %}
{% trans "Edit category" %}
{% else %}
{% trans "New category" %}
@ -24,7 +24,7 @@
{% include "form.html" %}
<p>
{% include "formbuttons_saveapply.html" %}
<a href='{% url 'motion_list' %}' class="btn">
<a href='{% url 'motion_category_list' %}' class="btn">
{% trans 'Cancel' %}
</a>
</p>

View File

@ -6,11 +6,40 @@
{% block title %}{{ block.super }} {% trans "Motions" %}{% endblock %}
{% block content %}
<h1>{% trans "Categories" %}</h1>
<h1>
{% trans "Categories" %}
<small class="pull-right">
{% if perms.motion.can_manage_motion %}
<a href="{% url 'motion_category_create' %}" class="btn btn-mini btn-primary" rel="tooltip" data-original-title="{% trans 'New motion' %}"><i class="icon-plus icon-white"></i> {% trans 'New' %}</a>
{% endif %}
<a href="{% url 'motion_list' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a>
</small>
</h1>
<table class="table table-striped table-bordered">
<tr>
<th class="mini_width">{% trans "Prefix" %}</th>
<th>{% trans "Category name" %}</th>
<th class="mini_width">{% trans "Actions" %}</th>
</tr>
{% for category in category_list %}
<p><a href="{% model_url category 'update' %}">{{ category }}</a></p>
<tr>
<td>{{ category.prefix }}</td>
<td><a href="{% model_url category 'update' %}">{{ category }}</a></td>
<td><span style="width: 1px; white-space: nowrap;">
<a href="{% model_url category 'update' %}" title="{% trans 'Edit' %}" class="btn btn-mini">
<i class="icon-pencil"></i>
</a>
<a href="{% model_url category 'delete' %}" title="{% trans 'Delete' %}" class="btn btn-mini">
<i class="icon-remove"></i>
</a>
</span>
</td>
</tr>
{% empty %}
<p>No Categories</p>
<tr>
<td colspan="3"><i>{% trans "No categories available." %}</i></td>
</tr>
{% endfor %}
</table>
{% endblock %}

View File

@ -4,18 +4,19 @@
{% load i18n %}
{% load staticfiles %}
{% block title %}{{ block.super }} {% trans "Motion" %} {{ motion.number }}{% endblock %}
{% block title %}{{ block.super }} {% trans "Motion" %} {{ motion.identifier }}{% endblock %}
{% block content %}
<h1>
{{ motion.title }} {{ motion.category }}
<br>
<small>
{% if motion.identifier != None %}
{% if motion.identifier %}
{% trans "Motion" %} {{ motion.identifier }},
{% else %}
<i>[{% trans "no number" %}]</i>,
{% endif %}
{# TODO: show only for complex workflow #}
{% trans "Version" %} {{ motion.version.version_number }}
</small>
<small class="pull-right">
@ -56,13 +57,20 @@
<div class="row-fluid">
<div class="span8">
{% if motion.active_version.id != motion.version.id %}
<span class="label label-warning"><i class="icon-warning-sign icon-white"></i>
{% if motion.version == motion.public_version %}
{% trans "This is not the newest version." %}</span> <a href="{% url 'motion_version_detail' motion.id motion.last_version.id %}">{% trans "Go to version" %} {{ motion.last_version.version_number }}.</a>
{% else %}
{% trans "This is not the authorized version." %}</span> <a href="{% url 'motion_view' motion.id %}">{% trans "Go to version" %} {{ motion.public_version.aid }}.</a>
{% endif %}
{# TODO: show only for complex workflow #}
{% if motion.version.version_number < motion.last_version.version_number %}
<span class="label label-warning">
<i class="icon-warning-sign icon-white"></i> {% trans "This is not the newest version." %}
</span>
<a href="{% model_url motion.last_version %}" class="btn btn-small">{% trans "Go to last version" %}
(#{{ motion.last_version.version_number }})</a>
{% endif %}
{% 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." %}
</span>
<a href="{% model_url motion.active_version %}" class="btn btn-small">{% trans "Go to last authorized version" %}
(#{{ motion.active_version.version_number }})</a>
{% endif %}
<!-- Text -->
@ -80,84 +88,60 @@
<br>
<!-- Version history -->
{% for version in motion.versions.all %}
{% if forloop.first %}
<h4>{% trans "Version history" %}:</h4>
<table class="table table-striped table-bordered">
<tr>
<th></th>
<th>{% trans "Version" %}</th>
<th>{% trans "Time" %}</th>
<th>{% trans "Title" %}</th>
<th>{% trans "Text" %}</th>
<th>{% trans "Reason" %}</th>
</tr>
{% endif %}
<tr>
<td class="nobr">
{% if version == motion.active_version %}
<span class="badge badge-success" title="{% trans 'This version is authorized' %}"><i class="icon-ok icon-white"></i></span>
{% else %}
{% if perms.motion.can_manage_motion %}
<a class="btn btn-mini" href="{% url 'motion_version_permit' motion.id version.id %}" title="{% trans 'Permit this version' %}"><i class="icon-ok"></i></a>
{% endif %}
{% if not version.rejected and version.id > motion.active_version.id and perms.motion.can_manage_motion %}
<a class="btn btn-mini" href="{% url 'motion_version_reject' version.id %}" title="{% trans 'Reject this version' %}"><i class="icon-ban-circle"></i></a>
{% endif %}
{% with versions=motion.versions.all %}
{% if versions|length > 1 %}
{% for version in versions %}
{% if forloop.first %}
<h4>{% trans "Version history" %}:</h4>
<form action="{% url 'motion_version_diff' motion.pk %}" method="get">
<table class="table table-striped table-bordered">
<tr>
<th></th>
<th>#</th>
<th>{% trans "Time" %}</th>
<th><button class="btn btn-small" type="submit">{% trans 'Difference' %}</button></th>
<th>{% trans "Actions" %}</th>
</tr>
{% endif %}
{% if version.rejected %}
<span class="badge badge-important" title="{% trans 'This version is rejected' %}"><i class="icon-ban-circle icon-white"></i></span>
{% endif %}
</td>
<td><a href="{% model_url version %}">{{ version.version_number }}</a></td>
<td><i>{{ version.creation_time }}</i></td>
<td>
{% ifchanged %}
<b>{{ version.title }}</b>
{% else %}
<i>[{% trans "unchanged" %}]</i>
{% endifchanged %}
</td>
<td>
{% ifchanged %}
{{ version.text|linebreaks }}
{% else %}
<i>[{% trans "unchanged" %}]</i>
{% endifchanged %}
</td>
<td>
{% ifchanged %}
{{ version.reason|linebreaks }}
{% else %}
<i>[{% trans "unchanged" %}]</i>
{% endifchanged %}
</td>
</tr>
{% if forloop.last %}
</table>
<tr {% if version == motion.version %}class="offline"{%endif %}>
<td class="nobr">
{% if version == motion.active_version %}
<span class="badge badge-success" title="{% trans 'This version is authorized' %}"><i class="icon-ok icon-white"></i></span>
{% else %}
{% if perms.motion.can_manage_motion %}
<a class="btn btn-mini" href="{% url 'motion_version_permit' motion.id version.version_number %}" title="{% trans 'Permit this version' %}"><i class="icon-ok"></i></a>
{% endif %}
{% if not version.rejected and version.id > motion.active_version.id and perms.motion.can_manage_motion %}
<a class="btn btn-mini" href="{% url 'motion_version_reject' motion.id version.version_number %}" title="{% trans 'Reject this version' %}"><i class="icon-ban-circle"></i></a>
{% endif %}
{% endif %}
{% if version.rejected %}
<span class="badge badge-important" title="{% trans 'This version is rejected' %}"><i class="icon-ban-circle icon-white"></i></span>
{% endif %}
</td>
<td>{{ version.version_number }}</td>
<td><i>{{ version.creation_time }}</i></td>
<td>
<input type="radio" value="{{ version.version_number }}" name="rev1">
<input type="radio" value="{{ version.version_number }}" name="rev2">
</td>
<td>
<a href="{% model_url version %}" title="{% trans 'Show version number' %} {{ version.version_number }}" class="btn btn-mini">
<i class="icon-search"></i>
</a>
{# TODO: add delete version function #}
<a href="{% model_url version 'delete' %}" title="{% trans 'Delete version number' %} {{ version.version_number }}" class="btn btn-mini">
<i class="icon-remove"></i>
</a>
</td>
</tr>
{% if forloop.last %}
</table>
</form>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
<!-- TODO: For testing -->
<ol>
{% for motion_version in motion.versions.all %}
<li>
{% if motion_version.id == motion.version.id %}
<strong><a href="{% model_url motion_version %}">{{ motion_version }}</a></strong>
{% else %}
<a href="{% model_url motion_version %}">{{ motion_version }}</a>
{% endif %}
{% if motion_version.active %}
(active)
{% endif %}
{% if motion_version.rejected %}
(rejected)
{% endif %}
</li>
{% endfor %}
</ol>
<!-- End TODO -->
{% endwith %}
<!-- Log -->
{% if perms.motion.can_manage_motion %}
@ -247,6 +231,10 @@
{% endif %}
{% endwith %}
<!-- Category -->
<h5>{% trans "Category" %}:</h5>
{{ motion.category }}
<!-- Creation Time -->
<h5>{% trans "Creation Time" %}:</h5>
{# TODO: use creation time of _first_ version #}
@ -287,7 +275,7 @@
<!-- Manage motion box -->
<div class="well">
<h4>{% trans "Manage motion" %}</h4>
<div class="btn-group">
<div class="btn-group btn-group-vertical">
{% for state in motion.state.next_states.all %}
<a href="{% url 'motion_set_state' motion.pk state.pk %}" class="btn btn-small">{{ state }}</a>
{% endfor %}
@ -303,5 +291,4 @@
</div> <!--/span-->
</div> <!--/row-->
{% endblock %}

View File

@ -0,0 +1,67 @@
{% extends "base.html" %}
{% load tags %}
{% load i18n %}
{% load staticfiles %}
{% block title %}{{ block.super }} {% trans "Motion" %} {{ motion.identifier }}{% endblock %}
{% block header %}
<link type="text/css" rel="stylesheet" media="all" href="{% static 'styles/motion.css' %}" />
{% endblock %}
{% block content %}
<h1>
{{ motion.title }}
<br>
<small>
{% if motion.identifier != None %}
{% trans "Motion" %} {{ motion.identifier }},
{% else %}
<i>[{% trans "no number" %}]</i>,
{% endif %}
{% trans "Diff view" %}
</small>
<small class="pull-right">
<div class="btn-toolbar">
<a href="{% url 'motion_detail' motion.id %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to motion" %}</a>
</div>
</small>
</h1>
{% if version_rev1 and version_rev2 %}
<table class="table table-striped table-bordered">
<tr>
<td><b>{% trans "Version" %} {{ version_rev1.version_number }}</b><br>
{% trans "created: " %} {{ version_rev1.creation_time }}<br>
<h4>{{ version_rev1.title }}</h4>
</td>
<td><b>{% trans "Version" %} {{ version_rev2.version_number }}</b><br>
{% trans "created: " %} {{ version_rev1.creation_time }}<br>
<h4>{{ version_rev2.title }}</h4>
</td>
</tr>
<!-- Text -->
<tr class="diff_row">
{% if not version_rev1.text == version_rev2.text %}
<td colspan="2">{{ diff_text|safe }}</td>
{% else %}
<td>{{ version_rev1.text }}</td>
<td>{{ version_rev2.text }}</td>
{% endif %}
</tr>
<!-- Reason -->
<tr><td colspan="2"><h4>{% trans "Reason" %}:</h4></td></tr>
<tr class="diff_row">
{% if not version_rev1.reason == version_rev2.reason %}
<td colspan="2">{{ diff_reason|safe }}</td>
{% else %}
<td>{{ version_rev1.reason }}</td>
<td>{{ version_rev2.reason }}</td>
{% endif %}
</tr>
</table>
{% endif %}
{% endblock %}

View File

@ -10,9 +10,10 @@
{% trans "Motions" %}
<small class="pull-right">
{% if perms.motion.can_create_motion %}
<a href="{% url 'motion_new' %}" class="btn btn-mini btn-primary" rel="tooltip" data-original-title="{% trans 'New motion' %}"><i class="icon-plus icon-white"></i> {% trans "New" %}</a>
<a href="{% url 'motion_new' %}" class="btn btn-mini btn-primary" rel="tooltip" data-original-title="{% trans 'New motion' %}"><i class="icon-plus icon-white"></i> {% trans 'New' %}</a>
{% endif %}
{% if perms.motion.can_manage_motion %}
<a href="{% url 'motion_category_list' %}" class="btn btn-mini" rel="tooltip" data-original-title="{% trans 'New motion' %}"><i class="icon-th-large"></i> {% trans 'Category' %}</a>
{# <a href="{% url 'motion_import' %}" class="btn btn-mini" rel="tooltip" data-original-title="{% trans 'Import motions' %}"><i class="icon-import"></i> {% trans 'Import' %}</a>#}
{% endif %}
<a href="{% url 'motion_list_pdf' %}" class="btn btn-mini" rel="tooltip" data-original-title="{% trans 'Print all motions as PDF' %}"><i class="icon-print"></i> PDF</a>
@ -60,7 +61,7 @@
</tr>
{% for motion in motion_list %}
<tr class="{% if motion.active %}activeline{% endif %}">
<td>{{ motion.number }}</td>
<td>{{ motion.identifier }}</td>
<td><a href="{% model_url motion %}">{{ motion.title }}</a></td>
{% if min_supporters > 0 %}
<td class="optional">{# motion.count_supporters #}</td>

View File

@ -3,7 +3,7 @@
{% load i18n %}
{% block title %}
{{ block.super }} - {% trans "Motion" %} {{ motion.number }}, {{ ballot }}. {% trans "Vote" %}
{{ block.super }} - {% trans "Motion" %} {{ motion.identifier }}, {{ ballot }}. {% trans "Vote" %}
{% endblock %}
{% block content %}
@ -11,7 +11,7 @@
{{ motion }}
<br>
<small>
{% trans "Motion" %} {{ motion.number }}, {{ ballot }}. {% trans "Vote" %}
{% trans "Motion" %} {{ motion.identifier }}, {{ ballot }}. {% trans "Vote" %}
</small>
<small class="pull-right">
<div class="btn-toolbar">

View File

@ -17,8 +17,8 @@
{{ motion.public_version.title }}
</a>
({% trans "motion" %}
{% if motion.number %}
{{ motion.number }})
{% if motion.identifier %}
{{ motion.identifier }})
{% else %}
<i>[{% trans "no number" %}]</i>)
{% endif %}

View File

@ -4,7 +4,7 @@
{% load i18n %}
{% load staticfiles %}
{% block title %}{{ block.super }} - {% trans "Motion" %} {{ motion.number }}{% endblock %}
{% block title %}{{ block.super }} - {% trans "Motion" %} {{ motion.identifier }}{% endblock %}
{% block content %}
<div id="sidebar">
<div class="box">
@ -59,8 +59,8 @@
</div>
<h1>
{% if motion.number != None %}
{% trans "Motion No." %} {{ motion.number }}
{% if motion.identifier %}
{% trans "Motion No." %} {{ motion.identifier }}
{% else %}
{% trans "Motion" %} <i>[{% trans "no number" %}]</i>
{% endif %}

View File

@ -60,6 +60,11 @@ urlpatterns = patterns('openslides.motion.views',
name='motion_version_reject',
),
url(r'^(?P<pk>\d+)/diff/$',
'version_diff',
name='motion_version_diff',
),
url(r'^(?P<pk>\d+)/support/$',
'motion_support',
name='motion_support',

View File

@ -25,7 +25,7 @@ from openslides.utils.views import (
TemplateView, RedirectView, UpdateView, CreateView, DeleteView, PDFView,
DetailView, ListView, FormView, QuestionMixin, SingleObjectMixin)
from openslides.utils.template import Tab
from openslides.utils.utils import html_strong
from openslides.utils.utils import html_strong, htmldiff
from openslides.poll.views import PollFormView
from openslides.projector.api import get_active_slide
from openslides.projector.projector import Widget, SLIDE
@ -251,6 +251,39 @@ class VersionRejectView(GetVersionMixin, SingleObjectMixin, QuestionMixin, Redir
version_reject = VersionRejectView.as_view()
class VersionDiffView(DetailView):
"""Show diff between two versions of a motion."""
permission_required = 'motion.can_see_motion'
model = Motion
template_name = 'motion/motion_diff.html'
def get_context_data(self, **kwargs):
"""Return the template context with versions and html diff strings."""
try:
rev1 = int(self.request.GET['rev1'])
rev2 = int(self.request.GET['rev2'])
version_rev1 = self.object.versions.get(version_number=self.request.GET['rev1'])
version_rev2 = self.object.versions.get(version_number=self.request.GET['rev2'])
diff_text = htmldiff(version_rev1.text, version_rev2.text)
diff_reason = htmldiff(version_rev1.reason, version_rev2.reason)
except (KeyError, ValueError, MotionVersion.DoesNotExist):
messages.error(self.request, _('At least one version number was not valid.'))
version_rev1 = None
version_rev2 = None
diff_text = None
diff_reason = None
context = super(VersionDiffView, self).get_context_data(**kwargs)
context.update({
'version_rev1': version_rev1,
'version_rev2': version_rev2,
'diff_text': diff_text,
'diff_reason': diff_reason,
})
return context
version_diff = VersionDiffView.as_view()
class SetIdentifierView(SingleObjectMixin, RedirectView):
"""Set the identifier of the motion.
@ -530,6 +563,7 @@ category_list = CategoryListView.as_view()
class CategoryCreateView(CreateView):
permission_required = 'motion.can_manage_motion'
model = Category
success_url_name = 'motion_category_list'
category_create = CategoryCreateView.as_view()
@ -537,6 +571,7 @@ category_create = CategoryCreateView.as_view()
class CategoryUpdateView(UpdateView):
permission_required = 'motion.can_manage_motion'
model = Category
success_url_name = 'motion_category_list'
category_update = CategoryUpdateView.as_view()
@ -544,6 +579,7 @@ category_update = CategoryUpdateView.as_view()
class CategoryDeleteView(DeleteView):
permission_required = 'motion.can_manage_motion'
model = Category
question_url_name = 'motion_category_list'
success_url_name = 'motion_category_list'
category_delete = CategoryDeleteView.as_view()

View File

@ -7,8 +7,8 @@
<li>
<a href="{% model_url motion 'view' %}">{{ motion.public_version.title }}</a>
({% trans "motion" %}
{% if motion.number %}
{{ motion.number }})
{% if motion.identifier %}
{{ motion.identifier }})
{% else %}
<i>[{% trans "no number" %}]</i>)
{% endif %}
@ -26,8 +26,8 @@
<li>
<a href="{% model_url motion 'view' %}">{{ motion.public_version.title }}</a>
({% trans "motion" %}
{% if motion.number %}
{{ motion.number }})
{% if motion.identifier %}
{{ motion.identifier }})
{% else %}
<i>[{% trans "no number" %}]</i>)
{% endif %}

View File

@ -10,8 +10,9 @@
:license: GNU GPL, see LICENSE for more details.
"""
import sys
import difflib
import json
import sys
from django.contrib import messages
from django.contrib.auth.models import Permission
@ -133,3 +134,10 @@ def ajax_request(data):
def html_strong(string):
return u"<strong>%s</strong>" % string
def htmldiff(text1, text2):
"""Return string of html diff between two strings (text1 and text2)"""
diff = difflib.HtmlDiff(wrapcolumn=60)
return diff.make_table(text1.splitlines(), text2.splitlines())