Aug 7 - Update External Inspector invitation
This commit is contained in:
@@ -79,7 +79,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
{# phase51 — an External Inspector is invited by email and chooses
|
||||
their own username and password, so the admin never sets one.
|
||||
The JS at the foot of this page swaps these two blocks when the
|
||||
role changes; the server decides independently of the JS. #}
|
||||
<div id="inviteNotice" class="alert alert-info d-none">
|
||||
<i class="bi bi-envelope me-1"></i>
|
||||
<strong>This account will be invited by email.</strong>
|
||||
External inspectors work outside the business, so we do not set
|
||||
a password for them. On save, an invitation is sent to the email
|
||||
address above with a link to choose their own username and
|
||||
password. The link is valid for 72 hours.
|
||||
</div>
|
||||
|
||||
<div class="row" id="passwordFields">
|
||||
<div class="col-md-6 mb-3">
|
||||
{{ form.password.label(class="form-label") }}
|
||||
{{ form.password(class="form-control", placeholder="Leave blank to keep current" if user else "") }}
|
||||
@@ -127,4 +140,27 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
'use strict';
|
||||
var roleSel = document.getElementById('role');
|
||||
var pwBlock = document.getElementById('passwordFields');
|
||||
var notice = document.getElementById('inviteNotice');
|
||||
if (!roleSel || !pwBlock || !notice) return; // director view has no role select
|
||||
|
||||
function sync() {
|
||||
var invited = roleSel.value === 'external_inspector';
|
||||
pwBlock.classList.toggle('d-none', invited);
|
||||
notice.classList.toggle('d-none', !invited);
|
||||
// Clear anything already typed so an invited account can never be created
|
||||
// with an admin-chosen password sitting in the POST body.
|
||||
if (invited) {
|
||||
pwBlock.querySelectorAll('input').forEach(function (i) { i.value = ''; });
|
||||
}
|
||||
}
|
||||
roleSel.addEventListener('change', sync);
|
||||
sync();
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -55,10 +55,17 @@
|
||||
</td>
|
||||
<td>{{ user.created_at.strftime('%Y-%m-%d') }}</td>
|
||||
<td>
|
||||
{% if user.active %}
|
||||
<span class="badge bg-success">Active</span>
|
||||
{% else %}
|
||||
{% if not user.active %}
|
||||
<span class="badge bg-secondary">Disabled</span>
|
||||
{% elif not user.password_set %}
|
||||
{# phase51 — invited but has not chosen a password yet;
|
||||
the login route refuses them until they do. #}
|
||||
<span class="badge bg-warning text-dark"
|
||||
title="Invitation sent — this person has not set their password yet">
|
||||
<i class="bi bi-envelope"></i> Invite pending
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="badge bg-success">Active</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
@@ -71,6 +78,17 @@
|
||||
<i class="bi bi-briefcase"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if not user.password_set %}
|
||||
<form method="POST" action="{{ url_for('auth.resend_invite', user_id=user.id) }}"
|
||||
class="d-inline"
|
||||
onsubmit="return confirm('Resend the invitation email to {{ user.email }}? The previous link will stop working.');">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-warning"
|
||||
title="Resend invitation email">
|
||||
<i class="bi bi-envelope-arrow-up"></i>
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if user.id != current_user.id %}
|
||||
<form method="POST" action="{{ url_for('auth.toggle_active', user_id=user.id) }}" class="d-inline">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
|
||||
Reference in New Issue
Block a user