canidate in assignment can be marked as elected

This commit is contained in:
Oskar Hahn 2011-09-03 11:42:44 +02:00
parent 2a89ccca5a
commit dcbeb452fb
10 changed files with 142 additions and 26 deletions

View File

@ -6,7 +6,6 @@
<link type="text/css" rel="stylesheet" media="all" href="/static/styles/tabledrag.css" /> <link type="text/css" rel="stylesheet" media="all" href="/static/styles/tabledrag.css" />
<link type="text/css" rel="stylesheet" media="all" href="/static/styles/agenda.css" /> <link type="text/css" rel="stylesheet" media="all" href="/static/styles/agenda.css" />
{% if perms.agenda.can_manage_agenda %} {% if perms.agenda.can_manage_agenda %}
<script type="text/javascript" src="/static/javascript/jquery.js"></script>
<script type="text/javascript" src="/static/javascript/jquery.once.js"></script> <script type="text/javascript" src="/static/javascript/jquery.once.js"></script>
<script type="text/javascript" src="/static/javascript/jquery.cookie.js"></script> <script type="text/javascript" src="/static/javascript/jquery.cookie.js"></script>
<script type="text/javascript" src="/static/javascript/jquery.tmpl.js"></script> <script type="text/javascript" src="/static/javascript/jquery.tmpl.js"></script>

View File

@ -28,6 +28,7 @@ class Assignment(models.Model):
assignment_number = models.PositiveSmallIntegerField(verbose_name = _("Number of available posts")) assignment_number = models.PositiveSmallIntegerField(verbose_name = _("Number of available posts"))
polldescription = models.CharField(max_length=50, null=True, blank=True, verbose_name = _("Short description (for ballot paper)")) polldescription = models.CharField(max_length=50, null=True, blank=True, verbose_name = _("Short description (for ballot paper)"))
profile = models.ManyToManyField(Profile, null=True, blank=True) profile = models.ManyToManyField(Profile, null=True, blank=True)
elected = models.ManyToManyField(Profile, null=True, blank=True, related_name='elected_set')
status = models.CharField(max_length=1, choices=STATUS, default='sea') status = models.CharField(max_length=1, choices=STATUS, default='sea')
def set_status(self, status): def set_status(self, status):
@ -66,13 +67,40 @@ class Assignment(models.Model):
else: else:
return False return False
@property
def candidates(self):
# list of candidates
from poll.models import Option
candidates = set()
for option in Option.objects.filter(poll__assignment=self):
candidates.add(option.value)
return candidates
def set_elected(self, profile, value=True):
if profile in self.candidates:
if value and not self.is_elected(profile):
self.elected.add(profile)
elif not value:
self.elected.remove(profile)
def is_elected(self, profile):
if profile in self.elected.all():
return True
return False
def gen_poll(self): def gen_poll(self):
from poll.models import Poll from poll.models import Poll
poll = Poll() poll = Poll()
poll.title = _("Election for %s") % self.name poll.title = _("Election for %s") % self.name
candidates = list(self.profile.all())
for elected in self.elected.all():
try:
candidates.remove(elected)
except ValueError:
pass
# Option A: candidates <= available posts -> yes/no/abstention # Option A: candidates <= available posts -> yes/no/abstention
if self.profile.count() <= self.assignment_number: if len(candidates) <= self.assignment_number - self.elected.count():
poll.optiondecision = True poll.optiondecision = True
else: else:
poll.optiondecision = False poll.optiondecision = False
@ -86,8 +114,8 @@ class Assignment(models.Model):
poll.assignment = self poll.assignment = self
poll.description = self.polldescription poll.description = self.polldescription
poll.save() poll.save()
for profile in self.profile.get_query_set(): for candidate in candidates:
poll.add_option(profile) poll.add_option(candidate)
return poll return poll
@models.permalink @models.permalink

View File

