Skip to content

Commit

Permalink
feat: add support for Django 4.2
Browse files Browse the repository at this point in the history
  • Loading branch information
Muhammad Soban Javed committed Sep 19, 2023
1 parent 8726b46 commit 6a9142d
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 39 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ jobs:
strategy:
matrix:
python-version: ["3.8"]
django-version: ["pinned", "4.2"]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
Expand All @@ -21,7 +22,12 @@ jobs:
- name: Install requirements
run: make requirements
- name: Upgrade packages
run: pip install -U pip wheel codecov
run: |
pip install -U pip wheel codecov
if [[ "${{ matrix.django-version }}" != "pinned" ]]; then
pip install "django~=${{ matrix.django-version }}.0"
pip check # fail if this test-reqs/Django combination is broken
fi
- name: Validate translations
run: make validate_translations
- name: Run tests
Expand Down
4 changes: 2 additions & 2 deletions license_manager/apps/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
All API URLs should be versioned, so urlpatterns should only
contain namespaces for the active versions of the API.
"""
from django.urls import include, re_path
from django.urls import include, path

from license_manager.apps.api.v1 import urls as v1_urls


app_name = 'api'
urlpatterns = [
re_path(r'^v1/', include(v1_urls)),
path('v1/', include(v1_urls)),
]
4 changes: 1 addition & 3 deletions license_manager/apps/core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from license_manager.apps.core.models import User


@admin.register(User)
class CustomUserAdmin(UserAdmin):
""" Admin configuration for the custom User model. """
list_display = ('username', 'email', 'full_name', 'first_name', 'last_name', 'is_staff')
Expand All @@ -17,6 +18,3 @@ class CustomUserAdmin(UserAdmin):
'groups', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)


admin.site.register(User, CustomUserAdmin)
90 changes: 67 additions & 23 deletions license_manager/apps/subscriptions/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,33 +81,45 @@ def get_queryset(self, request):
'subscription_plan',
)

@admin.display(
description='Subscription Plan'
)
def get_subscription_plan_title(self, obj):
return get_related_object_link(
'admin:subscriptions_subscriptionplan_change',
obj.subscription_plan.uuid,
obj.subscription_plan.title,
)
get_subscription_plan_title.short_description = 'Subscription Plan'

@admin.display(
description='License renewed to'
)
def get_renewed_to(self, obj):
"""
Returns License renewed to
"""
if not obj.renewed_to:
return ''
return get_related_object_link(
'admin:subscriptions_license_change',
obj.renewed_to.uuid,
obj.renewed_to.uuid,
)
get_renewed_to.short_description = 'License renewed to'

@admin.display(
description='License renewed from'
)
def get_renewed_from(self, obj):
"""
Returns License renewed from
"""
if not obj.renewed_from:
return ''
return get_related_object_link(
'admin:subscriptions_license_change',
obj.renewed_from.uuid,
obj.renewed_from.uuid,
)
get_renewed_from.short_description = 'License renewed from'

def _parse_snapshot_timestamp(self):
"""
Expand All @@ -120,6 +132,9 @@ def _parse_snapshot_timestamp(self):
# pylint: disable=no-value-for-parameter
return UTC.localize(snapshot_datetime)

@admin.action(
description='Revert licenses to snapshot'
)
def revert_licenses_to_snapshot_time(self, request, queryset):
"""
Sets a license back to whatever it was at some timestamp defined in config.
Expand All @@ -140,7 +155,6 @@ def revert_licenses_to_snapshot_time(self, request, queryset):
)
except Exception as exc: # pylint: disable=broad-except
messages.add_message(request, messages.ERROR, exc)
revert_licenses_to_snapshot_time.short_description = 'Revert licenses to snapshot'


@admin.register(SubscriptionPlan)
Expand Down Expand Up @@ -253,6 +267,9 @@ def get_readonly_fields(self, request, obj=None):
return self.read_only_fields
return ()

@admin.display(
description='Customer Agreement'
)
def get_customer_agreement_link(self, obj):
"""
Returns a link to the customer agreement for this plan.
Expand All @@ -264,7 +281,6 @@ def get_customer_agreement_link(self, obj):
obj.customer_agreement.enterprise_customer_slug,
)
return ''
get_customer_agreement_link.short_description = 'Customer Agreement'

