File size: 4,194 Bytes
ffd36e0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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']