arifRB's picture
Deploy GapGuide backend (Docker)
ffd36e0 verified
Raw
History Blame Contribute Delete
4.19 kB
from django import forms
from django.contrib import admin, messages
from django.db import transaction
from django.db.models import Max
from .models import Resource, ResourceCheckpoint, SkillResource
class SkillResourceInline(admin.TabularInline):
model = SkillResource
extra = 1
autocomplete_fields = ['skill']
class ResourceCheckpointInline(admin.TabularInline):
model = ResourceCheckpoint
extra = 0
fields = ('order_index', 'title', 'url_fragment', 'estimated_minutes', 'source')
ordering = ('order_index',)
class ResourceAdminForm(forms.ModelForm):
bulk_checkpoints = forms.CharField(
required=False,
widget=forms.Textarea(attrs={'rows': 12, 'cols': 80}),
label='Bulk add checkpoints',
help_text=(
'Paste module/lesson titles, one per line (source=manual). '
'Only applied when this resource has NO checkpoints yet; if it '
'already has any, the paste is ignored — edit the inline rows '
'below instead. Blank lines ignored.'
),
)
class Meta:
model = Resource
exclude = ['skills']
@admin.register(Resource)
class ResourceAdmin(admin.ModelAdmin):
form = ResourceAdminForm
list_display = ('title', 'provider', 'type', 'difficulty_level', 'duration', 'rating')
list_filter = ('provider', 'type', 'difficulty_level')
search_fields = ('title', 'provider', 'url')
inlines = [SkillResourceInline, ResourceCheckpointInline]
fieldsets = (
(None, {
'fields': ('title', 'provider', 'url', 'type', 'difficulty_level',
'duration', 'rating'),
}),
('Bulk checkpoint paste', {
'classes': ('collapse',),
'fields': ('bulk_checkpoints',),
'description': 'Optional shortcut for adding multiple checkpoints at once.',
}),
)
def save_model(self, request, obj, form, change):
bulk = (form.cleaned_data.get('bulk_checkpoints') or '').strip()
lines = [line.strip() for line in bulk.splitlines() if line.strip()] if bulk else []
with transaction.atomic():
super().save_model(request, obj, form, change)
if not lines:
return
# Refuse to append when checkpoints already exist — the admin
# should use the inline to edit existing rows. This prevents
# accidental duplication and silent orphaning of
# UserCheckpointProgress rows when the admin re-edits the list.
if obj.checkpoints.exists():
self.message_user(
request,
"Bulk paste ignored: this resource already has checkpoints. "
"Edit them via the inline below instead.",
level=messages.WARNING,
)
return
current_max = obj.checkpoints.aggregate(m=Max('order_index'))['m'] or 0
ResourceCheckpoint.objects.bulk_create([
ResourceCheckpoint(
resource=obj,
order_index=current_max + offset,
title=line,
source='manual',
)
for offset, line in enumerate(lines, start=1)
])
self.message_user(
request,
f"Added {len(lines)} checkpoint(s) via bulk paste.",
level=messages.SUCCESS,
)
@admin.register(ResourceCheckpoint)
class ResourceCheckpointAdmin(admin.ModelAdmin):
list_display = ('resource', 'order_index', 'title', 'source', 'estimated_minutes')
list_filter = ('source', 'resource__provider')
search_fields = ('title', 'resource__title')
ordering = ('resource', 'order_index')
@admin.register(SkillResource)
class SkillResourceAdmin(admin.ModelAdmin):
list_display = ('skill', 'resource', 'relevance_score')
list_filter = ('skill__category',)
search_fields = ('skill__skill_name', 'resource__title')
autocomplete_fields = ['skill', 'resource']