mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-15 03:25:42 +00:00
configurable ldap group classes (#8475)
* configurable ldap group classes * remove accidental duplicate line * fix style issues --------- Co-authored-by: Matthias Mair <code@mjmair.com> Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
This commit is contained in:
@ -62,7 +62,7 @@ class ClassValidationMixin:
|
||||
|
||||
if len(missing_attributes) > 0:
|
||||
errors.append(
|
||||
f"did not provide the following attributes: {', '.join(missing_attributes)}"
|
||||
f'did not provide the following attributes: {", ".join(missing_attributes)}'
|
||||
)
|
||||
if len(missing_overrides) > 0:
|
||||
missing_overrides_list = []
|
||||
@ -75,7 +75,7 @@ class ClassValidationMixin:
|
||||
else:
|
||||
missing_overrides_list.append(base_implementation.__name__)
|
||||
errors.append(
|
||||
f"did not override the required attributes: {', '.join(missing_overrides_list)}"
|
||||
f'did not override the required attributes: {", ".join(missing_overrides_list)}'
|
||||
)
|
||||
|
||||
if len(errors) > 0:
|
||||
|
@ -360,8 +360,8 @@ AUTHENTICATION_BACKENDS = CONFIG.get(
|
||||
# LDAP support
|
||||
LDAP_AUTH = get_boolean_setting('INVENTREE_LDAP_ENABLED', 'ldap.enabled', False)
|
||||
if LDAP_AUTH:
|
||||
import django_auth_ldap.config
|
||||
import ldap
|
||||
from django_auth_ldap.config import GroupOfUniqueNamesType, LDAPSearch
|
||||
|
||||
AUTHENTICATION_BACKENDS.append('django_auth_ldap.backend.LDAPBackend')
|
||||
|
||||
@ -412,7 +412,7 @@ if LDAP_AUTH:
|
||||
AUTH_LDAP_BIND_PASSWORD = get_setting(
|
||||
'INVENTREE_LDAP_BIND_PASSWORD', 'ldap.bind_password'
|
||||
)
|
||||
AUTH_LDAP_USER_SEARCH = LDAPSearch(
|
||||
AUTH_LDAP_USER_SEARCH = django_auth_ldap.config.LDAPSearch(
|
||||
get_setting('INVENTREE_LDAP_SEARCH_BASE_DN', 'ldap.search_base_dn'),
|
||||
ldap.SCOPE_SUBTREE,
|
||||
str(
|
||||
@ -439,12 +439,38 @@ if LDAP_AUTH:
|
||||
'INVENTREE_LDAP_CACHE_TIMEOUT', 'ldap.cache_timeout', 3600, int
|
||||
)
|
||||
|
||||
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
|
||||
AUTH_LDAP_MIRROR_GROUPS = get_boolean_setting(
|
||||
'INVENTREE_LDAP_MIRROR_GROUPS', 'ldap.mirror_groups', False
|
||||
)
|
||||
AUTH_LDAP_GROUP_OBJECT_CLASS = get_setting(
|
||||
'INVENTREE_LDAP_GROUP_OBJECT_CLASS',
|
||||
'ldap.group_object_class',
|
||||
'groupOfUniqueNames',
|
||||
str,
|
||||
)
|
||||
AUTH_LDAP_GROUP_SEARCH = django_auth_ldap.config.LDAPSearch(
|
||||
get_setting('INVENTREE_LDAP_GROUP_SEARCH', 'ldap.group_search'),
|
||||
ldap.SCOPE_SUBTREE,
|
||||
'(objectClass=groupOfUniqueNames)',
|
||||
f'(objectClass={AUTH_LDAP_GROUP_OBJECT_CLASS})',
|
||||
)
|
||||
AUTH_LDAP_GROUP_TYPE_CLASS = get_setting(
|
||||
'INVENTREE_LDAP_GROUP_TYPE_CLASS',
|
||||
'ldap.group_type_class',
|
||||
'GroupOfUniqueNamesType',
|
||||
str,
|
||||
)
|
||||
AUTH_LDAP_GROUP_TYPE_CLASS_ARGS = get_setting(
|
||||
'INVENTREE_LDAP_GROUP_TYPE_CLASS_ARGS', 'ldap.group_type_class_args', [], list
|
||||
)
|
||||
AUTH_LDAP_GROUP_TYPE_CLASS_KWARGS = get_setting(
|
||||
'INVENTREE_LDAP_GROUP_TYPE_CLASS_KWARGS',
|
||||
'ldap.group_type_class_kwargs',
|
||||
{'name_attr': 'cn'},
|
||||
dict,
|
||||
)
|
||||
AUTH_LDAP_GROUP_TYPE = getattr(django_auth_ldap.config, AUTH_LDAP_GROUP_TYPE_CLASS)(
|
||||
*AUTH_LDAP_GROUP_TYPE_CLASS_ARGS, **AUTH_LDAP_GROUP_TYPE_CLASS_KWARGS
|
||||
)
|
||||
AUTH_LDAP_GROUP_TYPE = GroupOfUniqueNamesType(name_attr='cn')
|
||||
AUTH_LDAP_REQUIRE_GROUP = get_setting(
|
||||
'INVENTREE_LDAP_REQUIRE_GROUP', 'ldap.require_group'
|
||||
)
|
||||
|
@ -1034,14 +1034,14 @@ class TestVersionNumber(TestCase):
|
||||
# Check that the current .git values work too
|
||||
|
||||
git_hash = str(
|
||||
subprocess.check_output('git rev-parse --short HEAD'.split()), 'utf-8'
|
||||
subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']), 'utf-8'
|
||||
).strip()
|
||||
|
||||
# On some systems the hash is a different length, so just check the first 6 characters
|
||||
self.assertEqual(git_hash[:6], version.inventreeCommitHash()[:6])
|
||||
|
||||
d = (
|
||||
str(subprocess.check_output('git show -s --format=%ci'.split()), 'utf-8')
|
||||
str(subprocess.check_output(['git', 'show', '-s', '--format=%ci']), 'utf-8')
|
||||
.strip()
|
||||
.split(' ')[0]
|
||||
)
|
||||
|
@ -260,7 +260,7 @@ class BaseMachineType(
|
||||
error_parts.append(
|
||||
f'{config_type.name} settings: ' + ', '.join(missing)
|
||||
)
|
||||
self.handle_error(f"Missing {' and '.join(error_parts)}")
|
||||
self.handle_error(f'Missing {" and ".join(error_parts)}')
|
||||
return
|
||||
|
||||
try:
|
||||
|
@ -112,7 +112,7 @@ class MachineConfig(models.Model):
|
||||
"""Get machine errors for django admin interface."""
|
||||
return format_html_join(
|
||||
mark_safe('<br>'), '{}', ((str(error),) for error in self.errors)
|
||||
) or mark_safe(f"<i>{_('No errors')}</i>")
|
||||
) or mark_safe(f'<i>{_("No errors")}</i>')
|
||||
|
||||
@admin.display(description=_('Machine status'))
|
||||
def get_machine_status(self):
|
||||
|
@ -470,7 +470,7 @@ class PurchaseOrder(TotalPriceMixin, Order):
|
||||
|
||||
def __str__(self):
|
||||
"""Render a string representation of this PurchaseOrder."""
|
||||
return f"{self.reference} - {self.supplier.name if self.supplier else _('deleted')}"
|
||||
return f'{self.reference} - {self.supplier.name if self.supplier else _("deleted")}'
|
||||
|
||||
reference = models.CharField(
|
||||
unique=True,
|
||||
@ -996,7 +996,7 @@ class SalesOrder(TotalPriceMixin, Order):
|
||||
|
||||
def __str__(self):
|
||||
"""Render a string representation of this SalesOrder."""
|
||||
return f"{self.reference} - {self.customer.name if self.customer else _('deleted')}"
|
||||
return f'{self.reference} - {self.customer.name if self.customer else _("deleted")}'
|
||||
|
||||
reference = models.CharField(
|
||||
unique=True,
|
||||
@ -2194,7 +2194,7 @@ class ReturnOrder(TotalPriceMixin, Order):
|
||||
|
||||
def __str__(self):
|
||||
"""Render a string representation of this ReturnOrder."""
|
||||
return f"{self.reference} - {self.customer.name if self.customer else _('no customer')}"
|
||||
return f'{self.reference} - {self.customer.name if self.customer else _("no customer")}'
|
||||
|
||||
reference = models.CharField(
|
||||
unique=True,
|
||||
|
@ -295,7 +295,7 @@ class PartImport(FileManagementFormView):
|
||||
|
||||
# Set alerts
|
||||
if import_done:
|
||||
alert = f"<strong>{_('Part-Import')}</strong><br>{_(f'Imported {import_done} parts')}"
|
||||
alert = f'<strong>{_("Part-Import")}</strong><br>{_(f"Imported {import_done} parts")}'
|
||||
messages.success(self.request, alert)
|
||||
if import_error:
|
||||
error_text = '\n'.join([
|
||||
@ -304,7 +304,7 @@ class PartImport(FileManagementFormView):
|
||||
])
|
||||
messages.error(
|
||||
self.request,
|
||||
f"<strong>{_('Some errors occurred:')}</strong><br><ul>{error_text}</ul>",
|
||||
f'<strong>{_("Some errors occurred:")}</strong><br><ul>{error_text}</ul>',
|
||||
)
|
||||
|
||||
return HttpResponseRedirect(reverse('part-index'))
|
||||
|
@ -31,7 +31,7 @@ class SampleLabelPrinter(LabelPrintingMixin, InvenTreePlugin):
|
||||
Normally here the connection to the printer and transfer of the label would take place.
|
||||
"""
|
||||
# Test that the expected kwargs are present
|
||||
print(f"Printing Label: {kwargs['filename']} (User: {kwargs['user']})")
|
||||
print(f'Printing Label: {kwargs["filename"]} (User: {kwargs["user"]})')
|
||||
|
||||
pdf_data = kwargs['pdf_data']
|
||||
png_file = self.render_to_png(
|
||||
|
@ -252,7 +252,7 @@ class RegistryTests(TestCase):
|
||||
def test_package_loading(self):
|
||||
"""Test that package distributed plugins work."""
|
||||
# Install sample package
|
||||
subprocess.check_output('pip install inventree-zapier'.split())
|
||||
subprocess.check_output(['pip', 'install', 'inventree-zapier'])
|
||||
|
||||
# Reload to discover plugin
|
||||
registry.reload_plugins(full_reload=True, collect=True)
|
||||
|
@ -62,7 +62,7 @@ if __name__ == '__main__':
|
||||
percentage = int(covered / total * 100) if total > 0 else 0
|
||||
|
||||
if verbose:
|
||||
print(f"| {locale.ljust(4, ' ')} : {str(percentage).rjust(4, ' ')}% |")
|
||||
print(f'| {locale.ljust(4, " ")} : {str(percentage).rjust(4, " ")}% |')
|
||||
|
||||
locales_perc[locale] = percentage
|
||||
|
||||
|
@ -18,7 +18,7 @@ class RedirectAssetView(TemplateView):
|
||||
def get(self, request, *args, **kwargs):
|
||||
"""Redirect to static asset."""
|
||||
return redirect(
|
||||
f"{settings.STATIC_URL}web/assets/{kwargs['path']}", permanent=True
|
||||
f'{settings.STATIC_URL}web/assets/{kwargs["path"]}', permanent=True
|
||||
)
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user