Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Add django admin for RestrictedCourseMetadata #970

Merged
merged 1 commit into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 99 additions & 5 deletions enterprise_catalog/apps/catalog/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.contrib import admin
from django.urls import reverse
from django.utils.html import format_html
from django.utils.html import format_html, format_html_join
from django.utils.safestring import mark_safe
from edx_rbac.admin import UserRoleAssignmentAdmin

from enterprise_catalog.apps.catalog.constants import (
Expand All @@ -15,9 +16,20 @@
ContentMetadata,
EnterpriseCatalog,
EnterpriseCatalogRoleAssignment,
RestrictedCourseMetadata,
RestrictedRunAllowedForRestrictedCourse,
)


def _html_list_from_objects(objs, viewname, str_callback=None):
str_callback = str_callback or str
return format_html_join(
sep=mark_safe('<br>'),
format_string='<a href="{}">{}</a>',
args_generator=((reverse(viewname, args=[obj.pk]), str_callback(obj)) for obj in objs),
)


class UnchangeableMixin(admin.ModelAdmin):
"""
Mixin for disabling changing models through the admin
Expand Down Expand Up @@ -59,17 +71,99 @@ class ContentMetadataAdmin(UnchangeableMixin):
)
readonly_fields = (
'associated_content_metadata',
'catalog_queries',
'get_catalog',
'get_catalog_queries',
'get_catalogs',
'get_restricted_courses',
'modified',
)
exclude = (
'catalog_queries',
)

@admin.display(description='Catalog Queries')
def get_catalog_queries(self, obj):
catalog_queries = obj.catalog_queries.all()
return _html_list_from_objects(
objs=catalog_queries,
viewname="admin:catalog_catalogquery_change",
str_callback=lambda cq: cq.short_str_for_listings(),
)

@admin.display(description='Enterprise Catalogs')
def get_catalog(self, obj):
def get_catalogs(self, obj):
catalogs = EnterpriseCatalog.objects.filter(
catalog_query_id__in=obj.catalog_queries.all().values_list('id')
)
return f"{list(catalogs)}"
return _html_list_from_objects(catalogs, "admin:catalog_enterprisecatalog_change")

@admin.display(description='Restricted For Courses')
def get_restricted_courses(self, obj):
restricted_runs_allowed_for_restricted_course = RestrictedRunAllowedForRestrictedCourse.objects.select_related(
'course',
).filter(
run=obj,
)
restricted_courses = (relationship.course for relationship in restricted_runs_allowed_for_restricted_course)
return _html_list_from_objects(restricted_courses, "admin:catalog_contentmetadata_change")


@admin.register(RestrictedCourseMetadata)
class RestrictedCourseMetadataAdmin(UnchangeableMixin):
""" Admin configuration for the custom RestrictedCourseMetadata model. """
list_display = (
'content_key',
'get_catalog_query_for_list',
'get_unrestricted_parent',
)
search_fields = (
'content_key',
'catalog_query',
)
readonly_fields = (
'get_catalog_query',
'get_catalogs',
'get_restricted_runs_allowed',
'modified',
)
exclude = (
'catalog_query',
)

@admin.display(
description='Catalog Query'
)
def get_catalog_query_for_list(self, obj):
link = reverse("admin:catalog_catalogquery_change", args=[obj.catalog_query.id])
return format_html('<a href="{}">{}</a>', link, obj.catalog_query.short_str_for_listings())

@admin.display(
description='Catalog Query'
)
def get_catalog_query(self, obj):
link = reverse("admin:catalog_catalogquery_change", args=[obj.catalog_query.id])
return format_html('<a href="{}">{}</a>', link, obj.catalog_query.pretty_print_content_filter())

@admin.display(
description='Unrestricted Parent'
)
def get_unrestricted_parent(self, obj):
link = reverse("admin:catalog_contentmetadata_change", args=[obj.unrestricted_parent.id])
return format_html('<a href="{}">{}</a>', link, str(obj.unrestricted_parent))

@admin.display(description='Enterprise Catalogs')
def get_catalogs(self, obj):
catalogs = EnterpriseCatalog.objects.filter(catalog_query=obj.catalog_query)
return _html_list_from_objects(catalogs, "admin:catalog_enterprisecatalog_change")

@admin.display(description='Restricted Runs Allowed')
def get_restricted_runs_allowed(self, obj):
restricted_runs_allowed_for_restricted_course = RestrictedRunAllowedForRestrictedCourse.objects.select_related(
'run',
).filter(
course=obj,
)
restricted_runs = (relationship.run for relationship in restricted_runs_allowed_for_restricted_course)
return _html_list_from_objects(restricted_runs, "admin:catalog_contentmetadata_change")


@admin.register(CatalogQuery)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 4.2.16 on 2024-10-11 00:52

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('catalog', '0041_restrictedcoursemetadata_and_more'),
]

operations = [
migrations.AlterModelOptions(
name='historicalrestrictedcoursemetadata',
options={'get_latest_by': ('history_date', 'history_id'), 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Restricted Course Metadata', 'verbose_name_plural': 'historical Restricted Course Metadata'},
),
migrations.AlterModelOptions(
name='restrictedcoursemetadata',
options={'verbose_name': 'Restricted Course Metadata', 'verbose_name_plural': 'Restricted Course Metadata'},
),
]
24 changes: 17 additions & 7 deletions enterprise_catalog/apps/catalog/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ def __str__(self):
f"and content_filter '{self.pretty_print_content_filter()}'>"
)

def short_str_for_listings(self):
"""
Return *short* human-readable string representation for listings.
"""
return (
f"<CatalogQuery: ({self.id}) with UUID '{self.uuid}'>"
)


class EnterpriseCatalog(TimeStampedModel):
"""
Expand Down Expand Up @@ -715,11 +723,7 @@ def __str__(self):
"""
Return human-readable string representation.
"""
return (
"<ContentMetadata for '{content_key}'>".format(
content_key=self.content_key
)
)
return f"<{self.__class__.__name__} for '{self.content_key}'>"


class ContentMetadata(BaseContentMetadata):
Expand Down Expand Up @@ -775,8 +779,8 @@ class RestrictedCourseMetadata(BaseContentMetadata):
.. no_pii:
"""
class Meta:
verbose_name = _("Restricted Content Metadata")
verbose_name_plural = _("Restricted Content Metadata")
verbose_name = _("Restricted Course Metadata")
verbose_name_plural = _("Restricted Course Metadata")
app_label = 'catalog'
unique_together = ('content_key', 'catalog_query')

Expand Down Expand Up @@ -810,6 +814,12 @@ class Meta:
)
history = HistoricalRecords()

def __str__(self):
"""
Return human-readable string representation.
"""
return f"<{self.__class__.__name__} for '{self.content_key}' and CatalogQuery ({self.catalog_query.id})>"


class RestrictedRunAllowedForRestrictedCourse(TimeStampedModel):
"""
Expand Down
Loading