Improvements to user management
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# Current target
|
||||
- User management
|
||||
|
||||
|
||||
# Ongoing
|
||||
|
||||
- Improve documentation
|
||||
- Test coverage
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 09:44
|
||||
|
||||
import anatomy.models
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('anatomy', '0066_remove_exam_stats_graph'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='anatomyquestion',
|
||||
name='image',
|
||||
field=models.ImageField(help_text="The image to use for the question. Ideally use use unmarked images and annotate (arrow) them on the test system. If you wish to reuse an image that is already uploaded 'clone' the question that contains it.", upload_to=anatomy.models.image_directory_path),
|
||||
),
|
||||
]
|
||||
@@ -858,4 +858,16 @@ details.filter {
|
||||
border: 1px solid gray;
|
||||
padding: 10px;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
/* Generic default styling for forms */
|
||||
|
||||
/* Highlight form errors */
|
||||
tr:has(.errorlist){
|
||||
border: 1px dashed red;
|
||||
}
|
||||
|
||||
.errorlist + input {
|
||||
background-color: red;
|
||||
color: darkblue;
|
||||
}
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
|
||||
<div class="floating-header">
|
||||
<a href="{% url 'atlas:finding_update' pk=finding.pk %}" title="Edit the Finding">Edit</a>
|
||||
<a href="{% url 'atlas:finding_delete' pk=finding.pk %}" title="Delete the Finding">Delete</a>
|
||||
|
||||
+4
-1
@@ -15,13 +15,15 @@ from .models import (
|
||||
CidUserExam,
|
||||
UserGrades,
|
||||
UserProfile,
|
||||
Supervisor,
|
||||
Site
|
||||
)
|
||||
|
||||
# from .models import Examination, Sign, Site, Condition
|
||||
|
||||
admin.site.register(Examination)
|
||||
admin.site.register(Sign)
|
||||
# admin.site.register(Site)
|
||||
admin.site.register(Site)
|
||||
admin.site.register(Condition)
|
||||
admin.site.register(Plane)
|
||||
admin.site.register(Contrast)
|
||||
@@ -32,3 +34,4 @@ admin.site.register(CidUserExam)
|
||||
admin.site.register(CidUserGroup)
|
||||
admin.site.register(UserProfile)
|
||||
admin.site.register(UserGrades)
|
||||
admin.site.register(Supervisor)
|
||||
|
||||
+21
-2
@@ -6,12 +6,15 @@ from django.forms import (
|
||||
ChoiceField,
|
||||
CharField,
|
||||
HiddenInput,
|
||||
EmailField,
|
||||
IntegerField
|
||||
|
||||
)
|
||||
from django.forms import inlineformset_factory
|
||||
from atlas.models import CaseCollection
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from generic.models import CidUser, CidUserGroup, Examination, QuestionNote, UserProfile, UserUserGroup
|
||||
from generic.models import CidUser, CidUserGroup, Examination, QuestionNote, Supervisor, UserProfile, UserUserGroup
|
||||
|
||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
from django.forms.widgets import RadioSelect, TextInput, Textarea
|
||||
@@ -258,4 +261,20 @@ class UserUserGroupForm(ModelForm):
|
||||
#class UserProfileForm(ModelForm):
|
||||
# class Meta:
|
||||
# model = UserProfile
|
||||
# fields = ["supervisor_name", "supervisor_email", "registration_number", "peninsula_trainee"]
|
||||
# fields = ["supervisor_name", "supervisor_email", "registration_number", "peninsula_trainee"]
|
||||
|
||||
class UserUserForm(Form):
|
||||
username = EmailField(required=True, help_text="Username / email should be the same. Ideally this should be an nhs email.")
|
||||
first_name = CharField(max_length=255, required=True)
|
||||
last_name = CharField(max_length=255, required=True)
|
||||
grade = IntegerField(min_value=1, max_value=6, required=False)
|
||||
supervisor = CharField(max_length=255, required=False) # Needs to be a user/object ref
|
||||
#
|
||||
# class Meta:
|
||||
#
|
||||
# fields = ("username", "first_name", "last_name")
|
||||
|
||||
class SupervisorForm(ModelForm):
|
||||
class Meta:
|
||||
model = Supervisor
|
||||
exclude = ("",)
|
||||
@@ -0,0 +1,26 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 09:44
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('generic', '0036_ciduserexam_results_emailed_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Supervisor',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('email', models.EmailField(blank=True, max_length=254)),
|
||||
('name', models.CharField(blank=True, max_length=255)),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('user', models.OneToOneField(blank=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 13:18
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('generic', '0037_supervisor'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='supervisor',
|
||||
name='user',
|
||||
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 13:19
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('generic', '0038_alter_supervisor_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='supervisor',
|
||||
name='user',
|
||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 13:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('generic', '0039_alter_supervisor_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='supervisor',
|
||||
name='email',
|
||||
field=models.EmailField(blank=True, max_length=254, unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,54 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 13:55
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('generic', '0040_alter_supervisor_email'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='site',
|
||||
name='initials',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='site',
|
||||
name='site',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='site',
|
||||
name='full_name',
|
||||
field=models.CharField(blank=True, help_text='Name of the site', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='site',
|
||||
name='short_code',
|
||||
field=models.CharField(blank=True, help_text='Shortcode/name of the site', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='supervisor',
|
||||
name='site',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='generic.site'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='supervisor',
|
||||
name='email',
|
||||
field=models.EmailField(blank=True, help_text='The (nhs.net) email address of the supervisor', max_length=254, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='supervisor',
|
||||
name='name',
|
||||
field=models.CharField(blank=True, help_text='Name of the supervisor', max_length=255),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='supervisor',
|
||||
name='user',
|
||||
field=models.OneToOneField(blank=True, help_text='If the supervisor has an account on the test system that can be associated here', null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 14:01
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('generic', '0041_auto_20221114_1355'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='userprofile',
|
||||
name='supervisor',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='generic.supervisor'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 14:07
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('generic', '0042_userprofile_supervisor'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='userprofile',
|
||||
name='supervisor',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='trainee', to='generic.supervisor'),
|
||||
),
|
||||
]
|
||||
+29
-4
@@ -56,11 +56,13 @@ class Examination(models.Model):
|
||||
|
||||
|
||||
class Site(models.Model):
|
||||
site = models.CharField(max_length=200)
|
||||
initials = models.CharField(max_length=200)
|
||||
"""Model to hold site details"""
|
||||
full_name = models.CharField(max_length=255, blank=True, help_text="Name of the site")
|
||||
short_code = models.CharField(max_length=255, blank=True, help_text="Shortcode/name of the site")
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return self.site
|
||||
return self.short_code
|
||||
|
||||
|
||||
class Condition(tagulous.models.TagModel):
|
||||
@@ -667,6 +669,7 @@ class UserProfile(models.Model):
|
||||
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||||
supervisor_email = models.EmailField(blank=True)
|
||||
supervisor_name = models.CharField(max_length=100, blank=True)
|
||||
supervisor = models.ForeignKey("Supervisor", on_delete=models.SET_NULL, blank=True, null=True, related_name="trainee")
|
||||
registration_number = models.CharField(max_length=25, blank=True)
|
||||
grade = models.ForeignKey(UserGrades, null=True, blank=True, help_text="User grade", on_delete=models.CASCADE)
|
||||
peninsula_trainee = models.BooleanField(default=False)
|
||||
@@ -675,7 +678,28 @@ class UserProfile(models.Model):
|
||||
def getusername(self):
|
||||
return self.user.username
|
||||
|
||||
def __str__(self):
|
||||
return f"Userprofile {self.user}"
|
||||
|
||||
username = property(getusername)
|
||||
|
||||
class Supervisor(models.Model):
|
||||
"""Model to hold individual supervisor details (email and name)
|
||||
|
||||
This can be linked with a user account.
|
||||
"""
|
||||
email = models.EmailField(blank=True, unique=True, help_text="The (nhs.net) email address of the supervisor")
|
||||
name = models.CharField(max_length=255, blank=True, help_text="Name of the supervisor")
|
||||
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True, help_text="If the supervisor has an account on the test system that can be associated here")
|
||||
site = models.ForeignKey("Site", on_delete=models.SET_NULL, null=True, blank=True)
|
||||
active = models.BooleanField(default=True)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.name} ({self.email})"
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('generic:supervisor_detail', kwargs={'pk': self.pk})
|
||||
|
||||
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
@@ -685,4 +709,5 @@ def create_user_profile(sender, instance, created, **kwargs):
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def save_user_profile(sender, instance, **kwargs):
|
||||
instance.userprofile.save()
|
||||
instance.userprofile.save()
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<a href="{% url 'generic:cid_group_view' %}">Cid Groups</a> /
|
||||
<a href="{% url 'generic:user_group_view' %}">User Groups</a> /
|
||||
<a href="{% url 'accounts_list' %}">Manage Users</a> /
|
||||
<a href="{% url 'generic:supervisor' %}">Manage Supervisors</a>
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -91,13 +91,13 @@
|
||||
<summary>Email results</summary>
|
||||
User results emailed: {{exam.exam_results_emailed|default:"Never"}}<br/>
|
||||
<button id="email-results-button"
|
||||
title="Email results to users and their supervisors"
|
||||
title="Email results to users and their supervisor"
|
||||
hx-get="{% url exam.app_name|add:':exam_report_email' exam_id=exam.pk %}"
|
||||
hx-target="#user-details"
|
||||
hx-confirm="This will email results, please make sure scores have been refreshed before continuing"
|
||||
hx-prompt="Please enter an additional email to send to (user and supervisor will automatically be used if available) if required"
|
||||
>Email user results</button>
|
||||
<button id="email-unsent-results-button" title="Email results to users and their supervisors"
|
||||
<button id="email-unsent-results-button" title="Email results to users and their supervisor"
|
||||
hx-get="{% url exam.app_name|add:':exam_report_email_unsent' exam_id=exam.pk %}"
|
||||
hx-target="#user-details"
|
||||
hx-confirm="This will email results, please make sure scores have been refreshed before continuing"
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{% extends 'generic/base.html' %}
|
||||
|
||||
{% block navigation %}
|
||||
{{block.super}}
|
||||
<br/>
|
||||
Supervisors: <a href="{% url 'generic:supervisor' %}">View all</a>
|
||||
<a href="{% url 'generic:supervisor_create' %}">Create new</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
|
||||
{% endblock %}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{% extends 'generic/supervisor_base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Supervisor: {{object.name}}</h2>
|
||||
{{object.email}}
|
||||
|
||||
<br/>User account: {{object.user}}
|
||||
<br/>Site: {{object.site}}
|
||||
<br/>Trainee(s): {% for trainee in object.trainee.all %}
|
||||
<a href="{% url 'account_profile' trainee.user.username %}">{{trainee.user}}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
<div>
|
||||
<a href="{% url 'generic:supervisor_edit' pk=object.pk %}"> Edit</a>
|
||||
<a href="{% url 'generic:supervisor_delete' pk=object.pk %}"> Delete</a>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
|
||||
<style>
|
||||
td, th { padding-left: 10px }
|
||||
</style>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,32 @@
|
||||
{% extends "generic/supervisor_base.html" %}
|
||||
<!-- {% load static from static %} -->
|
||||
|
||||
{% block css %}
|
||||
<style>
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
||||
{{form.media}}
|
||||
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
|
||||
<!-- {{ form.media }} -->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h2>Edit Supervisor / {{object.cid}}</h2>
|
||||
Use this form to create / edit a supervisor
|
||||
{% if errors %}
|
||||
<div class="alert alert-info" role="alert">{{errors}}</a></div>
|
||||
{% endif %}
|
||||
<form action="" method="post" enctype="multipart/form-data" id="condition-form">
|
||||
{% csrf_token %}
|
||||
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||
</form>
|
||||
{% endblock %}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{% extends 'generic/supervisor_base.html' %}
|
||||
{% block content %}
|
||||
|
||||
<h2>Supervisors</h2>
|
||||
|
||||
<ul>
|
||||
{% for supervisor in object_list %}
|
||||
<li><a href="{% url 'generic:supervisor_detail' pk=supervisor.pk %}">Supervisor: {{supervisor.name}}</a>
|
||||
<br/>{{supervisor.email}}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<style>
|
||||
td, th { padding-left: 10px }
|
||||
</style>
|
||||
{% endblock %}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{% extends "generic/base.html" %}
|
||||
<!-- {% load static from static %} -->
|
||||
|
||||
{% block css %}
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
||||
{{form.media}}
|
||||
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
|
||||
<!-- {{ form.media }} -->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h2>Edit User / {{ciduser.cid}}</h2>
|
||||
Use this form to create a user.
|
||||
{% if errors %}
|
||||
<div class="alert alert-info" role="alert">{{errors}}</a></div>
|
||||
{% endif %}
|
||||
<form action="" method="post" enctype="multipart/form-data" id="condition-form">
|
||||
{% csrf_token %}
|
||||
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -92,6 +92,11 @@ urlpatterns = [
|
||||
),
|
||||
path("cids/create", views.manage_cid_users, name="manage_cid_users"),
|
||||
path("cids/create/email", views.create_cid_email, name="create_cid_email"),
|
||||
path("supervisor", views.SupervisorList.as_view(), name="supervisor"),
|
||||
path("supervisor/<int:pk>", views.SupervisorDetail.as_view(), name="supervisor_detail"),
|
||||
path("supervisor/<int:pk>/edit", views.SupervisorUpdate.as_view(), name="supervisor_edit"),
|
||||
path("supervisor/create", views.SupervisorCreate.as_view(), name="supervisor_create"),
|
||||
path("supervisor/<int:pk>/delete", views.SupervisorDelete.as_view(), name="supervisor_delete"),
|
||||
]
|
||||
|
||||
|
||||
|
||||
+87
-2
@@ -1,5 +1,6 @@
|
||||
from collections import defaultdict, Counter
|
||||
from pathlib import Path
|
||||
import secrets
|
||||
import statistics
|
||||
import threading
|
||||
from dal import autocomplete
|
||||
@@ -35,6 +36,8 @@ import urllib
|
||||
|
||||
from django.views import View
|
||||
from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
||||
from django.views.generic.list import ListView
|
||||
from django.views.generic.detail import DetailView
|
||||
from django_filters.views import FilterView
|
||||
from django_filters import FilterSet, OrderingFilter
|
||||
from django_tables2.views import SingleTableMixin
|
||||
@@ -49,10 +52,12 @@ from .forms import (
|
||||
CidUserForm,
|
||||
ExaminationForm,
|
||||
CidUserGroupForm,
|
||||
SupervisorForm,
|
||||
UserUserForm,
|
||||
UserUserGroupForm,
|
||||
)
|
||||
|
||||
from .models import CidUser, CidUserGroup, Examination, QuestionNote, UserUserGroup, get_next_cid
|
||||
from .models import CidUser, CidUserGroup, Examination, QuestionNote, Supervisor, UserGrades, UserProfile, UserUserGroup, get_next_cid
|
||||
|
||||
from rapids.models import Rapid as RapidQuestion
|
||||
from rapids.models import Exam as RapidExam
|
||||
@@ -2500,4 +2505,84 @@ class ExamDeleteBase(RevisionMixin, DeleteView):
|
||||
|
||||
|
||||
def exam_inactive(request, context):
|
||||
return render(request, "exam_inactive.html", context)
|
||||
return render(request, "exam_inactive.html", context)
|
||||
|
||||
#class UserUserCreate(CidManagerRequiredMixin, CreateView):
|
||||
# model = User
|
||||
# form_class = UserUserForm
|
||||
# template_name: str = "generic/user_creation_form.html"
|
||||
#
|
||||
# success_url = reverse_lazy("accounts_list")
|
||||
|
||||
def create_user(request, context=None):
|
||||
# if this is a POST request we need to process the form data
|
||||
if request.method == 'POST':
|
||||
# create a form instance and populate it with data from the request:
|
||||
form = UserUserForm(request.POST)
|
||||
# check whether it's valid:
|
||||
if form.is_valid():
|
||||
try:
|
||||
user_dict = {
|
||||
"username": request.POST["username"],
|
||||
"first_name": request.POST["first_name"],
|
||||
"last_name": request.POST["last_name"],
|
||||
"email": request.POST["username"],
|
||||
"password": secrets.token_hex(nbytes=16)
|
||||
}
|
||||
|
||||
|
||||
new_user = User.objects.create_user(**user_dict)
|
||||
except Exception as error:
|
||||
errors = f"Unable to create account: {error}"
|
||||
return render(request, 'generic/user_creation_form.html', {'form': form, "errors": errors})
|
||||
|
||||
try:
|
||||
|
||||
user_profile = UserProfile.objects.get(user=new_user)
|
||||
user_profile.peninsula_trainee = True
|
||||
#if "supervisor_email" in user:
|
||||
# user_profile.supervisor_email = user["supervisor_email"]
|
||||
#if "supervisor_name" in user:
|
||||
# user_profile.supervisor_name = user["supervisor_name"]
|
||||
|
||||
|
||||
if request.POST["grade"]:
|
||||
grade = UserGrades.objects.get(name=f"ST{ request.POST['grade'] }")
|
||||
user_profile.grade = grade
|
||||
|
||||
user_profile.save()
|
||||
|
||||
except Exception as error:
|
||||
errors = f"Unable to create account profile {error}"
|
||||
return render(request, 'generic/user_creation_form.html', {'form': form, "errors": errors})
|
||||
|
||||
return HttpResponseRedirect(reverse_lazy("accounts_list"))
|
||||
return reverse_lazy("accounts_list")
|
||||
|
||||
# if a GET (or any other method) we'll create a blank form
|
||||
else:
|
||||
form = UserUserForm()
|
||||
|
||||
return render(request, 'generic/user_creation_form.html', {'form': form})
|
||||
|
||||
class SupervisorDetail(CidManagerRequiredMixin, DetailView):
|
||||
model = Supervisor
|
||||
|
||||
|
||||
class SupervisorDelete(CidManagerRequiredMixin, DeleteView):
|
||||
model = Supervisor
|
||||
template_name: str = "confirm_delete.html"
|
||||
success_url = reverse_lazy("generic:supervisor")
|
||||
|
||||
class SupervisorUpdate(CidManagerRequiredMixin, UpdateView):
|
||||
model = Supervisor
|
||||
form_class = SupervisorForm
|
||||
#success_url = reverse_lazy("generic:supervisor_detail", kwargs={'pk': self.pk})
|
||||
|
||||
class SupervisorCreate(CidManagerRequiredMixin, CreateView):
|
||||
model = Supervisor
|
||||
form_class = SupervisorForm
|
||||
#success_url = reverse_lazy("generic:supervisor_detail")
|
||||
|
||||
class SupervisorList(CidManagerRequiredMixin, ListView):
|
||||
model = Supervisor
|
||||
@@ -27,6 +27,8 @@ from rapids import views as rapid_views
|
||||
from anatomy import views as anatomy_views
|
||||
from longs import views as long_views
|
||||
|
||||
from generic import views as generic_views
|
||||
|
||||
from rest_framework import routers
|
||||
|
||||
from django.conf.urls import handler400, handler403, handler404, handler500
|
||||
@@ -61,6 +63,9 @@ urlpatterns = [
|
||||
path(
|
||||
"accounts/bulk_create/", views.accounts_bulk_create, name="accounts_bulk_create"
|
||||
),
|
||||
path(
|
||||
"accounts/create/", generic_views.create_user, name="create_user"
|
||||
),
|
||||
path(
|
||||
"accounts/update/<str:slug>/",
|
||||
views.UpdateUserView.as_view(),
|
||||
|
||||
@@ -525,6 +525,7 @@ class UpdateUserProfileView(CidManagerRequiredMixin, UpdateView):
|
||||
fields = [
|
||||
"supervisor_name",
|
||||
"supervisor_email",
|
||||
"supervisor",
|
||||
"grade",
|
||||
"registration_number",
|
||||
"peninsula_trainee",
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
<div>
|
||||
Grade: {{ user.userprofile.grade }}
|
||||
</div>
|
||||
<div>
|
||||
<div style="border:1px dashed red">
|
||||
Supervisor: {{ user.userprofile.supervisor_name }}<br/>
|
||||
Supervisor Email: {{ user.userprofile.supervisor_email }}<br/>
|
||||
</div>
|
||||
<div>
|
||||
Supervisor: {{ user.userprofile.supervisor }}<br/>
|
||||
</div>
|
||||
<div>
|
||||
Registration number: {{ user.userprofile.registration_number }}
|
||||
</div>
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
</form>
|
||||
</details>
|
||||
{{object_list|length}} Users shown.
|
||||
<ul>
|
||||
<ul id="user-list">
|
||||
{% for list_user in object_list %}
|
||||
<li>Username: <a href="{% url 'account_profile' list_user.username %}">{{ list_user.username }}</a><br/>
|
||||
Name: {{list_user.first_name}} {{list_user.last_name}}<br/>
|
||||
Grade: {{list_user.userprofile.grade}} / Supervisor: {{list_user.userprofile.supervisor_name}} [{{list_user.userprofile.supervisor_email}}]<br/>
|
||||
Registration number: {{list_user.registration_number}}
|
||||
<li><span class="username">Username: <a href="{% url 'account_profile' list_user.username %}">{{ list_user.username }}</a></span>
|
||||
<span class="name">Name: {{list_user.first_name}} {{list_user.last_name}}</span>
|
||||
{% if list_user.userprofile.grade %}<span class="grade">Grade: {{list_user.userprofile.grade}}</span>{% endif %} Supervisor: {{list_user.userprofile.supervisor_name}} [{{list_user.userprofile.supervisor_email}}]
|
||||
<br/> Registration number: {{list_user.registration_number}}
|
||||
<button class="small-url-button"><a href="{% url 'account_update' list_user.username %}">Edit user</a></button>
|
||||
<button class="small-url-button"><a href="{% url 'account_profile_update' list_user.username %}">Edit profile</a></button>
|
||||
|
||||
@@ -30,5 +30,18 @@
|
||||
</ul>
|
||||
|
||||
<a href="{% url 'accounts_bulk_create' %}">Bulk create users</a>
|
||||
<a href="{% url 'create_user' %}">Create single user</a>
|
||||
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block css %}
|
||||
|
||||
<style>
|
||||
#user-list .name, #user-list .grade {
|
||||
padding-left: 50px;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% endblock css %}
|
||||
|
||||
Reference in New Issue
Block a user