def lesson(lesson, page, solution=None): """Render the html of the given lesson page.""" lesson_url, subpage_url, static_url = relative_url_functions( request.path, None, lesson) page = lesson.pages[page] content = page_content(lesson, page, solution=solution, lesson_url=lesson_url, subpage_url=subpage_url, static_url=static_url) content = content["content"] allowed_elements_parser.reset_and_feed(content) kwargs = {} if solution is not None: kwargs["solution_number"] = int(solution) return render_template("lesson.html", content=content, page=page, lesson=lesson, edit_info=get_edit_info(page.edit_path), title=page.title, **kwargs)
def course_calendar_ics(course): if not course.start_date: abort(404) if course.is_link(): naucse.utils.routes.forks_raise_if_disabled() try: data_from_fork = course.render_calendar_ics( request_url=request.path) except POSSIBLE_FORK_EXCEPTIONS as e: if raise_errors_from_forks(): raise logger.error("There was an error rendering url %s for course '%s'", request.path, course.slug) logger.exception(e) return render_template( "error_in_fork.html", malfunctioning_course=course, edit_info=get_edit_info(course.edit_path), faulty_page="calendar", root_slug=model.meta.slug, travis_build_id=os.environ.get("TRAVIS_BUILD_ID"), ) calendar = data_from_fork["calendar"] else: try: calendar = generate_calendar_ics(course) except ValueError: abort(404) return Response(str(calendar), mimetype="text/calendar")
def course_calendar(course): if course.is_link(): naucse.utils.routes.forks_raise_if_disabled() try: data_from_fork = course.render_calendar(request_url=request.path) course = process_course_data(data_from_fork.get("course"), slug=course.slug) edit_info = links.process_edit_info( data_from_fork.get("edit_info")) except POSSIBLE_FORK_EXCEPTIONS as e: if raise_errors_from_forks(): raise logger.error("There was an error rendering url %s for course '%s'", request.path, course.slug) logger.exception(e) return render_template( "error_in_fork.html", malfunctioning_course=course, edit_info=get_edit_info(course.edit_path), faulty_page="calendar", root_slug=model.meta.slug, travis_build_id=os.environ.get("TRAVIS_BUILD_ID"), ) kwargs = { "course": course, "edit_info": edit_info, "content": data_from_fork.get("content") } else: if not course.start_date: abort(404) content = course_calendar_content(course) allowed_elements_parser.reset_and_feed(content) kwargs = { "course": course, "edit_info": get_edit_info(course.edit_path), "content": content } return render_template('course_calendar.html', **kwargs)
def course(course): if course.is_link(): naucse.utils.routes.forks_raise_if_disabled() try: data_from_fork = course.render_course(request_url=request.path) except POSSIBLE_FORK_EXCEPTIONS as e: if raise_errors_from_forks(): raise # there's no way to replace this page, render an error page instead logger.error("There was an error rendering url %s for course '%s'", request.path, course.slug) logger.exception(e) return render_template( "error_in_fork.html", malfunctioning_course=course, edit_info=get_edit_info(course.edit_path), faulty_page="course", root_slug=model.meta.slug, travis_build_id=os.environ.get("TRAVIS_BUILD_ID"), ) kwargs = { "course_content": data_from_fork.get("content"), "edit_info": links.process_edit_info(data_from_fork.get("edit_info")), } else: content = course_content(course) allowed_elements_parser.reset_and_feed(content) kwargs = { "course_content": content, "edit_info": get_edit_info(course.edit_path), } recent_runs = get_recent_runs(course) try: return render_template("course.html", course=course, title=course.title, recent_runs=recent_runs, **kwargs) except TemplateNotFound: abort(404)
def runs(year=None, all=None): today = datetime.date.today() # List of years to show in the pagination # If the current year is not there (no runs that start in the current year # yet), add it manually all_years = model.safe_run_years.keys() if today.year not in all_years: all_years.append(today.year) first_year, last_year = min(all_years), max(all_years) if year is not None: if year > last_year: # Instead of showing a future year, redirect to the 'Current' page return redirect(url_for('runs')) if year not in all_years: # Otherwise, if there are no runs in requested year, return 404. abort(404) if all is not None: run_data = model.safe_run_years paginate_prev = {'year': first_year} paginate_next = {'all': 'all'} elif year is None: run_data = model.ongoing_and_recent_runs paginate_prev = {'year': None} paginate_next = {'year': last_year} else: run_data = model.runs_from_year(year) past_years = [y for y in all_years if y < year] if past_years: paginate_next = {'year': max(past_years)} else: paginate_next = {'all': 'all'} future_years = [y for y in all_years if y > year] if future_years: paginate_prev = {'year': min(future_years)} else: paginate_prev = {'year': None} return render_template("run_list.html", run_data=run_data, title="Seznam offline kurzů Pythonu", today=datetime.date.today(), year=year, all=all, all_years=all_years, paginate_next=paginate_next, paginate_prev=paginate_prev, edit_info=get_edit_info(model.runs_edit_path))
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(): safe_courses.append(course) elif naucse.utils.routes.forks_enabled() and does_course_return_info( course): safe_courses.append(course) return render_template("course_list.html", courses=safe_courses, title="Seznam online kurzů Pythonu", edit_info=get_edit_info(model.courses_edit_path))
def render(page_type: str, slug: str, *args, **kwargs) -> Dict[str, Any]: """ Returns a rendered page for a course, based on page_type and slug. """ course = get_course_from_slug(slug) if course.is_link(): raise ValueError("Circular dependency.") path = [] if kwargs.get("request_url"): path = [kwargs["request_url"]] logger = UrlForLogger(routes.app) with routes.app.test_request_context(*path): with logger: info = { "course": { "title": course.title, "url": routes.course_url(course), "vars": course.vars, "canonical": course.canonical, "is_derived": course.is_derived, }, } if page_type == "course": info["content"] = routes.course_content(course) info["edit_info"] = get_edit_info(course.edit_path) elif page_type == "calendar": info["content"] = routes.course_calendar_content(course) info["edit_info"] = get_edit_info(course.edit_path) elif page_type == "calendar_ics": info["calendar"] = str(routes.generate_calendar_ics(course)) info["edit_info"] = get_edit_info(course.edit_path) elif page_type == "course_page": lesson_slug, page, solution, *_ = args lesson = routes.model.get_lesson(lesson_slug) content_offer_key = kwargs.get("content_key") not_processed = object() content = not_processed if content_offer_key is not None: # the base repository has a cached version of the content content_key = page_content_cache_key( Repo("."), lesson_slug, page, solution, course.vars) # if the key matches what would be produced here, let's not return anything # and the cached version will be used if content_offer_key == content_key: content = None request_url = kwargs.get("request_url") if request_url is None: request_url = url_for('course_page', course=course, lesson=lesson, page=page, solution=solution) lesson_url, subpage_url, static_url = routes.relative_url_functions( request_url, course, lesson) page, session, prv, nxt = routes.get_page(course, lesson, page) # if content isn't cached or the version was refused, let's render # the content here (but just the content and not the whole page with headers, menus etc) if content is not_processed: content = routes.page_content(lesson, page, solution, course, lesson_url=lesson_url, subpage_url=subpage_url, static_url=static_url, without_cache=True) if content is None: info["content"] = None info["content_urls"] = [] else: info["content"] = content["content"] info["content_urls"] = content["urls"] info.update({ "page": { "title": page.title, "css": page.info.get( "css" ), # not page.css since we want the css without limitation "latex": page.latex, "attributions": page.attributions, "license": serialize_license(page.license), "license_code": serialize_license(page.license_code) }, "edit_info": get_edit_info(page.edit_path) }) if session is not None: info["session"] = { "title": session.title, "url": url_for("session_coverpage", course=course.slug, session=session.slug), "slug": session.slug, } prev_link, session_link, next_link = routes.get_footer_links( course, session, prv, nxt, lesson_url) info["footer"] = { "prev_link": prev_link, "session_link": session_link, "next_link": next_link } elif page_type == "session_coverpage": session_slug, coverpage, *_ = args session = course.sessions.get(session_slug) info.update({ "session": { "title": session.title, "url": url_for("session_coverpage", course=course.slug, session=session.slug), }, "content": routes.session_coverpage_content(course, session, coverpage), "edit_info": get_edit_info(session.get_edit_path(course, coverpage)), }) else: raise ValueError("Invalid page type.") # generate list of absolute urls which need to be frozen further urls = set() for endpoint, values in logger.iter_calls(): url = url_for(endpoint, **values) if url.startswith( f"/{slug}" ): # this is checked once again in main repo, but let's save cache space urls.add(url) info["urls"] = list(urls) return info
def session_coverpage(course, session, coverpage): """Render the session coverpage. Args: course course where the session belongs session name of the session coverpage coverpage of the session, front is default Returns: rendered session coverpage """ if course.is_link(): naucse.utils.routes.forks_raise_if_disabled() try: data_from_fork = course.render_session_coverpage( session, coverpage, request_url=request.path) kwargs = { "course": process_course_data(data_from_fork.get("course"), slug=course.slug), "session": process_session_data(data_from_fork.get("session"), slug=session), "edit_info": links.process_edit_info(data_from_fork.get("edit_info")), "content": data_from_fork["content"] } except POSSIBLE_FORK_EXCEPTIONS as e: if raise_errors_from_forks(): raise # there's no way to replace this page, render an error page instead logger.error("There was an error rendering url %s for course '%s'", request.path, course.slug) logger.exception(e) return render_template( "error_in_fork.html", malfunctioning_course=course, edit_info=get_edit_info(course.edit_path), faulty_page=f"session_{coverpage}", session=session, root_slug=model.meta.slug, travis_build_id=os.environ.get("TRAVIS_BUILD_ID"), ) else: session = course.sessions.get(session) content = session_coverpage_content(course, session, coverpage) allowed_elements_parser.reset_and_feed(content) kwargs = { "course": course, "session": session, "edit_info": get_edit_info(session.get_edit_path(course, coverpage)), "content": content } return render_template("coverpage.html", **kwargs)
def course_page(course, lesson, page, solution=None): lesson_slug = lesson page_slug = page try: lesson = model.get_lesson(lesson_slug) canonical_url = url_for('lesson', lesson=lesson, _external=True) except LookupError: lesson = canonical_url = None kwargs = {} prev_link = session_link = next_link = session = None if course.is_link(): naucse.utils.routes.forks_raise_if_disabled() fork_kwargs = {"request_url": request.path} try: # checks if the rendered page content is in cache locally to offer it to the fork # ``course.vars`` calls ``course_info`` so it has to be in the try block # the function can also raise FileNotFoundError if the lesson doesn't exist in repo content_key = page_content_cache_key( arca.get_repo(course.repo, course.branch), lesson_slug, page, solution, course.vars) content_offer = arca.region.get(content_key) # we've got the fragment in cache, let's offer it to the fork; if content_offer: fork_kwargs["content_key"] = content_key data_from_fork = course.render_page(lesson_slug, page, solution, **fork_kwargs) content = data_from_fork["content"] if content is None: # if a offer was accepted content = content_offer["content"] absolute_urls_to_freeze.extend([ get_absolute_url(request.path, x) for x in content_offer["urls"] ]) else: # if the offer was rejected or the the fragment was not in cache arca.region.set(content_key, { "content": content, "urls": data_from_fork["content_urls"] }) absolute_urls_to_freeze.extend([ get_absolute_url(request.path, x) for x in data_from_fork["content_urls"] ]) # compatability page = process_page_data(data_from_fork.get("page")) course = process_course_data(data_from_fork.get("course"), slug=course.slug) session = process_session_data(data_from_fork.get("session")) kwargs["edit_info"] = links.process_edit_info( data_from_fork.get("edit_info")) prev_link, session_link, next_link = process_footer_data( data_from_fork.get("footer")) title = '{}: {}'.format(course["title"], page["title"]) except POSSIBLE_FORK_EXCEPTIONS as e: if raise_errors_from_forks(): raise rendered_replacement = False logger.error("There was an error rendering url %s for course '%s'", request.path, course.slug) if lesson is not None: try: logger.error( "Rendering the canonical version with a warning.") lesson_url, subpage_url, static_url = relative_url_functions( request.path, course, lesson) page = lesson.pages[page] content = page_content(lesson, page, solution, course, lesson_url=lesson_url, subpage_url=subpage_url, static_url=static_url)["content"] title = '{}: {}'.format(course.title, page.title) try: prev_link, session_link, next_link = course.get_footer_links( lesson.slug, page_slug, request_url=request.path) except POSSIBLE_FORK_EXCEPTIONS as e: if raise_errors_from_forks(): raise # the fork is failing spectacularly, the footer links aren't that important logger.error( "Could not retrieve even footer links from the fork at page %s", request.path) logger.exception(e) rendered_replacement = True kwargs["edit_info"] = get_edit_info(page.edit_path) kwargs["error_in_fork"] = True kwargs["travis_build_id"] = os.environ.get( "TRAVIS_BUILD_ID") except Exception as canonical_error: logger.error("Rendering the canonical version failed.") logger.exception(canonical_error) if not rendered_replacement: logger.exception(e) return render_template( "error_in_fork.html", malfunctioning_course=course, edit_info=get_edit_info(course.edit_path), faulty_page="lesson", lesson=lesson_slug, pg=page_slug, # avoid name conflict solution=solution, root_slug=model.meta.slug, travis_build_id=os.environ.get("TRAVIS_BUILD_ID"), ) else: if lesson is None: abort(404) lesson_url, subpage_url, static_url = relative_url_functions( request.path, course, lesson) page, session, prv, nxt = get_page(course, lesson, page) prev_link, session_link, next_link = get_footer_links( course, session, prv, nxt, lesson_url) content = page_content(lesson, page, solution, course=course, lesson_url=lesson_url, subpage_url=subpage_url, static_url=static_url) content = content["content"] allowed_elements_parser.reset_and_feed(content) title = '{}: {}'.format(course.title, page.title) kwargs["edit_info"] = get_edit_info(page.edit_path) if solution is not None: kwargs["solution_number"] = int(solution) return render_template("lesson.html", canonical_url=canonical_url, title=title, content=content, prev_link=prev_link, session_link=session_link, next_link=next_link, root_slug=model.meta.slug, course=course, lesson=lesson, page=page, solution=solution, session=session, **kwargs)
def index(): return render_template("index.html", edit_info=get_edit_info(Path(".")))