diff --git a/anatomy/migrations/0025_exam_created_exam_updated.py b/anatomy/migrations/0025_exam_created_exam_updated.py new file mode 100644 index 00000000..e9c4aa0c --- /dev/null +++ b/anatomy/migrations/0025_exam_created_exam_updated.py @@ -0,0 +1,25 @@ +# Generated by Django 5.2.7 on 2026-01-26 11:05 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('anatomy', '0024_exam_results_supervisor_visible'), + ] + + operations = [ + migrations.AddField( + model_name='exam', + name='created', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'), + preserve_default=False, + ), + migrations.AddField( + model_name='exam', + name='updated', + field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'), + ), + ] diff --git a/atlas/migrations/0090_casecollection_created_casecollection_updated.py b/atlas/migrations/0090_casecollection_created_casecollection_updated.py new file mode 100644 index 00000000..dc66189f --- /dev/null +++ b/atlas/migrations/0090_casecollection_created_casecollection_updated.py @@ -0,0 +1,25 @@ +# Generated by Django 5.2.7 on 2026-01-26 11:05 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('atlas', '0089_remove_condition_primary_remove_condition_synonym'), + ] + + operations = [ + migrations.AddField( + model_name='casecollection', + name='created', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'), + preserve_default=False, + ), + migrations.AddField( + model_name='casecollection', + name='updated', + field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'), + ), + ] diff --git a/atlas/templates/atlas/index.html b/atlas/templates/atlas/index.html index be43b9bd..1816376b 100644 --- a/atlas/templates/atlas/index.html +++ b/atlas/templates/atlas/index.html @@ -20,7 +20,14 @@ hx-swap="innerHTML"> Collections to view / take +
+ diff --git a/atlas/templates/atlas/partials/_user_related_collections.html b/atlas/templates/atlas/partials/_user_related_collections.html new file mode 100644 index 00000000..d5a2568a --- /dev/null +++ b/atlas/templates/atlas/partials/_user_related_collections.html @@ -0,0 +1,19 @@ +
+
+
Related collections
+ + + +
+
\ No newline at end of file diff --git a/atlas/urls.py b/atlas/urls.py index 2fdcbbee..d21b80ba 100755 --- a/atlas/urls.py +++ b/atlas/urls.py @@ -37,6 +37,7 @@ urlpatterns = [ path("collection/case_search", views.case_search, name="case_search"), path("collection/", views.CollectionView.as_view(), name="collection_view"), path("collection/user", views.user_collections, name="user_collections"), + path("collection/related", views.user_related_collections, name="user_related_collections"), path("uploads", views.user_uploads, name="user_uploads"), path("uploads//user", views.other_user_uploads, name="other_user_uploads"), path("uploads/all", views.all_uploads, name="all_uploads"), diff --git a/atlas/views.py b/atlas/views.py index 0c913aae..15580884 100755 --- a/atlas/views.py +++ b/atlas/views.py @@ -1151,6 +1151,39 @@ def user_collections(request): # endpoint is called by HTMX we prefer returning a small fragment so it # can be swapped into the index page without duplicating layout. + +@login_required +def user_related_collections(request): + """Return up to 10 most recently modified collections where the user + is an author or a marker. If called via HTMX return a fragment suitable + for swapping into the index page. + """ + user = request.user + qs = ( + CaseCollection.objects.filter(Q(author=user) | Q(markers=user)) + .distinct() + .order_by("-updated")[:10] + ) + + related = [] + for c in qs: + related.append( + { + "collection": c, + "is_author": c.author.filter(id=user.id).exists(), + "is_marker": c.markers.filter(id=user.id).exists(), + } + ) + + context = {"related_collections": related} + + is_htmx = getattr(request, "htmx", False) or request.headers.get("HX-Request", "").lower() == "true" + if is_htmx: + html = render_to_string("atlas/partials/_user_related_collections.html", context, request=request) + return HttpResponse(html) + + return render(request, "atlas/user_collections.html", context) + @login_required def collection_options(request): if not request.htmx: diff --git a/generic/models.py b/generic/models.py index 2110b507..c14ea5be 100644 --- a/generic/models.py +++ b/generic/models.py @@ -667,6 +667,9 @@ class ExamOrCollectionGenericBase(models.Model, AuthorMixin): name = models.CharField(max_length=200, help_text="Name of the exam/collection") + created = models.DateTimeField(auto_now_add=True, help_text="Creation timestamp") + updated = models.DateTimeField(auto_now=True, help_text="Last updated timestamp") + start_date = models.DateTimeField( help_text="Date (and time) the exam/collection starts", null=True, blank=True ) diff --git a/longs/migrations/0034_exam_created_exam_updated.py b/longs/migrations/0034_exam_created_exam_updated.py new file mode 100644 index 00000000..a524704e --- /dev/null +++ b/longs/migrations/0034_exam_created_exam_updated.py @@ -0,0 +1,25 @@ +# Generated by Django 5.2.7 on 2026-01-26 11:05 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('longs', '0033_alter_longseriesimage_image_md5_hash'), + ] + + operations = [ + migrations.AddField( + model_name='exam', + name='created', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'), + preserve_default=False, + ), + migrations.AddField( + model_name='exam', + name='updated', + field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'), + ), + ] diff --git a/physics/migrations/0018_exam_created_exam_updated.py b/physics/migrations/0018_exam_created_exam_updated.py new file mode 100644 index 00000000..1ebabb89 --- /dev/null +++ b/physics/migrations/0018_exam_created_exam_updated.py @@ -0,0 +1,25 @@ +# Generated by Django 5.2.7 on 2026-01-26 11:05 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('physics', '0017_exam_results_supervisor_visible'), + ] + + operations = [ + migrations.AddField( + model_name='exam', + name='created', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'), + preserve_default=False, + ), + migrations.AddField( + model_name='exam', + name='updated', + field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'), + ), + ] diff --git a/rapids/migrations/0017_exam_created_exam_updated.py b/rapids/migrations/0017_exam_created_exam_updated.py new file mode 100644 index 00000000..4d6b0683 --- /dev/null +++ b/rapids/migrations/0017_exam_created_exam_updated.py @@ -0,0 +1,25 @@ +# Generated by Django 5.2.7 on 2026-01-26 11:05 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('rapids', '0016_exam_results_supervisor_visible'), + ] + + operations = [ + migrations.AddField( + model_name='exam', + name='created', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'), + preserve_default=False, + ), + migrations.AddField( + model_name='exam', + name='updated', + field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'), + ), + ] diff --git a/sbas/migrations/0023_exam_created_exam_updated.py b/sbas/migrations/0023_exam_created_exam_updated.py new file mode 100644 index 00000000..5c1e70b7 --- /dev/null +++ b/sbas/migrations/0023_exam_created_exam_updated.py @@ -0,0 +1,25 @@ +# Generated by Django 5.2.7 on 2026-01-26 11:05 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sbas', '0022_question_frcr_appropriate'), + ] + + operations = [ + migrations.AddField( + model_name='exam', + name='created', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'), + preserve_default=False, + ), + migrations.AddField( + model_name='exam', + name='updated', + field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'), + ), + ] diff --git a/shorts/migrations/0011_exam_created_exam_updated.py b/shorts/migrations/0011_exam_created_exam_updated.py new file mode 100644 index 00000000..51fedf82 --- /dev/null +++ b/shorts/migrations/0011_exam_created_exam_updated.py @@ -0,0 +1,25 @@ +# Generated by Django 5.2.7 on 2026-01-26 11:05 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('shorts', '0010_alter_useranswer_candidate_feedback_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='exam', + name='created', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'), + preserve_default=False, + ), + migrations.AddField( + model_name='exam', + name='updated', + field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'), + ), + ]