def update_pages(secret): params = Params.query.one() if secret != params.git_hook_url or 'git' not in syllabus.get_config( )['pages']: return seeother("/") syllabus.utils.pages.init_and_sync_repo(force_sync=True) return "done"
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_lti_url(user_id, task_id): config = syllabus.get_config() consumer = ToolConsumer( consumer_key=config['inginious']['lti']['consumer_key'], consumer_secret=config['inginious']['lti']['consumer_secret'], launch_url='%s/lti/%s/%s' % (config['inginious']['url'], config['inginious']['course_id'], task_id), params={ 'lti_message_type': 'basic-lti-launch-request', 'lti_version': "1.1", 'resource_link_id': "syllabus_%s" % task_id, 'user_id': user_id, } ) d = consumer.generate_launch_data() data = parse.urlencode(d).encode() req = urllib_request.Request('%s/lti/%s/%s' % (config['inginious']['url'], config['inginious']['course_id'], task_id), data=data) resp = urllib_request.urlopen(req) task_url = resp.geturl() if not lti_url_regex.match(task_url): pass #raise Exception("INGInious returned the wrong url: %s vs %s" % (task_url, str(lti_url_regex))) return task_url
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 git_force_sync(course, origin, repo): git_config = syllabus.get_config()['courses'][course]['pages']['git'] private_key_path = git_config['repository_private_key'] branch = git_config['branch'] if private_key_path is not None: # We need to be compatible with git < 2.3 as CentOS7 uses an older version, so here is an ugly code # to use a deployment key that will work with old git versions # set the ssh executable ssh_executable_path = os.path.join(syllabus.get_root_path(), "ssh_executable.sh") with open(ssh_executable_path, "w") as f: f.write( '#!/bin/sh\nID_RSA=%s\nssh -o StrictHostKeyChecking=no -i $ID_RSA "$@"' % private_key_path) os.system("chmod +x %s" % ssh_executable_path) with repo.git.custom_environment(GIT_SSH=ssh_executable_path): origin.fetch() # complete synchronization (local changes will be overwritten) repo.git.reset('--hard', 'origin/%s' % branch) # Hereunder is a more pretty version, uncomment it when the git version is >= 2.3 # with repo.git.custom_environment(GIT_SSH_COMMAND='ssh -i %s -o StrictHostKeyChecking=no' % private_key_path): # origin.fetch() # # complete synchronization (local changes will be overwritten) # repo.git.reset('--hard', 'origin/%s' % branch) else: origin.fetch() # complete synchronization (local changes will be overwritten) repo.git.reset('--hard', 'origin/%s' % branch)
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 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 config_edition(): if request.method == "POST": inpt = request.form if "new_config" in inpt: try: # check YAML validity config = yaml.load(inpt["new_config"]) # TODO: check that the configuration has the appropriate fields # update the config old_config = syllabus.get_config() syllabus.set_config(inpt["new_config"]) # sync the git repo if it has changed try: courses = set(list(old_config["courses"].keys()) + list(config["courses"].keys())) for course in courses: old_pages_config = old_config["courses"].get(course, {}).get("pages", {}) pages_config = config["courses"].get(course, {}).get("pages", {}) if ("git" not in old_pages_config and "git" in pages_config) or old_pages_config["git"] != pages_config["git"]: syllabus.utils.pages.init_and_sync_repo(course, force_sync=True) except KeyError as e: pass except AttributeError: return seeother(request.path, Feedback(feedback_type="error", message="The git repository has " "failed to synchronize. " "Please check your " "configuration.")) return seeother(request.path, Feedback(feedback_type="success", message="The table of contents has been" " modified successfully !")) except yaml.YAMLError: return seeother(request.path, feedback=Feedback(feedback_type="error", message="The submitted configuration is not " "written in valid YAML.")) else: params = Params.query.one() config = syllabus.get_config() hook_paths = [("/update_pages/{}/{}".format(params.git_hook_url, course)) if "git" in config["courses"][course]["pages"] and params.git_hook_url is not None else None for course in syllabus.get_courses()] try: with open(syllabus.get_config_path(), 'r') as f: return render_template('edit_configuration.html', active_element=sidebar['active_element'], sidebar_elements=sidebar['elements'], config=f.read(), hook_paths=hook_paths, feedback=pop_feeback(session)) except TemplateNotFound: abort(404)
def saml(): if "saml" not in syllabus.get_config()['authentication_methods']: abort(404) req = prepare_request(request) req['request_uri'] = request.path # hack to ensure to have the correct path and to avoid RelayState loops auth = init_saml_auth(req, saml_config) # if 'sso' in request.args: # return if request.method == "GET": return redirect(auth.login()) else: auth.process_response() errors = auth.get_errors() # Try and check if IdP is using several signature certificates # This is a limitation of python3-saml for cert in saml_config["idp"].get("additionalX509certs", []): if auth.get_last_error_reason( ) == "Signature validation failed. SAML Response rejected": import copy # Change used IdP certificate new_settings = copy.deepcopy(saml_config) new_settings["idp"]["x509cert"] = cert # Retry processing response auth = init_saml_auth(req, new_settings) auth.process_response() errors = auth.get_errors() if len(errors) == 0: attrs = auth.get_attributes() # session['samlNameId'] = auth.get_nameid() # session['samlSessionIndex'] = auth.get_session_index() username = attrs[saml_config['sp']['attrs']['username']][0] realname = attrs[saml_config['sp']['attrs']['realname']][0] email = attrs[saml_config['sp']['attrs']['email']][0] user = User.query.filter(User.email == email).first() if user is None: # The user does not exist in our DB user = User(name=username, full_name=realname, email=email, hash_password=None, change_password_url=None) db_session.add(user) db_session.commit() session["user"] = user.to_dict() session["user"].update({"login_method": "saml"}) self_url = OneLogin_Saml2_Utils.get_self_url(req) if 'RelayState' in request.form and self_url != request.form[ 'RelayState']: return redirect(auth.redirect_to(request.form['RelayState'])) return seeother("/")
def get_lti_submission(user_id, task_id): config = syllabus.get_config() lti_url = get_lti_url(user_id, task_id) match = lti_regex_match.findall(lti_url) if len(match) == 1: cookie = match[0] response = json.loads(urllib_request.urlopen('%s/@%s@/lti/bestsubmission' % (config['inginious']['url'], cookie)).read().decode("utf-8")) if response["status"] == "success" and response["submission"] is not None: return response["submission"]["input"]['q1'] return None
def post_inginious(course): inpt = request.form data = parse.urlencode(inpt).encode() inginious_config = syllabus.get_config()['courses'][course]['inginious'] inginious_course_url = "%s/%s" % (inginious_config['url'], inginious_config['course_id']) req = urllib_request.Request(inginious_course_url, data=data) resp = urllib_request.urlopen(req) response = make_response(resp.read().decode()) response.headers['Content-Type'] = 'text/json' return response
def post_inginious(course): inpt = request.form data = parse.urlencode(inpt).encode() inginious_config = syllabus.get_config()['courses'][course]['inginious'] path = safe_join(inginious_config.get("simple_grader_pattern", "/"), inginious_config['course_id']) inginious_sandbox_url = urllib.parse.urljoin(inginious_config["url"], path) req = urllib_request.Request(inginious_sandbox_url, data=data) resp = urllib_request.urlopen(req) response = make_response(resp.read().decode()) response.headers['Content-Type'] = 'text/json' return response
def reset_password(secret): user = db_session.query(User).filter(User.change_password_url == secret).first() if user is None: # TODO: log return seeother("/") if request.method == "GET": return render_template("reset_password.html", alert_hidden=True) if request.method == "POST": inpt = request.form password = inpt["password"] password_confirm = inpt["password_confirm"] if password != password_confirm: return render_template("reset_password.html", alert_hidden=False) password_hash = hash_password_func(email=user.email, password=password, global_salt=syllabus.get_config().get('password_salt', None), n_iterations=syllabus.get_config().get('password_hash_iterations', 100000)) user.hash_password = password_hash user.change_password_url = None db_session.commit() return seeother("/login")
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 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=TOC, 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), course_str=course, render_rst_str=syllabus.utils.pages.render_rst_str) session["print_mode"] = False return retval
def get_lti_data(course, user_id, task_id): inginious_config = syllabus.get_config()['courses'][course]['inginious'] consumer = ToolConsumer( consumer_key=inginious_config['lti']['consumer_key'], consumer_secret=inginious_config['lti']['consumer_secret'], launch_url='%s/lti/%s/%s' % (inginious_config['url'], inginious_config['course_id'], task_id), params={ 'lti_message_type': 'basic-lti-launch-request', 'lti_version': "1.1", 'resource_link_id': "syllabus_%s" % task_id, 'user_id': user_id, }) d = consumer.generate_launch_data() return d, consumer.launch_url
def get_lti_submission(course, user_id, task_id): config = syllabus.get_config() try: lti_url = get_lti_url(course, user_id, task_id) except HTTPError: return None match = lti_regex_match.findall(lti_url) if len(match) == 1: cookie = match[0] try: response = json.loads(urllib_request.urlopen('%s/@%s@/lti/bestsubmission' % (config['courses'][course]['inginious']['url'], cookie), timeout=5).read().decode("utf-8")) except (JSONDecodeError, HTTPError): response = {"status": "error"} if response["status"] == "success" and response["submission"] is not None: return response return None
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 activate_account(): email = request.args.get('email') mac = request.args.get('token') try: ts = int(request.args.get('ts')) except TypeError: abort(404) return None email_activation_config = syllabus.get_config()["authentication_methods"]["local"].get("email_activation", {}) if not verify_activation_mac(email=email, secret=email_activation_config["secret"], mac_to_verify=mac, timestamp=ts): # the mac does not match the provided email abort(404) return None if User.query.filter(User.email == email).count() != 0: set_feedback(session, ErrorFeedback("This user is already activated."), feedback_type="login") return seeother("/login") if request.method == "GET": return render_template("local_register_confirmed_account.html", feedback=pop_feeback(session, feedback_type="login")) if request.method == "POST": inpt = request.form try: u = handle_user_registration_infos(inpt, email, False) except UnicodeEncodeError: # TODO: log return seeother("/login") if u is None: return seeother("/activate?{}".format(urllib.parse.urlencode({"email": email, "token": mac, "ts": ts}))) try: locally_register_new_user(u, activated=True) feedback_message = "You have been successfully registered." set_feedback(session, SuccessFeedback(feedback_message), feedback_type="login") return seeother("/login") except UserAlreadyExists: db_session.rollback() set_feedback(session, ErrorFeedback("Could not register: this user already exists."), feedback_type="login") return seeother("/register/{}/{}".format(email, mac)) set_feedback(session, SuccessFeedback("Your account has been successfully activated"), feedback_type="login") return seeother("/login")
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 log_in(): if request.method == "GET": return render_template("login.html", auth_methods=syllabus.get_config()['authentication_methods']) if request.method == "POST": inpt = request.form username = inpt["username"] password = inpt["password"] try: password_hash = hash_password(password.encode("utf-8")) except UnicodeEncodeError: # TODO: log return seeother("/login") user = User.query.filter(User.username == username).first() if user is None or user.hash_password != password_hash: abort(403) session['user'] = user.to_dict() return seeother('/')
def saml(): if "saml" not in syllabus.get_config()['authentication_methods']: abort(404) req = prepare_request(request) req['request_uri'] = request.path # hack to ensure to have the correct path and to avoid RelayState loops auth = init_saml_auth(req, saml_config) # if 'sso' in request.args: # return if request.method == "GET": return redirect(auth.login()) elif 'acs' in request.args: auth.process_response() errors = auth.get_errors() if len(errors) == 0: attrs = auth.get_attributes() # session['samlNameId'] = auth.get_nameid() # session['samlSessionIndex'] = auth.get_session_index() username = attrs[saml_config['sp']['attrs']['username']][0] realname = attrs[saml_config['sp']['attrs']['realname']][0] email = attrs[saml_config['sp']['attrs']['email']][0] user = User.query.filter(User.email == email).first() if user is None: # The user does not exist in our DB user = User(name=username, full_name=realname, email=email, hash_password=None, change_password_url=None) db_session.add(user) db_session.commit() session["user"] = user.to_dict() session["user"].update({"login_method": "saml"}) self_url = OneLogin_Saml2_Utils.get_self_url(req) if 'RelayState' in request.form and self_url != request.form[ 'RelayState']: return redirect(auth.redirect_to(request.form['RelayState'])) return seeother("/")
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 get_syllabus_content(course, content_path: str, print_mode=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_mode 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 get_lti_data(course, user_id, task_id): course_config = syllabus.get_config()['courses'][course] inginious_config = course_config['inginious'] lti_config = inginious_config['lti'] consumer = ToolConsumer( consumer_key=inginious_config['lti']['consumer_key'], consumer_secret=inginious_config['lti']['consumer_secret'], launch_url='%s/lti/%s/%s' % (inginious_config['url'], inginious_config['course_id'], task_id), params={ 'lti_message_type': 'basic-lti-launch-request', 'lti_version': "1.1", 'resource_link_id': "syllabus_%s" % task_id, 'tool_consumer_instance_name': 'Interactive syllabus (%s)' % course_config['title'], 'tool_consumer_instance_url': lti_config.get('tool_url', None), 'tool_consumer_instance_description': lti_config.get('tool_description', None), 'context_id': lti_config.get('tool_context_id', None), 'context_label': lti_config.get('tool_context_label', None), 'context_title': lti_config.get('tool_context_title', None), 'user_id': user_id, } ) d = consumer.generate_launch_data() return d, consumer.launch_url
def index(print=False): default_course = syllabus.get_config().get("default_course", None) if not default_course: return "No default course" return redirect(url_for("course_index", course=default_course))
def feedback_page(): return render_template("feedback_page.html", auth_methods=syllabus.get_config()['authentication_methods'], feedback=pop_feeback(session, feedback_type="login"))
def register(): if "local" not in syllabus.get_config()['authentication_methods']: abort(404) timestamp = int(datetime.datetime.now(datetime.timezone.utc).timestamp()) email_activation_config = syllabus.get_config()["authentication_methods"]["local"].get("email_activation", {}) activation_required = email_activation_config.get("required", True) if request.method == "GET": return render_template("register.html", auth_methods=syllabus.get_config()['authentication_methods'], feedback=pop_feeback(session, feedback_type="login"), activation_required=activation_required) if request.method == "POST": inpt = request.form if activation_required: # send the email confirmation email = inpt["email"] auth_config = email_activation_config.get("authentication", {}) parsed_url = urllib.parse.urlparse(urllib.parse.urljoin(request.host_url, "activate")) parsed_url = parsed_url._replace(query=urllib.parse.urlencode({ "email": email, "token": get_activation_mac(email=email, secret=email_activation_config["secret"], timestamp=timestamp), "ts": timestamp })) url = urllib.parse.urlunparse(parsed_url) if auth_config.get("required", False): send_authenticated_confirmation_mail(email_activation_config["sender_email_address"], email, url, email_activation_config["smtp_server"], username=auth_config["username"], password=auth_config["password"], smtp_port=email_activation_config["smtp_server_port"]) else: send_confirmation_mail(email_activation_config["sender_email_address"], email, url, email_activation_config["smtp_server"], use_ssl=email_activation_config["use_ssl"], smtp_port=email_activation_config["smtp_server_port"]) feedback_message = "Registration successful. Please activate your account using the activation link you received by e-mail." \ "Click <a href=\"/login\">here</a> to log in." set_feedback(session, SuccessFeedback(feedback_message), feedback_type="login") return seeother("/activation_needed") # here, the activation is not required try: u = handle_user_registration_infos(inpt, inpt["email"], False) except UnicodeEncodeError: # TODO: log return seeother("/login") if u is None: return seeother("/register") try: locally_register_new_user(u, not activation_required) feedback_message = "You have been successfully registered." set_feedback(session, SuccessFeedback(feedback_message), feedback_type="login") return seeother("/login") except UserAlreadyExists as e: set_feedback(session, ErrorFeedback("Could not register: this user already exists{}.".format( (": %s" % e.reason) if e.reason is not None else "")), feedback_type="login") db_session.rollback() return seeother("/register")
from syllabus.database import init_db, db_session, update_database from syllabus.models.params import Params from syllabus.models.user import hash_password, User from syllabus.saml import prepare_request, init_saml_auth from syllabus.utils.inginious_lti import get_lti_data, get_lti_submission from syllabus.utils.pages import seeother, get_content_data, permission_admin from syllabus.utils.toc import Content, Chapter, TableOfContent, ContentNotFoundError, Page app = Flask(__name__, template_folder=os.path.join(syllabus.get_root_path(), 'templates'), static_folder=os.path.join(syllabus.get_root_path(), 'static')) app.register_blueprint(admin_blueprint, url_prefix='/admin') app.config['TEMPLATES_AUTO_RELOAD'] = True app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False session_sk = syllabus.get_config().get("sessions_secret_key", None) if session_sk is None or session_sk == "": raise Exception( "You must give a session secret key to use the application") app.secret_key = session_sk directives.register_directive('inginious', syllabus.utils.directives.InginiousDirective) directives.register_directive( 'inginious-sandbox', syllabus.utils.directives.InginiousSandboxDirective) directives.register_directive('table-of-contents', syllabus.utils.directives.ToCDirective) directives.register_directive('author', syllabus.utils.directives.AuthorDirective) directives.register_directive('teacher', syllabus.utils.directives.TeacherDirective) directives.register_directive('framed',