diff --git a/__pycache__/config.cpython-311.pyc b/__pycache__/config.cpython-311.pyc index 5fa11ac..41e977b 100644 Binary files a/__pycache__/config.cpython-311.pyc and b/__pycache__/config.cpython-311.pyc differ diff --git a/app/__pycache__/__init__.cpython-311.pyc b/app/__pycache__/__init__.cpython-311.pyc index be449ed..fc92dee 100644 Binary files a/app/__pycache__/__init__.cpython-311.pyc and b/app/__pycache__/__init__.cpython-311.pyc differ diff --git a/app/__pycache__/forms.cpython-311.pyc b/app/__pycache__/forms.cpython-311.pyc index 020f382..34fd422 100644 Binary files a/app/__pycache__/forms.cpython-311.pyc and b/app/__pycache__/forms.cpython-311.pyc differ diff --git a/app/__pycache__/routes.cpython-311.pyc b/app/__pycache__/routes.cpython-311.pyc index d415f5c..c5ae448 100644 Binary files a/app/__pycache__/routes.cpython-311.pyc and b/app/__pycache__/routes.cpython-311.pyc differ diff --git a/app/forms.py b/app/forms.py index cd95e1a..fdc8acd 100644 --- a/app/forms.py +++ b/app/forms.py @@ -1,10 +1,55 @@ from flask_wtf import FlaskForm -from wtforms.fields import SubmitField +from wtforms.fields import (SubmitField, + PasswordField, + StringField, + TextAreaField, + IntegerField, + BooleanField, + RadioField) +from wtforms.validators import InputRequired, Length +from flask_wtf.file import FileField, FileRequired +from werkzeug.utils import secure_filename from flask_codemirror.fields import CodeMirrorField -class TemplateForm(FlaskForm): - template_code = CodeMirrorField( - language='htmlembedded', - config={'lineNumbers': 'true'}) - submit = SubmitField('Submit') + +class ApiKey(FlaskForm): + api_key = PasswordField('Api Key', + validators=[InputRequired(), + Length(min=20, max=25)] + ) + + +class TemplateForm(FlaskForm): + name = StringField("Template File Name", + validators=[InputRequired()]) + + body = TextAreaField("Template Code", + validators=[InputRequired()]) + + submit = SubmitField('Upload Templates') + + # template_code = CodeMirrorField( language='htmlembedded', + # config={'lineNumbers': 'true'}) + +class CsvForm(FlaskForm): + file = FileField(validators=[FileRequired()]) + all_or_some = RadioField("All or Some", + choices=['All learners in all groups', + 'Learners only in adjacent groups'], + validators=[InputRequired()]) + + + +class CourseForm(FlaskForm): + title = StringField('Title', + validators=[InputRequired(), + Length(min=10, max=100)]) + description = TextAreaField('Course Description', + validators=[InputRequired(), + Length(max=200)]) + price = IntegerField('Price', validators=[InputRequired()]) + level = RadioField('Level', + choices=['Beginner', 'Intermediate', 'Advanced'], + validators=[InputRequired()]) + available = BooleanField('Available', default='checked') diff --git a/app/routes.py b/app/routes.py index 0fe81bf..5b5129f 100644 --- a/app/routes.py +++ b/app/routes.py @@ -13,6 +13,7 @@ from flask import ( session, make_response, url_for, + g, ) from werkzeug.utils import secure_filename from app import app, forms @@ -26,6 +27,7 @@ ALLOWED_EXTENSIONS = {"csv"} # Global Variables url = "https://api.northpass.com/" + def download_csv(): if request.method == "GET": download = make_response(session["dfcsv"]) @@ -57,11 +59,13 @@ def allowed_file(filename): def key_required(check): @wraps(check) def decorated_function(*args, **kwargs): - if session.get('key') is None: - return redirect('/',code=302) + if session.get("key") is None: + return redirect("/", code=302) return check(*args, **kwargs) + return decorated_function + @app.route("/", methods=["GET", "POST"]) def ask_key(): """This is the main function that asks for the API Key. @@ -71,8 +75,9 @@ def ask_key(): specials = '"!@#$%^&*()-+?_=,<>/"' if request.method == "POST": session["key"] = request.form.get("apikey") - if (any(char in specials for char in session["key"]) or - re.search(r"[\s]", session["key"])): + if any(char in specials for char in session["key"]) or re.search( + r"[\s]", session["key"] + ): error = "Invalid Key." session.clear() return render_template("index.html", title="Home", error=error) @@ -100,7 +105,7 @@ def render_home(): def clear_session(): if session.get("key"): session.clear() - error="Session Cleared!" + error = "Session Cleared!" return render_template("index.html", error=error, title="Home, New session") return render_template("index.html", title="Home, New session") @@ -109,6 +114,7 @@ def clear_session(): def table(): return render_template("table.html", tables=[session["table"]], titles=["Table"]) + @app.route("/upload_file", methods=["GET", "POST"]) @key_required def upload_file(): @@ -133,11 +139,12 @@ def upload_file(): return divide_values(file) return render_template("home.html", title="Bulk Add") + def divide_values(file): emails = [] groups = [] - selection = request.form.get('learner-groups') - if request.form['submit']: + selection = request.form.get("learner-groups") + if request.form["submit"]: if selection == "all-groups": for item in file[1:]: emails.append(item[0]) @@ -160,13 +167,12 @@ def divide_values(file): return api_csv_parse(emails, groups) return emails - if request.form['preview']: - error="Preview Button Still Under Construction. Try again later." + if request.form["preview"]: + error = "Preview Button Still Under Construction. Try again later." return render_template("bulk_add.html", error=error, title="Preview Not Yet") - return render_template( - "bulk_add.html", title="Uploaded File" - ) + return render_template("bulk_add.html", title="Uploaded File") + def api_csv_parse(emails, groups): if emails and groups: @@ -175,13 +181,15 @@ def api_csv_parse(emails, groups): return api_add_ppl(emails) elif groups: return api_add_groups(groups) - return render_template("bulk_add.html", table=htmlcsv, title="CSV Submission") + return render_template("bulk_add.html", title="CSV Submission") + @app.route("/bulk_add_opts", methods=["GET", "POST"]) @key_required def bulk_add_opts(): return render_template("bulk_add.html", titles="Bulk Add Options") + @app.route("/bulk_add", methods=["GET", "POST"]) @key_required def bulk_add(): @@ -223,8 +231,8 @@ def api_add_ppl(emails): payload2 = [] endpoint = "v2/bulk/people" for email in emails: - payload2.append({"email": email }) - payload = {"data": {"attributes": {"people": payload2 }}} + payload2.append({"email": email}) + payload = {"data": {"attributes": {"people": payload2}}} headers = { "accept": "application/json", "content-type": "application/json", @@ -239,8 +247,8 @@ def api_add_groups(groups): payload2 = [] endpoint = "v2/bulk/people" for group in groups: - payload2.append({"groups" : group }) - payload = {"data": {"attributes": {"people": payload2 }}} + payload2.append({"groups": group}) + payload = {"data": {"attributes": {"people": payload2}}} headers = { "accept": "application/json", "content-type": "application/json", @@ -257,9 +265,7 @@ def api_add_ppl_groups(emails, groups): combinations = list(itertools.product(emails, groups)) for combo in combinations: payload2.append({"email": combo[0], "groups": combo[1]}) - payload = { - "data": {"attributes": {"people": payload2 }} - } + payload = {"data": {"attributes": {"people": payload2}}} headers = { "accept": "application/json", @@ -267,8 +273,8 @@ def api_add_ppl_groups(emails, groups): "X-Api-Key": session["key"], } return payload - #response = requests.post(url + endpoint, json=payload, headers=headers) - #return check_response(response) + # response = requests.post(url + endpoint, json=payload, headers=headers) + # return check_response(response) def check_response(response): @@ -286,11 +292,12 @@ def check_response(response): error = "Something went wrong, but I'm not sure what." return render_template("bulk_add.html", title="Shrug", error=error) + @app.route("/load_templates", methods=["GET", "POST"]) @key_required def load_templates(): count = 0 - templates= [] + templates = [] while True: count += 1 @@ -300,33 +307,44 @@ def load_templates(): "content-type": "application/json", "X-Api-Key": session["key"], } - response = requests.get(url+endpoint, headers=headers) + response = requests.get(url + endpoint, headers=headers) data = response.json() nextlink = data["links"] for response in data["data"]: - name, body = ( - response["attributes"]["name"], response["attributes"]["body"]) - templates.append((name,body)) + last_updated = response["attributes"]["updated_at"].split("T") + last_updated = last_updated[0] + name, body, last_updated = ( + response["attributes"]["name"], + response["attributes"]["body"], + last_updated, + ) + templates.append((name, body, last_updated)) if "next" not in nextlink: break - return render_template("templates.html", - title="Templates", - templates=templates, - ) + save_templates_backup(templates) + return render_template( + "templates.html", + title="Templates", + templates=templates, + ) return render_template("options.html") + @app.route("/templates", methods=["GET", "POST"]) @key_required def templates(): if request.method == "POST": - if request.form['submit-template']: - name = request.form.get('template_name') - body = request.form.get("loaded-content") + if request.form["submit-template"]: + name = request.form.get("template_name") + body = request.form.get("body") + g.last_template = name if body == "": - error = "Ooph. Looks like you didn't load the changes before submitting." + error = ( + "Ooph. Looks like you didn't load the changes before submitting." + ) return render_template("templates.html", error=error) else: endpoint = "v2/custom_templates" @@ -335,22 +353,21 @@ def templates(): "content-type": "application/json", "X-Api-Key": session["key"], } - payload = {"custom_template": { - "name":name, - "body":body - }} - response = requests.post(url+endpoint, json=payload, headers=headers) + payload = {"custom_template": {"name": name, "body": body}} + response = requests.post(url + endpoint, json=payload, headers=headers) return check_templates(response) return load_templates() + def check_templates(response): print(response) response = str(response) if "201" in response: error = "Success! Templates Uploaded." - return render_template("templates.html", - title="Templates Added", - error=error) + button = "Undo" + return render_template( + "templates.html", title="Templates Added", error=error, button=button + ) elif "403" in response: error = "Uh oh. Looks like you don't have appropriate privileges." return render_template("templates.html", error=error) @@ -362,28 +379,44 @@ def check_templates(response): return render_template("templates.html", title="Shrug", error=error) -@app.route("/bulk_courses_to_groups", methods=["GET", "POST"]) +def save_templates_backup(templates): + g.client_path = os.path.join(UPLOAD_FOLDER, session["school"]) + if os.path.exists(g.client_path): + pass + else: + os.mkdir(g.client_path) + + for tupe in templates: + file_name = tupe[0] + ".liquid" + file_body = tupe[1] + complete_path = os.path.join(g.client_path, file_name) + + with open(complete_path, "w+") as temp: + temp.write(file_body) + temp.close + + +@app.route("/undo_template", methods=["POST"]) @key_required -def bulk_courses_to_groups(): - pass +def undo_template(): + print(g.client_path) + template_path = os.path.join(g.client_path, g.last_template) + if request.method == "POST": + if request.form["undo_templates"]: + if os.path.exists(template_path): + print(template_path) -@app.route("/bulk_invite_ppl", methods=["GET", "POST"]) -@key_required -def bulk_invite_ppl(): - pass - -@app.route('/cmtest', methods = ['GET', 'POST']) +@app.route("/cmtest", methods=["GET", "POST"]) def cmtest(): form = TemplateForm() if form.validate_on_submit(): text = form.template_code.data - return render_template('templates.html', form=form) - + return render_template("templates.html", form=form) app.secret_key = "@&I\x1a?\xce\x94\xbb0w\x17\xbf&Y\xa2\xc2(A\xf5\xf2\x97\xba\xeb\xfa" -#if __name__ == "__main__": +# if __name__ == "__main__": # ask_key() diff --git a/app/static/files/[Sandbox] Norm's Academy/_cards_course.html.liquid b/app/static/files/[Sandbox] Norm's Academy/_cards_course.html.liquid new file mode 100644 index 0000000..7d08608 --- /dev/null +++ b/app/static/files/[Sandbox] Norm's Academy/_cards_course.html.liquid @@ -0,0 +1,49 @@ + +
+ {% if course.ribbon %} +
+ {{ course.ribbon }} +
+ {% endif %} + +
+

