Clear session now deletes all the templates. Added socketio disconnect function too. Need to remove special characters from filepath since glob can't recognize.

This commit is contained in:
Norm Rasmussen
2023-03-16 17:36:10 -04:00
parent dae2eb440e
commit 44259a8c51
16 changed files with 55 additions and 656 deletions

View File

@ -1,8 +1,13 @@
import requests import requests
import shutil
import itertools import itertools
import re import re
import os import os
import csv import csv
import glob
import pathlib
from flask_socketio import SocketIO
from datetime import datetime, timezone
from .forms import TemplateForm from .forms import TemplateForm
from functools import wraps from functools import wraps
from flask import ( from flask import (
@ -19,12 +24,15 @@ from werkzeug.utils import secure_filename
from app import app, forms from app import app, forms
# Upload folder # Upload folder
UPLOAD_FOLDER = "/Users/normrasmussen/Documents/Projects/CSM_webapp/app/static/files" UPLOAD_FOLDER = "/Users/normrasmussen/Documents/Projects/CSM_webapp/app/static/files/csv"
# UPLOAD_FOLDER = 'static/files' TEMPLATES_FOLDER = "/Users/normrasmussen/Documents/Projects/CSM_webapp/app/static/files/templates/"
app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER
app.config["TEMPLATES_FOLDER"] = TEMPLATES_FOLDER
ALLOWED_EXTENSIONS = {"csv"} ALLOWED_EXTENSIONS = {"csv"}
# Global Variables # Global Variables
socketio = SocketIO(app)
specials = '"!@#$%^&[]*()-+?_=,<>/"'
url = "https://api.northpass.com/" url = "https://api.northpass.com/"
@ -72,7 +80,6 @@ def ask_key():
Without this key, no other functions will work. Without this key, no other functions will work.
It also assigns the api key to the session and clears the session upon each reload. It also assigns the api key to the session and clears the session upon each reload.
""" """
specials = '"!@#$%^&*()-+?_=,<>/"'
if request.method == "POST": if request.method == "POST":
session["key"] = request.form.get("apikey") session["key"] = request.form.get("apikey")
if any(char in specials for char in session["key"]) or re.search( if any(char in specials for char in session["key"]) or re.search(
@ -104,6 +111,19 @@ def render_home():
@app.route("/clear_session", methods=["GET", "POST"]) @app.route("/clear_session", methods=["GET", "POST"])
def clear_session(): def clear_session():
if session.get("key"): if session.get("key"):
if session.get("client_path"):
client = session["client_path"]
print(client)
wildcard = glob.glob(client + '_*')
print(wildcard)
for directory in wildcard:
print(directory)
try:
shutil.rmtree(directory)
print(directory)
except OSError:
print(OSError)
print("Error?")
session.clear() session.clear()
error = "Session Cleared!" error = "Session Cleared!"
return render_template("index.html", error=error, title="Home, New session") return render_template("index.html", error=error, title="Home, New session")
@ -118,7 +138,6 @@ def table():
@app.route("/upload_file", methods=["GET", "POST"]) @app.route("/upload_file", methods=["GET", "POST"])
@key_required @key_required
def upload_file(): def upload_file():
print("Uploading CSV")
if request.method == "POST": if request.method == "POST":
if "file" not in request.files: if "file" not in request.files:
flash("No file found or uploaded") flash("No file found or uploaded")
@ -312,6 +331,8 @@ def load_templates():
nextlink = data["links"] nextlink = data["links"]
for response in data["data"]: for response in data["data"]:
last_updated = response["attributes"]["updated_at"].split("T") last_updated = response["attributes"]["updated_at"].split("T")
full_updated = response["attributes"]["updated_at"]
g.full_updated = datetime.fromisoformat(full_updated)
last_updated = last_updated[0] last_updated = last_updated[0]
name, body, last_updated = ( name, body, last_updated = (
response["attributes"]["name"], response["attributes"]["name"],
@ -340,7 +361,6 @@ def templates():
if request.form["submit-template"]: if request.form["submit-template"]:
name = request.form.get("template_name") name = request.form.get("template_name")
body = request.form.get("body") body = request.form.get("body")
g.last_template = name
if body == "": if body == "":
error = ( error = (
"Ooph. Looks like you didn't load the changes before submitting." "Ooph. Looks like you didn't load the changes before submitting."
@ -355,15 +375,18 @@ def templates():
} }
payload = {"custom_template": {"name": name, "body": body}} payload = {"custom_template": {"name": name, "body": body}}
response = requests.post(url + endpoint, json=payload, headers=headers) response = requests.post(url + endpoint, json=payload, headers=headers)
return check_templates(response) return check_templates(response, name)
return load_templates() return load_templates()
def check_templates(response): def check_templates(response, name):
print(response)
response = str(response) response = str(response)
if "201" in response: if "201" in response:
error = "Success! Templates Uploaded." error = (
f"Success! The {name} template was successfully uploaded for "
+ session["school"]
+ "."
)
button = "Undo" button = "Undo"
return render_template( return render_template(
"templates.html", title="Templates Added", error=error, button=button "templates.html", title="Templates Added", error=error, button=button
@ -380,16 +403,25 @@ def check_templates(response):
def save_templates_backup(templates): def save_templates_backup(templates):
g.client_path = os.path.join(UPLOAD_FOLDER, session["school"]) session["client_path"] = os.path.join(TEMPLATES_FOLDER, session["school"])
if os.path.exists(g.client_path): if any(char in specials for char in session["client_path"]):
for char in specials:
session["sanitized_path"] = session["client_path"].replace(char,"")
print(session["sanitized_path"])
else:
session["sanitized_path"] = session["client_path"]
print(session["client_path"])
today = datetime.now(timezone.utc)
if os.path.exists(session["client_path"]):
pass pass
else: else:
os.mkdir(g.client_path) path = session["client_path"] + "_" + str(today)
os.mkdir(path)
for tupe in templates: for tupe in templates:
file_name = tupe[0] + ".liquid" file_name = tupe[0] + ".liquid"
file_body = tupe[1] file_body = tupe[1]
complete_path = os.path.join(g.client_path, file_name) complete_path = os.path.join(path, file_name)
with open(complete_path, "w+") as temp: with open(complete_path, "w+") as temp:
temp.write(file_body) temp.write(file_body)
@ -399,12 +431,18 @@ def save_templates_backup(templates):
@app.route("/undo_template", methods=["POST"]) @app.route("/undo_template", methods=["POST"])
@key_required @key_required
def undo_template(): def undo_template():
print(g.client_path)
template_path = os.path.join(g.client_path, g.last_template)
if request.method == "POST": if request.method == "POST":
if request.form["undo_templates"]: if request.form["undo_templates"]:
if os.path.exists(template_path): pass
print(template_path)
@socketio.on("disconnect")
def test_disconnect():
print("Client disconnected")
@socketio.on("connect")
def test_connect():
print("connection established")
@app.route("/cmtest", methods=["GET", "POST"]) @app.route("/cmtest", methods=["GET", "POST"])

View File

@ -1,49 +0,0 @@
<a class="np-card" href="{% route course_enrollment, code: course.enrollment_code %}">
<div class="np-card-container">
{% if course.ribbon %}
<div class="np-card-ribbon">
{{ course.ribbon }}
</div>
{% endif %}
<video class='left-video' autoplay muted loop>
<source src="{{course.promo_video_embed_url}}" type="video/mp4" alt="{{ course.name }}">
</video>
<div class="np-card-content-bottom">
<h3 class="np-card-content-title np-color-white">
{{ course.name }}
</h3>
<div class='np-card-content-description'>
{{ course.full_description }}
</div>
<div class="np-card-content-progress np-button-color">
{% t shared.progress, count: course.progress %}
</div>
<div class="np-card-content-category">
{{course.categories.first.name}}
</div>
</div>
</div>
</a>
<style>
.np-card {
text-decoration: none;
color: white;
}
.np-card-content-category {
border-top: 1px solid lightgray;
padding: 10px;
}
.np-card-content-description {
display: block;
color: lightgray;
}
.np-card-content-bottom {
padding: 15px;
}
.np-button-color {
color: lightslategray;
font-size: 15px;
padding-bottom: 10px;
}
</style>

View File

@ -1,44 +0,0 @@
<div class="np-card np-no-horizontal-padding">
<div class="np-card-container">
<div class="np-learning-path np-featured-course">
<div class="np-featured-course-img-container" style="overflow: hidden">
<video class='featured-video' autoplay muted loop style="margin-left: -60px;">
<source id="featured_video" src="{{course.promo_video_embed_url}}" type="video/mp4" alt="{{ course.name }}" />
</video>
<div class="np-card-image-content-top">
</div>
</div>
<div class="np-card-text-wrapper">
<div class="np-card-content np-card-padding np-card-content-vertical">
<h3 class="np-card-content-title">
{{ course.name }}
</h3>
<div class="np-card-content-description">
{{ course.full_description }}
</div>
<div class="np-card-content-footer" style='display: flex; flex-direction: row; justify-content: space-between;'>
<a
class="np-top-button np-button-font-color np-button" href="{% route course_enrollment, code: course.enrollment_code %}"
>
{% if course.enrolled? == false %}
{% t shared.enroll %}
{% elsif course.started? == false %}
{% t shared.start, key: current_school.course_vocabulary %}
{% elsif course.completed? %}
{% t shared.course.view, key: current_school.course_vocabulary %}
{% else %}
{% t shared.continue %}
{% endif %}
</a>
<div class="np-card-image-content-bottom" style="position: unset;">
<div class="np-card-content-progress np-button-color">
{% t shared.progress, count: course.progress %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,80 +0,0 @@
<footer class="np-footer">
<div class="np-footer-top">
{% if website_footer.show_navigation_links? %}
<div class="np-footer-navigation">
<ul class="np-footer-navigation-list">
{% for website_navigation in navigations.footer_navigations %}
{% if website_navigation.external? %}
<li class="np-footer-navigation-item">
<a
class="np-footer-navigation-link np-button-color"
href="{{ website_navigation.path }}"
{% if website_navigation.external? %} target="_blank" {% endif %}
>
{{ website_navigation.name }}
</a>
</li>
{% endif %}
{% endfor %}
</ul>
</div>
{% endif %}
{% if current_school.logo_url %}
<h2 class="np-footer-logo">
<a href="{% route home %}">
<img
alt="{{ current_school.name }}"
class="np-footer-logo-image"
src="{{ current_school.logo_url }}"
/>
</a>
</h2>
{% else %}
<div class="np-school-name np-header-font-color">
{{ current_school.name }}
</div>
{% endif %}
</div>
<div class="np-footer-bottom">
<nav class="np-footer-social-links">
{% if website_footer.show_social_media_links? %}
<ul class="np-footer-social-links-list">
{% for social_media_link in website_footer.social_media_links %}
<li class="np-footer-social-links-item">
<a
class="np-footer-social-links-link np-button-color"
href="{{ social_media_link.link }}"
target="_blank" title="{{ social_media_link.name }}"
>
<i class="np-footer-social-links-icon
np-button-color
fab fa-{{ social_media_link.name }}"
></i>
</a>
</li>
{% endfor %}
</ul>
{% endif %}
</nav>
{% if website_footer.show_customer_service_email? and
website_footer.school_customer_service_email
%}
<div class="np-footer-support">
<div class="np-footer-support-item np-footer-support-help np-fc-white np-opacity-50">
{% t .need_help %}
</div>
<div class="np-footer-support-item np-footer-support-email np-fc-white np-opacity-50">
{% t .email %}
</div>
<a
class="np-footer-support-item np-footer-support-link np-button-color"
href="mailto:{{ website_footer.school_customer_service_email }}"
>
support@menlosecurity.com
</a>
</div>
{% endif %}
</div>
</footer>

View File

@ -1,11 +0,0 @@
{% styles default %}
{% styles colors %}
{% styles custom %}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Raleway:wght@200;300;400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.css" integrity="sha512-wR4oNhLBHf7smjy0K4oqzdWumd+r5/+6QO/vDda76MW5iug4PT7v86FoEkySIJft3XA0Ae6axhIvHrqwm793Nw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.js" type="text/javascript"></script>

View File

@ -1,183 +0,0 @@
<header class="np-header np-header-color" >
<div class="np-header-content">
<div class="np-hidden-desktop np-header-mobile-menu-nav">
{% if current_person.signed_in? %}
<button
data-toggle-class="np-hidden"
class="np-header-mobile-menu-nav-button fal fa-times np-hidden np-header-font-color"
data-toggle-target=".np-header-mobile-avatar-menu,
.np-header-mobile-menu-content, .np-main, .np-footer"
></button>
<button
data-test="open-mobile-menu"
data-toggle-class="np-hidden"
class="np-header-mobile-menu-nav-button np-header-mobile-avatar-menu"
data-toggle-target=".fa-times, .np-header-mobile-menu-content, .np-main, .np-footer"
>
<img
alt="{{ current_person.name }}"
class="np-header-avatar-image"
src="{{ current_person.avatar_url }}"
/>
</button>
{% endif %}
</div>
{% if current_school.logo_url %}
<h1 class="np-header-logo">
<a href="{% route home %}">
<img
alt="{{ current_school.name }}"
class="np-header-logo-image"
src="{{ current_school.logo_url }}"
/>
</a>
</h1>
{% else %}
<a href="{% route home %}" class="np-school-name np-header-font-color">
{{ current_school.name }}
</a>
{% endif %}
<div class="np-hidden-mobile np-header-desktop-nav">
<ul class="np-header-desktop-nav-list">
{% for website_navigation in navigations.header_navigations_external %}
<li class= "np-header-desktop-nav-item">
<a
href="{{ website_navigation.path }}"
class="np-header-desktop-nav-link np-header-font-color"
target="_blank"
>
{{ website_navigation.name }}
</a>
</li>
{% endfor %}
</ul>
</div>
{% if current_person.signed_in? %}
<div class="np-hidden-mobile np-header-search np-header-search-expanded">
<form action="{% route search %}" method="get" data-test="desktop-search">
<input
aria-label="{% t .search %}"
class="np-header-search-input np-header-font-background-color"
type="text"
name="q"
placeholder="{% t .search %}"
/>
<i class="np-header-search-icon far fa-search"></i>
</form>
</div>
<div class="np-hidden-mobile np-header-avatar">
<button
class="np-header-avatar-button"
data-test="open-desktop-menu"
data-toggle-class-on-target="np-hidden"
data-toggle-target=".np-header-avatar-tooltip"
data-toggle-outside
>
<img
alt="{{ current_person.name }}"
class="np-header-avatar-image"
src="{{ current_person.avatar_url }}"
>
</button>
<div class="np-header-avatar-tooltip np-hidden" role="tooltip">
<span class="np-header-avatar-tooltip-arrow-up"></span>
<div class="np-header-avatar-tooltip-learner">
<div class="np-header-avatar-tooltip-learner-name">
{{ current_person.name }}
</div>
<div class="np-header-avatar-tooltip-learner-email">
{{ current_person.email }}
</div>
</div>
<nav class="np-header-avatar-tooltip-navigation">
<a class="np-header-avatar-tooltip-navigation-link" onclick="buildURL(window.location.pathname)" style="cursor:pointer">
Default
</a>
{% unless current_school.sso_active? %}
<a
class="np-header-avatar-tooltip-navigation-link"
href="{% route account %}"
>
{% t .profile_settings %}
</a>
{% endunless %}
<a
class="np-header-avatar-tooltip-navigation-link np-danger"
href="{% route logout %}"
>
{% t .sign_out %}
</a>
</nav>
</div>
</div>
{% else %}
<a
class="np-header-sign-in np-header-desktop-nav-link np-header-font-color"
href="{% route login %}"
>
{% t shared.sign_in %}
</div>
{% endif %}
</div>
</header>
<div class="np-hidden-desktop">
<div class="np-header-mobile-menu-content np-hidden">
{% if current_person.signed_in? %}
<img
alt="{{ current_person.name }}"
class="np-header-mobile-menu-content-avatar"
src="{{ current_person.avatar_url }}"
/>
<div class="np-header-mobile-menu-content-name">
{{ current_person.name }}
</div>
{% endif %}
<div class="np-header-mobile-menu-content-nav">
<form
class="np-header-search"
data-test="mobile-search"
method="get"
action="{% route search %}"
>
<input
aria-label="{% t .search %}"
class="np-header-search-input"
type="text"
name="q"
placeholder="{% t .search %}"
/>
<i class="np-header-search-icon far fa-search"></i>
</form>
{% for website_navigation in navigations.header_navigations %}
<a
href="{{ website_navigation.path }}"
class="np-header-mobile-menu-content-button"
{% if website_navigation.external? %} target="_blank" {% endif %}
>
{{ website_navigation.name }}
</a>
{% endfor %}
<div class="np-header-mobile-menu-content-line"></div>
{% unless current_school.sso_active? %}
<a
class="np-header-mobile-menu-content-button"
href="{% route account %}"
>
{% t .profile_settings %}
</a>
{% endunless %}
<a
class="np-header-mobile-menu-content-button np-danger"
href="{% route logout %}"
>
{% t .sign_out %}
</a>
</div>
</div>
</div>
{% include "messages" %}

View File

@ -1,109 +0,0 @@
<div class="np-homepage-featured np-faq np-max-width">
<div class="np-homepage-featured-text">
<div class="np-homepage-headline">
Frequently Asked Questions
</div>
</div>
<div class="row np-faqs">
<div class="col-md-6">
<div class="np-accordion">
<div class="accordion-btn">
<i class="fal fa-plus"></i>
<div class="accordion-title"><strong>Q:</strong> I'm not in shape. Can I still go to a climbing gym?</div>
</div>
<div class="accordion-panel">
<div class="accordion-panel-content">
<p><strong>A:</strong> Absolutely. Climbing is a wonderful full-body and full-mind workout. If you're looking to get in shapre but tired of pumping iron, climbing is a fantastic option.</p>
</div>
</div>
</div>
<div class="np-accordion">
<div class="accordion-btn">
<i class="fal fa-plus"></i>
<div class="accordion-title"><strong>Q:</strong> I'm scared of heights. Should I try climbing?</div>
</div>
<div class="accordion-panel">
<div class="accordion-panel-content">
<p><strong>A:</strong> Many climbers have a fear of heights! However, it goes away when you use your own strength and technique to get to the top of a wall. Start small by climbing in a gym first.</p>
</div>
</div>
</div>
<div class="np-accordion">
<div class="accordion-btn">
<i class="fal fa-plus"></i>
<div class="accordion-title"><strong>Q:</strong> Should I hire someone to belay me at a gym?</div>
</div>
<div class="accordion-panel">
<div class="accordion-panel-content">
<p><strong>A:</strong> You absolutely can as a quick introduction. However, what would be even better is to grab a friend and take a belay class at your local gym.</p>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="np-accordion">
<div class="accordion-btn">
<i class="fal fa-plus"></i>
<div class="accordion-title"><strong>Q:</strong> What is bouldering?</div>
</div>
<div class="accordion-panel">
<div class="accordion-panel-content">
<p><strong>A:</strong> Great question! Bouldering is a form of climbing, done on shorter walls. You use a crash pad under your climb to cushion your fall. Be warned, bouldering is much more powerful and has a steeper learning curve.</p>
</div>
</div>
</div>
<div class="np-accordion">
<div class="accordion-btn">
<i class="fal fa-plus"></i>
<div class="accordion-title"><strong>Q:</strong> What are those people with all that gear hanging from their harness doing?</div>
</div>
<div class="accordion-panel">
<div class="accordion-panel-content">
<p><strong>A:</strong> Chances are you saw a trad climber! Short for traditional climbing, that gear serves as removable protection. When the climbing pair is done with the climb, nothing is left on the rock.</p>
</div>
</div>
</div>
<div class="np-accordion">
<div class="accordion-btn">
<i class="fal fa-plus"></i>
<div class="accordion-title"><strong>Q:</strong> None of my friends are interested in climbing. How can I find partners?</div>
</div>
<div class="accordion-panel">
<div class="accordion-panel-content">
<p><strong>A:</strong>The best way to meet people is to join a gym a start climbing! Climbers are social and you'll start meeting people. You can also use online resources like Mountain Project's Partner Finder.</p>
</div>
</div>
</div>
</div>
</div>
</div>
/
<style>
.fa-plus {
background-image: unset;
background: #0297FA;
}
.fa-minus {
background-image: unset;
background: #0297FA; }
</style>
<script>
let accordions = document.getElementsByClassName("accordion-btn");
for (let i = 0; i < accordions.length; i++) {
accordions[i].addEventListener("click", function() {
this.querySelector('.fal').classList.toggle("fa-plus");
this.querySelector('.fal').classList.toggle("fa-minus");
let panel = this.nextElementSibling;
panel.classList.toggle("panel-open");
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
});
}
</script>

View File

@ -1,91 +0,0 @@
<div class="np-homepage-featured np-homepage-featured-items np-max-width">
<div class="np-homepage-featured-text">
<div class="np-homepage-headline">
Recommended Gear
</div>
</div>
<div class="featured-photography-carousel np-carousel np-carousel-bg-blue" id="featured-photography-carousel">
<div class="np-carousel-card">
<div>
<img src=https://5prq858zcb-flywheel.netdna-ssl.com/wp-content/uploads/2016/12/50823_4WhiteBG-1-600x625.png" alt="Featured Photography" class='customer-carousel-image'/>
<div class="slide-label">Misty Mountain Cadillav Harness</div>
</div>
</div>
<div class="np-carousel-card">
<div>
<img src="https://outdoorgearlab-mvnab3pwrvp3t0.stackpathdns.com/photos/18/97/311203_1848_XXXL.jpg" alt="Featured Photography" class='customer-carousel-image'/>
<div class="slide-label">Gri-Gri Belay Device</div>
</div>
</div>
<div class="np-carousel-card">
<div>
<img src="https://lcdn.sportiva.com/pub/media/catalog/product/8/0/800_yellow_katanalace_1_7_4.jpg" alt="Featured Photography" class='customer-carousel-image'/>
<div class="slide-label">La Sportiva Katana Lace Shoes</div>
</div>
</div>
<div class="np-carousel-card">
<div>
<img src="https://s3.amazonaws.com/static.northpass.com/demos/hsbc-old-logo.png" alt="Featured Photography" class='customer-carousel-image'/>
<div class="slide-label">Metolious Helmet</div>
</div>
</div>
<div class="np-carousel-card">
<div>
<img src="https://s3.amazonaws.com/static.northpass.com/demos/sandia-labs-logo.jpg" alt="Featured Photography" class='customer-carousel-image'/>
<div class="slide-label">Unknown</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$("#featured-photography-carousel").slick({
slidesToShow: 3.5,
prevArrow: '<i class="fal fa-chevron-left"></i>',
nextArrow: '<i class="fal fa-chevron-right"></i>',
infinite: false,
responsive: [
{
breakpoint: 1350,
settings: {
slidesToShow: 2.3,
}
},
{
breakpoint: 1024,
settings: {
slidesToShow: 2,
}
},
{
breakpoint: 768,
settings: {
slidesToShow: 1,
}
}
]
});
});
</script>
<style>
.featured-photography-carousel .fa-chevron-right::before {
right: -6px !important;
}
.customer-carousel-image {
width: 292px;
height: 292px;
object-fit: contain;
}
.featured-photography-carousel .slick-initialized .slick-slide {
margin: 10px 10px;
}
</style>

View File

@ -1,39 +0,0 @@
{% include "header" %}
{% include "course_version_outdated_alert", courses: courses.in_catalog %}
<div class="np-homepage-hero">
<div class="np-homepage-hero-image">
</div>
<div class="np-homepage-hero-content">
<div class="np-homepage-headline np-header-font-color">
Menlo Security Resrouces
</div>
<div class="np-homepage-subheadline np-header-font-color">
Resources to help you make the most of your Security Training
</div>
</div>
</div>
{% include "sub_navigation" %}
{% include "courses_catalog" %}
</main>
{% include "footer" %}
<style>
.np-card-content-description {
height: 100px;
}
.np-card-content-title {
height: 58px;
overflow: clip;
}
</style>
<script>
window.onload = function() {
[].slice.call(document.getElementsByClassName("np-card-content-description")).forEach(function(element) {
if(element.innerText.length > 150){
element.innerText = element.innerText.slice(0,150) + '...'
}
});
}
</script>

View File

@ -1,33 +0,0 @@
{% include 'header' %}
<main class="np-main np-homepage">
<div class="np-homepage-hero">
<h1 class="community-headline">Explore</h1>
</div>
{% include 'sub_navigation' %}
<div class='discussion-container' style="border: 18px solid rgb(0, 0, 0); overflow: hidden; margin-left: 100px; margin-top: 35px; width: 1065px;">
<iframe scrolling="yes" src="https://www.mountainproject.com/" style="border: 0px none; margin-left: 15px auto; height: 1954px; margin-top: -100px; width: 1060px;"></iframe>
</div>
</main>
{% include 'footer' %}
<style>
.discussion-frame {
min-width: 100%;
margin-left: -10px;
display: flex;
justify-content: center;
}
.discussion-container {
display: flex;
justify-content: center;
}
.community-headline {
font-size: 32px;
line-height: 48px;
font-family: "Raleway", "Helvetic", "Arial" sans-serif;
color: #ffffff;
}
</style>