diff --git a/src/backend/InvenTree/InvenTree/api.py b/src/backend/InvenTree/InvenTree/api.py index cfc243ca83..c3a851cd62 100644 --- a/src/backend/InvenTree/InvenTree/api.py +++ b/src/backend/InvenTree/InvenTree/api.py @@ -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 diff --git a/src/backend/InvenTree/InvenTree/helpers.py b/src/backend/InvenTree/InvenTree/helpers.py index 1565aa4d50..e5ec5e9e16 100644 --- a/src/backend/InvenTree/InvenTree/helpers.py +++ b/src/backend/InvenTree/InvenTree/helpers.py @@ -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 + ] diff --git a/src/backend/InvenTree/InvenTree/templatetags/inventree_extras.py b/src/backend/InvenTree/InvenTree/templatetags/inventree_extras.py index 228b5aeb39..ca85a755b3 100644 --- a/src/backend/InvenTree/InvenTree/templatetags/inventree_extras.py +++ b/src/backend/InvenTree/InvenTree/templatetags/inventree_extras.py @@ -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'{ref}') - 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 diff --git a/src/backend/InvenTree/part/test_part.py b/src/backend/InvenTree/part/test_part.py index 558c460e97..a575049143 100644 --- a/src/backend/InvenTree/part/test_part.py +++ b/src/backend/InvenTree/part/test_part.py @@ -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): diff --git a/src/backend/InvenTree/templates/503.html b/src/backend/InvenTree/templates/503.html index 8630d794a0..5e4b65ea9d 100644 --- a/src/backend/InvenTree/templates/503.html +++ b/src/backend/InvenTree/templates/503.html @@ -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 %} diff --git a/src/backend/InvenTree/templates/account/base.html b/src/backend/InvenTree/templates/account/base.html index 0e298e8cc0..eee8f0bc5c 100644 --- a/src/backend/InvenTree/templates/account/base.html +++ b/src/backend/InvenTree/templates/account/base.html @@ -3,7 +3,7 @@ {% load inventree_extras %} {% block body %} - +