a number of updates
This commit is contained in:
+8
-2
@@ -50,6 +50,7 @@ class UserUserFilter(django_filters.FilterSet):
|
||||
#"userprofile__grade": ["exact"],
|
||||
#"userprofile__supervisor": ["exact"],
|
||||
"email": ["contains"],
|
||||
"is_active": ["exact"]
|
||||
}
|
||||
|
||||
@property
|
||||
@@ -57,11 +58,16 @@ class UserUserFilter(django_filters.FilterSet):
|
||||
parent = super().qs
|
||||
|
||||
## filter_active = getattr(self.request, 'active', True)
|
||||
#if "active" not in self.request.GET:
|
||||
# return parent.filter(active=True)
|
||||
if "is_active" not in self.request.GET:
|
||||
return parent.filter(is_active=True)
|
||||
|
||||
return parent
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(UserUserFilter, self).__init__(*args, **kwargs)
|
||||
self.form.initial['is_active'] = True
|
||||
|
||||
|
||||
class ExaminationFilter(django_filters.FilterSet):
|
||||
class Meta:
|
||||
model = Examination
|
||||
|
||||
@@ -18,16 +18,7 @@
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<div id="table-div">
|
||||
<span id="manage-span">
|
||||
{% render_table table %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<a href="{% url 'accounts_bulk_create' %}">Bulk create users</a>
|
||||
<a href="{% url 'create_user' %}">Create single user</a>
|
||||
|
||||
<details>
|
||||
<details class="bulk-edit">
|
||||
<summary>
|
||||
Bulk edit
|
||||
</summary>
|
||||
@@ -39,19 +30,47 @@
|
||||
hx-include="[name='selection']"
|
||||
hx-confirm="This will delete supervisors from all selected users, are you sure you wish to continue?"
|
||||
hx-target="#htmx-info"
|
||||
_='on click put "" into #htmx-options'
|
||||
>Delete supervisors</button>
|
||||
<button id="bulk-edit-grade-button"
|
||||
hx-post="{% url 'generic:users_bulk_edit' %}"
|
||||
hx-include="[name='selection']"
|
||||
hx-target="#htmx-options"
|
||||
title="Changes the selected users grade."
|
||||
|
||||
>Edit grade</button>
|
||||
<button id="bulk-add-group-button"
|
||||
hx-post="{% url 'generic:users_bulk_edit' %}"
|
||||
hx-include="[name='selection']"
|
||||
hx-target="#htmx-options"
|
||||
title="Adds the selected user to a group."
|
||||
|
||||
>Add group</button>
|
||||
<button id="bulk-remove-group-button"
|
||||
hx-post="{% url 'generic:users_bulk_edit' %}"
|
||||
hx-include="[name='selection']"
|
||||
hx-target="#htmx-options"
|
||||
title="Removes the selected user from a group."
|
||||
|
||||
>Remove group</button>
|
||||
<button id="bulk-deactivate-user-button"
|
||||
hx-post="{% url 'generic:users_bulk_edit' %}"
|
||||
hx-include="[name='selection']"
|
||||
hx-target="#htmx-options"
|
||||
hx-confirm="This will deactivate all selected users, are you sure you wish to continue?"
|
||||
title="Deactivates the selected users"
|
||||
|
||||
>Deactivate</button>
|
||||
</details>
|
||||
|
||||
<div id="table-div">
|
||||
<span id="manage-span">
|
||||
{% render_table table %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<a href="{% url 'accounts_bulk_create' %}">Bulk create users</a>
|
||||
<a href="{% url 'create_user' %}">Create single user</a>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
+113
-66
@@ -208,7 +208,6 @@ def examination_merge(request, pk):
|
||||
if examination.merge_into(examination_to_merge_into):
|
||||
success = True
|
||||
|
||||
|
||||
else:
|
||||
examination_to_merge_into = False
|
||||
return render(
|
||||
@@ -218,7 +217,7 @@ def examination_merge(request, pk):
|
||||
"form": form,
|
||||
"examination": examination,
|
||||
"examination_to_merge_into": examination_to_merge_into,
|
||||
"success": success
|
||||
"success": success,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -2474,83 +2473,131 @@ def users_bulk_delete_supervisors(request):
|
||||
return HttpResponse("No users selected", content_type="text/plain")
|
||||
|
||||
|
||||
class NoUsersSelected(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_user_selection_from_request(request):
|
||||
selected_users = request.POST.getlist("selection")
|
||||
|
||||
if not selected_users:
|
||||
raise NoUsersSelected
|
||||
user_models = User.objects.filter(id__in=selected_users)
|
||||
return user_models
|
||||
|
||||
|
||||
@user_is_cid_user_manager
|
||||
def users_bulk_edit(request):
|
||||
print(request.htmx.trigger)
|
||||
print(request.htmx.trigger_name)
|
||||
match request.htmx.trigger:
|
||||
case r if r is None:
|
||||
return HttpResponse("None", content_type="text/html")
|
||||
|
||||
case "bulk-edit-grade-button":
|
||||
user_grades = UserGrades.objects.all()
|
||||
try:
|
||||
match request.htmx.trigger:
|
||||
case r if r is None:
|
||||
html = "None"
|
||||
case "bulk-deactivate-user-button":
|
||||
user_models = get_user_selection_from_request(request)
|
||||
|
||||
html = "".join(
|
||||
[
|
||||
f"""<button class='change-grade-button' id='add-grade--{grade.id}'
|
||||
hx-post="{reverse('generic:users_bulk_edit')}"
|
||||
hx-include="[name='selection']"
|
||||
hx-confirm="This will modify grades of all selected users, are you sure you wish to continue?"
|
||||
hx-target="#htmx-info"
|
||||
>{grade.name}</button>"""
|
||||
for grade in user_grades
|
||||
]
|
||||
)
|
||||
# TODO: work out how to actually use hyperscript
|
||||
html = (
|
||||
html
|
||||
+ "<button _='on click for el in .change-grade-button remove el end then remove me'>Cancel</button>"
|
||||
)
|
||||
# u: User
|
||||
for u in user_models:
|
||||
u.is_active = False
|
||||
u.save()
|
||||
|
||||
return HttpResponse(html, content_type="text/html")
|
||||
case r if r.startswith("add-grade"):
|
||||
selected_users = request.POST.getlist("selection")
|
||||
html = "Users deactivated"
|
||||
|
||||
if not selected_users:
|
||||
return HttpResponse("No users selected", content_type="text/html")
|
||||
user_models = User.objects.filter(id__in=selected_users)
|
||||
case "bulk-edit-grade-button":
|
||||
user_grades = UserGrades.objects.all()
|
||||
|
||||
# u: User
|
||||
for u in user_models:
|
||||
u.userprofile.grade_id = r.split("--")[-1]
|
||||
u.save()
|
||||
return HttpResponse("Grades update", content_type="text/html")
|
||||
case "bulk-add-group-button":
|
||||
user_groups = UserUserGroup.objects.all()
|
||||
html = "".join(
|
||||
[
|
||||
f"""<button class='change-grade-button' id='add-grade--{grade.id}'
|
||||
hx-post="{reverse('generic:users_bulk_edit')}"
|
||||
hx-include="[name='selection']"
|
||||
hx-confirm="This will modify grades of all selected users, are you sure you wish to continue?"
|
||||
hx-target="#htmx-info"
|
||||
_='on click put "" into #htmx-options'
|
||||
>{grade.name}</button>"""
|
||||
for grade in user_grades
|
||||
]
|
||||
)
|
||||
# TODO: work out how to actually use hyperscript
|
||||
html = (
|
||||
html
|
||||
+ "<button class='cancel-button' _='on click for el in .change-grade-button remove el end then remove me'>Cancel</button>"
|
||||
)
|
||||
|
||||
html = "".join(
|
||||
[
|
||||
f"""<button class='add-group-button' id='add-group--{group.id}'
|
||||
hx-post="{reverse('generic:users_bulk_edit')}"
|
||||
hx-include="[name='selection']"
|
||||
hx-confirm="This will add the group '{group.name}' to all selected users, are you sure you wish to continue?"
|
||||
hx-target="#htmx-info"
|
||||
>{group.name}</button>"""
|
||||
for group in user_groups
|
||||
]
|
||||
)
|
||||
# TODO: work out how to actually use hyperscript
|
||||
html = (
|
||||
html
|
||||
+ "<button _='on click for el in .add-group-button remove el end then remove me'>Cancel</button>"
|
||||
)
|
||||
case r if r.startswith("add-grade"):
|
||||
user_models = get_user_selection_from_request(request)
|
||||
|
||||
return HttpResponse(html, content_type="text/html")
|
||||
case r if r.startswith("add-group"):
|
||||
selected_users = request.POST.getlist("selection")
|
||||
# u: User
|
||||
for u in user_models:
|
||||
u.userprofile.grade_id = r.split("--")[-1]
|
||||
u.save()
|
||||
html = "Grades updated"
|
||||
case "bulk-add-group-button":
|
||||
user_groups = UserUserGroup.objects.all()
|
||||
|
||||
if not selected_users:
|
||||
return HttpResponse("No users selected", content_type="text/html")
|
||||
user_models = User.objects.filter(id__in=selected_users)
|
||||
html = "".join(
|
||||
[
|
||||
f"""<button class='add-group-button' id='add-group--{group.id}'
|
||||
hx-post="{reverse('generic:users_bulk_edit')}"
|
||||
hx-include="[name='selection']"
|
||||
hx-confirm="This will add the group '{group.name}' to all selected users, are you sure you wish to continue?"
|
||||
hx-target="#htmx-info"
|
||||
_='on click put "" into #htmx-options'
|
||||
>{group.name}</button>"""
|
||||
for group in user_groups
|
||||
]
|
||||
)
|
||||
# TODO: work out how to actually use hyperscript
|
||||
html = (
|
||||
html
|
||||
+ "<button class='cancel-button'_='on click for el in .add-group-button remove el end then remove me'>Cancel</button>"
|
||||
)
|
||||
|
||||
# u: User
|
||||
for u in user_models:
|
||||
pass
|
||||
u.user_groups.add(r.split("--")[-1])
|
||||
u.save()
|
||||
return HttpResponse("Group added", content_type="text/html")
|
||||
case _:
|
||||
return HttpResponse("Error", content_type="text/html")
|
||||
case "bulk-remove-group-button":
|
||||
user_groups = UserUserGroup.objects.all()
|
||||
|
||||
html = "".join(
|
||||
[
|
||||
f"""<button class='remove-group-button' id='remove-group--{group.id}'
|
||||
hx-post="{reverse('generic:users_bulk_edit')}"
|
||||
hx-include="[name='selection']"
|
||||
hx-confirm="This will remove the group '{group.name}' from all selected users, are you sure you wish to continue?"
|
||||
hx-target="#htmx-info"
|
||||
_='on click put "" into #htmx-options'
|
||||
>{group.name}</button>"""
|
||||
for group in user_groups
|
||||
]
|
||||
)
|
||||
# TODO: work out how to actually use hyperscript
|
||||
html = (
|
||||
html
|
||||
+ "<button class='cancel-button'_='on click for el in .add-group-button remove el end then remove me'>Cancel</button>"
|
||||
)
|
||||
|
||||
case r if r.startswith("add-group"):
|
||||
user_models = get_user_selection_from_request(request)
|
||||
|
||||
# u: User
|
||||
for u in user_models:
|
||||
pass
|
||||
u.user_groups.add(r.split("--")[-1])
|
||||
u.save()
|
||||
html = "Group added"
|
||||
case r if r.startswith("remove-group"):
|
||||
user_models = get_user_selection_from_request(request)
|
||||
|
||||
# u: User
|
||||
for u in user_models:
|
||||
group_id = r.split("--")[-1]
|
||||
u.user_groups.remove(group_id)
|
||||
html = "Group removed"
|
||||
case _:
|
||||
html = "None"
|
||||
return HttpResponse(html, content_type="text/html")
|
||||
except NoUsersSelected:
|
||||
return HttpResponse("No users selected", content_type="text/html")
|
||||
|
||||
|
||||
@user_is_cid_user_manager
|
||||
|
||||
+47
-26
@@ -588,6 +588,7 @@ td.user-answer-score-2.rapid-ans::after {
|
||||
.series-block-popup-link {
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.series-block-popup-link a {
|
||||
color: rgb(0, 153, 255);
|
||||
opacity: 50%;
|
||||
@@ -758,7 +759,7 @@ input {
|
||||
.sba-finish-list a {
|
||||
text-decoration: none;
|
||||
color: unset;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.sba-finish-list span {
|
||||
@@ -915,7 +916,10 @@ summary h5 {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
button a, button a:link, button a:visited, button a:hover {
|
||||
button a,
|
||||
button a:link,
|
||||
button a:visited,
|
||||
button a:hover {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
@@ -929,17 +933,17 @@ details.filter {
|
||||
/* Generic default styling for forms */
|
||||
|
||||
/* Highlight form errors */
|
||||
tr:has(.errorlist){
|
||||
border: 1px dashed red;
|
||||
tr:has(.errorlist) {
|
||||
border: 1px dashed red;
|
||||
}
|
||||
|
||||
.errorlist + input {
|
||||
background-color: red;
|
||||
color: darkblue;
|
||||
.errorlist+input {
|
||||
background-color: red;
|
||||
color: darkblue;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
border: 1px dashed red;
|
||||
border: 1px dashed red;
|
||||
|
||||
}
|
||||
|
||||
@@ -954,7 +958,7 @@ tr:has(.errorlist){
|
||||
opacity: 25%;
|
||||
}
|
||||
|
||||
.control-group:hover .help-block{
|
||||
.control-group:hover .help-block {
|
||||
opacity: 100%;
|
||||
}
|
||||
|
||||
@@ -971,7 +975,12 @@ form .submit-button {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
@@ -986,24 +995,23 @@ h1, h2, h3, h4, h5, h6 {
|
||||
}
|
||||
|
||||
|
||||
.cid-candidate-list div {
|
||||
}
|
||||
.cid-candidate-list div {}
|
||||
|
||||
.stamp-white {
|
||||
display: inline-block;
|
||||
z-index:1;
|
||||
font-family:Arial,sans-serif;
|
||||
transform: rotate(-15deg);
|
||||
font-size:20px;
|
||||
color:white;
|
||||
border:solid 2px white;
|
||||
padding:5px;
|
||||
border-radius:5px;
|
||||
zoom:1;
|
||||
filter:alpha(opacity=20);
|
||||
opacity:0.9;
|
||||
text-shadow: 0 0 2px white;
|
||||
box-shadow: 0 0 2px white;
|
||||
display: inline-block;
|
||||
z-index: 1;
|
||||
font-family: Arial, sans-serif;
|
||||
transform: rotate(-15deg);
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
border: solid 2px white;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
zoom: 1;
|
||||
filter: alpha(opacity=20);
|
||||
opacity: 0.9;
|
||||
text-shadow: 0 0 2px white;
|
||||
box-shadow: 0 0 2px white;
|
||||
}
|
||||
|
||||
.self-feedback-block {
|
||||
@@ -1018,4 +1026,17 @@ h1, h2, h3, h4, h5, h6 {
|
||||
.collection-name-blend {
|
||||
opacity: 70%;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.cancel-button {
|
||||
color: darkblue;
|
||||
border-color: darkblue;
|
||||
}
|
||||
|
||||
.bulk-edit {
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
background-color: black;
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
+1
-1
@@ -588,7 +588,7 @@ class DeleteUserView(CidManagerRequiredMixin, DeleteView):
|
||||
|
||||
class UpdateUserView(CidManagerRequiredMixin, UpdateView):
|
||||
model = User
|
||||
fields = ["first_name", "last_name", "email"] # Keep listing whatever fields
|
||||
fields = ["first_name", "last_name", "email", "is_active"] # Keep listing whatever fields
|
||||
# the combined UserProfile and User exposes.
|
||||
template_name = "user_update.html"
|
||||
slug_field = "username"
|
||||
|
||||
Reference in New Issue
Block a user