Finished the manual upload and now working on CSV
This commit is contained in:
Binary file not shown.
291
app/routes.py
291
app/routes.py
@ -3,7 +3,7 @@ import itertools
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import glob
|
import csv
|
||||||
from app import app
|
from app import app
|
||||||
from flask import (
|
from flask import (
|
||||||
redirect,
|
redirect,
|
||||||
@ -59,6 +59,7 @@ def correct_key(response):
|
|||||||
def allowed_file(filename):
|
def allowed_file(filename):
|
||||||
return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS
|
return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS
|
||||||
|
|
||||||
|
|
||||||
@app.route("/dev", methods=["GET", "POST"])
|
@app.route("/dev", methods=["GET", "POST"])
|
||||||
def dev_test():
|
def dev_test():
|
||||||
return render_template("options.html", title="Dev Test")
|
return render_template("options.html", title="Dev Test")
|
||||||
@ -106,6 +107,10 @@ def clear_session():
|
|||||||
return render_template("index.html", title="Home, New session")
|
return render_template("index.html", title="Home, New session")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/table")
|
||||||
|
def table():
|
||||||
|
return render_template("table.html", tables=[session["dfhtml"]], titles=["Table"])
|
||||||
|
|
||||||
"""
|
"""
|
||||||
uploaded_file = request.files['file']
|
uploaded_file = request.files['file']
|
||||||
if uploaded_file.filename != '':
|
if uploaded_file.filename != '':
|
||||||
@ -114,44 +119,99 @@ uploaded_file.save(uploaded_file.filename)
|
|||||||
return render_template("options.html", title="Home, Now with CSV!")
|
return render_template("options.html", title="Home, Now with CSV!")
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@app.route("/upload_file", methods=["GET", "POST"])
|
||||||
@app.route("/csv", methods=["GET", "POST"])
|
@app.route("/bulk_add", methods=["GET", "POST"])
|
||||||
def csv():
|
def upload_file():
|
||||||
print("Uploading CSV")
|
print("Uploading CSV")
|
||||||
csvData = pd.DataFrame()
|
csvData = pd.DataFrame()
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
if "file" not in request.files:
|
if "file" not in request.files:
|
||||||
print("file not in request.files")
|
|
||||||
flash("No file found or uploaded")
|
flash("No file found or uploaded")
|
||||||
return redirect(request.url)
|
return redirect(url_for("bulk_add_opts"))
|
||||||
file = request.files["file"]
|
file = request.files["file"]
|
||||||
if file.filename == "":
|
if file.filename == "":
|
||||||
print("no file exists")
|
print("no file exists")
|
||||||
flash("No file found or uploaded")
|
flash("No file found or uploaded")
|
||||||
return redirect(request.url)
|
return redirect(url_for("bulk_add_opts"))
|
||||||
|
# return redirect(request.url)
|
||||||
if file and allowed_file(file.filename):
|
if file and allowed_file(file.filename):
|
||||||
filename = secure_filename(file.filename)
|
filename = secure_filename(file.filename)
|
||||||
session["file"] = filename
|
session["file"] = filename
|
||||||
file_path = os.path.join(app.config["UPLOAD_FOLDER"], filename)
|
file_path = os.path.join(app.config["UPLOAD_FOLDER"], filename)
|
||||||
session["filepath"] = file_path
|
session["filepath"] = file_path
|
||||||
file.save(file_path)
|
file.save(file_path)
|
||||||
csvData = pd.read_csv(file_path, usecols=["Email"], index_col=False)
|
# csvData = pd.read_csv(file_path)
|
||||||
html_data = csvData.to_html()
|
file = list(csv.reader(open(file_path, "r")))
|
||||||
|
emails = []
|
||||||
|
groups = []
|
||||||
|
for col in file:
|
||||||
|
emails.append(col[0])
|
||||||
|
#groups.append(col(range(1,20)))
|
||||||
|
print(emails)
|
||||||
|
#print(groups)
|
||||||
|
|
||||||
|
#print(emails)
|
||||||
|
# for item in data:
|
||||||
|
# print(item[0])
|
||||||
|
# lines = reader(csvData)
|
||||||
|
# csvData = list(lines)
|
||||||
|
# print(csvData)
|
||||||
|
selection = request.form.get('learner-groups')
|
||||||
|
if selection == "all-groups":
|
||||||
|
if request.form['preview']:
|
||||||
|
return api_csv_all_groups(csvData)
|
||||||
|
elif request.form['submit']:
|
||||||
|
return "Submitted Selection"
|
||||||
|
elif selection == "some-groups":
|
||||||
|
return api_csv_some_groups(csvData)
|
||||||
return render_template(
|
return render_template(
|
||||||
"options.html", table=html_data, title="Uploaded File"
|
"bulk_add.html", table=html_data, title="Uploaded File"
|
||||||
)
|
)
|
||||||
# TODO: Figure out how to delete the file after use.
|
|
||||||
print("nothing happened")
|
|
||||||
return render_template("options.html", title="Home, now with a CSV Table!")
|
return render_template("options.html", title="Home, now with a CSV Table!")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/table")
|
def api_csv_all_groups(csvData):
|
||||||
def table():
|
# htmlcsv = csvData.to_html()
|
||||||
return render_template("table.html", tables=[session["dfhtml"]], titles=["Table"])
|
# for items in csvData:
|
||||||
|
|
||||||
|
|
||||||
|
# emails = csvData['Email'].values.tolist()
|
||||||
|
# emails = [nan for nan in emails if str(nan) != 'nan']
|
||||||
|
|
||||||
|
# groups = csvData['Groups'].values.tolist()
|
||||||
|
# groups = [nan for nan in groups if str(nan) != 'nan']
|
||||||
|
|
||||||
|
if emails and groups:
|
||||||
|
return api_add_ppl_groups(emails, groups)
|
||||||
|
elif emails:
|
||||||
|
return api_add_ppl(emails)
|
||||||
|
elif groups:
|
||||||
|
return api_add_groups(groups)
|
||||||
|
return render_template("bulk_add.html", table=htmlcsv, title="CSV Submission")
|
||||||
|
|
||||||
|
def api_csv_some_groups(csvData):
|
||||||
|
htmlcsv = csvData.to_html()
|
||||||
|
|
||||||
|
emails = csvData['Email'].values.tolist()
|
||||||
|
emails = [nan for nan in emails if str(nan) != 'nan']
|
||||||
|
|
||||||
|
groups = csvData['Groups'].values.tolist()
|
||||||
|
groups = [nan for nan in groups if str(nan) != 'nan']
|
||||||
|
|
||||||
|
print(emails)
|
||||||
|
print(groups)
|
||||||
|
|
||||||
|
# print(email)
|
||||||
|
# return groups
|
||||||
|
# row_list = csvData.loc[2, :].values.flatten().tolist()
|
||||||
|
|
||||||
|
return htmlcsv
|
||||||
|
|
||||||
@app.route("/bulk_add_opts", methods=["GET", "POST"])
|
@app.route("/bulk_add_opts", methods=["GET", "POST"])
|
||||||
def bulk_add_opts():
|
def bulk_add_opts():
|
||||||
|
return render_template("bulk_add.html", titles="Bulk Add Options")
|
||||||
|
|
||||||
|
'''
|
||||||
array = []
|
array = []
|
||||||
dict_response = {}
|
dict_response = {}
|
||||||
dataframe = pd.DataFrame()
|
dataframe = pd.DataFrame()
|
||||||
@ -159,48 +219,9 @@ def bulk_add_opts():
|
|||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
if session.get("file"):
|
if session.get("file"):
|
||||||
print("file exists! uploading data...")
|
pass
|
||||||
return "File Exists! Test Complete"
|
#print("file exists! uploading data...")
|
||||||
else:
|
#return "File Exists! Test Complete"
|
||||||
while True:
|
|
||||||
count += 1
|
|
||||||
endpoint = f"v2/groups?page={count}"
|
|
||||||
headers = {"accept": "application/json", "X-Api-Key": session["key"]}
|
|
||||||
response = requests.get(url + endpoint, headers=headers)
|
|
||||||
data = response.json()
|
|
||||||
nextlink = data["links"]
|
|
||||||
|
|
||||||
for response in data["data"]:
|
|
||||||
uuid = response["id"]
|
|
||||||
dict_response = {"id": uuid}
|
|
||||||
for keys, values in response["attributes"].items():
|
|
||||||
dict_response[keys] = values
|
|
||||||
array.append(dict_response)
|
|
||||||
dataframe = pd.DataFrame(array).drop(
|
|
||||||
"group_enrollment_link", axis=1
|
|
||||||
)
|
|
||||||
print(dataframe)
|
|
||||||
|
|
||||||
if "next" not in nextlink:
|
|
||||||
break
|
|
||||||
|
|
||||||
dfgroups = dataframe.to_html()
|
|
||||||
session["dfcsv"] = dataframe.to_csv()
|
|
||||||
return render_template(
|
|
||||||
"bulk_add.html", table=dfgroups, titles="Bulk Add"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return "This isn't working. Let's go our own way."
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/bulk_add_groups_opts", methods=["GET", "POST"])
|
|
||||||
def bulk_add_groups_opts():
|
|
||||||
array = []
|
|
||||||
dict_response = {}
|
|
||||||
count = 0
|
|
||||||
dataframe = pd.DataFrame()
|
|
||||||
|
|
||||||
if request.method == "POST":
|
|
||||||
while True:
|
while True:
|
||||||
count += 1
|
count += 1
|
||||||
endpoint = f"v2/groups?page={count}"
|
endpoint = f"v2/groups?page={count}"
|
||||||
@ -215,20 +236,20 @@ def bulk_add_groups_opts():
|
|||||||
for keys, values in response["attributes"].items():
|
for keys, values in response["attributes"].items():
|
||||||
dict_response[keys] = values
|
dict_response[keys] = values
|
||||||
array.append(dict_response)
|
array.append(dict_response)
|
||||||
dataframe = pd.DataFrame(array).drop("group_enrollment_link", axis=1)
|
dataframe = pd.DataFrame(array).drop(
|
||||||
|
"group_enrollment_link", axis=1
|
||||||
|
)
|
||||||
print(dataframe)
|
print(dataframe)
|
||||||
|
|
||||||
if "next" not in nextlink:
|
if "next" not in nextlink:
|
||||||
break
|
break
|
||||||
|
|
||||||
session["dfgroups"] = dataframe.to_html()
|
dfgroups = dataframe.to_html()
|
||||||
session["dfcsv"] = dataframe.to_csv()
|
session["dfcsv"] = dataframe.to_csv()
|
||||||
return render_template(
|
return render_template("bulk_add.html", table=dfgroups, titles="Bulk Add")
|
||||||
"bulk_add_groups.html", table=session["dfgroups"], titles="Bulk Add Groups"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
return "This isn't working. Let's go our own way."
|
return "This isn't working. Let's go our own way."
|
||||||
|
'''
|
||||||
|
|
||||||
@app.route("/bulk_add", methods=["GET", "POST"])
|
@app.route("/bulk_add", methods=["GET", "POST"])
|
||||||
def bulk_add():
|
def bulk_add():
|
||||||
@ -239,35 +260,36 @@ def bulk_add():
|
|||||||
if "\n" in emails:
|
if "\n" in emails:
|
||||||
emails = emails.split("\n")
|
emails = emails.split("\n")
|
||||||
emails = [email.strip() for email in emails]
|
emails = [email.strip() for email in emails]
|
||||||
emails = [re.sub(r'[,]', "", email) for email in emails]
|
emails = [re.sub(r"[,]", "", email) for email in emails]
|
||||||
elif "," in emails:
|
elif "," in emails:
|
||||||
emails = emails.split(",")
|
emails = emails.split(",")
|
||||||
emails = [email.strip() for email in emails]
|
emails = [email.strip() for email in emails]
|
||||||
else:
|
else:
|
||||||
emails = []
|
emails = emails.split()
|
||||||
emails.append(emails)
|
else:
|
||||||
|
emails = []
|
||||||
|
emails.append(emails)
|
||||||
if groups:
|
if groups:
|
||||||
if "\n" in groups:
|
if "\n" in groups:
|
||||||
groups = groups.split("\n")
|
groups = groups.split("\n")
|
||||||
groups = [group.strip() for group in groups]
|
groups = [group.strip() for group in groups]
|
||||||
groups = [re.sub(r'[,]', "", group) for group in groups]
|
groups = [re.sub(r"[,]", "", group) for group in groups]
|
||||||
elif "," in groups:
|
elif "," in groups:
|
||||||
groups = groups.split(",")
|
groups = groups.split(",")
|
||||||
groups = [group.strip() for group in groups]
|
groups = [group.strip() for group in groups]
|
||||||
else:
|
else:
|
||||||
groups = []
|
groups = groups.split()
|
||||||
groups.append(groups)
|
else:
|
||||||
|
groups = []
|
||||||
|
groups.append(groups)
|
||||||
|
|
||||||
if emails and groups:
|
if emails and groups:
|
||||||
print(emails)
|
|
||||||
print(groups)
|
|
||||||
return api_add_ppl_groups(emails, groups)
|
return api_add_ppl_groups(emails, groups)
|
||||||
elif emails:
|
elif emails:
|
||||||
return api_add_ppl(emails)
|
return api_add_ppl(emails)
|
||||||
elif groups:
|
elif groups:
|
||||||
return api_add_groups(groups)
|
return api_add_groups(groups)
|
||||||
|
return render_template("bulk_add.html")
|
||||||
return render_template('bulk_add.html')
|
|
||||||
|
|
||||||
|
|
||||||
# for group in groups:
|
# for group in groups:
|
||||||
@ -276,57 +298,56 @@ def bulk_add():
|
|||||||
|
|
||||||
|
|
||||||
def api_add_ppl(emails):
|
def api_add_ppl(emails):
|
||||||
print(emails)
|
payload2 = []
|
||||||
endpoint = "v2/bulk/people"
|
endpoint = "v2/bulk/people"
|
||||||
payload = {
|
for email in emails:
|
||||||
"data": {
|
payload2.append({"email": email })
|
||||||
"attributes": {"people": [{"email": emails}]}
|
payload = {"data": {"attributes": {"people": payload2 }}}
|
||||||
}
|
|
||||||
}
|
|
||||||
headers = {
|
headers = {
|
||||||
"accept": "application/json",
|
"accept": "application/json",
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
"X-Api-Key": session["key"],
|
"X-Api-Key": session["key"],
|
||||||
}
|
}
|
||||||
response = requests.post(url + endpoint, json=payload, headers=headers)
|
return payload
|
||||||
return check_response(response)
|
# response = requests.post(url + endpoint, json=payload, headers=headers)
|
||||||
|
# return check_response(response)
|
||||||
|
|
||||||
|
|
||||||
def api_add_groups(groups):
|
def api_add_groups(groups):
|
||||||
print(groups)
|
payload2 = []
|
||||||
endpoint = "v2/bulk/people"
|
endpoint = "v2/bulk/people"
|
||||||
payload = {
|
for group in groups:
|
||||||
"data": {
|
payload2.append({"groups" : group })
|
||||||
"attributes": {"people": [{"groups": groups}]}
|
payload = {"data": {"attributes": {"people": payload2 }}}
|
||||||
}
|
|
||||||
}
|
|
||||||
headers = {
|
headers = {
|
||||||
"accept": "application/json",
|
"accept": "application/json",
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
"X-Api-Key": session["key"],
|
"X-Api-Key": session["key"],
|
||||||
}
|
}
|
||||||
response = requests.post(url + endpoint, json=payload, headers=headers)
|
return payload
|
||||||
return check_response(response)
|
# response = requests.post(url + endpoint, json=payload, headers=headers)
|
||||||
|
# return check_response(response)
|
||||||
|
|
||||||
|
|
||||||
def api_add_ppl_groups(emails, groups):
|
def api_add_ppl_groups(emails, groups):
|
||||||
endpoint = "v2/bulk/people"
|
payload2 = []
|
||||||
print(len(groups))
|
endpoint = "v2/bulk/people"
|
||||||
combinations = list(itertools.product(emails, groups))
|
combinations = list(itertools.product(emails, groups))
|
||||||
print(combinations)
|
for combo in combinations:
|
||||||
payload = {
|
payload2.append({"email": combo[0], "groups": combo[1]})
|
||||||
"data": {
|
payload = {
|
||||||
"attributes": {"people": [{"email": emails, "groups": groups}]}
|
"data": {"attributes": {"people": payload2 }}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
print(payload)
|
headers = {
|
||||||
headers = {
|
"accept": "application/json",
|
||||||
"accept": "application/json",
|
"content-type": "application/json",
|
||||||
"content-type": "application/json",
|
"X-Api-Key": session["key"],
|
||||||
"X-Api-Key": session["key"],
|
}
|
||||||
}
|
return payload
|
||||||
response = requests.post(url + endpoint, json=payload, headers=headers)
|
#response = requests.post(url + endpoint, json=payload, headers=headers)
|
||||||
return check_response(response)
|
#return check_response(response)
|
||||||
|
|
||||||
|
|
||||||
def check_response(response):
|
def check_response(response):
|
||||||
response = str(response)
|
response = str(response)
|
||||||
@ -343,67 +364,11 @@ def check_response(response):
|
|||||||
error = "Shrug"
|
error = "Shrug"
|
||||||
return render_template("bulk_add.html", title="Shrug", errors=error)
|
return render_template("bulk_add.html", title="Shrug", errors=error)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/templates", methods=["GET", "POST"])
|
@app.route("/templates", methods=["GET", "POST"])
|
||||||
def templates():
|
def templates():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
'''
|
|
||||||
@app.route("/bulk_add_groups", methods=["GET", "POST"])
|
|
||||||
def bulk_add_groups():
|
|
||||||
grouparr = []
|
|
||||||
count = 0
|
|
||||||
if request.method == "POST":
|
|
||||||
groups = request.form.get("groups")
|
|
||||||
if "\n" in groups:
|
|
||||||
groups.split("\n")
|
|
||||||
groups = [group.strip() for group in groups]
|
|
||||||
elif "," in groups:
|
|
||||||
groups.split(",")
|
|
||||||
groups = [group.strip() for group in groups]
|
|
||||||
for group in groups:
|
|
||||||
groupdict = {}
|
|
||||||
groupdict["name"] = group
|
|
||||||
grouparr.append(groupdict)
|
|
||||||
|
|
||||||
endpoint = "v2/bulk/groups"
|
|
||||||
payload = {"data": {"attributes": {"groups": grouparr}}}
|
|
||||||
headers = {
|
|
||||||
"accept": "application/json",
|
|
||||||
"content-type": "application/json",
|
|
||||||
"X-Api-Key": session["key"],
|
|
||||||
}
|
|
||||||
response = requests.post(url + endpoint, json=payload, headers=headers)
|
|
||||||
print(type(response))
|
|
||||||
response = str(response)
|
|
||||||
if "202" in response:
|
|
||||||
error = "Success! Groups have been added successfully."
|
|
||||||
return render_template(
|
|
||||||
"bulk_add_groups.html",
|
|
||||||
table=session["dfgroups"],
|
|
||||||
title="Groups Added",
|
|
||||||
error=error,
|
|
||||||
)
|
|
||||||
elif "403" in response:
|
|
||||||
error = [
|
|
||||||
"Uh oh. Looks like you're not the",
|
|
||||||
"admin or don't have appropriate privileges.",
|
|
||||||
"Please talk to your academy admin.",
|
|
||||||
]
|
|
||||||
elif "422" in response:
|
|
||||||
error = [
|
|
||||||
"Hm. Looks like something was wrong with the group names.",
|
|
||||||
"Reach out to the manager of this app.",
|
|
||||||
]
|
|
||||||
return render_template(
|
|
||||||
"bulk_add_groups.html",
|
|
||||||
table=session["dfgroups"],
|
|
||||||
title="Groups Added",
|
|
||||||
error=error,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
error = "Shrug"
|
|
||||||
return render_template("bulk_add_groups.html", title="Shrug", errors=error)
|
|
||||||
'''
|
|
||||||
|
|
||||||
@app.route("/bulk_courses_to_groups", methods=["GET", "POST"])
|
@app.route("/bulk_courses_to_groups", methods=["GET", "POST"])
|
||||||
def bulk_courses_to_groups():
|
def bulk_courses_to_groups():
|
||||||
|
|||||||
4
app/static/files/FLASK-TEST_-_Sheet1.csv
Normal file
4
app/static/files/FLASK-TEST_-_Sheet1.csv
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Email,Groups
|
||||||
|
norm+72@northpass.com,All Apologies,Come as you are
|
||||||
|
norm+90@northpass.com,Come as you are
|
||||||
|
norm+98@northpass.com,The Pines,The Sea,An Ocean
|
||||||
|
4
app/static/files/FLASK-TEST_-_Sheet1_1.csv
Normal file
4
app/static/files/FLASK-TEST_-_Sheet1_1.csv
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Email,Groups,
|
||||||
|
norm+72@northpass.com,All Apologies,Come As You Are
|
||||||
|
norm+90@northpass.com,Come As You Are,
|
||||||
|
norm+98@northpass.com,Unplugged,
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
<p> </p>
|
<p> </p>
|
||||||
<div class="man-csv-opts">
|
<div class="man-csv-opts">
|
||||||
<div class="manual-opts">
|
<div class="manual-opts">
|
||||||
<p><label for="Bulk Add People"> Each item must be comma separated or placed on a
|
<p><label for="Bulk Add"> Each item must be comma separated or placed on a
|
||||||
new line.</label></p>
|
new line.</label></p>
|
||||||
<form action="{{ url_for("bulk_add")}}" method="post">
|
<form action="{{ url_for("bulk_add")}}" method="post">
|
||||||
<p>Emails</p>
|
<p>Emails</p>
|
||||||
@ -52,5 +52,7 @@
|
|||||||
{% include 'csv.html' %}
|
{% include 'csv.html' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% include 'table.html' %}
|
{% if table %}
|
||||||
|
{% include 'table.html' %}
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -3,18 +3,19 @@
|
|||||||
<h3> If you'd like to upload a CSV. Please do so here:</h3>
|
<h3> If you'd like to upload a CSV. Please do so here:</h3>
|
||||||
<p></p>
|
<p></p>
|
||||||
<form method="POST"
|
<form method="POST"
|
||||||
action="{{ url_for('csv') }}"
|
action="{{ url_for('upload_file') }}"
|
||||||
enctype="multipart/form-data">
|
enctype="multipart/form-data">
|
||||||
<p><input type="file" name="file"></p>
|
<p><input type="file" name="file"></p>
|
||||||
<div class="radio-options">
|
<div class="radio-options">
|
||||||
<input type="radio" id="all-groups" name="all-groups" value="all-groups">
|
<input type="radio" id="all-groups" name="learner-groups" value="all-groups" checked>
|
||||||
<label for="all-groups">All Learners in All Groups</label>
|
<label for="learner-groups">All Learners in All Groups</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="radio-options">
|
<div class="radio-options">
|
||||||
<input type="radio" id="some-groups" name="some-groups" value="some-groups">
|
<input type="radio" id="some-groups" name="learner-groups" value="some-groups">
|
||||||
<label for="some-groups">Learners Only in Adjacent Groups</label>
|
<label for="learner-groups">Learners Only in Adjacent Groups</label>
|
||||||
</div>
|
</div>
|
||||||
<p><input type="submit" value="Submit CSV"></p>
|
<p><input type="submit" name="preview" value="Preview"></p>
|
||||||
|
<input type="submit" name="submit" value="Submit to Academy"></input>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user