+ {{ course.name }} +

+
+ {{ course.full_description }} +
+ +
+ {% t shared.progress, count: course.progress %} +
+ +
+
+
+ diff --git a/app/static/files/[Sandbox] Norm's Academy/_cards_featured_course.html.liquid b/app/static/files/[Sandbox] Norm's Academy/_cards_featured_course.html.liquid new file mode 100644 index 0000000..70cba72 --- /dev/null +++ b/app/static/files/[Sandbox] Norm's Academy/_cards_featured_course.html.liquid @@ -0,0 +1,44 @@ +
+
+ +
+
diff --git a/app/static/files/[Sandbox] Norm's Academy/_course_details.html.liquid b/app/static/files/[Sandbox] Norm's Academy/_course_details.html.liquid new file mode 100644 index 0000000..e69de29 diff --git a/app/static/files/[Sandbox] Norm's Academy/_footer.html.liquid b/app/static/files/[Sandbox] Norm's Academy/_footer.html.liquid new file mode 100644 index 0000000..79a0481 --- /dev/null +++ b/app/static/files/[Sandbox] Norm's Academy/_footer.html.liquid @@ -0,0 +1,80 @@ + diff --git a/app/static/files/[Sandbox] Norm's Academy/_head.html.liquid b/app/static/files/[Sandbox] Norm's Academy/_head.html.liquid new file mode 100644 index 0000000..bde9ff3 --- /dev/null +++ b/app/static/files/[Sandbox] Norm's Academy/_head.html.liquid @@ -0,0 +1,11 @@ +{% styles default %} +{% styles colors %} +{% styles custom %} + + + + + + + + diff --git a/app/static/files/[Sandbox] Norm's Academy/_header.html.liquid b/app/static/files/[Sandbox] Norm's Academy/_header.html.liquid new file mode 100644 index 0000000..56b76c5 --- /dev/null +++ b/app/static/files/[Sandbox] Norm's Academy/_header.html.liquid @@ -0,0 +1,183 @@ +
+
+
+ {% if current_person.signed_in? %} + + + {% endif %} +
+ {% if current_school.logo_url %} +