@ -1,6 +1,11 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load tags %} {% load tags %}
{% block header %}
<link type="text/css" rel="stylesheet" media="all" href="/static/styles/assignment.css" />
<script type="text/javascript" src="/static/javascript/assignment.js"></script>
{% endblock %}
{% block submenu %} {% block submenu %}
{% url election_overview as url_electionoverview %} {% url election_overview as url_electionoverview %}
<h4 class="sectiontitle">{%trans "Elections" %}</h4> <h4 class="sectiontitle">{%trans "Elections" %}</h4>

View File

@ -111,7 +111,7 @@
<h3>{% trans "Election results" %}</h3> <h3>{% trans "Election results" %}</h3>
{% if assignment.poll_set.all.count > 0 %} {% if assignment.poll_set.all.count > 0 %}
<table style="width: auto;"> <table id="election_table" style="width: auto;">
<tr> <tr>
<th></th> <th></th>
{% with ballotnumber=assignment.poll_set.all.count %} {% with ballotnumber=assignment.poll_set.all.count %}
@ -145,7 +145,17 @@
{% for vote in votes %} {% for vote in votes %}
<tr class="{% cycle 'odd' '' %}"> <tr class="{% cycle 'odd' '' %}">
{% for v in vote %} <td class="candidate">
{% with vote|first as candidate %}
{{ candidate.0 }}
{% if candidate.1 %}
<a class="election_link iselected" href='{% url assignment_user_not_elected assignment.id candidate.0.id %}'>{% trans 'not elected' %}</a>
{% else %}
<a class="election_link" href='{% url assignment_user_elected assignment.id candidate.0.id %}'>{% trans 'elected' %}</a>
{% endif %}
{% endwith %}
</td>
{% for v in vote|last %}
<td style="white-space:nowrap;">{% if v %} <td style="white-space:nowrap;">{% if v %}
{% if v|length == 3 %} {% if v|length == 3 %}
<img src="/static/images/icons/voting-yes.png" title="{% trans 'Yes' %}"> {% if v.0 %}{{ v.0 }}{% else %}&empty;{% endif %}<br> <img src="/static/images/icons/voting-yes.png" title="{% trans 'Yes' %}"> {% if v.0 %}{{ v.0 }}{% else %}&empty;{% endif %}<br>

View File

@ -51,4 +51,10 @@ urlpatterns = patterns('assignment.views',
url(r'^assignment/poll/(?P<poll_id>\d+)/del$', 'delete_poll', \ url(r'^assignment/poll/(?P<poll_id>\d+)/del$', 'delete_poll', \
name='assignment_poll_delete'), name='assignment_poll_delete'),
url(r'^assignment/(?P<assignment_id>\d+)/elected/(?P<profile_id>\d+)$', 'set_elected', {'elected': True}, \
name='assignment_user_elected'),
url(r'^assignment/(?P<assignment_id>\d+)/notelected/(?P<profile_id>\d+)$', 'set_elected', {'elected': False}, \
name='assignment_user_not_elected'),
) )

View File

