Added functions and grid squares. Good progress! Need to figure out how to get the session key into the javascript file.

This commit is contained in:
Norm Rasmussen
2023-02-21 16:59:41 -05:00
parent 1bcbef6220
commit e81b9e2c14
12 changed files with 328 additions and 269 deletions

View File

@ -1,39 +0,0 @@
{% extends 'head.html' %}
{% block content %}
<body>
<div class="container">
<header class="header">
<div>
<h1>Hello there, <span id="userName">CUSTOMER SUCCESS MANAGER</span>.</h1>
<img src="/static/NP-Logo-Primary-FC.png" alt="Northpass Full Color Logo"></img>
<p>Today is <span id="currentDate">Monday 1, January 2000</span>.</p>
</div>
<p id="currentTime">{{ request.form.apikey }}</p>
</header>
<h4>Hello! Please select what you'd like to do.</h4>
<main id="cardContainer">
<form class="card"
action="{{ url_for('get_courses')}}"
method="post">
<a class="card"
onclick="document.forms[0].submit()"
style="cursor:pointer;">
<i class="ri-plane-line card__icon"></i>
<p class="card__name">Get Fucked</p>
</a>
</form>
<main id="cardContainer">
<form class="card"
action="{{ url_for('get_courses')}}"
method="post">
<a class="card"
onclick="document.forms[0].submit()"
style="cursor:pointer;">
<i class="ri-plane-line card__icon"></i>
<p class="card__name">Get Fucked</p>
</a>
</form>
</main>
</div>
</body>
{% endblock %}

View File

@ -8,61 +8,126 @@ import re
@app.route("/", methods=["GET", "POST"]) @app.route("/", methods=["GET", "POST"])
def ask_key(): def ask_key():
session.clear()
if request.method == "POST": if request.method == "POST":
session['key'] = request.form.get('apikey') session["key"] = request.form.get("apikey")
print(session['key']) if re.search("\s", session["key"]):
flash(session['key']) error = "Hm. That doesn't seem right"
if re.search(r'(\S+\w+)', session['key']) and len(session['key']) > 5: return render_template("index.html", title="Home", error=error)
print("regex worked") elif session["key"] is not None and len(session["key"]) > 10:
print(len(session['key'])) return render_template("options.html", title="Options")
return render_template("get.html", title="Options")
else: else:
error = "Hm. That doesn't seem right" error = "Hm. That doesn't seem right"
return render_template("index.html", title="Home", error=error) return render_template("index.html", title="Home", error=error)
else: else:
return render_template("index.html", title="Home") return render_template("index.html", title="Home")
@app.route("/", methods=["GET", "POST"])
def render_home():
return render_template("index.html", title="Home")
@app.route("/get_courses", methods=["GET", "POST"]) @app.route("/get_courses", methods=["GET", "POST"])
def get_courses(): def get_courses():
array = [] array = []
df = pd.DataFrame() df = pd.DataFrame()
tempdf = pd.DataFrame()
pd.set_option("display.max_colwidth", 100)
x = 0
if request.method == "POST": if request.method == "POST":
url = "https://api.northpass.com/v2/courses" while True:
headers = {"accept": "application/json", "X-Api-Key": session['key']} x += 1
response = requests.get(url, headers=headers) url = f"https://api.northpass.com/v2/courses?page={x}"
jsonresponse = response.json() headers = {"accept": "application/json", "X-Api-Key": session["key"]}
dt = jsonresponse["data"] response = requests.get(url, headers=headers)
for course in dt: jsonresponse = response.json()
df = df.append(course["attributes"], ignore_index=True) dt = jsonresponse["data"]
next = jsonresponse["links"]
for course in dt:
df = df.append(course["attributes"], ignore_index=True)
df = df.drop("list_image_url", axis=1)
if "next" not in next:
break
dfhtml = df.to_html(col_space=5)
session["dfcsv"] = df.to_csv()
return render_template("table.html", tables=dfhtml, titles="Course List")
else: else:
return "This isn't working. Let's go our own way." return "This isn't working. Let's go our own way."
print(df)
download = make_response(df.to_csv())
download.headers["Content-Disposition"] = "attachment; filename=export.csv" @app.route("/table")
download.headers["Content-Type"] = "text/csv" def table():
return download return render_template("table.html", tables=[session["dfhtml"]], titles=["Table"])
@app.route("/downloadcsv", methods=["GET", "POST"])
def download_csv():
if request.method == "GET":
download = make_response(session["dfcsv"])
download.headers["Content-Disposition"] = "attachment; filename=export.csv"
download.headers["Content-Type"] = "text/csv"
return download
@app.route("/get_people", methods=["GET", "POST"]) @app.route("/get_people", methods=["GET", "POST"])
def get_people(): def get_people():
print(session['key']) array = []
df = pd.DataFrame()
x = 0
if request.method == "POST": if request.method == "POST":
url = "https://api.northpass.com/v2/people" while True:
headers = {"accept": "application/json", "X-Api-Key": session['key']} x += 1
response = requests.get(url, headers=headers) url = f"https://api.northpass.com/v2/people?page={x}"
jsonresponse = response.json() headers = {"accept": "application/json", "X-Api-Key": session["key"]}
dt = jsonresponse response = requests.get(url, headers=headers)
person = dt jsonresponse = response.json()
print(person) dt = jsonresponse["data"]
return person next = jsonresponse["links"]
for person in dt:
print(person)
df = df.append(person["attributes"], ignore_index=True)
if "next" not in next:
break
dfppl = df.to_html(col_space=5)
session["dfcsv"] = df.to_csv()
return render_template("table.html", tables=dfppl, titles="People List")
else: else:
return "what what" return "what what"
@app.route("/startpage", methods=["GET", "POST"]) @app.route("/add_options")
def startpage(): def add_options():
return render_template("startpage.html", title="StartTest") return render_template("bulk_add.html", title="Bulk Add Learners")
@app.route("/bulk_add", methods=["GET", "POST"])
def bulk_add():
if request.method == "POST":
emails = request.form.get("emails")
groups = request.form.get("groups")
url = "https://api.northpass.com/v2/bulk/people"
payload = {
"data": {"attributes": {"people": [{"email": emails, "groups": groups}]}}
}
headers = {
"accept": "application/json",
"content-type": "application/json",
"X-Api-Key": session["key"],
}
app.secret_key = "@&I\x1a?\xce\x94\xbb0w\x17\xbf&Y\xa2\xc2(A\xf5\xf2\x97\xba\xeb\xfa" app.secret_key = "@&I\x1a?\xce\x94\xbb0w\x17\xbf&Y\xa2\xc2(A\xf5\xf2\x97\xba\xeb\xfa"

