-
Notifications
You must be signed in to change notification settings - Fork 119
Session cover pages #54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c0682c9
064c4d2
00e8e52
60d1c41
fcb506d
5763356
a0ad2a0
ff609ce
d778cb9
f687549
5606962
03b77f4
94957c3
10a44b7
2d4baba
0c86ad4
ada1347
19e9a3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| from jinja2 import PrefixLoader, FileSystemLoader, StrictUndefined, Markup | ||
| from jinja2.exceptions import TemplateNotFound | ||
| from werkzeug.local import LocalProxy | ||
| from collections import namedtuple | ||
|
|
||
| from naucse import models | ||
| from naucse.urlconverters import register_url_converters | ||
|
|
@@ -13,8 +14,11 @@ | |
|
|
||
| app = Flask('naucse') | ||
| app.config['TEMPLATES_AUTO_RELOAD'] = True | ||
| app.config['TRAP_HTTP_EXCEPTIONS'] = True | ||
|
|
||
|
|
||
| lesson_template_loader = FileSystemLoader(os.path.join(app.root_path, '..', 'lessons')) | ||
| session_template_loader = FileSystemLoader(os.path.join(app.root_path, '..', 'runs')) | ||
|
|
||
|
|
||
| @LocalProxy | ||
|
|
@@ -33,21 +37,18 @@ def set_vars(): | |
|
|
||
| @app.route('/') | ||
| def index(): | ||
| """Index page.""" | ||
| return render_template("index.html", | ||
| page_wip=True) | ||
|
|
||
|
|
||
| @app.route('/about/') | ||
| def about(): | ||
| """About page.""" | ||
| return render_template("about.html", | ||
| page_wip=True) | ||
|
|
||
|
|
||
| @app.route('/runs/') | ||
| def runs(): | ||
| """Runs page.""" | ||
| return render_template("run_list.html", | ||
| run_years=model.run_years, | ||
| title="Seznam offline kurzů Pythonu", | ||
|
|
@@ -56,23 +57,29 @@ def runs(): | |
|
|
||
| @app.route('/courses/') | ||
| def courses(): | ||
| """Page with listed online courses.""" | ||
| return render_template("course_list.html", courses=model.courses, | ||
| title="Seznam online kurzů Pythonu", | ||
| page_wip=True) | ||
|
|
||
|
|
||
| @app.route('/lessons/<lesson:lesson>/static/<path:path>') | ||
| def lesson_static(lesson, path): | ||
| """Static files in lessons.""" | ||
| """Get the endpoint for static files in lessons. | ||
|
|
||
| Args: | ||
| lesson location of the file <lesson_type>/<lesson_name> | ||
| path path to file in the static folder | ||
|
|
||
| Returns: | ||
| endpoint for the static file | ||
| """ | ||
| directory = str(lesson.path) | ||
| filename = os.path.join('static', path) | ||
| return send_from_directory(directory, filename) | ||
|
|
||
|
|
||
| @app.route('/courses/<course:course>/') | ||
| def course_page(course): | ||
| """Course page.""" | ||
| try: | ||
| return render_template('course.html', | ||
| course=course, plan=course.sessions, | ||
|
|
@@ -83,11 +90,9 @@ def course_page(course): | |
|
|
||
| @app.route('/<run:run>/') | ||
| def run(run): | ||
| """Run's page.""" | ||
| g.vars = dict(run.vars) | ||
|
|
||
| def lesson_url(lesson, *args, **kwargs): | ||
| """Link to the specific lesson.""" | ||
| return url_for('run_page', run=run, lesson=lesson, *args, **kwargs) | ||
|
|
||
| try: | ||
|
|
@@ -99,23 +104,35 @@ def lesson_url(lesson, *args, **kwargs): | |
|
|
||
|
|
||
| def prv_nxt_teller(run, lesson): | ||
| """Determine the previous and the next lesson.""" | ||
| lessons = [ | ||
| material.lesson | ||
| for session in run.sessions.values() | ||
| for material in session.materials | ||
| if material.lesson | ||
| ] | ||
| """Determine the previous and the next lesson and the parent session. | ||
|
|
||
| Args: | ||
| run run of the current lesson | ||
| lesson current lesson | ||
|
|
||
| Returns: | ||
| 3-tuple: previous lesson, next lesson and the parent session | ||
| """ | ||
| lessons = [material.lesson for session in run.sessions.values() for material in session.materials if material.lesson] | ||
|
|
||
| session_link = None | ||
| for session in run.sessions.values(): | ||
| for material in session.materials: | ||
| if str(material.lesson) == str(lesson): | ||
| session_link = models.Navigation(session.title, session.slug) | ||
|
|
||
| prv, nxt = None, None | ||
|
|
||
| for prev, current, next in zip([None] + lessons, | ||
| lessons, | ||
| lessons[1:] + [None]): | ||
| if current.slug == lesson.slug: | ||
| if prev: | ||
| prev = prev.index_page | ||
| prv = models.Navigation(prev.title, prev.slug) | ||
| if next: | ||
| next = next.index_page | ||
| return prev, next | ||
| return None, None | ||
| nxt = models.Navigation(next.title, next.slug) | ||
|
|
||
| return prv, nxt, session_link | ||
|
|
||
|
|
||
| def lesson_template_or_404(lesson, page): | ||
|
|
@@ -161,45 +178,61 @@ def subpage_url(page_slug): | |
| template_name = 'solution.html' | ||
| kwargs.setdefault('solution_number', solution) | ||
|
|
||
| # XXX: Link to fragment | ||
| kwargs['prv'] = page | ||
| kwargs['nxt'] = None | ||
| else: | ||
| template_name = 'lesson.html' | ||
|
|
||
| kwargs['prv'] = page.previous_page(kwargs.get('prv')) | ||
| kwargs['nxt'] = page.next_page(kwargs.get('nxt')) | ||
|
|
||
| kwargs.setdefault('title', page.title) | ||
| kwargs.setdefault('content', content) | ||
|
|
||
| if (page.subpages != None and page.slug in page.subpages.keys() | ||
| and "prev" in page.subpages[page.slug].keys() and "next" in page.subpages[page.slug].keys()) : | ||
| prev_segments = page.subpages[page.slug]["prev"].split(':') | ||
| next_segments = page.subpages[page.slug]["next"].split(':') | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I'm reading correctly, this way the title of the link can't have a colon in it. Is that a reasonable limitation? The configuration already comes from YAML. Why invent a special format for this field? |
||
|
|
||
| if len(next_segments) == 2: | ||
| next_segments.append("index") | ||
|
|
||
| if len(prev_segments) == 2: | ||
| prev_segments.append("index") | ||
|
|
||
| kwargs['prv'] = models.Navigation(prev_segments[0], prev_segments[1], prev_segments[2]) | ||
| kwargs['nxt'] = models.Navigation(next_segments[0], next_segments[1], next_segments[2]) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All the code to create a |
||
|
|
||
| return render_template(template_name, **kwargs) | ||
|
|
||
|
|
||
| @app.route('/<run:run>/<lesson:lesson>/', defaults={'page': 'index'}) | ||
| @app.route('/<run:run>/<lesson:lesson>/<page>/') | ||
| @app.route('/<run:run>/<lesson:lesson>/<page>/solutions/<int:solution>/') | ||
| def run_page(run, lesson, page, solution=None): | ||
| """Run's lesson page.""" | ||
| """Render the lesson page of the run. | ||
|
|
||
| Args: | ||
| run where the lesson belongs | ||
| lesson name of the lesson <lesson_type>/<lesson_name> | ||
| page page of the lesson, index is default | ||
|
|
||
| Returns: | ||
| rendered lesson page | ||
| """ | ||
| page = lesson.pages[page] | ||
| g.vars = dict(run.vars) | ||
| g.vars.update(page.vars) | ||
|
|
||
| def lesson_url(lesson, *args, **kwargs): | ||
| """Link to the specific lesson.""" | ||
| return url_for('run_page', run=run, lesson=lesson, *args, **kwargs) | ||
|
|
||
| def subpage_url(page_slug): | ||
| return url_for('run_page', run=run, lesson=lesson, page=page_slug) | ||
|
|
||
| prv, nxt = prv_nxt_teller(run, lesson) | ||
| prv, nxt, session_link = prv_nxt_teller(run, lesson) | ||
| title = title='{}: {}'.format(run.title, page.title) | ||
|
|
||
| return render_page(page=page, title=title, | ||
| lesson_url=lesson_url, | ||
| subpage_url=subpage_url, | ||
| run=run, nxt=nxt, prv=prv, | ||
| run=run, prv=prv, nxt=nxt, | ||
| session_link=session_link, | ||
| page_wip=not page.license, | ||
| solution=solution) | ||
|
|
||
|
|
@@ -208,7 +241,48 @@ def subpage_url(page_slug): | |
| @app.route('/lessons/<lesson:lesson>/<page>/') | ||
| @app.route('/lessons/<lesson:lesson>/<page>/solutions/<int:solution>/') | ||
| def lesson(lesson, page, solution=None): | ||
| """Lesson page.""" | ||
| """Render the lesson page. | ||
|
|
||
| Args: | ||
| lesson name of the lesson <lesson_type>/<lesson_name> | ||
| page page of the lesson, index is default | ||
|
|
||
| Returns: | ||
| rendered lesson page | ||
| """ | ||
| page = lesson.pages[page] | ||
| g.vars = dict(page.vars) | ||
| return render_page(page=page, page_wip=True, solution=solution) | ||
|
|
||
|
|
||
| def session_template_or_404(run, session, page): | ||
| env = app.jinja_env.overlay(loader=session_template_loader) | ||
| name = '{}/sessions/{}/{}.md'.format(run.slug, session, page) | ||
| try: | ||
| return env.get_template(name) | ||
| except TemplateNotFound: | ||
| abort(404) | ||
|
|
||
|
|
||
| @app.route('/runs/<run:run>/sessions/<session>/', defaults={'page': 'front'}) | ||
| @app.route('/runs/<run:run>/sessions/<session>/<page>/') | ||
| def session_page(run, session, page): | ||
| """Render the session page. | ||
|
|
||
| Args: | ||
| run run where the session belongs | ||
| session name of the session | ||
| page page of the session, front is default | ||
|
|
||
| Returns: | ||
| rendered session page | ||
| """ | ||
|
|
||
| def session_url(session): | ||
| return url_for('session_page', run=run, session=session, page=page) | ||
|
|
||
| template = session_template_or_404(run, session, page) | ||
| content = Markup(template.render()) | ||
| md_content = Markup(convert_markdown(content)) | ||
|
|
||
| return render_template('lesson.html', content=md_content, page=page, session=True) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not really a URL.