def delete_content(course, inpt, TOC): pages_path = syllabus.get_pages_path(course) content_path = inpt["content-path"] path = os.path.join(pages_path, content_path) content_to_delete = TOC.get_content_from_path(content_path) TOC.remove_content_from_toc(content_to_delete) # dump the TOC and reload it syllabus.save_toc(course, TOC) syllabus.get_toc(course, force=True) # remove the files if asked if inpt.get("delete-files", None) == "on": if type(content_to_delete) is Chapter: # delete a chapter shutil.rmtree(os.path.join(path)) else: # delete a page os.remove(path) set_feedback( session, Feedback(feedback_type="success", message="The content has been successfully deleted")) return seeother(request.path)
def init_and_sync_repo(course, force_sync=False): """ Initializes a git repository in the pages folder if no repository already exists, then synchronizes it with the remote specified in the configuration file if the origin didn't exist before or if force_sync is True. Warning: the local changes will be overwritten. :return: """ path = os.path.join(syllabus.get_root_path(), syllabus.get_pages_path(course)) git_config = syllabus.get_config()['courses'][course]['pages']['git'] try: if not os.path.exists(path): os.makedirs(path) repo = Repo(path) except InvalidGitRepositoryError: # this is currently not a git repo repo = Repo.init(path) try: origin = repo.remote("origin").set_url(git_config['remote']) except: origin = repo.create_remote("origin", git_config['remote']) # sync the repo if the origin wasn't already there force_sync = True if force_sync: git_force_sync(course, origin, repo) syllabus.get_toc(course, True)
def toc_edition(course): if not course in syllabus.get_config()["courses"].keys(): abort(404) toc = syllabus.get_toc(course) if toc.ignored and not has_feedback(session): set_feedback( session, Feedback(feedback_type="warning", message="The following contents have not been found :\n" + "<pre>" + "\n".join(toc.ignored) + "</pre>")) if request.method == "POST": inpt = request.form if "new_content" in inpt: try: # check YAML validity toc_dict = yaml.load(inpt["new_content"], OrderedDictYAMLLoader) if not TableOfContent.is_toc_dict_valid( syllabus.get_pages_path(course), toc_dict): set_feedback( session, Feedback(feedback_type="error", message="The submitted table of contents " "is not consistent with the files " "located in the pages directory.")) return seeother(request.path) except yaml.YAMLError: set_feedback( session, Feedback(feedback_type="error", message="The submitted table of contents is not " "written in valid YAML.")) return seeother(request.path) # the YAML is valid, write it in the ToC with open( os.path.join(syllabus.get_pages_path(course), "toc.yaml"), "w") as f: f.write(inpt["new_content"]) syllabus.get_toc(course, force=True) set_feedback( session, Feedback(feedback_type="success", message="The table of contents has been modified " "successfully !")) return seeother(request.path) else: with open(os.path.join(syllabus.get_pages_path(course), "toc.yaml"), "r") as f: try: return render_template( 'edit_table_of_content.html', active_element=sidebar['active_element'], sidebar_elements=sidebar['elements'], content=f.read(), feedback=pop_feeback(session)) except TemplateNotFound: abort(404)
def _render_rst_to_jinja_templating(course, page_path, content): cache_pages = syllabus.get_config()["caching"]["cache_pages"] toc = syllabus.get_toc(course) print_mode = session.get("print_mode", False) # look if we have a cached version of this content if cache_pages and toc.has_cached_content(content, print_mode): with open( safe_join(syllabus.get_pages_path(course), content.cached_path(print_mode)), "r") as f: rendered = f.read() else: # render the content with open(safe_join(syllabus.get_pages_path(course), page_path), "r") as f: rendered = publish_string(f.read(), writer_name='html', settings_overrides=default_rst_opts) if cache_pages: # cache the content if needed if type(content) is Page: parent = toc.get_parent_of(content) os.makedirs(safe_join( toc.cached_path(print_mode), parent.path if parent is not None else ""), exist_ok=True) else: os.makedirs(safe_join(toc.cached_path(print_mode), content.path), exist_ok=True) with open( safe_join(syllabus.get_pages_path(course), content.cached_path(print_mode)), "w") as cached_content: cached_content.write(rendered) return rendered
def get_chapter_printable_content(course: str, chapter: Chapter, toc: TableOfContent): TOC = syllabus.get_toc(course) def fetch_content(chapter): printable_content = [chapter] for content in toc.get_direct_content_of(chapter): if type(content) is Chapter: printable_content += fetch_content(content) else: printable_content.append(content) return printable_content session["print_mode"] = True try: retval = render_template( "print_multiple_contents.html", contents=fetch_content(chapter), render_rst=lambda content, **kwargs: syllabus.utils.pages. render_content(course, content, **kwargs), toc=TOC) session["print_mode"] = False return retval except: session["print_mode"] = False raise
def get_syllabus_content(course, content_path: str, print=False): if not course in syllabus.get_config()["courses"].keys(): abort(404) session["course"] = course if content_path[-1] == "/": content_path = content_path[:-1] TOC = syllabus.get_toc(course) if request.args.get("edit") is not None: return edit_content(course, content_path, TOC) print_mode = print or request.args.get("print") is not None try: try: # assume that it is an RST page return render_web_page(course, TOC.get_page_from_path("%s.rst" % content_path), print_mode=print_mode) except ContentNotFoundError: # it should be a chapter if request.args.get("print") == "all_content": # we want to print all the content of the chapter return get_chapter_printable_content( course, TOC.get_chapter_from_path(content_path), TOC) # we want to access the index of the chapter return render_web_page(course, TOC.get_chapter_from_path(content_path), print_mode=print_mode) except ContentNotFoundError: abort(404)
def print_all_syllabus(course): if not course in syllabus.get_config()["courses"].keys(): abort(404) session["course"] = course TOC = syllabus.get_toc(course) session["print_mode"] = True retval = render_template( "print_multiple_contents.html", contents=syllabus.get_toc(course), render_rst=lambda content, **kwargs: syllabus.utils.pages. render_content(course, content, **kwargs), toc=TOC, get_lti_data=get_lti_data, get_lti_submission=get_lti_submission, logged_in=session.get("user", None)) session["print_mode"] = False return retval
def index(print=False): TOC = syllabus.get_toc() if request.args.get("edit") is not None: return edit_content(TOC.index.path, TOC) print_mode = print or request.args.get("print") is not None try: # only display the button to print the whole syllabus in the index return render_web_page(TOC.index, print_mode=print_mode, display_print_all=True) except ContentNotFoundError: abort(404)
def course_index(course, print_mode=False): if not course in syllabus.get_config()["courses"].keys(): abort(404) session["course"] = course try: TOC = syllabus.get_toc(course) if request.args.get("edit") is not None: return edit_content(course, TOC.index.path, TOC) print_mode = print_mode or request.args.get("print") is not None # only display the button to print the whole syllabus in the index return render_web_page(course, TOC.index, print_mode=print_mode, display_print_all=True) except ContentNotFoundError: abort(404)
def render_web_page(course: str, content: Content, print_mode=False, display_print_all=False): try: TOC = syllabus.get_toc(course) session["print_mode"] = print_mode try: previous = TOC.get_previous_content(content) except KeyError: previous = None try: next = TOC.get_next_content(content) except KeyError: next = None config = syllabus.get_config() inginious_config = config['courses'][course]['inginious'] inginious_course_url = "%s/%s" % (inginious_config['url'], inginious_config['course_id']) same_origin_proxy = inginious_config['same_origin_proxy'] retval = render_template( 'rst_page.html' if not print_mode else 'print_page.html', logged_in=session.get("user", None), inginious_course_url=inginious_course_url if not same_origin_proxy else ("/postinginious/" + course), inginious_url=inginious_config['url'], containing_chapters=TOC.get_containing_chapters_of(content), this_content=content, render_rst=lambda content, **kwargs: syllabus.utils.pages. render_content(course, content, **kwargs), content_at_same_level=TOC.get_content_at_same_level(content), course_str=course, courses_titles={ course: config["courses"][course]["title"] for course in syllabus.get_courses() }, toc=TOC, direct_content=TOC.get_direct_content_of(content), next=next, previous=previous, display_print_all=display_print_all, get_lti_data=get_lti_data, get_lti_submission=get_lti_submission) session["print_mode"] = False except Exception: # ensure that the print mode is disabled session["print_mode"] = False raise return retval
def course_index(course, print_mode=False): if not course in syllabus.get_config()["courses"].keys(): abort(404) session["course"] = course course_config = syllabus.get_config()["courses"][course] if course_config.get("sphinx"): return seeother("/syllabus/{}/{}".format(course, course_config["sphinx"].get("index_page", "index.html"))) try: TOC = syllabus.get_toc(course) if request.args.get("edit") is not None: return edit_content(course, TOC.index.path, TOC) print_mode = print_mode or request.args.get("print") is not None # only display the button to print the whole syllabus in the index return render_web_page(course, TOC.index, print_mode=print_mode, display_print_all=True) except ContentNotFoundError: abort(404)
def get_syllabus_asset(course, asset_path: str, content_path: str = None): if not course in syllabus.get_config()["courses"].keys(): abort(404) session["course"] = course TOC = syllabus.get_toc(course) if content_path is None: return send_from_directory(TOC.get_global_asset_directory(), asset_path) if content_path[-1] == "/": content_path = content_path[:-1] try: # explicitly check that the chapter exists chapter = TOC.get_chapter_from_path(content_path) # secured way to serve a static file # TODO: use X-Sendfile with this method to be efficient return send_from_directory(TOC.get_asset_directory(chapter), asset_path) except ContentNotFoundError: abort(404)
def render_web_page(course: str, content: Content, print_mode=False, display_print_all=False): try: TOC = syllabus.get_toc(course) session["print_mode"] = print_mode try: previous = TOC.get_previous_content(content) except KeyError: previous = None try: next = TOC.get_next_content(content) except KeyError: next = None config = syllabus.get_config() inginious_config = config['courses'][course]['inginious'] inginious_course_url = "%s/%s" % (inginious_config['url'], inginious_config['course_id']) path = safe_join(inginious_config.get("simple_grader_pattern", "/"), inginious_config['course_id']) inginious_sandbox_url = urllib.parse.urljoin(inginious_config["url"], path) same_origin_proxy = inginious_config['same_origin_proxy'] retval = render_template('rst_page.html' if not print_mode else 'print_page.html', logged_in=session.get("user", None), inginious_config = syllabus.get_config()['courses'][course]['inginious'], inginious_course_url=inginious_course_url if not same_origin_proxy else ("/postinginious/" + course), inginious_sandbox_url=inginious_sandbox_url, inginious_url=inginious_config['url'], containing_chapters=TOC.get_containing_chapters_of(content), this_content=content, render_rst=lambda content, **kwargs: syllabus.utils.pages.render_content(course, content, **kwargs), render_footer= lambda course: syllabus.utils.pages.render_footer(course), content_at_same_level=TOC.get_content_at_same_level(content), course_str=course, courses_titles={course: config["courses"][course]["title"] for course in syllabus.get_courses()}, toc=TOC, direct_content=TOC.get_direct_content_of(content), next=next, previous=previous, display_print_all=display_print_all, get_lti_data=get_lti_data, get_lti_submission=get_lti_submission, render_rst_str=syllabus.utils.pages.render_rst_str, login_img="/static/login.png" if os.path.exists(os.path.join(app.static_folder, "login.png")) else None, auth_methods=syllabus.get_config()["authentication_methods"]) session["print_mode"] = False except Exception: # ensure that the print mode is disabled session["print_mode"] = False raise return retval
def refresh(course): TOC = syllabus.get_toc(course) data = request.form['content'] config = syllabus.get_config() inginious_config = config['courses'][course]['inginious'] inginious_course_url = "%s/%s" % (inginious_config['url'], inginious_config['course_id']) same_origin_proxy = inginious_config['same_origin_proxy'] code_html = render_template_string(publish_string(data, writer_name='html', settings_overrides=default_rst_opts), logged_in=session.get("user", None), inginious_course_url=inginious_course_url if not same_origin_proxy else ("/postinginious/" + course), inginious_url=inginious_config['url'], this_content=data, render_rst=lambda content, **kwargs: syllabus.utils.pages.render_content(course, content, **kwargs), course_str=course, courses_titles={course: config["courses"][course]["title"] for course in syllabus.get_courses()}, toc=TOC, get_lti_data=get_lti_data, get_lti_submission=get_lti_submission, render_rst_str=syllabus.utils.pages.render_rst_str) return "<div id=\"preview\" style=\"overflow-y: scroll\">"+code_html+"</div>"
def render_web_page(content: Content, print_mode=False, display_print_all=False): try: TOC = syllabus.get_toc() session["print_mode"] = print_mode try: previous = TOC.get_previous_content(content) except KeyError: previous = None try: next = TOC.get_next_content(content) except KeyError: next = None inginious_config = syllabus.get_config()['inginious'] inginious_course_url = "%s/%s" % (inginious_config['url'], inginious_config['course_id']) same_origin_proxy = inginious_config['same_origin_proxy'] retval = render_template( 'rst_page.html' if not print_mode else 'print_page.html', logged_in=session.get("user", None), inginious_course_url=inginious_course_url if not same_origin_proxy else "/postinginious", inginious_url=inginious_config['url'], containing_chapters=TOC.get_containing_chapters_of(content), this_content=content, render_rst=syllabus.utils.pages.render_content, content_at_same_level=TOC.get_content_at_same_level(content), toc=TOC, direct_content=TOC.get_direct_content_of(content), next=next, previous=previous, display_print_all=display_print_all) session["print_mode"] = False except Exception: # ensure that the print mode is disabled session["print_mode"] = False raise return retval
def print_all_syllabus(): return render_template("print_multiple_contents.html", contents=syllabus.get_toc(), render_rst=syllabus.utils.pages.render_content)
def content_edition(course): if not course in syllabus.get_config()["courses"].keys(): abort(404) TOC = syllabus.get_toc(course) if TOC.ignored and not has_feedback(session): set_feedback( session, Feedback(feedback_type="warning", message="The following contents have not been found :\n" + "<pre>" + "\n".join(TOC.ignored) + "</pre>")) if request.method == "POST": inpt = request.form if inpt["action"] == "delete_content": return delete_content(course, inpt, TOC) containing_chapter = None try: if inpt["containing-chapter"] != "": containing_chapter = TOC.get_chapter_from_path( inpt["containing-chapter"]) except ContentNotFoundError: set_feedback( session, Feedback(feedback_type="error", message="The containing chapter for this page " "does not exist")) return seeother(request.path) # sanity checks on the filename: refuse empty filenames of filenames with spaces if len(inpt["name"]) == 0 or len(re.sub( r'\s+', '', inpt["name"])) != len(inpt["name"]): set_feedback( session, Feedback( feedback_type="error", message='The file name cannot be empty or contain spaces.') ) return seeother(request.path) if os.sep in inpt["name"]: set_feedback( session, Feedback( feedback_type="error", message= 'The file name cannot contain the "%s" forbidden character.' % os.sep)) return seeother(request.path) pages_path = syllabus.get_pages_path() content_path = os.path.join( containing_chapter.path, inpt["name"]) if containing_chapter is not None else inpt["name"] path = os.path.join(pages_path, content_path) # ensure that we do not create a page at the top level if containing_chapter is None and inpt["action"] == "create_page": set_feedback( session, Feedback(feedback_type="error", message="Pages cannot be at the top level of the " "syllabus.")) return seeother(request.path) # check that there is no chapter with the same title in the containing chapter if containing_chapter is None: for content in TOC.get_top_level_content(): if content.title == inpt["title"]: set_feedback( session, Feedback(feedback_type="error", message="There is already a top level " "chapter with this title.")) return seeother(request.path) else: for content in TOC.get_direct_content_of(containing_chapter): if content.title == inpt["title"]: set_feedback( session, Feedback(feedback_type="error", message="There is already a chapter/page " "with this title in this chapter.")) return seeother(request.path) if inpt["action"] == "create_page": # add the extension to the page filename content_path += ".rst" path += ".rst" # when file/directory already exists if os.path.isdir(path) or os.path.isfile(path): set_feedback( session, Feedback(feedback_type="error", message="A file or directory with this name " "already exists.")) return seeother(request.path) # create a new page open(path, "w").close() page = Page(path=content_path, title=inpt["title"], pages_path=syllabus.get_pages_path(course)) TOC.add_content_in_toc(page) elif inpt["action"] == "create_chapter": # creating a new chapter try: os.mkdir(path) except FileExistsError: set_feedback( session, Feedback(feedback_type="error", message="A file or directory with this name " "already exists.")) return seeother(request.path) chapter = Chapter(path=content_path, title=inpt["title"], pages_path=syllabus.get_pages_path(course)) TOC.add_content_in_toc(chapter) # dump the TOC and reload it syllabus.save_toc(course, TOC) syllabus.get_toc(course, force=True) return seeother(request.path) try: return render_template('content_edition.html', active_element=sidebar['active_element'], course_str=course, sidebar_elements=sidebar['elements'], TOC=TOC, feedback=pop_feeback(session)) except TemplateNotFound: abort(404)