Repository: inventree/InvenTree

Issue:
[FR] White labeling
**Problem**
A lot of companies do not want it to be known which software they use. Either for not letting their competitor know what they use or for security reasons.

**Suggested solution**
Removing all tags and graphics that identify InvenTree would be a great option.
Also hiding normal debug and version info from users should be an option.

**Describe alternatives you've considered**
This is nice to have.

**Examples of other systems**
Most 'big vendor' solutions come with a very reduced custom login page (that they charge for like they invented HTML). That should be enough.

**Do you want to develop this?**
Yes



Discussion:
Fair enough as a run-time configuration option!
> 
> 
> Fair enough as a run-time configuration option!

@SchrodingersGat  I would phase it sometime after 0.7 - could you maybe add a 1.0 milestone for that? There is a ton to do before that gets important.
@SchrodingersGat I would start working on an option to remove any and every mention of inventree and all logos if that is ok with you. Should I go ahead for 0.7.0 or is this better for later?
0.7.0 would be fine for this

Resolving patch:
diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py
--- a/InvenTree/InvenTree/settings.py
+++ b/InvenTree/InvenTree/settings.py
@@ -25,6 +25,7 @@
 import yaml
 from django.utils.translation import gettext_lazy as _
 from django.contrib.messages import constants as messages
+from django.core.files.storage import default_storage
 import django.conf.locale
 
 from .config import get_base_dir, get_config_file, get_plugin_file, get_setting
@@ -913,3 +914,20 @@ def _is_true(x):
 PLUGIN_TESTING_SETUP = get_setting('PLUGIN_TESTING_SETUP', False)  # load plugins from setup hooks in testing?
 PLUGIN_RETRY = get_setting('PLUGIN_RETRY', 5)  # how often should plugin loading be tried?
 PLUGIN_FILE_CHECKED = False                    # Was the plugin file checked?
+
+# user interface customization values
+CUSTOMIZE = get_setting(
+    'INVENTREE_CUSTOMIZE',
+    CONFIG.get('customize', {}),
+    {}
+)
+
+CUSTOM_LOGO = get_setting(
+    'INVENTREE_CUSTOM_LOGO',
+    CUSTOMIZE.get('logo', False)
+)
+
+# check that the logo-file exsists in media
+if CUSTOM_LOGO and not default_storage.exists(CUSTOM_LOGO):
+    CUSTOM_LOGO = False
+    logger.warning("The custom logo file could not be found in the default media storage")
diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py
--- a/InvenTree/common/models.py
+++ b/InvenTree/common/models.py
@@ -684,7 +684,7 @@ def save(self, *args, **kwargs):
         },
 
         'INVENTREE_INSTANCE': {
-            'name': _('InvenTree Instance Name'),
+            'name': _('Server Instance Name'),
             'default': 'InvenTree server',
             'description': _('String descriptor for the server instance'),
         },
@@ -696,6 +696,13 @@ def save(self, *args, **kwargs):
             'default': False,
         },
 
+        'INVENTREE_RESTRICT_ABOUT': {
+            'name': _('Restrict showing `about`'),
+            'description': _('Show the `about` modal only to superusers'),
+            'validator': bool,
+            'default': False,
+        },
+
         'INVENTREE_COMPANY_NAME': {
             'name': _('Company name'),
             'description': _('Internal company name'),
@@ -1353,7 +1360,7 @@ class InvenTreeUserSetting(BaseInvenTreeSetting):
 
         'STICKY_HEADER': {
             'name': _('Fixed Navbar'),
-            'description': _('InvenTree navbar position is fixed to the top of the screen'),
+            'description': _('The navbar position is fixed to the top of the screen'),
             'default': False,
             'validator': bool,
         },
diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py
--- a/InvenTree/part/templatetags/inventree_extras.py
+++ b/InvenTree/part/templatetags/inventree_extras.py
@@ -18,7 +18,8 @@
 from django import template
 from django.urls import reverse
 from django.utils.safestring import mark_safe
-from django.templatetags.static import StaticNode
+from django.templatetags.static import StaticNode, static
+from django.core.files.storage import default_storage
 
 from InvenTree import version, settings
 
@@ -166,6 +167,14 @@ def inventree_demo_mode(*args, **kwargs):
     return djangosettings.DEMO_MODE
 
 
+@register.simple_tag()
+def inventree_show_about(user, *args, **kwargs):
+    """ Return True if the about modal should be shown """
+    if InvenTreeSetting.get_setting('INVENTREE_RESTRICT_ABOUT') and not user.is_superuser:
+        return False
+    return True
+
+
 @register.simple_tag()
 def inventree_docker_mode(*args, **kwargs):
     """ Return True if the server is running as a Docker image """
@@ -220,8 +229,13 @@ def python_version(*args, **kwargs):
 
 
 @register.simple_tag()
-def inventree_version(*args, **kwargs):
+def inventree_version(shortstring=False, *args, **kwargs):
     """ Return InvenTree version string """
+    if shortstring:
+        return _("{title} v{version}".format(
+            title=version.inventreeInstanceTitle(),
+            version=version.inventreeVersion()
+        ))
     return version.inventreeVersion()
 
 
@@ -512,6 +526,22 @@ def mail_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 inventree_logo(*args, **kwargs):
+    """ Return the path to the logo-file """
+
+    if settings.CUSTOM_LOGO:
+        return default_storage.url(settings.CUSTOM_LOGO)
+    return static('img/inventree.png')
+
+
 class I18nStaticNode(StaticNode):
     """
     custom StaticNode


Test patch:
diff --git a/InvenTree/common/tests.py b/InvenTree/common/tests.py
--- a/InvenTree/common/tests.py
+++ b/InvenTree/common/tests.py
@@ -63,8 +63,8 @@ def test_settings_functions(self):
         report_test_obj = InvenTreeSetting.get_setting_object('REPORT_ENABLE_TEST_REPORT')
 
         # check settings base fields
-        self.assertEqual(instance_obj.name, 'InvenTree Instance Name')
-        self.assertEqual(instance_obj.get_setting_name(instance_ref), 'InvenTree Instance Name')
+        self.assertEqual(instance_obj.name, 'Server Instance Name')
+        self.assertEqual(instance_obj.get_setting_name(instance_ref), 'Server Instance Name')
         self.assertEqual(instance_obj.description, 'String descriptor for the server instance')
         self.assertEqual(instance_obj.get_setting_description(instance_ref), 'String descriptor for the server instance')
 
diff --git a/InvenTree/report/templates/report/inventree_test_report_base.html b/InvenTree/report/templates/report/inventree_test_report_base.html
--- a/InvenTree/report/templates/report/inventree_test_report_base.html
+++ b/InvenTree/report/templates/report/inventree_test_report_base.html
@@ -14,7 +14,7 @@
 {% endblock %}
 
 {% block bottom_center %}
-content: "InvenTree v{% inventree_version %}";
+content: "{% inventree_version shortstring=True %}";
 {% endblock %}
 
 {% block top_center %}