diff --git a/codeweekeu/settings.py b/codeweekeu/settings.py index 931a4ca6..7706e881 100644 --- a/codeweekeu/settings.py +++ b/codeweekeu/settings.py @@ -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 diff --git a/requirements.txt b/requirements.txt index 27c00e4a..b8a3e0ec 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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 diff --git a/server-requirements.txt b/server-requirements.txt index 8a355f15..f0a5f584 100644 --- a/server-requirements.txt +++ b/server-requirements.txt @@ -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 diff --git a/static/scss/_768up.scss b/static/scss/_768up.scss index f4728035..705df25d 100644 --- a/static/scss/_768up.scss +++ b/static/scss/_768up.scss @@ -17,4 +17,5 @@ background-color: $whitesmoke; color: $black; padding-left: 25px; -} \ No newline at end of file +} + diff --git a/static/scss/_base.scss b/static/scss/_base.scss index baf2ad56..bcdaaa6b 100644 --- a/static/scss/_base.scss +++ b/static/scss/_base.scss @@ -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; +} + diff --git a/web/processors/event.py b/web/processors/event.py index 104bc9b5..08deca62 100644 --- a/web/processors/event.py +++ b/web/processors/event.py @@ -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 @@ -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 + 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) diff --git a/web/templates/pages/scoreboard.html b/web/templates/pages/scoreboard.html new file mode 100644 index 00000000..b1f7487d --- /dev/null +++ b/web/templates/pages/scoreboard.html @@ -0,0 +1,19 @@ +{% extends 'base.html' %} + +{% block title %}- Events Scoreboard{% endblock title %} + +{% block content %} +
+

#codeEU Events Scoreboard

+

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!

+ {% for country in countsĀ %} +
+ {{ country.country_name }} + + {{ country.country_name }} is participating with + {{ country.events }} event{% if country.events != 1 %}s{% endif %} + +
+ {% endfor %} +
+{% endblock content %} diff --git a/web/tests/test_events_processors.py b/web/tests/test_events_processors.py index 919530d8..0fa3d605 100644 --- a/web/tests/test_events_processors.py +++ b/web/tests/test_events_processors.py @@ -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): @@ -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() + + diff --git a/web/urls.py b/web/urls.py index e83c2b62..53d2eb03 100644 --- a/web/urls.py +++ b/web/urls.py @@ -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\d+)/$', 'events.change_status', name='web.change_status'), url(r'^reject_status/(?P\d+)/$', 'events.reject_status', name='web.reject_status'), # Note: do not place any url after this one of it will not work diff --git a/web/views/events.py b/web/views/events.py index eda2f16e..0ae1e650 100644 --- a/web/views/events.py +++ b/web/views/events.py @@ -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 @@ -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