Add functionality to create linked supervisor account when creating a user
This commit is contained in:
+7
-1
@@ -12,7 +12,7 @@ from django.forms import (
|
|||||||
DateField,
|
DateField,
|
||||||
SplitDateTimeField,
|
SplitDateTimeField,
|
||||||
SplitDateTimeWidget,
|
SplitDateTimeWidget,
|
||||||
|
BooleanField,
|
||||||
)
|
)
|
||||||
from django.forms import inlineformset_factory
|
from django.forms import inlineformset_factory
|
||||||
from atlas.models import CaseCollection
|
from atlas.models import CaseCollection
|
||||||
@@ -812,6 +812,12 @@ class UserUserForm(Form):
|
|||||||
first_name = CharField(max_length=255, required=True)
|
first_name = CharField(max_length=255, required=True)
|
||||||
last_name = CharField(max_length=255, required=True)
|
last_name = CharField(max_length=255, required=True)
|
||||||
grade = ModelChoiceField(UserGrades.objects.all(), required=False)
|
grade = ModelChoiceField(UserGrades.objects.all(), required=False)
|
||||||
|
create_supervisor = BooleanField(
|
||||||
|
required=False,
|
||||||
|
label="Create linked supervisor account",
|
||||||
|
help_text="If checked, a supervisor profile with this user's name and email will be automatically created.",
|
||||||
|
initial=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TraineeForm(Form):
|
class TraineeForm(Form):
|
||||||
|
|||||||
@@ -1,30 +1,42 @@
|
|||||||
{% extends "generic/base.html" %}
|
{% extends "generic/base.html" %}
|
||||||
<!-- {% load static from static %} -->
|
|
||||||
|
|
||||||
{% load crispy_forms_tags %}
|
{% load crispy_forms_tags %}
|
||||||
{% block css %}
|
|
||||||
{% endblock %}
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
{{ form.media }}
|
||||||
{{form.media}}
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- {{ form.media }} -->
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Create Trainee</h2>
|
<div class="container py-4">
|
||||||
Use this form to create a user. Only existing supervisors can be added (<a href="{% url 'generic:supervisor_create' %}">create them first</a> and refresh this page or add them later if they do not exist).
|
<div class="row justify-content-center">
|
||||||
{% if errors %}
|
<div class="col-md-8">
|
||||||
<div class="alert alert-info" role="alert">{{errors}}</a></div>
|
<div class="card shadow-sm border border-secondary border-opacity-20">
|
||||||
{% endif %}
|
<div class="card-header bg-primary text-white py-3">
|
||||||
<form action="" method="post" enctype="multipart/form-data" id="condition-form">
|
<h4 class="mb-0"><i class="bi bi-person-plus me-2"></i>Create Trainee</h4>
|
||||||
{% csrf_token %}
|
</div>
|
||||||
|
<div class="card-body p-4">
|
||||||
|
<p class="text-muted mb-4">Use this form to create a user. Only existing supervisors can be added (if they don't exist, <a href="{% url 'generic:supervisor_create' %}" class="fw-bold">create them first</a> and refresh this page or add them later).</p>
|
||||||
|
|
||||||
<table>
|
{% if errors %}
|
||||||
{{ form|crispy }}
|
<div class="alert alert-danger" role="alert">
|
||||||
</table>
|
<i class="bi bi-exclamation-triangle-fill me-2"></i>{{ errors }}
|
||||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
</div>
|
||||||
</form>
|
{% endif %}
|
||||||
|
|
||||||
|
<form action="" method="post" enctype="multipart/form-data" id="condition-form">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form|crispy }}
|
||||||
|
<div class="mt-4 d-flex justify-content-between">
|
||||||
|
<a href="{% url 'accounts_list' %}" class="btn btn-outline-secondary">
|
||||||
|
<i class="bi bi-x-lg me-1"></i>Cancel
|
||||||
|
</a>
|
||||||
|
<button type="submit" class="btn btn-primary px-4">
|
||||||
|
<i class="bi bi-check-lg me-1"></i>Create Trainee
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,30 +1,42 @@
|
|||||||
{% extends "generic/base.html" %}
|
{% extends "generic/base.html" %}
|
||||||
<!-- {% load static from static %} -->
|
|
||||||
{% load crispy_forms_tags %}
|
{% load crispy_forms_tags %}
|
||||||
|
|
||||||
{% block css %}
|
|
||||||
{% endblock %}
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
{{ form.media }}
|
||||||
{{form.media}}
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- {{ form.media }} -->
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Create User</h2>
|
<div class="container py-4">
|
||||||
Use this form to create a user. Create a trainee <a href="{% url 'create_trainee' %}">here</a>.
|
<div class="row justify-content-center">
|
||||||
{% if errors %}
|
<div class="col-md-8">
|
||||||
<div class="alert alert-info" role="alert">{{errors}}</a></div>
|
<div class="card shadow-sm border border-secondary border-opacity-20">
|
||||||
{% endif %}
|
<div class="card-header bg-primary text-white py-3">
|
||||||
<form action="" method="post" enctype="multipart/form-data" id="condition-form">
|
<h4 class="mb-0"><i class="bi bi-person-plus me-2"></i>Create User</h4>
|
||||||
{% csrf_token %}
|
</div>
|
||||||
|
<div class="card-body p-4">
|
||||||
|
<p class="text-muted mb-4">Use this form to create a new user. To create a trainee instead, click <a href="{% url 'create_trainee' %}" class="fw-bold">here</a>.</p>
|
||||||
|
|
||||||
<table>
|
{% if errors %}
|
||||||
{{ form|crispy }}
|
<div class="alert alert-danger" role="alert">
|
||||||
</table>
|
<i class="bi bi-exclamation-triangle-fill me-2"></i>{{ errors }}
|
||||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
</div>
|
||||||
</form>
|
{% endif %}
|
||||||
|
|
||||||
|
<form action="" method="post" enctype="multipart/form-data" id="condition-form">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form|crispy }}
|
||||||
|
<div class="mt-4 d-flex justify-content-between">
|
||||||
|
<a href="{% url 'accounts_list' %}" class="btn btn-outline-secondary">
|
||||||
|
<i class="bi bi-x-lg me-1"></i>Cancel
|
||||||
|
</a>
|
||||||
|
<button type="submit" class="btn btn-primary px-4">
|
||||||
|
<i class="bi bi-check-lg me-1"></i>Create User
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
+14
-1
@@ -5948,9 +5948,22 @@ def create_user(request, context=None, trainee: bool = False):
|
|||||||
if trainee and form.cleaned_data.get("supervisor"):
|
if trainee and form.cleaned_data.get("supervisor"):
|
||||||
supervisor = form.cleaned_data["supervisor"]
|
supervisor = form.cleaned_data["supervisor"]
|
||||||
user_profile.supervisor = supervisor
|
user_profile.supervisor = supervisor
|
||||||
|
|
||||||
user_profile.save()
|
user_profile.save()
|
||||||
|
|
||||||
|
if not trainee and form.cleaned_data.get("create_supervisor"):
|
||||||
|
from generic.models import Supervisor
|
||||||
|
supervisor, created = Supervisor.objects.get_or_create(
|
||||||
|
email=new_user.email,
|
||||||
|
defaults={
|
||||||
|
"name": f"{new_user.first_name} {new_user.last_name}".strip(),
|
||||||
|
"user": new_user,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if not created and not supervisor.user:
|
||||||
|
supervisor.user = new_user
|
||||||
|
supervisor.name = f"{new_user.first_name} {new_user.last_name}".strip()
|
||||||
|
supervisor.save(update_fields=["user", "name"])
|
||||||
|
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
errors = f"Unable to create account profile {error}"
|
errors = f"Unable to create account profile {error}"
|
||||||
return render(
|
return render(
|
||||||
|
|||||||
@@ -280,5 +280,57 @@ def test_hide_exams_and_collections(client, create_users):
|
|||||||
assert b"Test Physics Exam" in response_unhidden.content
|
assert b"Test Physics Exam" in response_unhidden.content
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_create_user_with_linked_supervisor(client, create_cid_manager, django_user_model):
|
||||||
|
from generic.models import Supervisor
|
||||||
|
|
||||||
|
client.force_login(create_cid_manager)
|
||||||
|
|
||||||
|
# 1. Create a user WITH create_supervisor checked
|
||||||
|
response = client.post(
|
||||||
|
reverse("create_user"),
|
||||||
|
{
|
||||||
|
"username": "newsupervisor@example.com",
|
||||||
|
"first_name": "New",
|
||||||
|
"last_name": "Supervisor",
|
||||||
|
"grade": "",
|
||||||
|
"create_supervisor": True,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse("accounts_list")
|
||||||
|
|
||||||
|
# Verify user created
|
||||||
|
new_user = django_user_model.objects.get(username="newsupervisor@example.com")
|
||||||
|
assert new_user.first_name == "New"
|
||||||
|
assert new_user.last_name == "Supervisor"
|
||||||
|
|
||||||
|
# Verify linked supervisor created
|
||||||
|
supervisor = Supervisor.objects.get(email="newsupervisor@example.com")
|
||||||
|
assert supervisor.name == "New Supervisor"
|
||||||
|
assert supervisor.user == new_user
|
||||||
|
|
||||||
|
# 2. Create a user WITHOUT create_supervisor checked
|
||||||
|
response_no_sv = client.post(
|
||||||
|
reverse("create_user"),
|
||||||
|
{
|
||||||
|
"username": "regularuser@example.com",
|
||||||
|
"first_name": "Regular",
|
||||||
|
"last_name": "User",
|
||||||
|
"grade": "",
|
||||||
|
"create_supervisor": False,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response_no_sv.status_code == 302
|
||||||
|
|
||||||
|
# Verify user created
|
||||||
|
regular_user = django_user_model.objects.get(username="regularuser@example.com")
|
||||||
|
# Verify no supervisor was created
|
||||||
|
assert not Supervisor.objects.filter(email="regularuser@example.com").exists()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user