+ + {{ current_school.name }} + +

+ {% else %} + + {{ current_school.name }} + + {% endif %} + +
+ +
+ + {% if current_person.signed_in? %} + +
+ + +
+ {% else %} +
+ {% endif %} + +
+ +
+
+
+
+ +{% include "messages" %} + diff --git a/app/static/files/[Sandbox] Norm's Academy/_section_faqs.html.liquid b/app/static/files/[Sandbox] Norm's Academy/_section_faqs.html.liquid new file mode 100644 index 0000000..7e6d46f --- /dev/null +++ b/app/static/files/[Sandbox] Norm's Academy/_section_faqs.html.liquid @@ -0,0 +1,109 @@ + +/ + + + \ No newline at end of file diff --git a/app/static/files/[Sandbox] Norm's Academy/_section_instructors.html.liquid b/app/static/files/[Sandbox] Norm's Academy/_section_instructors.html.liquid new file mode 100644 index 0000000..2433e20 --- /dev/null +++ b/app/static/files/[Sandbox] Norm's Academy/_section_instructors.html.liquid @@ -0,0 +1,91 @@ + + + + + \ No newline at end of file diff --git a/app/static/files/[Sandbox] Norm's Academy/catalog.html.liquid b/app/static/files/[Sandbox] Norm's Academy/catalog.html.liquid new file mode 100644 index 0000000..8ce1105 --- /dev/null +++ b/app/static/files/[Sandbox] Norm's Academy/catalog.html.liquid @@ -0,0 +1,39 @@ +{% include "header" %} +{% include "course_version_outdated_alert", courses: courses.in_catalog %} +
+
+
+
+
+ Menlo Security Resrouces +
+
+ Resources to help you make the most of your Security Training +
+
+
+{% include "sub_navigation" %} + {% include "courses_catalog" %} + +{% include "footer" %} + + + + + \ No newline at end of file diff --git a/app/static/files/[Sandbox] Norm's Academy/community.html.liquid b/app/static/files/[Sandbox] Norm's Academy/community.html.liquid new file mode 100644 index 0000000..9157fd7 --- /dev/null +++ b/app/static/files/[Sandbox] Norm's Academy/community.html.liquid @@ -0,0 +1,33 @@ + {% include 'header' %} +
+
+

