2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 03:26:45 +00:00

refactor(backend): reduce tags (#8932)

* reduce tags more

* remove splashscreen usage

* fix test

* reintroduce inventree_logo

* re-add splashscreen fnct

* re-add needed tag

* re-add date renderer

* simplify away user specific stuff - there are no users in reports

* and simplify a bit more

* increase coverage

* fix format

* and more coverage

* fix render_date

* more coverage
This commit is contained in:
Matthias Mair 2025-01-31 03:58:04 +01:00 committed by GitHub
parent cfa248aad9
commit fff0b99b08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 87 additions and 335 deletions

View File

@ -22,11 +22,11 @@ import InvenTree.version
import users.models
from InvenTree import helpers
from InvenTree.mixins import ListCreateAPI
from InvenTree.templatetags.inventree_extras import plugins_info
from part.models import Part
from plugin.serializers import MetadataSerializer
from users.models import ApiToken
from .helpers import plugins_info
from .helpers_email import is_email_configured
from .mixins import ListAPI, RetrieveUpdateAPI
from .status import check_system_health, is_worker_running

View File

@ -1070,3 +1070,20 @@ def pui_url(subpath: str) -> str:
if not subpath.startswith('/'):
subpath = '/' + subpath
return f'/{settings.FRONTEND_URL_BASE}{subpath}'
def plugins_info(*args, **kwargs):
"""Return information about activated plugins."""
from plugin.registry import registry
# Check if plugins are even enabled
if not settings.PLUGINS_ENABLED:
return False
# Fetch plugins
plug_list = [plg for plg in registry.plugins.values() if plg.plugin_config().active]
# Format list
return [
{'name': plg.name, 'slug': plg.slug, 'version': plg.version}
for plg in plug_list
]

View File

@ -4,25 +4,20 @@ from datetime import date, datetime
from django import template
from django.conf import settings as djangosettings
from django.urls import NoReverseMatch, reverse
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
import structlog
import common.models
import InvenTree.helpers
import InvenTree.helpers_model
import plugin.models
from common.currency import currency_code_default
from common.settings import get_global_setting
from InvenTree import settings, version
from plugin import registry
from InvenTree import version
from plugin.plugin import InvenTreePlugin
register = template.Library()
import structlog
logger = structlog.get_logger('inventree')
@ -44,12 +39,8 @@ def decimal(x, *args, **kwargs):
@register.simple_tag(takes_context=True)
def render_date(context, date_object):
"""Renders a date according to the preference of the provided user.
Note that the user preference is stored using the formatting adopted by moment.js,
which differs from the python formatting!
"""
def render_date(date_object):
"""Renders a date object as a string."""
if date_object is None:
return None
@ -67,29 +58,7 @@ def render_date(context, date_object):
logger.warning('Tried to convert invalid date string: %s', date_object)
return None
# We may have already pre-cached the date format by calling this already!
user_date_format = context.get('user_date_format', None)
if user_date_format is None:
user = context.get('user', None)
if user and user.is_authenticated:
# User is specified - look for their date display preference
user_date_format = common.models.InvenTreeUserSetting.get_setting(
'DATE_DISPLAY_FORMAT', user=user
)
else:
user_date_format = 'YYYY-MM-DD'
# Convert the format string to Pythonic equivalent
replacements = [('YYYY', '%Y'), ('MMM', '%b'), ('MM', '%m'), ('DD', '%d')]
for o, n in replacements:
user_date_format = user_date_format.replace(o, n)
# Update the context cache
context['user_date_format'] = user_date_format
user_date_format = '%Y-%m-%d'
if isinstance(date_object, (datetime, date)):
return date_object.strftime(user_date_format)
return date_object
@ -119,40 +88,6 @@ def to_list(*args):
return args
@register.simple_tag()
def plugins_enabled(*args, **kwargs):
"""Return True if plugins are enabled for the server instance."""
return djangosettings.PLUGINS_ENABLED
@register.simple_tag()
def plugins_install_disabled(*args, **kwargs):
"""Return True if plugin install is disabled for the server instance."""
return djangosettings.PLUGINS_INSTALL_DISABLED
@register.simple_tag()
def plugins_info(*args, **kwargs):
"""Return information about activated plugins."""
# Check if plugins are even enabled
if not djangosettings.PLUGINS_ENABLED:
return False
# Fetch plugins
plug_list = [plg for plg in registry.plugins.values() if plg.plugin_config().active]
# Format list
return [
{'name': plg.name, 'slug': plg.slug, 'version': plg.version}
for plg in plug_list
]
@register.simple_tag()
def inventree_db_engine(*args, **kwargs):
"""Return the InvenTree database backend e.g. 'postgresql'."""
return version.inventreeDatabase() or _('Unknown database')
@register.simple_tag()
def inventree_instance_name(*args, **kwargs):
"""Return the InstanceName associated with the current database."""
@ -169,29 +104,11 @@ def inventree_title(*args, **kwargs):
def inventree_logo(**kwargs):
"""Return the InvenTree logo, *or* a custom logo if the user has provided one.
Returns a path to an image file, which can be rendered in the web interface
Returns a path to an image file, which can be rendered in the web interface.
"""
return InvenTree.helpers.getLogoImage(**kwargs)
@register.simple_tag()
def inventree_splash(**kwargs):
"""Return the URL for the InvenTree splash screen, *or* a custom screen if the user has provided one."""
return InvenTree.helpers.getSplashScreen(**kwargs)
@register.simple_tag()
def inventree_base_url(*args, **kwargs):
"""Return the base URL of the InvenTree server."""
return InvenTree.helpers_model.get_base_url()
@register.simple_tag()
def python_version(*args, **kwargs):
"""Return the current python version."""
return version.inventreePythonVersion()
@register.simple_tag()
def inventree_version(shortstring=False, *args, **kwargs):
"""Return InvenTree version string."""
@ -200,36 +117,6 @@ def inventree_version(shortstring=False, *args, **kwargs):
return version.inventreeVersion()
@register.simple_tag()
def inventree_is_development(*args, **kwargs):
"""Returns True if this is a development version of InvenTree."""
return version.isInvenTreeDevelopmentVersion()
@register.simple_tag()
def inventree_is_release(*args, **kwargs):
"""Returns True if this is a release version of InvenTree."""
return not version.isInvenTreeDevelopmentVersion()
@register.simple_tag()
def inventree_docs_version(*args, **kwargs):
"""Returns the InvenTree documentation version."""
return version.inventreeDocsVersion()
@register.simple_tag()
def inventree_api_version(*args, **kwargs):
"""Return InvenTree API version."""
return version.inventreeApiVersion()
@register.simple_tag()
def django_version(*args, **kwargs):
"""Return Django version string."""
return version.inventreeDjangoVersion()
@register.simple_tag()
def inventree_commit_hash(*args, **kwargs):
"""Return InvenTree git commit hash string."""
@ -242,60 +129,6 @@ def inventree_commit_date(*args, **kwargs):
return version.inventreeCommitDate()
@register.simple_tag()
def inventree_installer(*args, **kwargs):
"""Return InvenTree package installer string."""
return version.inventreeInstaller()
@register.simple_tag()
def inventree_branch(*args, **kwargs):
"""Return InvenTree git branch string."""
return version.inventreeBranch()
@register.simple_tag()
def inventree_target(*args, **kwargs):
"""Return InvenTree target string."""
return version.inventreeTarget()
@register.simple_tag()
def inventree_platform(*args, **kwargs):
"""Return InvenTree platform string."""
return version.inventreePlatform()
@register.simple_tag()
def inventree_github_url(*args, **kwargs):
"""Return URL for InvenTree github site."""
return version.inventreeGithubUrl()
@register.simple_tag()
def inventree_docs_url(*args, **kwargs):
"""Return URL for InvenTree documentation site."""
return version.inventreeDocUrl()
@register.simple_tag()
def inventree_app_url(*args, **kwargs):
"""Return URL for InvenTree app site."""
return version.inventreeAppUrl()
@register.simple_tag()
def inventree_credits_url(*args, **kwargs):
"""Return URL for InvenTree credits site."""
return version.inventreeCreditsUrl()
@register.simple_tag()
def default_currency(*args, **kwargs):
"""Returns the default currency code."""
return currency_code_default()
@register.simple_tag()
def setting_object(key, *args, **kwargs):
"""Return a setting object specified by the given key.
@ -346,24 +179,6 @@ def settings_value(key, *args, **kwargs):
return get_global_setting(key)
@register.simple_tag()
def user_settings(user, *args, **kwargs):
"""Return all USER settings as a key:value dict."""
return common.models.InvenTreeUserSetting.allValues(user=user)
@register.simple_tag()
def global_settings(*args, **kwargs):
"""Return all GLOBAL InvenTree settings as a key:value dict."""
return common.models.InvenTreeSetting.allValues()
@register.simple_tag()
def visible_global_settings(*args, **kwargs):
"""Return any global settings which are not marked as 'hidden'."""
return common.models.InvenTreeSetting.allValues(exclude_hidden=True)
@register.filter
def keyvalue(dict, key):
"""Access to key of supplied dict.
@ -374,88 +189,7 @@ def keyvalue(dict, key):
return dict.get(key)
@register.simple_tag()
def authorized_owners(group):
"""Return authorized owners."""
owners = []
try:
for owner in group.get_related_owners(include_group=True):
owners.append(owner.owner)
except AttributeError:
# group is None
pass
except TypeError:
# group.get_users returns None
pass
return owners
@register.simple_tag()
def object_link(url_name, pk, ref):
"""Return highlighted link to object."""
try:
ref_url = reverse(url_name, kwargs={'pk': pk})
return mark_safe(f'<b><a href="{ref_url}">{ref}</a></b>')
except NoReverseMatch:
return None
@register.simple_tag()
def mail_configured():
"""Return if mail is configured."""
return bool(settings.EMAIL_HOST)
@register.simple_tag()
def inventree_customize(reference, *args, **kwargs):
"""Return customization values for the user interface."""
return djangosettings.CUSTOMIZE.get(reference, '')
@register.simple_tag()
def admin_index(user):
"""Return a URL for the admin interface."""
if not djangosettings.INVENTREE_ADMIN_ENABLED:
return ''
if not user.is_staff:
return ''
return reverse('admin:index')
@register.simple_tag()
def admin_url(user, table, pk):
"""Generate a link to the admin site for the given model instance.
- If the admin site is disabled, an empty URL is returned
- If the user is not a staff user, an empty URL is returned
- If the user does not have the correct permission, an empty URL is returned
"""
app, model = table.strip().split('.')
from django.urls import reverse
if not djangosettings.INVENTREE_ADMIN_ENABLED:
return ''
if not user.is_staff:
return ''
# Check the user has the correct permission
perm_string = f'{app}.change_{model}'
if not user.has_perm(perm_string):
return ''
# Fallback URL
url = reverse(f'admin:{app}_{model}_changelist')
if pk:
try:
url = reverse(f'admin:{app}_{model}_change', args=(pk,))
except NoReverseMatch:
pass
return url

View File

@ -6,17 +6,11 @@ from django.conf import settings
from django.core.cache import cache
from django.core.exceptions import ValidationError
from django.test import TestCase
from django.test.utils import override_settings
from allauth.account.models import EmailAddress
import part.settings
from common.models import (
InvenTreeSetting,
InvenTreeUserSetting,
NotificationEntry,
NotificationMessage,
)
from common.models import NotificationEntry, NotificationMessage
from common.notifications import UIMessageNotification, storage
from common.settings import get_global_setting, set_global_setting
from InvenTree import version
@ -53,34 +47,26 @@ class TemplateTagTest(InvenTreeTestCase):
"""Test that the 'add."""
self.assertEqual(int(inventree_extras.add(3, 5)), 8)
def test_plugins_enabled(self):
"""Test the plugins_enabled tag."""
self.assertEqual(inventree_extras.plugins_enabled(), True)
def test_plugins_install_disabled(self):
"""Test the plugins_install_disabled tag."""
self.assertEqual(inventree_extras.plugins_install_disabled(), False)
def test_inventree_instance_name(self):
"""Test the 'instance name' setting."""
self.assertEqual(inventree_extras.inventree_instance_name(), 'InvenTree')
@override_settings(SITE_URL=None)
def test_inventree_base_url(self):
"""Test that the base URL tag returns correctly."""
self.assertEqual(inventree_extras.inventree_base_url(), '')
def test_inventree_title(self):
"""Test the 'inventree_title' setting."""
self.assertEqual(inventree_extras.inventree_title(), 'InvenTree')
def test_inventree_is_release(self):
"""Test that the release version check functions as expected."""
def test_inventree_customize(self):
"""Test the 'inventree_customize' template tag."""
self.assertEqual(inventree_extras.inventree_customize('abc'), '')
def test_inventree_version(self):
"""Test the 'version' setting."""
self.assertEqual(
inventree_extras.inventree_is_release(),
not version.isInvenTreeDevelopmentVersion(),
inventree_extras.inventree_version(), version.inventreeVersion()
)
def test_inventree_docs_version(self):
"""Test that the documentation version template tag returns correctly."""
self.assertEqual(
inventree_extras.inventree_docs_version(), version.inventreeDocsVersion()
self.assertNotEqual(
inventree_extras.inventree_version(shortstring=True),
version.inventreeVersion(),
)
def test_hash(self):
@ -103,48 +89,63 @@ class TemplateTagTest(InvenTreeTestCase):
else:
self.assertEqual(len(d.split('-')), 3)
def test_github(self):
"""Test that the github URL template tag returns correctly."""
self.assertIn('github.com', inventree_extras.inventree_github_url())
def test_docs(self):
"""Test that the documentation URL template tag returns correctly."""
self.assertIn('docs.inventree.org', inventree_extras.inventree_docs_url())
def test_keyvalue(self):
"""Test keyvalue template tag."""
self.assertEqual(inventree_extras.keyvalue({'a': 'a'}, 'a'), 'a')
def test_mail_configured(self):
"""Test that mail configuration returns False."""
self.assertEqual(inventree_extras.mail_configured(), False)
def test_to_list(self):
"""Test the 'to_list' template tag."""
self.assertEqual(inventree_extras.to_list(1, 2, 3), (1, 2, 3))
def test_user_settings(self):
"""Test user settings."""
result = inventree_extras.user_settings(self.user)
self.assertEqual(len(result), len(InvenTreeUserSetting.SETTINGS))
def test_render_date(self):
"""Test the 'render_date' template tag."""
self.assertEqual(inventree_extras.render_date('2021-01-01'), '2021-01-01')
def test_global_settings(self):
"""Test global settings."""
result = inventree_extras.global_settings()
self.assertEqual(len(result), len(InvenTreeSetting.SETTINGS))
self.assertEqual(inventree_extras.render_date(None), None)
self.assertEqual(inventree_extras.render_date(' '), None)
self.assertEqual(inventree_extras.render_date('aaaa'), None)
self.assertEqual(inventree_extras.render_date(1234), 1234)
def test_visible_global_settings(self):
"""Test that hidden global settings are actually hidden."""
result = inventree_extras.visible_global_settings()
def test_setting_object(self):
"""Test the 'setting_object' template tag."""
# Normal
self.assertEqual(
inventree_extras.setting_object('PART_ALLOW_DUPLICATE_IPN').value, True
)
n = len(result)
# User
self.assertEqual(
inventree_extras.setting_object(
'PART_ALLOW_DUPLICATE_IPN', user=self.user
).value,
'',
)
n_hidden = 0
n_visible = 0
# Method
self.assertEqual(
inventree_extras.setting_object(
'PART_ALLOW_DUPLICATE_IPN', method='abc', user=self.user
).value,
'',
)
for val in InvenTreeSetting.SETTINGS.values():
if val.get('hidden', False):
n_hidden += 1
else:
n_visible += 1
def test_settings_value(self):
"""Test the 'settings_value' template tag."""
# Normal
self.assertEqual(
inventree_extras.settings_value('PART_ALLOW_DUPLICATE_IPN'), True
)
self.assertEqual(n, n_visible)
# User
self.assertEqual(
inventree_extras.settings_value('PART_ALLOW_DUPLICATE_IPN', user=self.user),
'',
)
self.logout()
self.assertEqual(
inventree_extras.settings_value('PART_ALLOW_DUPLICATE_IPN', user=self.user),
'',
)
class PartTest(TestCase):

View File

@ -11,7 +11,7 @@
{% trans 'Site is in Maintenance' %}
{% endblock page_title %}
{% block body_class %}login-screen' style='background: url({% inventree_splash %}); background-size: cover;{% endblock body_class %}
{% block body_class %}login-screen{% endblock body_class %}
{% block body %}

View File

@ -3,7 +3,7 @@
{% load inventree_extras %}
{% block body %}
<body class='login-screen' style='background: url({% inventree_splash %}); background-size: cover;'>
<body class='login-screen'>
<div class='container-fluid'>
<div class='notification-area' id='alerts'>
<!-- Div for displayed alerts -->