示例#1
0
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)
示例#2
0
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)
示例#3
0
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)
示例#4
0
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
示例#5
0
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
示例#6
0
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)
示例#7
0
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)
示例#10
0
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)
示例#17
0
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)