@ -20,7 +20,7 @@ from poll.models import Poll, Option
from poll.forms import OptionResultForm, PollInvalidForm from poll.forms import OptionResultForm, PollInvalidForm
from assignment.models import Assignment from assignment.models import Assignment
from assignment.forms import AssigmentForm, AssigmentRunForm from assignment.forms import AssigmentForm, AssigmentRunForm
from utils.utils import template, permission_required, gen_confirm_form, del_confirm_form from utils.utils import template, permission_required, gen_confirm_form, del_confirm_form, ajax_request
from utils.pdf import print_assignment_poll from utils.pdf import print_assignment_poll
from participant.models import Profile from participant.models import Profile
@ -65,24 +65,18 @@ def view(request, assignment_id=None):
if request.user.has_perm('assignment.can_nominate_other'): if request.user.has_perm('assignment.can_nominate_other'):
form = AssigmentRunForm() form = AssigmentRunForm()
# list of candidates
candidates = set()
for option in Option.objects.filter(poll__assignment=assignment):
candidates.add(option.value)
votes = [] votes = []
for candidate in candidates: for candidate in assignment.candidates:
tmplist = [] tmplist = [[candidate, assignment.is_elected(candidate)], []]
tmplist.append(candidate)
for poll in assignment.poll_set.all(): for poll in assignment.poll_set.all():
if candidate in poll.options_values: if candidate in poll.options_values:
option = Option.objects.filter(poll=poll).filter(user=candidate)[0] option = Option.objects.filter(poll=poll).filter(user=candidate)[0]
if poll.optiondecision: if poll.optiondecision:
tmplist.append([option.yes, option.no, option.undesided]) tmplist[1].append([option.yes, option.no, option.undesided])
else: else:
tmplist.append(option.yes) tmplist[1].append(option.yes)
else: else:
tmplist.append("-") tmplist[1].append("-")
votes.append(tmplist) votes.append(tmplist)
return {'assignment': assignment, return {'assignment': assignment,
@ -142,6 +136,26 @@ def set_status(request, assignment_id=None, status=None):
return redirect(reverse('assignment_view', args=[assignment_id])) return redirect(reverse('assignment_view', args=[assignment_id]))
@permission_required('assignment.can_manage_assignment')
def set_elected(request, assignment_id, profile_id, elected=True):
assignment = Assignment.objects.get(pk=assignment_id)
profile = Profile.objects.get(pk=profile_id)
assignment.set_elected(profile, elected)
if request.is_ajax():
if elected:
link = reverse('assignment_user_not_elected', args=[assignment.id, profile.id])
text = _('not elected')
else:
link = reverse('assignment_user_elected', args=[assignment.id, profile.id])
text = _('elected')
return ajax_request({'elected': elected,
'link': link,
'text': text})
return redirect(reverse('assignment_view', args=[assignment_id]))
@permission_required('assignment.can_nominate_self') @permission_required('assignment.can_nominate_self')
def run(request, assignment_id): def run(request, assignment_id):
assignment = Assignment.objects.get(pk=assignment_id) assignment = Assignment.objects.get(pk=assignment_id)

View File

@ -24,7 +24,9 @@ function renderSlide(slide) {
$(function() { $(function() {
// Set Active Slide with Ajax
$('.activate_link').click(function(event) { $('.activate_link').click(function(event) {
event.preventDefault(); event.preventDefault();
$.ajax({ $.ajax({

View File

@ -0,0 +1,47 @@
$(function() {
$('a.iselected').parent().parent().children('td').addClass('iselected');
$('.election_link').click(function(event) {
event.preventDefault();
line = $(this);
$.ajax({
type: 'GET',
url: line.attr('href'),
dataType: 'json',
success: function(data) {
if (line.hasClass('iselected') && !data.elected) {
line.removeClass('iselected')
line.parent().parent().children('td').removeClass('iselected')
} else if (!line.hasClass('iselected') && data.elected) {
line.addClass('iselected')
line.parent().parent().children('td').addClass('iselected')
}
line.attr('href', data.link);
line.text(data.text);
},
error: function () {
alert("Ajax Error");
}
});
});
$('.close_link').click(function(event) {
event.preventDefault();
slide = $(this);
$.ajax({
type: 'GET',
url: slide.attr('href'),
dataType: 'json',
success: function(data) {
if (data.closed) {
newclass = 'closed';
} else {
newclass = 'open';
}
slide.removeClass('closed open').addClass(newclass);
slide.attr('href', data.link);
}
});
});
});

View File

@ -0,0 +1,5 @@
td.iselected {
background-color: green !important;
}

View File

@ -7,8 +7,8 @@
<title>{% block title %}{% get_config 'event_name' %}{% endblock %}</title> <title>{% block title %}{% get_config 'event_name' %}{% endblock %}</title>
<link type="text/css" rel="stylesheet" media="all" href="/static/styles/base.css" /> <link type="text/css" rel="stylesheet" media="all" href="/static/styles/base.css" />
<link rel="shortcut icon" href="/static/images/favicon.png" type="image/png" /> <link rel="shortcut icon" href="/static/images/favicon.png" type="image/png" />
{% block header %}
<script type="text/javascript" src="/static/javascript/jquery.js"></script> <script type="text/javascript" src="/static/javascript/jquery.js"></script>
{% block header %}
{% endblock %} {% endblock %}
</head> </head>
<body> <body>