Files
penracourses/templates/accounts_bulk_create.html
T

344 lines
14 KiB
HTML

{% extends 'generic/base.html' %}
{% block content %}
{% if created_users %}
<div class="alert alert-success">
The following users have been created: {{created_users}}
</div>
{% endif %}
{% if error %}
<div class="alert alert-warning">
{{error}}
</div>
{% endif %}
{% if message %}
<div class="alert alert-info">
{{message}}
</div>
{% endif %}
<p>
Prepare a spreadsheet with the following format.
<table>
<tr><th>First name</th><th>Last name</th><th>Email</th><th>Grade</th><th>Supervisor</th><th>Supervisor email</th></tr>
<tr><td>name 1</td><td>last name 1</td><td>email1@email.com</td><td>ST1</td><td>supervisor 1</td><td>Supervisor@email.com</td></tr>
<tr><td>name 2</td><td>last name 2</td><td>email2@email.com</td><td>ST2</td><td>supervisor 2</td><td>Supervisor2@email.com</td></tr>
</table>
On your spreadsheet then "copy" the data (not including header), come to this page, put focus on the &lt;textarea> box and "paste" the text in. In some instance (large data sets) this might take a couple of seconds.
Once there simply click the button and check the users that will be created below.
</p>
<p>Please note users created this way bypass some of the validations so check details such as email addresses are correct</p>
<div class="mb-2">
<label for="input-format" class="form-label">Input format</label>
<select id="input-format" class="form-select form-control-max-300">
<option value="spreadsheet">First,Last,Email,Grade,Supervisor,SupervisorEmail (spreadsheet)</option>
<option value="name-supervisor-email-grade">User \t Educational Supervisor \t Email \t Grade</option>
</select>
</div>
<textarea id="csv" class="form-control form-control-max-300" rows="4" placeholder="Paste users content here"></textarea><br/>
<input type="button" value="Load Data" _="on click createTable()" >
<div role="alert" id="alert" class="alert alert-info "
_="on load hide me">
</div>
<div>
<ul id="users-list">
</ul>
</div>
<form id="user-list-form" method="post">
{% csrf_token %}
<input type="text" name="usersjson" id="user-list-json" hidden>
<input type="submit" id="submit-users" name="submit-users" value="Create Users" style="display: none">
</form>
<script>
function createTable() {
// Get the data
var excelData = document.getElementById('csv').value.trim()+"\n";
// split into rows
excelRow = excelData.split(String.fromCharCode(10));
// If the first row looks like a header (contains words like 'user', 'email', 'grade', 'supervisor'), drop it
if (excelRow.length) {
var firstRowCols = excelRow[0].split(String.fromCharCode(9)).map(function(c){return c.trim().toLowerCase();});
var headerKeywords = ['user','first name','last name','email','grade','educational supervisor','supervisor','first','last'];
var isHeader = firstRowCols.some(function(c){
if (!c) return false;
if (headerKeywords.indexOf(c) !== -1) return true;
if (c.indexOf('email') !== -1) return true;
if (c.indexOf('supervisor') !== -1) return true;
return false;
});
if (isHeader) {
// remove header row
excelRow.shift();
}
}
// split rows into columns
for (i=0; i<excelRow.length; i++) {
excelRow[i] = excelRow[i].split(String.fromCharCode(9));
}
// start to create the HTML table
var myTable = document.createElement("table");
var myTbody = document.createElement("tbody");
// Loop over the rows
var format = document.getElementById('input-format').value;
var elements = ["first_name", "last_name", "email", "grade", "supervisor_name", "supervisor_email"];
// For alternate format: User\tEducational Supervisor\tEmail\tGrade
// columns: full name, supervisor name, email, grade
if (format === 'name-supervisor-email-grade') {
elements = ['full_name', 'supervisor_name', 'email', 'grade'];
}
var users = [];
$("#users-list").empty();
$("#users-list").append(`The following users will be created. "undefined" fields will be left blank. Emails will be used as usernames. Supervisors will be created automatically if required. If an incorrect grade is used the user will not be created.`);
var emails = [];
for (i=0; i<excelRow.length - 1; i++) {
//users[i] = {};
user = {};
// create a row in the HTML table
var myRow = document.createElement("tr");
// Loop over the columns and add TD to the TR
for (j=0; j<excelRow[i].length; j++) {
if (excelRow[i][j].length != 0) {
var myCell = document.createElement("td");
myCell.innerHTML = excelRow[i][j].trim();
var key = elements[j] || null;
if (key) {
user[key] = excelRow[i][j].trim();
}
}
myRow.appendChild(myCell);
}
// If alternate format, split full_name into first_name/last_name and ensure supervisor_email empty
if (format === 'name-supervisor-email-grade') {
var full = user.full_name || '';
full = full.trim();
if (full.indexOf(' ') > -1) {
var parts = full.split(/\s+/);
user.first_name = parts[0];
user.last_name = parts.slice(1).join(' ');
} else {
user.first_name = full;
user.last_name = '';
}
// supervisor email not provided in this format
user.supervisor_email = '';
}
myTbody.appendChild(myRow);
users.push(user)
emails.push(user.email)
console.log(user)
$("#users-list").append(`<li data-index="${i}">Name: <span class="name">${user.first_name} ${user.last_name}</span><br/>Email: <span class="email">${user.email}</span><br/>Grade: <span class="grade">${user.grade}</span><br/>Supervisor: <span class="supervisor_name">${user.supervisor_name || ''}</span><br/>
<form>
Supervisor email: <input class="supervisor-email-input form-control form-control-sm form-control-max-320" name="supervisor_email" type="text" value="${user.supervisor_email || ''}" placeholder="supervisor email" style="display: none;" /> <br/>
<input type="text" name="first_name" value="${user.first_name}" hidden>
<input type="text" name="last_name" value="${user.last_name}" hidden>
<input type="text" name="email" value="${user.email}" hidden>
<input type="text" name="grade" value="${user.grade}" hidden>
<input type="text" name="supervisor_name" value="${user.supervisor_name}" hidden>
<button
hx-post="{% url 'accounts_bulk_create_check' %}"
hx-trigger="load"
hx-target="next span"
name="user"
class="hide"
>CHECK</button>
</form><span class="check-status"></span></li>`)
}
myTable.appendChild(myTbody);
$.post("{% url 'accounts_check_users' %}", { csrfmiddlewaretoken: "{{ csrf_token }}",
user_list: JSON.stringify(emails) }, function(data) {
console.log("Existing users", data)
})
$("#users-list").append(`${users.length} users to create/update.`)
// Make sure the new hyperscript works
_hyperscript.processNode($("#users-list")[0]);
htmx.process($("#users-list")[0]);
$("#user-list-json").val(JSON.stringify(users));
// Run the supervisor input toggle once HTMX has processed the checks
updateSupervisorInputs();
$("#user-list-json").val(JSON.stringify(users));
$("#submit-users").show();
// When submit is clicked, rebuild users JSON from current DOM values (to pick up any edited supervisor emails)
window.prepareAndSubmit = function(){
var rebuilt = [];
$("#users-list li").each(function(idx, li){
var $li = $(li);
var first_last = $li.find('.name').text().trim();
var parts = first_last.split(/\s+/);
var first = parts[0] || '';
var last = parts.slice(1).join(' ') || '';
var email = $li.find('.email').text().trim();
var grade = $li.find('.grade').text().trim();
var supervisor_name = $li.find('.supervisor_name').text().trim();
var supervisor_email = $li.find('.supervisor-email-input').val().trim();
rebuilt.push({
first_name: first,
last_name: last,
email: email,
grade: grade,
supervisor_name: supervisor_name,
supervisor_email: supervisor_email
});
});
$("#user-list-json").val(JSON.stringify(rebuilt));
// submit the form
document.getElementById('user-list-form').submit();
};
// Attach form submit handler to rebuild JSON just before submit (covers cases where user presses Enter)
$('#user-list-form').on('submit', function(e){
e.preventDefault();
// rebuild
var rebuilt = [];
$("#users-list li").each(function(idx, li){
var $li = $(li);
var first_last = $li.find('.name').text().trim();
var parts = first_last.split(/\s+/);
var first = parts[0] || '';
var last = parts.slice(1).join(' ') || '';
var email = $li.find('.email').text().trim();
var grade = $li.find('.grade').text().trim();
var supervisor_name = $li.find('.supervisor_name').text().trim();
var supervisor_email = $li.find('.supervisor-email-input').val().trim();
rebuilt.push({
first_name: first,
last_name: last,
email: email,
grade: grade,
supervisor_name: supervisor_name,
supervisor_email: supervisor_email
});
});
$("#user-list-json").val(JSON.stringify(rebuilt));
// submit without triggering this handler again
$(this).off('submit');
this.submit();
});
// If we want to show the table
//document.body.appendChild(myTable);
document.addEventListener('htmx:afterRequest', function(evt) {
updateWarnings();
updateSupervisorInputs();
});
}
</script>
<script>
// Hide the supervisor email input if the server has indicated the supervisor exists
function updateSupervisorInputs(){
try {
document.querySelectorAll('#users-list li').forEach(function(li){
var statusSpan = li.querySelector('.check-status');
if (!statusSpan) return;
var text = statusSpan.textContent.trim().toLowerCase();
var input = li.querySelector('.supervisor-email-input');
if (!input) return;
// If the server response indicates the supervisor exists (and not 'does not exist'), hide the input
if (text.indexOf('supervisor exists') !== -1 && text.indexOf('does not exist') === -1) {
input.style.display = 'none';
} else {
input.style.display = '';
}
});
} catch (e) {
console.error('updateSupervisorInputs error', e);
}
}
</script>
<script type="text/hyperscript">
def updateWarnings()
log "test"
then
if <#users-list li:has(.error)/> is not empty
put "Errors<br/>" into #alert
then for error in<#users-list li:has(.error)/>
put textContent of .name in error at end of #alert
then
put " " + textContent of .error in error at end of #alert
then make a <br/> then put it at the end of #alert
then add .alert-warning to #alert
end
else
put "No errors" into #alert
end
then show #alert
end
</script>
<style>
table{
{% comment %} border-collapse: collapse; {% endcomment %}
border: 1px solid silver;
}
tr{
border-bottom: 1px solid silver;
}
td, th {
border: 1px solid silver;
padding: 2px;
padding-left: 4px;
padding-right: 4px;
}
#users-list li {
border: 1px solid blue;
margin: 10px;
padding: 10px;
}
.check-status {
color: blue;
}
.error {
color:red;
}
#users-list li:has(.error) {
border: 1px solid red;
}
</style>
{% endblock content %}