View File

@ -1,143 +0,0 @@
/*****************/
/* EDITABLE INFO */
/*****************/
/* -------------------------------------------------------- */
const NAME = "Norm";
const CARDS = [
{
name: "Get all Users",
icon: "ri-admin-line",
link: "submit",
},
{
name: "Get all Courses",
icon: "ri-mail-line",
link: "submit",
},
{
name: "Get all Assignments",
icon: "ri-calendar-line",
link: "submit",
},
];
/* -------------------------------------------------------- */
/******************/
/* CLOCK FUNCTION */
/******************/
const DAYS = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
const MONTHS = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
const updateDate = () => {
// Create a new Date object and get the complete Date/Time information
const completeDate = new Date();
// Time Variables
let currentHour = formatDigit(completeDate.getHours());
let currentMinute = formatDigit(completeDate.getMinutes());
// Date Variables
let currentDay = completeDate.getDay();
let currentNumber = completeDate.getDate();
let currentMonth = completeDate.getMonth();
let currentYear = completeDate.getFullYear();
// Update the Time
currentTime.innerHTML = `${
currentHour % 12 == 0 ? "12" : currentHour % 12
}:${currentMinute} ${currentHour > 11 ? "PM" : "AM"}`;
// Update the Date
currentDate.innerHTML = `${DAYS[currentDay]} ${currentNumber}, ${MONTHS[currentMonth]} ${currentYear}`;
// Create a Loop
setTimeout(() => {
updateDate();
}, 1000);
};
const formatDigit = (digit) => {
return digit > 9 ? `${digit}` : `0${digit}`;
};
/******************/
/* CARDS FUNCTION */
/******************/
const printCards = () => {
for (const card of CARDS) {
let currentCard = document.createElement("a");
let currentCardText = document.createElement("p");
currentCardText.appendChild(document.createTextNode(card.name));
let currentCardIcon = document.createElement("i");
currentCardIcon.classList.add(card.icon);
// Style the Card Element
currentCard.classList.add("card");
currentCard.href = card.link;
// Handle the click event
currentCard.addEventListener("click", async (event) => {
//document.forms["apiform"].submit();
// Copy the href to the clipboard
try {
await navigator.clipboard.writeText(card.link);
currentCard.blur();
currentCardText.innerText = "Saved to clipboard!";
setTimeout(() => {
currentCardText.innerText = card.name;
}, 1500);
} catch {
currentCardText.innerText = "Unable to copy";
setTimeout(() => {
currentCardText.innerText = card.name;
}, 1500);
}
});
// Style the Icon
currentCardIcon.classList.add("card__icon");
// Style the Text
currentCardText.classList.add("card__name");
currentCard.append(currentCardIcon);
currentCard.append(currentCardText);
cardContainer.appendChild(currentCard);
}
};
/****************/
/* STARTER CODE */
/****************/
userName.innerHTML = NAME;
printCards();
updateDate();

