Skip to content

Commit

Permalink
feat: dev mode admin + refactor api init (#7628)
Browse files Browse the repository at this point in the history
* feat: style admin site in dev mode

* refactor: eliminate base_site.html

* fix: remove debug

* fix: commit missing __init__.py

* refactor: make method static; fix tests

* refactor: move api init to AppConfig.ready()

Avoids interacting with the app registry before
it's ready.
  • Loading branch information
jennifer-richards authored Aug 7, 2024
1 parent b90820e commit 95a7e14
Show file tree
Hide file tree
Showing 11 changed files with 85 additions and 30 deletions.
Empty file added ietf/admin/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions ietf/admin/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright The IETF Trust 2024, All Rights Reserved
from django.contrib.admin import apps as admin_apps


class AdminConfig(admin_apps.AdminConfig):
default_site = "ietf.admin.sites.AdminSite"
15 changes: 15 additions & 0 deletions ietf/admin/sites.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright The IETF Trust 2024, All Rights Reserved
from django.contrib.admin import AdminSite as _AdminSite
from django.conf import settings
from django.utils.safestring import mark_safe


class AdminSite(_AdminSite):
site_title = "Datatracker admin"

@staticmethod
def site_header():
if settings.SERVER_MODE == "production":
return "Datatracker administration"
else:
return mark_safe('Datatracker administration <span class="text-danger">&delta;</span>')
43 changes: 17 additions & 26 deletions ietf/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@

from urllib.parse import urlencode

from django.conf import settings
from django.apps import apps as django_apps
from django.core.exceptions import ObjectDoesNotExist
from django.utils.module_loading import autodiscover_modules


import debug # pyflakes:ignore

Expand All @@ -19,40 +21,29 @@
from tastypie.exceptions import ApiFieldError
from tastypie.fields import ApiField


_api_list = []

for _app in settings.INSTALLED_APPS:
_module_dict = globals()
if '.' in _app:
_root, _name = _app.split('.', 1)
if _root == 'ietf':
if not '.' in _name:
_api = Api(api_name=_name)
_module_dict[_name] = _api
_api_list.append((_name, _api))

def populate_api_list():
for app_config in django_apps.get_app_configs():
_module_dict = globals()
if '.' in app_config.name:
_root, _name = app_config.name.split('.', 1)
if _root == 'ietf':
if not '.' in _name:
_api = Api(api_name=_name)
_module_dict[_name] = _api
_api_list.append((_name, _api))

def autodiscover():
"""
Auto-discover INSTALLED_APPS resources.py modules and fail silently when
not present. This forces an import on them to register any admin bits they
not present. This forces an import on them to register any resources they
may want.
"""
autodiscover_modules("resources")

from importlib import import_module
from django.conf import settings
from django.utils.module_loading import module_has_submodule

for app in settings.INSTALLED_APPS:
mod = import_module(app)
# Attempt to import the app's admin module.
try:
import_module('%s.resources' % (app, ))
except:
# Decide whether to bubble up this error. If the app just
# doesn't have an admin module, we can ignore the error
# attempting to import it, otherwise we want it to bubble up.
if module_has_submodule(mod, "resources"):
raise

class ModelResource(tastypie.resources.ModelResource):
def generate_cache_key(self, *args, **kwargs):
Expand Down
1 change: 1 addition & 0 deletions ietf/api/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ class Serializer(): ...
class ToOneField(tastypie.fields.ToOneField): ...
class TimedeltaField(tastypie.fields.ApiField): ...

def populate_api_list() -> None: ...
def autodiscover() -> None: ...
15 changes: 15 additions & 0 deletions ietf/api/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from django.apps import AppConfig
from . import populate_api_list


class ApiConfig(AppConfig):
name = "ietf.api"

def ready(self):
"""Hook to do init after the app registry is fully populated
Importing models or accessing the app registry is ok here, but do not
interact with the database. See
https://docs.djangoproject.com/en/4.2/ref/applications/#django.apps.AppConfig.ready
"""
populate_api_list()
1 change: 1 addition & 0 deletions ietf/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from ietf.submit import views as submit_views
from ietf.utils.urls import url


api.autodiscover()

urlpatterns = [
Expand Down
2 changes: 1 addition & 1 deletion ietf/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ def skip_unreadable_post(record):

INSTALLED_APPS = [
# Django apps
'django.contrib.admin',
'ietf.admin', # replaces django.contrib.admin
'django.contrib.admindocs',
'django.contrib.auth',
'django.contrib.contenttypes',
Expand Down
27 changes: 27 additions & 0 deletions ietf/templates/admin/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{% extends 'admin/base.html' %}
{% load static %}
{% block extrastyle %}{{ block.super }}
{% if server_mode and server_mode != "production" %}
<style>
{# grab colors that match bootstrap so we don't have to import the css #}
html, :root{
--bs-danger-bg-subtle: #F8D7DAFF;
--bs-danger-text-emphasis: #58151CFF;
--bs-danger: #DC3545FF;
--bs-secondary: #6C757DFF;
--bs-primary-text-emphasis: #052C65FF;
}
html[data-theme="light"], :root {
--primary: var(--bs-danger-bg-subtle);
--secondary: var(--bs-danger-bg-subtle);
--accent: var(--bs-danger-text-emphasis);
--primary-fg: var(--bs-primary-text-emphasis);
--link-fg: var(--bs-danger-text-emphasis);
--header-color: var(--bs-secondary);
--breadcrumbs-fg: var(--bs-secondary);
--breadcrumbs-link-fg: var(--link-fg);
}
span.text-danger { color: var(--bs-danger); }
</style>
{% endif %}
{% endblock %}
2 changes: 0 additions & 2 deletions ietf/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
from ietf.utils.urls import url


admin.autodiscover()

# sometimes, this code gets called more than once, which is an
# that seems impossible to work around.
try:
Expand Down
3 changes: 2 additions & 1 deletion ietf/utils/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

import debug # pyflakes:ignore

from ietf.admin.sites import AdminSite
from ietf.person.name import name_parts, unidecode_name
from ietf.submit.tests import submission_file
from ietf.utils.draft import PlaintextDraft, getmeta
Expand Down Expand Up @@ -325,7 +326,7 @@ def test_all_model_admins_exist(self):
User.objects.create_superuser('admin', '[email protected]', 'admin+password')
self.client.login(username='admin', password='admin+password')
rtop = self.client.get("/admin/")
self.assertContains(rtop, 'Django administration')
self.assertContains(rtop, AdminSite.site_header())
for name in self.apps:
app_name = self.apps[name]
self.assertContains(rtop, name)
Expand Down

0 comments on commit 95a7e14

Please sign in to comment.