Implement hiding and showing functionality for user exams and collections

This commit is contained in:
Ross
2026-06-15 11:23:00 +01:00
parent 35ab7443d2
commit c50ace771e
11 changed files with 400 additions and 50 deletions
+30
View File
@@ -0,0 +1,30 @@
# Generated by Django 6.0.1 on 2026-06-15 09:44
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('generic', '0032_ciduserexam_shared_with_users'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='UserHiddenItem',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('object_id', models.PositiveIntegerField()),
('created_at', models.DateTimeField(auto_now_add=True)),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='hidden_items', to=settings.AUTH_USER_MODEL)),
],
options={
'constraints': [models.UniqueConstraint(fields=('user', 'content_type', 'object_id'), name='unique_user_hidden_item')],
},
),
]
+31
View File
@@ -698,6 +698,12 @@ class ExamOrCollectionGenericBase(models.Model, AuthorMixin):
default=True,
)
@property
def content_type_id(self) -> int:
from django.contrib.contenttypes.models import ContentType
return ContentType.objects.get_for_model(self).id
authors_only = models.BooleanField(
help_text="If true only exam/collection authors will be able to view.",
default=False,
@@ -2390,3 +2396,28 @@ class FindingBase(models.Model):
return get_pretty_json(json.loads(self.viewport_json))
except Exception:
return ""
class UserHiddenItem(models.Model):
"""Model to track which exams or collections have been hidden by a user.
"""
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="hidden_items",
)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey("content_type", "object_id")
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
constraints = [
models.UniqueConstraint(
fields=["user", "content_type", "object_id"],
name="unique_user_hidden_item",
)
]
def __str__(self):
return f"{self.user} hid {self.content_object}"
+1
View File
@@ -11,6 +11,7 @@ urlpatterns = [
# User content review views
path("user-content/", views.user_content_list, name="user_content_list"),
path("user-content/<int:user_id>/", views.user_content_review, name="user_content_review"),
path("toggle-hide-item/", views.toggle_hide_item, name="toggle_hide_item"),
path("examination/", views.ExaminationView.as_view(), name="examination_view"),
path("examination/<int:pk>", views.examination_detail, name="examination_detail"),
path(
+39
View File
@@ -7114,4 +7114,43 @@ def user_content_review(request, user_id):
# Render HTMX partial (or full page if not HTMX)
template = "generic/partials/user_content_review.html"
return render(request, template, context)
@login_required
@require_POST
def toggle_hide_item(request):
"""Toggle the hidden status of an exam or collection for the current user.
Scope: Authenticated end users.
Functionality: Adds or removes a UserHiddenItem record for the given
content_type_id and object_id, then triggers a page reload via HX-Refresh.
"""
from django.contrib.contenttypes.models import ContentType
from generic.models import UserHiddenItem
content_type_id = request.POST.get("content_type_id")
object_id = request.POST.get("object_id")
if not content_type_id or not object_id:
return HttpResponse("Missing parameters", status=400)
try:
content_type = ContentType.objects.get(pk=int(content_type_id))
object_id = int(object_id)
except (ContentType.DoesNotExist, ValueError):
return HttpResponse("Invalid parameters", status=400)
hidden_item, created = UserHiddenItem.objects.get_or_create(
user=request.user,
content_type=content_type,
object_id=object_id,
)
if not created:
hidden_item.delete()
response = HttpResponse("")
response["HX-Refresh"] = "true"
return response