Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/assets.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ hash-name = false

[bootstrap]
recipe = hexagonit.recipe.download
url = https://github.com/twbs/bootstrap/releases/download/v3.3.1/bootstrap-3.3.1-dist.zip
url = https://github.com/twbs/bootstrap/releases/download/v3.3.5/bootstrap-3.3.5-dist.zip
hash-name = false
strip-top-level-dir = true

Expand Down
1 change: 1 addition & 0 deletions pylab/core/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('website', '0002_auto_20150728_0303'),
]

operations = [
Expand Down
48 changes: 48 additions & 0 deletions pylab/core/migrations/0006_auto_20150806_0437.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
from django.conf import settings
import django_extensions.db.fields
import django.utils.timezone
import autoslug.fields


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('core', '0005_auto_20150730_0231'),
]

operations = [
migrations.CreateModel(
name='Vote',
fields=[
('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
('created', django_extensions.db.fields.CreationDateTimeField(editable=False, default=django.utils.timezone.now, blank=True)),
('modified', django_extensions.db.fields.ModificationDateTimeField(editable=False, default=django.utils.timezone.now, blank=True)),
('vote_time', models.DateTimeField(null=True)),
('points', models.IntegerField(verbose_name='Points', null=True)),
('project', models.ForeignKey(to='core.Project')),
('voter', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='VotingPoll',
fields=[
('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
('created', django_extensions.db.fields.CreationDateTimeField(editable=False, default=django.utils.timezone.now, blank=True)),
('modified', django_extensions.db.fields.ModificationDateTimeField(editable=False, default=django.utils.timezone.now, blank=True)),
('slug', autoslug.fields.AutoSlugField(editable=False)),
('title', models.CharField(verbose_name='Title', max_length=255)),
('description', models.TextField(blank=True, verbose_name='Description')),
('author', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddField(
model_name='vote',
name='voting_poll',
field=models.ForeignKey(to='core.VotingPoll'),
),
]
19 changes: 19 additions & 0 deletions pylab/core/migrations/0007_auto_20150808_1812.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

dependencies = [
('core', '0006_auto_20150806_0437'),
]

operations = [
migrations.AlterField(
model_name='vote',
name='points',
field=models.PositiveIntegerField(verbose_name='Points', null=True, blank=True),
),
]
19 changes: 19 additions & 0 deletions pylab/core/migrations/0008_auto_20150809_0654.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

dependencies = [
('core', '0007_auto_20150808_1812'),
]

operations = [
migrations.RenameField(
model_name='vote',
old_name='vote_time',
new_name='voted',
),
]
25 changes: 25 additions & 0 deletions pylab/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,28 @@ def __str__(self):

def get_absolute_url(self):
return reverse('event-details', args=[self.starts.year, self.starts.month, self.starts.day, self.slug])


class VotingPoll(models.Model):
created = CreationDateTimeField()
modified = ModificationDateTimeField()
author = models.ForeignKey(User)
slug = AutoSlugField(populate_from='title')
title = models.CharField(_("Title"), max_length=255)
description = models.TextField(_("Description"), blank=True)

def __str__(self):
return self.title


class Vote(models.Model):
created = CreationDateTimeField()
modified = ModificationDateTimeField()
voted = models.DateTimeField(null=True)
voting_poll = models.ForeignKey(VotingPoll)
voter = models.ForeignKey(User)
project = models.ForeignKey(Project)
points = models.PositiveIntegerField(_("Points"), null=True, blank=True)

def __str__(self):
return '%s, %s' % (self.voting_poll.title, self.voter.get_full_name() or self.voter.get_username())
8 changes: 5 additions & 3 deletions pylab/website/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import allauth.socialaccount.admin as allauth

from pylab.core.models import Project, Event
import pylab.core.models as core_models


class AdminSite(admin.AdminSite):
Expand Down Expand Up @@ -50,8 +50,10 @@ def get_changeform_initial_data(self, request):
site = AdminSite()

site.register(auth_models.User, auth_admin.UserAdmin)
site.register(Project)
site.register(Event, EventAdmin)

site.register(core_models.Project)
site.register(core_models.Event, EventAdmin)
site.register(core_models.VotingPoll)

site.register(allauth.SocialApp, allauth.SocialAppAdmin)
site.register(allauth.SocialToken, allauth.SocialTokenAdmin)
Expand Down
34 changes: 33 additions & 1 deletion pylab/website/forms.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import datetime

from django import forms
from django.forms.models import BaseModelFormSet
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _

from pylab.core.models import Project, Event
from pylab.core.models import Project, Event, Vote


class ProjectForm(forms.ModelForm):
Expand Down Expand Up @@ -49,3 +52,32 @@ def clean(self):

if title and starts:
self.check_existing_events(title, starts)


class VotePointsForm(forms.ModelForm):
class Meta:
model = Vote
fields = ('points',)
widgets = {
'points': forms.NumberInput(attrs={'max': 99, 'class': 'vote-points-input'}),
}

def save(self, commit=True, *args, **kwargs):
vote = super(VotePointsForm, self).save(commit=False, *args, **kwargs)
vote.voted = datetime.datetime.now()
vote.save()


class BaseTotalPointsFormset(BaseModelFormSet):
def clean(self, *args, **kwargs):
super(BaseTotalPointsFormset, self).clean(*args, **kwargs)
total_points = 0

for form in self.forms:
if form.cleaned_data['points']:
total_points += form.cleaned_data['points']

if total_points < 0 or total_points > 15:
raise forms.ValidationError(ugettext(
"Sum of voting points is out of bounds. Expected from 0 to 15, but got %s."
) % total_points)
Empty file removed pylab/website/models.py
Empty file.
20 changes: 20 additions & 0 deletions pylab/website/static/css/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,23 @@
.event-time {
padding-left: 16px;
}

.vote-points-input {
width: 38px;
text-align: right;
font-weight: bold;
}

.vote-points-form {
padding-top: 10px;
padding-left: 30px;
padding-bottom: 30px;
}

.vote-button {
margin-top: 15px;
}

#total-points {
display: none;
}
27 changes: 27 additions & 0 deletions pylab/website/static/js/update_points_left.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
var total_points = Number($('#total-points').html());
function count_points_left () {
var sum = 0;
$('.vote-points-input').each(function() { sum += Number($(this).val()); });
return total_points - sum;
};
$('#points-left').html(count_points_left());
$('.vote-points-input').each(function() {
this.oldValue = this.value;
});

function clear_value_if_zero(elem) {
if (elem.value === "0") {
elem.value = "";
};
};

$('.vote-points-input').change(function (ev) {
var points_left = count_points_left();
if (points_left < 0) {
this.value = this.oldValue;
} else {
this.oldValue = this.value;
$('#points-left').html(points_left);
};
clear_value_if_zero(this);
});
2 changes: 2 additions & 0 deletions pylab/website/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,7 @@
<script src="{% static "js/bootstrap.min.js" %}"></script>
<script src="{% static "typeahead.bundle.min.js" %}"></script>
<script data-main="{% static "js/main.js" %}" src="{% static "require.min.js" %}"></script>
{% block scripts %}
{% endblock %}
</body>
</html>
46 changes: 46 additions & 0 deletions pylab/website/templates/website/voting_page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{% extends "base.html" %}
{% load trans from i18n %}
{% load static from staticfiles %}
{% load markdown from websitetags %}


{% block content %}

<h1>{{ voting_poll.title }}</h1>

<p>{{ voting_poll.description|markdown }}</p>

<div class="vote-points-form">
{% trans "Points left: " %}
<b><span id="points-left"></span></b>
<span id="total-points">{{ total_points }}</span>

<form action="." method="post">{% csrf_token %}
{{ formset.non_form_errors }}
{{ formset.management_form }}
{% for form in formset %}
<div class="form-group">
{{ form.errors }}
<p>
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.errors }}
{{ field }} <a href="{{ form.instance.project.get_absolute_url }}">{{ form.instance.project.title }}</a>
</div>
{% endfor %}
</p>
</div>
{% endfor %}
<button class="btn btn-primary vote-button">{% trans "Vote" %}</button>
</form>
</div>

{% endblock %}

{% block scripts %}
<script src="{% static "js/update_points_left.js" %}"></script>
{% endblock %}

10 changes: 10 additions & 0 deletions pylab/website/templatetags/debug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import ipdb

from django import template

register = template.Library()


@register.simple_tag(name='pdb', takes_context=True)
def pdb(context, *args, **kwargs): # pylint: disable=unused-argument
ipdb.set_trace()
42 changes: 42 additions & 0 deletions pylab/website/tests/test_projects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import django_webtest

import django.contrib.auth.models as auth_models

from pylab.core.models import Project


class StaticPagesTests(django_webtest.WebTest):
def setUp(self):
super().setUp()
auth_models.User.objects.create_user('u1')

def test_project_creation_and_editing(self):
resp = self.app.get('/projects/create/', user='u1')
self.assertEqual(resp.status_int, 200)

resp.form['title'] = 'Test project'
resp.form['description'] = 'Test description'
resp = resp.form.submit()
self.assertEqual(resp.status_int, 302)

resp = self.app.get('/projects/test-project/', user='u1')
self.assertEqual(resp.status_int, 200)

self.assertEqual(
list(Project.objects.values_list('title', 'description')),
[('Test project', 'Test description')]
)

resp = self.app.get('/projects/test-project/update/', user='u1')
resp.form['title'] = 'Test project2'
resp.form['description'] = 'Test description2'
resp = resp.form.submit()
self.assertEqual(resp.status_int, 302)

self.assertEqual(
list(Project.objects.values_list('title', 'description')),
[('Test project2', 'Test description2')]
)

resp = self.app.get('/projects/test-project/', user='u1')
self.assertEqual(resp.status_int, 200)
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import django.contrib.auth.models as auth_models


class IndexPageTests(django_webtest.WebTest):
class StaticPagesTests(django_webtest.WebTest):
def setUp(self):
super().setUp()
auth_models.User.objects.create_user('u1')
Expand All @@ -15,3 +15,11 @@ def test_index_page_with_anonymous_user(self):
def test_index_page_with_logged_in_user(self):
resp = self.app.get('/', user='u1')
self.assertEqual(resp.status_int, 200)

def test_about_page_with_anonymous_user(self):
resp = self.app.get('/about/')
self.assertEqual(resp.status_int, 200)

def test_about_page_with_logged_in_user(self):
resp = self.app.get('/about/', user='u1')
self.assertEqual(resp.status_int, 200)
Loading