Skip to content
This repository was archived by the owner on Sep 19, 2018. It is now read-only.

Added scoreboard that ranks countries based on number of events #343

Merged
merged 16 commits into from
Sep 24, 2014
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: 2 additions & 0 deletions codeweekeu/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@
'social.apps.django_app.default',
# django-countries country listing
'django_countries',
# additional info about countries
'countries_plus',
# avatar handling
'avatar',
# support for tags
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ django-appconf==0.6
django-avatar==2.0
django-compressor==1.4
django-countries==2.0c1
django-countries-plus==0.3
django-debug-toolbar==1.0.1
django-endless-pagination==2.0
django-geoposition==0.1.5
Expand Down
1 change: 1 addition & 0 deletions server-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ django-appconf==0.6
django-avatar==2.0
django-compressor==1.4
django-countries==2.0c1
django-countries-plus==0.3
django-debug-toolbar==1.0.1
django-endless-pagination==2.0
django-geoposition==0.1.5
Expand Down
3 changes: 2 additions & 1 deletion static/scss/_768up.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
background-color: $whitesmoke;
color: $black;
padding-left: 25px;
}
}

22 changes: 22 additions & 0 deletions static/scss/_base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -534,3 +534,25 @@ LIST EVENTS STYLES
}
}

/*********************
SCOREBOARD STYLES
*********************/

.country {
border-bottom:1px solid #ccc;
border:1px solid #ccc;
.country-name {
font-weight: 800;
font-size: 1.2em;
}
.event-number {
font-weight: 800;
font-size: 1.5em;
}
background-color: #F5F5F5;
}

.highlighted {
background-color: #F0F8FF;
}

29 changes: 29 additions & 0 deletions web/processors/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from django.contrib.gis.geoip import GeoIP
from api.models import Event
from django_countries import countries
from countries_plus.models import Country

from web.processors import media
from mailer.event_report_mailer import send_email_to_country_ambassadors
Expand Down Expand Up @@ -120,6 +121,34 @@ def get_country(country_code, user_ip):
return country


def count_approved_events_for_country(past=True):
"""
Count the number of approved events and score for each country
"""

all_events = Event.objects.filter(status='APPROVED')

country_count = []

# not including the first two fake countries in the list
for country in list(countries)[2:]:
country_code = country[0]
country_name = country[1]
number_of_events = all_events.filter(country=country_code).count()
population = Country.objects.get(iso=country_code).population
country_score = 0
if number_of_events > 0 and population > 0 and population != "":
country_score = 1. * number_of_events / population
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Population can be zero or null & might break the code (division by zero).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, added an extra check!

country_entry = {'country_code': country_code,
'country_name': country_name,
'events': number_of_events,
'score': country_score}
country_count.append(country_entry)

sorted_count = sorted(country_count, key=lambda k: k['score'], reverse=True)
return sorted_count


def change_event_status(event_id):
event = Event.objects.get(pk=event_id)

Expand Down
19 changes: 19 additions & 0 deletions web/templates/pages/scoreboard.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{% extends 'base.html' %}

{% block title %}- Events Scoreboard{% endblock title %}

{% block content %}
<div class="container">
<h1>#codeEU Events Scoreboard</h1>
<p>Which countries in Europe are buzzing with coding activity? The scoreboard is sorted by the number of listed coding events per population, so don't be surprised to see some of the smaller countries higher up on the list!</p>
{% for country in counts %}
<div class="col-md-6 country{% if forloop.counter < 11 %} highlighted{% endif %}">
<img src="/static/flags/{{ country.country_code|lower }}.png" alt="{{ country.country_name }}" />
<span class="icon-flag">
<span class="country-name">{{ country.country_name }}</span> is participating with
<span class="event-number"><a href="{% url 'web.search_events' %}?country_code={{ country.country_code }}&amp;past=yes">{{ country.events }}</span> event{% if country.events != 1 %}s{% endif %}</a>
</span>
</div>
{% endfor %}
</div>
{% endblock content %}
65 changes: 64 additions & 1 deletion web/tests/test_events_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from api.processors import get_approved_events
from api.processors import get_next_or_previous
from api.processors import get_nearby_events

from web.processors.event import count_approved_events_for_country

class EventTestCase(TestCase):
def get_user(self):
Expand Down Expand Up @@ -345,3 +345,66 @@ def test_create_event_in_moldova(admin_user, db):

assert "MD" == test_event.country.code

@pytest.mark.django_db
def test_scoreboard_counter(admin_user, db):

initial_counter = count_approved_events_for_country()

counted_events_before = 0

for country in initial_counter:
if country['country_code'] == 'SI':
counted_events_before = country['events']

# Adding one approved and one pending event in same country
# the count for events for the country should increase by 1
event_data = {
'audience': [3],
'theme': [1,2],
'country': u'SI',
'description': u'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\r\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\r\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\r\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\r\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\r\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
'location': u'Ljubljana, Slovenia',
'organizer': u'testko',
"creator": admin_user,
'start_date': datetime.datetime.now(),
'end_date': datetime.datetime.now() + datetime.timedelta(days=3, hours=3),
'title': u'Test Approved Event',
'status':"APPROVED",
}

test_approved_event = create_or_update_event(event_id=None, **event_data)

event_data = {
'audience': [3],
'theme': [1,2],
'country': u'SI',
'description': u'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\r\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\r\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\r\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\r\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\r\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
'location': u'Ljubljana, Slovenia',
'organizer': u'testko',
"creator": admin_user,
'start_date': datetime.datetime.now(),
'end_date': datetime.datetime.now() + datetime.timedelta(days=3, hours=3),
'title': u'Test Pending Event',
'status':"PENDING",
}

test_pending_event = create_or_update_event(event_id=None, **event_data)

new_counter = count_approved_events_for_country()

counted_events_after = 0

for country in new_counter:
if country['country_code'] == 'SI':
counted_events_after = country['events']

# An extra check with a direct DB query
counted_events_query = Event.objects.filter(status='APPROVED').filter(country='SI').count()

assert counted_events_after == counted_events_before + 1
assert counted_events_after == counted_events_query

test_approved_event.delete()
test_pending_event.delete()


1 change: 1 addition & 0 deletions web/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
url(r'^about/$', TemplateView.as_view(template_name="pages/about.html"), name='web.about'),
url(r'^login/$', 'users.login', name='web.login'),
url(r'^ambassadors/$', 'users.ambassadors', name='web.ambassadors'),
url(r'^scoreboard/$', 'events.scoreboard', name='web.scoreboard'),
url(r'^change_status/(?P<event_id>\d+)/$', 'events.change_status', name='web.change_status'),
url(r'^reject_status/(?P<event_id>\d+)/$', 'events.reject_status', name='web.reject_status'),
# Note: do not place any url after this one of it will not work
Expand Down
12 changes: 12 additions & 0 deletions web/views/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from web.processors.event import list_countries
from web.processors.event import get_country
from web.processors.event import get_country_from_user_ip
from web.processors.event import count_approved_events_for_country
from web.processors.media import process_image
from web.processors.media import ImageSizeTooLargeException
from web.processors.media import UploadImageError
Expand Down Expand Up @@ -309,6 +310,17 @@ def search_events(request):
},
context_instance=RequestContext(request))

def scoreboard(request):
template = 'pages/scoreboard.html'

counts = count_approved_events_for_country()

return render_to_response(
template, {
'counts': counts,
},
context_instance=RequestContext(request))


@login_required
@can_moderate_event
Expand Down