diff --git a/naucse/data/stats.yml b/naucse/data/stats.yml
new file mode 100644
index 0000000000..4b6c4c330d
--- /dev/null
+++ b/naucse/data/stats.yml
@@ -0,0 +1,40 @@
+entries:
+
+ - label: active_runs
+ text:
+ - '%d právě probíhající kurz'
+ - '%d právě probíhající kurzy'
+ - '%d právě probíhajících kurzů'
+
+ - label: all_runs
+ text:
+ - '%d kurz celkem'
+ - '%d kurzy celkem'
+ - '%d kurzů celkem'
+
+ - label: sessions_delivered
+ text:
+ - '%d lekci odučeno'
+ - '%d lekce odučeno'
+ - '%d lekcí odučeno'
+
+ - label: sessions_available
+ text:
+ - 'materiály pro %d lekci'
+ - 'materiály pro %d různé lekce'
+ - 'materiály pro %d různých lekcí'
+
+ - label: cheatsheets
+ text:
+ - '%d tahák'
+ - '%d taháky'
+ - '%d taháků'
+
+ - label: contributors
+ text:
+ - '%d autor'
+ - '%d autoři'
+ - '%d autorů'
+
+ - label: price
+ text: '%d Kč'
diff --git a/naucse/static/css/index.css b/naucse/static/css/index.css
index 74106282e3..afd798d8a3 100644
--- a/naucse/static/css/index.css
+++ b/naucse/static/css/index.css
@@ -46,3 +46,14 @@ nav.header * {
background-color: #296e62;
outline-color: #3fb0ac;
}
+
+.statlabels {
+ text-align: center;
+}
+
+.statlabel {
+ font-size: 1.5rem;
+ margin: 0.3rem;
+ color: #FFF;
+ background-color: #3b4f5a;
+}
diff --git a/naucse/templates/index.html b/naucse/templates/index.html
index b39691135f..82ee368661 100644
--- a/naucse/templates/index.html
+++ b/naucse/templates/index.html
@@ -49,6 +49,14 @@
Nauč se Python!
+
+
+ {% for stat_label in stat_labels.entries %}
+ {{ stat_label|fill_label }}
+ {% endfor %}
+
+
+
diff --git a/naucse/utils/views.py b/naucse/utils/views.py
index 146aa49456..ac0169b015 100644
--- a/naucse/utils/views.py
+++ b/naucse/utils/views.py
@@ -232,3 +232,27 @@ def get_edit_info(edit_path):
"page_name": get_edit_page_name(),
"url": edit_link(edit_path)
}
+
+def czech_plural(text, n):
+ """
+ Chooses the Czech plural form based on n.
+ This either gets and immediately returns a string,
+ or it gets a list of 3 strings:
+ * for 1 item
+ * for 2-4 items
+ * for the rest
+ Picks the right one and returns it.
+ Uses the more modern option where e.g. 21 is NOT pluralized as 1
+ http://prirucka.ujc.cas.cz/?id=792
+ """
+ if isinstance(text, str):
+ return text
+
+ # we don't expect negative numbers here, but just to be sure
+ n = abs(n)
+
+ if n == 1:
+ return text[0]
+ if 1 < n < 5:
+ return text[1]
+ return text[2]
diff --git a/naucse/views.py b/naucse/views.py
index bace195e2b..682b9c51ee 100644
--- a/naucse/views.py
+++ b/naucse/views.py
@@ -28,8 +28,11 @@
from naucse.utils.views import does_course_return_info
from naucse.utils.views import raise_errors_from_forks
from naucse.utils.views import page_content_cache_key, get_edit_info
+from naucse.utils.views import czech_plural
from naucse.validation import DisallowedStyle, DisallowedElement, InvalidHTML
+import yaml
+
# so it can be mocked
import naucse.utils.views
@@ -44,7 +47,6 @@
_cached_model = None
-
@LocalProxy
def model():
"""Return the root of the naucse model
@@ -97,10 +99,19 @@ def session_url(course, session, coverpage='front'):
coverpage=coverpage)
+def load_stat_labels():
+ datafile = os.path.join(os.path.dirname(__file__), 'data/stats.yml')
+ with open(datafile) as fstr:
+ stat_labels = yaml.load(fstr)
+
+ return stat_labels
+
+
@app.route('/')
def index():
return render_template("index.html",
- edit_info=get_edit_info(Path(".")))
+ edit_info=get_edit_info(Path(".")),
+ stat_labels=load_stat_labels())
@app.route('/runs/')
@@ -172,23 +183,28 @@ def runs(year=None, all=None):
edit_info=get_edit_info(model.runs_edit_path))
+def safe_courses():
+ courses = []
+
+ for course in model.courses.values():
+ if not course.is_link():
+ if not course.is_meta:
+ courses.append(course)
+ elif naucse.utils.views.forks_enabled() and does_course_return_info(course):
+ courses.append(course)
+
+ return courses
+
@app.route('/courses/')
def courses():
# since even the basic info about the forked courses can be broken,
# we need to make sure the required info is provided.
# If ``RAISE_FORK_ERRORS`` is set, exceptions are raised here,
# otherwise the course is ignored completely.
- safe_courses = []
-
- for course in model.courses.values():
- if not course.is_link():
- if not course.is_meta:
- safe_courses.append(course)
- elif naucse.utils.views.forks_enabled() and does_course_return_info(course):
- safe_courses.append(course)
+ courses = safe_courses()
return render_template("course_list.html",
- courses=safe_courses,
+ courses=courses,
title="Seznam online kurzů Pythonu",
edit_info=get_edit_info(model.courses_edit_path))
@@ -920,3 +936,75 @@ def course_calendar_ics(course):
abort(404)
return Response(str(calendar), mimetype="text/calendar")
+
+def active_runs():
+ today = datetime.date.today()
+
+ runs = (model.runs_from_year(today.year) +
+ model.runs_from_year(today.year - 1) +
+ model.runs_from_year(today.year - 2))
+ ongoing = [run for run in runs if
+ run.start_date <= today and run.end_date >= today]
+
+ return len(ongoing)
+
+def all_runs():
+ all_years = list(model.safe_run_years.keys())
+
+ return sum([len(model.runs_from_year(year)) for year in all_years])
+
+def sessions_delivered():
+ today = datetime.date.today()
+ all_years = list(model.safe_run_years.keys())
+
+ all_runs = []
+ for year in all_years:
+ all_runs.extend(model.runs_from_year(year))
+
+ all_sessions = []
+ for run in all_runs:
+ all_sessions.extend(list(run.sessions.values()))
+
+ return len([session for session in all_sessions if session.date < today])
+
+def sessions_available():
+ uniq_sessions = {}
+ for course in safe_courses():
+ for session in course.sessions.values():
+ uniq_sessions[session.slug] = session
+
+ return len(uniq_sessions)
+
+def cheatsheets():
+ sheets = 0
+ for course in safe_courses():
+ for session in course.sessions.values():
+ for material in session.materials:
+ if (material.url_type == 'cheatsheet'):
+ sheets += 1
+
+ return sheets
+
+
+# This could use some caching, but for now it's the simplest way
+def basic_stat(name):
+ if name == 'active_runs':
+ return active_runs()
+ elif name == 'all_runs':
+ return all_runs()
+ elif name == 'sessions_delivered':
+ return sessions_delivered()
+ elif name == 'sessions_available':
+ return sessions_available()
+ elif name == 'cheatsheets':
+ return cheatsheets()
+ else: # contributors, price
+ return 0
+
+@app.template_filter('fill_label')
+def fill_label(label):
+ stat_number = basic_stat(label['label'])
+
+ formatstr = czech_plural(label['text'], stat_number)
+
+ return formatstr % stat_number