Explore

+
+ {% include 'sub_navigation' %} +
+ +
+
+{% include 'footer' %} + + + \ No newline at end of file diff --git a/app/templates/cmtest.html b/app/templates/cmtest.html new file mode 100644 index 0000000..4131146 --- /dev/null +++ b/app/templates/cmtest.html @@ -0,0 +1,13 @@ + +{% include 'head.html' %} +{% include 'header.html' %} +{% include 'logo.html' %} +

 

+{% if error %} +

{{ error }}

+{% endif %} + +
+ {{ form.name.label }} {{ form.name(size=20) }} + +
diff --git a/app/templates/head.html b/app/templates/head.html index e54e670..f4f9abd 100644 --- a/app/templates/head.html +++ b/app/templates/head.html @@ -17,8 +17,8 @@ - - + + diff --git a/app/templates/index.html b/app/templates/index.html index 53eb833..8ca25c5 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -11,7 +11,7 @@

- +
diff --git a/app/templates/templates.html b/app/templates/templates.html index 9e0d08d..be0e5cd 100644 --- a/app/templates/templates.html +++ b/app/templates/templates.html @@ -6,6 +6,17 @@ {% if error %}

{{ error }}

{% endif %} + +{% if button %} +
+
+ +
+{% endif %} + {% if templates %}

Here are the liquid templates for

{{ session.school }}

@@ -18,10 +29,9 @@ id="templates" action="{{ url_for('templates')}}" method="post"> -

- {{ templates[0] }} -

- {{ templates[0] }} +

Last Updated: {{ templates [2] }}

+ {{ templates[1] }} - @@ -42,12 +48,6 @@ value="{{ templates[0] }}">

 

-
Click here to load changes

 

{% endfor %} - + +{% endif %} - -