View File

@ -2,10 +2,12 @@
/* Custom Variables | Color Scheme */ /* Custom Variables | Color Scheme */
:root { :root {
--primary: #fff; --primary: #66C92D;
--text-light: #E5E9F0; --text-light: #FFFFFF;
--background: #3B4252; --text-dark: #667E8A;
--background-light: #4C566A; --background: #667E8A;
--background-light: #E5E9EB;
height: 100%;
} }
*, *,
@ -17,21 +19,17 @@
} }
body { body {
margin-bottom: 0; /*background: linear-gradient(
flex-grow: 1;
background: linear-gradient(
145deg, #81A1C1, #88C0D0, #8FBCBB, #A3BE8C, #EBCB8B, #D08770 145deg, #81A1C1, #88C0D0, #8FBCBB, #A3BE8C, #EBCB8B, #D08770
); );
background-size: 700% 550%; background-size: 700% 550%;
animation: gradient 7s ease-in-out infinite; animation: gradient 7s ease-in-out infinite;*/
height: 125vh; color: var(--text-dark);
margin-top: -100px;
padding-top: 100px;
color: var(--text-light);
font-family: 'Space Grotesk', sans-serif; font-family: 'Space Grotesk', sans-serif;
padding: 2rem 4rem; background-color: var(--background-light);
background-color: var(--background);
box-sizing: border-box; box-sizing: border-box;
text-align: center;
width: 100%;
} }
@keyframes gradient { @keyframes gradient {
@ -46,6 +44,42 @@ body {
} }
} }
html {
display: flex;
justify-content: center;
}
input,
select {
width: 200px;
height: 25px;
margin: 2px;
--moz-box-sizing: border-box;
--webkit-box-sizing: border-box;
box-sizing: border-box;
}
.dataframe {
font-size: 11pt;
border-collapse: collapse;
border: 1px solid #66C92D;
width: 100%;
text-align: left !important;
}
.dataframe td, th {
padding: 5px;
}
.dataframe tr:nth-child(even) {
background: #193D4F;
}
.dataframe tr:hover {
background: #096F8E;
cursor: pointer;
}
h1 { h1 {
font-size: 4rem; font-size: 4rem;
font-weight: bold; font-weight: bold;
@ -61,13 +95,11 @@ h4 {
} }
img { img {
height: 50px; height: 80px;
width 500px;
align-items: flex-start;
} }
main { main {
margin: 4px; margin: 4px;
display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
} }
@ -75,9 +107,7 @@ main {
.header { .header {
font-weight: 200; font-weight: 200;
margin-top: 80px; margin-top: 80px;
display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center;
} }
#currentDate { #currentDate {
@ -91,7 +121,7 @@ main {
@media screen and (max-width: 1250px) { @media screen and (max-width: 1250px) {
h1 { h1 {
display: none; display: flex;
} }
.header { .header {
@ -107,7 +137,26 @@ main {
text-align: center; text-align: center;
} }
} }
ul {
display: flex;
}
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 100px;
grid-gap: 2rem;
padding: 20px;
}
.card {
background-color: #089FB7;
padding: 5px;
border-radius: 10px;
border: 1px solid #66C92D;
color: #FFFFFF;
}
/*
.card:link, .card:link,
.card:visited { .card:visited {
color: white; color: white;
@ -117,8 +166,6 @@ main {
padding: 4rem 8rem; padding: 4rem 8rem;
background-color: var(--background-light); background-color: var(--background-light);
border-radius: 15px;
border: 1px solid #B48EAD;
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -130,13 +177,10 @@ main {
outline: none; outline: none;
transition: 0.1s; transition: 0.1s;
} }*/
.card:hover, .card:hover,
.card:focus { .card:focus {
border-color: var(--primary);
color: var(--primary);
transform: scale(1.02); transform: scale(1.02);
} }
@ -151,17 +195,13 @@ main {
.card__icon { .card__icon {
font-size: 2rem; font-size: 2rem;
padding: 1rem; padding: 1rem;
background-color: #81A1C1;
border-radius: 50%;
display: grid; display: grid;
place-items: center;
} }
.card__name { .card__name {
font-weight: 400; font-weight: 400;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
position: absolute; position: relative;
bottom: -25%;
left: 50%; left: 50%;
transition: 0.1s; transition: 0.1s;
} }

View File

@ -0,0 +1,40 @@
document.addEventListener("DOMContentLoaded", function() {
getAllGroups();
});
const apiKey = 'session["key"]';
const groups= [];
const getAllGroups = async (num) => {
if(num === 1){
}
let page = num;
await axios({
method: 'get',
url: `https://api.northpass.com/v2/groups?page=${page}`,
headers: {
'accept': '*/*',
'x-api-key': apiKey,
'content-type': 'application/json'
}
})
.then(async (res) => {
if (res.data.links.next != null) {
page++;
for (let i = 0; i < res.data.data.length; i++) {
let groupName = res.data.data[i].attributes.name;
selectInput = '<option value='+ groupName +'>'+ groupName+'</option>';
$('#groups').append(selectInput);
groups.push(res.data.data[i].attributes.name);
}
await getAllGroups(page);
} else {
for (let i = 0; i < res.data.data.length; i++) {
groups.push(res.data.data[i].attributes.name);
}
}
})
.catch(err => {
console.log(err);
})
}

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
{% extends 'head.html' %}
{% block content %}
<h4>Hello! Please enter the emails below.</h4>
{% if error %}
<p class=error><strong> </strong>{{ error }}
{% endif %}
<p><label for="Bulk Add"> Please select the appropriate options below.</label></p>
<form action="{{ url_for("bulk_add")}}" method="post">
<p>Please Copy and Paste Emails of learners you'd like to add</p>
<textarea id="emails" name="emails" rows="4" cols="50"></textarea>
<p>Please select which Groups these learners should be added to. </p>
<select name="groups" id="groups" multiple>
<option></option>
<input type="submit" value="Submit"></select>
</form>
</div>
</div>
</body>
<script src="{{ url_for('static', filename='getallgroups.js')}}"></script>
{% endblock %}

View File

@ -1,21 +1,13 @@
<!DOCTYPE html>
{% extends 'head.html' %} {% extends 'head.html' %}
{% block content %} {% block content %}
<body>
<div class="container">
<header class="header">
<div>
<h1>Hello there, <span id="userName">CUSTOMER SUCCESS MANAGER</span>.</h1>
<img src="/static/NP-Logo-Primary-FC.png" alt="Northpass Full Color Logo"></img>
<p>Today is <span id="currentDate">Monday 1, January 2000</span>.</p>
</div>
<p id="currentTime">{{ request.form.apikey }}</p>
</header>
<h4>Hello! Please select what you'd like to do.</h4> <h4>Hello! Please select what you'd like to do.</h4>
<main id="cardContainer"> </div>
<div class="card-grid">
<form class="card" <form class="card"
action="{{ url_for('get_people')}}" action="{{ url_for('get_people')}}"
method="post"> method="post">
<a class="card" <a class="a-card"
onclick="document.forms[0].submit()" onclick="document.forms[0].submit()"
style="cursor:pointer;"> style="cursor:pointer;">
<i class="ri-car-line card__icon"></i> <i class="ri-car-line card__icon"></i>
@ -23,19 +15,29 @@
</a> </a>
</form> </form>
<main id="cardContainer">
<form class="card" <form class="card"
id="get_courses" id="get_courses"
action="{{ url_for('get_courses')}}" action="{{ url_for('get_courses')}}"
method="post"> method="post">
<a class="card" <a class="a-card"
onclick="document.forms['get_courses'].submit()" onclick="document.forms['get_courses'].submit()"
style="cursor:pointer;"> style="cursor:pointer;">
<i class="ri-plane-line card__icon"></i> <i class="ri-plane-line card__icon"></i>
<p class="card__name">Get Courses</p> <p class="card__name">Get Courses</p>
</a> </a>
</form> </form>
</main>
<div class="card"
href = "/add"
>
<a class="a-card"
onclick="document.forms['bulk_add'].submit()"
style="cursor:pointer;">
<i class="ri-plane-line card__icon"></i>
<p class="card__name">Get Courses</p>
</a>
</div> </div>
</body> </body>
{% endblock %} {% endblock %}

View File

@ -9,12 +9,30 @@
rel="stylesheet" rel="stylesheet"
/> />
<title>CSM Bulk Actions</title> <title>CSM Bulk App</title>
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap" <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap"
rel="stylesheet"> rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename="css/styles.css") }}" /> <link rel="stylesheet" href="{{ url_for('static', filename="css/styles.css") }}" />
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head> </head>
<body>
<div class="three-verts">
<div class="container">
<header class="header">
<div class="main">
<a href="{{ url_for('render_home')}}">
<img
src="{{ url_for('static', filename="NP-Logo-Primary-FC.png") }}"
alt="Northpass Full Color Logo"
>
</img></a>
</header>
</div>
{% for message in get_flashed_messages() %}
<h2> {{ message }} </h2>
{% endfor %}
{% block content %} {% endblock %} {% block content %} {% endblock %}
</html> </html>

View File

@ -1,20 +1,15 @@
<!DOCTYPE html>
{% extends 'head.html' %} {% extends 'head.html' %}
{% block content %} {% block content %}
<body>
<div class="container">
<header class="header">
<div>
<h1>Hello there, CUSTOMER SUCCESS MANAGER.</h1>
<img src="/static/NP-Logo-Primary-FC.png" alt="Northpass Full Color Logo"></img>
</header>
<h4>Hello! Please click below to enter your key.</h4> <h4>Hello! Please click below to enter your key.</h4>
{% if error %} {% if error %}
<p class=error><strong>Error! </strong>{{ error }} <p class=error><strong> </strong>{{ error }}
{% endif %} {% endif %}
<form action="{{ url_for("ask_key")}}" method="post"> <form action="{{ url_for("ask_key")}}" method="post">
<input type="text" name="apikey"> <input type="text" name="apikey">
<input type="submit" value="Submit"> <input type="submit" value="Submit">
</form> </form>
</div> </div>
</div>
</body> </body>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
{% extends 'head.html' %}
{% block content %}
<h4>Hello! Please select what you'd like to do.</h4>
</div>
<div class="card-grid">
<form class="card"
action="{{ url_for('get_people')}}"
method="post">
<a class="a-card"
onclick="document.forms[0].submit()"
style="cursor:pointer;">
<i class="ri-car-line card__icon"></i>
<p class="card__name">Get People</p>
</a>
</form>
<form class="card"
id="get_courses"
action="{{ url_for('get_courses')}}"
method="post">
<a class="a-card"
onclick="document.forms['get_courses'].submit()"
style="cursor:pointer;">
<i class="ri-plane-line card__icon"></i>
<p class="card__name">Get Courses</p>
</a>
</form>
<div class="card" >
<a class="a-card" href="{{ url_for('add_options')}}"
style="cursor:pointer; color: inherit; text-decoration: none">
<i class="ri-building-line card__icon"></i>
<p class="card__name">Bulk Add</p>
</a>
</div>
</body>
{% endblock %}

17
app/templates/table.html Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
{% extends 'head.html' %}
{% block content %}
<h4>Hello! Here are your results.</h4>
<a id="download" href="/downloadcsv">Click here to download as CSV.</a>
</div>
<div class="panda-table">
<!-- Display Converted Table -->
{% for table in tables %}
<h2> {{ titles }}</h2>
{{ table | safe }}
{% endfor %}
</div>
</div>
</body>
{% endblock %}