def formfield_for_foreignkey(self, db_field, request, **kwargs):
"""
Expand All @@ -274,6 +290,9 @@ def formfield_for_foreignkey(self, db_field, request, **kwargs):
kwargs['queryset'] = CustomerAgreement.objects.filter().order_by('enterprise_customer_slug')
return super().formfield_for_foreignkey(db_field, request, **kwargs)

@admin.action(
description='Freeze selected Subscription Plans (deletes unused licenses)'
)
def process_unused_licenses_post_freeze(self, request, queryset):
"""
Used as an action; this function deletes unused licenses after a plan is frozen.
Expand All @@ -285,9 +304,6 @@ def process_unused_licenses_post_freeze(self, request, queryset):
messages.add_message(request, messages.SUCCESS, 'Successfully froze selected Subscription Plans.')
except UnprocessableSubscriptionPlanFreezeError as exc:
messages.add_message(request, messages.ERROR, exc)
process_unused_licenses_post_freeze.short_description = (
'Freeze selected Subscription Plans (deletes unused licenses)'
)

def save_model(self, request, obj, form, change):
# Record change reason for simple history
Expand Down Expand Up @@ -344,6 +360,9 @@ class CustomerAgreementAdmin(admin.ModelAdmin):
)
actions = ['sync_agreement_with_enterprise_customer']

@admin.action(
description='Sync enterprise customer fields for selected records'
)
def sync_agreement_with_enterprise_customer(self, request, queryset):
"""
Django action handler to sync any updates made to the enterprise customer
Expand All @@ -364,8 +383,6 @@ def sync_agreement_with_enterprise_customer(self, request, queryset):
except CustomerAgreementError as exc:
messages.add_message(request, messages.ERROR, exc)

sync_agreement_with_enterprise_customer.short_description = 'Sync enterprise customer fields for selected records'

def save_model(self, request, obj, form, change):
"""
Saves the CustomerAgreement instance.
Expand Down Expand Up @@ -399,6 +416,9 @@ def get_readonly_fields(self, request, obj=None):
'get_subscription_plan_links',
)

