Add user-related collections feature with HTMX support and timestamps for collections
This commit is contained in:
@@ -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'),
|
||||
),
|
||||
]
|
||||
@@ -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'),
|
||||
),
|
||||
]
|
||||
@@ -20,7 +20,14 @@
|
||||
hx-swap="innerHTML">
|
||||
Collections to view / take
|
||||
</button>
|
||||
<button class="btn btn-outline-primary ms-2"
|
||||
hx-get="{% url 'atlas:user_related_collections' %}"
|
||||
hx-target="#user-related-collections-placeholder"
|
||||
hx-swap="innerHTML">
|
||||
My collections
|
||||
</button>
|
||||
<div id="user-collections-placeholder" class="mt-3"></div>
|
||||
<div id="user-related-collections-placeholder" class="mt-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Related collections</h5>
|
||||
|
||||
<ul class="list-unstyled">
|
||||
{% for item in related_collections %}
|
||||
<li>
|
||||
<a href="{% url 'atlas:collection_detail' item.collection.pk %}">{{ item.collection.name }}</a>
|
||||
{% if item.is_author %}<span class="badge bg-primary ms-2">Author</span>{% endif %}
|
||||
{% if item.is_marker %}<span class="badge bg-secondary ms-2">Marker</span>{% endif %}
|
||||
{% if item.collection.description %}<small class="text-muted"> — {{ item.collection.description }}</small>{% endif %}
|
||||
</li>
|
||||
{% empty %}
|
||||
<li class="text-muted">No related collections.</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -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/<int:user_pk>/user", views.other_user_uploads, name="other_user_uploads"),
|
||||
path("uploads/all", views.all_uploads, name="all_uploads"),
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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'),
|
||||
),
|
||||
]
|
||||
@@ -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'),
|
||||
),
|
||||
]
|
||||
@@ -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'),
|
||||
),
|
||||
]
|
||||
@@ -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'),
|
||||
),
|
||||
]
|
||||
@@ -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'),
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user