@admin.display(
description='Subscription Plans'
)
def get_subscription_plan_links(self, obj):
"""
Gets links to all active subscription plans for this customer agreement.
Expand All @@ -414,7 +434,6 @@ def get_subscription_plan_links(self, obj):
)
)
return mark_safe(' '.join(links))
get_subscription_plan_links.short_description = 'Subscription Plans'


@admin.register(SubscriptionPlanRenewal)
Expand Down Expand Up @@ -444,33 +463,59 @@ class SubscriptionPlanRenewalAdmin(DjangoQLSearchMixin, admin.ModelAdmin):
)
actions = ['process_renewal']

@admin.action(
description='Process selected renewal records'
)
def process_renewal(self, request, queryset):
"""
Process selected renewal records
"""
for renewal in queryset:
renew_subscription(renewal)
process_renewal.short_description = 'Process selected renewal records'

@admin.display(
description='Subscription Title',
ordering='prior_subscription_plan__title',
)
def get_prior_subscription_plan_title(self, obj):
"""
Returns Subscription Title
"""
return obj.prior_subscription_plan.title
get_prior_subscription_plan_title.short_description = 'Subscription Title'
get_prior_subscription_plan_title.admin_order_field = 'prior_subscription_plan__title'

@admin.display(
description='Subscription UUID',
ordering='prior_subscription_plan__uuid',
)
def get_prior_subscription_plan_uuid(self, obj):
"""
Returns Subscription UUID
"""
return obj.prior_subscription_plan.uuid
get_prior_subscription_plan_uuid.short_description = 'Subscription UUID'
get_prior_subscription_plan_uuid.admin_order_field = 'prior_subscription_plan__uuid'

@admin.display(
description='Enterprise Customer UUID',
ordering='prior_subscription_plan__enterprise_customer_uuid',
)
def get_prior_subscription_plan_enterprise_customer(self, obj):
"""
Returns Enterprise Customer UUID
"""
return obj.prior_subscription_plan.enterprise_customer_uuid
get_prior_subscription_plan_enterprise_customer.short_description = 'Enterprise Customer UUID'
get_prior_subscription_plan_enterprise_customer.admin_order_field = \
'prior_subscription_plan__enterprise_customer_uuid'

@admin.display(
description='Enterprise Catalog UUID',
ordering='prior_subscription_plan__enterprise_catalog_uuid',
)
def get_prior_subscription_plan_enterprise_catalog(self, obj):
"""
Returns Enterprise Catalog UUID
"""
return obj.prior_subscription_plan.enterprise_catalog_uuid
get_prior_subscription_plan_enterprise_catalog.short_description = 'Enterprise Catalog UUID'
get_prior_subscription_plan_enterprise_catalog.admin_order_field = \
'prior_subscription_plan__enterprise_catalog_uuid'

@admin.display(
description='Renewed Subscription Plan'
)
def get_renewed_plan_link(self, obj):
"""
Returns a link to the renewed subscription plan.
Expand All @@ -482,7 +527,6 @@ def get_renewed_plan_link(self, obj):
'{}: {}'.format(obj.renewed_subscription_plan.title, obj.renewed_subscription_plan.uuid),
)
return ''
get_renewed_plan_link.short_description = 'Renewed Subscription Plan'

def has_change_permission(self, request, obj=None):
"""
Expand Down
1 change: 0 additions & 1 deletion license_manager/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,6 @@


DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
DEFAULT_HASHING_ALGORITHM = "sha1"

DEFAULT_DAYS_BEFORE_LICENSE_PURGE = 90

Expand Down
18 changes: 9 additions & 9 deletions license_manager/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from auth_backends.urls import oauth2_urlpatterns
from django.conf import settings
from django.contrib import admin
from django.urls import include, re_path
from django.urls import include, path
from drf_yasg.views import get_schema_view
from edx_api_doc_tools import make_api_info
from rest_framework import permissions
Expand All @@ -38,18 +38,18 @@
)

urlpatterns = [
re_path(r'', include(oauth2_urlpatterns)),
re_path(r'', include('csrf.urls')), # Include csrf urls from edx-drf-extensions
re_path(r'^admin/', admin.site.urls),
re_path(r'^api/', include(api_urls)),
re_path(r'^api-docs/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
re_path(r'^auto_auth/$', core_views.AutoAuth.as_view(), name='auto_auth'),
re_path(r'^health/$', core_views.health, name='health'),
path('', include(oauth2_urlpatterns)),
path('', include('csrf.urls')), # Include csrf urls from edx-drf-extensions
path('admin/', admin.site.urls),
path('api/', include(api_urls)),
path('api-docs/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
path('auto_auth/', core_views.AutoAuth.as_view(), name='auto_auth'),
path('health/', core_views.health, name='health'),
]


if settings.DEBUG and os.environ.get('ENABLE_DJANGO_TOOLBAR', False): # pragma: no cover
# Disable pylint import error because we don't install django-debug-toolbar
# for CI build
import debug_toolbar # pylint: disable=import-error,useless-suppression
urlpatterns.append(re_path(r'^__debug__/', include(debug_toolbar.urls)))
urlpatterns.append(path('__debug__/', include(debug_toolbar.urls)))

0 comments on commit 6a9142d

Please sign in to comment.