utils.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import importlib
  2. from django.core.exceptions import ImproperlyConfigured
  3. from django.db import models
  4. from django.db.models import Q
  5. from taggit.managers import _TaggableManager
  6. from netbox.context import current_request
  7. from .validators import CustomValidator
  8. __all__ = (
  9. 'SharedObjectViewMixin',
  10. 'image_upload',
  11. 'is_report',
  12. 'is_script',
  13. 'is_taggable',
  14. 'run_validators',
  15. )
  16. class SharedObjectViewMixin:
  17. def get_queryset(self, request):
  18. """
  19. Return only shared objects, or those owned by the current user, unless this is a superuser.
  20. """
  21. queryset = super().get_queryset(request)
  22. if request.user.is_superuser:
  23. return queryset
  24. if request.user.is_anonymous:
  25. return queryset.filter(shared=True)
  26. return queryset.filter(
  27. Q(shared=True) | Q(user=request.user)
  28. )
  29. def filename_from_model(model: models.Model) -> str:
  30. """Standardises how we generate filenames from model class for exports"""
  31. base = model._meta.verbose_name_plural.lower().replace(' ', '_')
  32. return f'netbox_{base}'
  33. def filename_from_object(context: dict) -> str:
  34. """Standardises how we generate filenames from model class for exports"""
  35. if 'device' in context:
  36. base = f"{context['device'].name or 'config'}"
  37. elif 'virtualmachine' in context:
  38. base = f"{context['virtualmachine'].name or 'config'}"
  39. else:
  40. base = 'config'
  41. return base
  42. def is_taggable(obj):
  43. """
  44. Return True if the instance can have Tags assigned to it; False otherwise.
  45. """
  46. if hasattr(obj, 'tags'):
  47. if issubclass(obj.tags.__class__, _TaggableManager):
  48. return True
  49. return False
  50. def image_upload(instance, filename):
  51. """
  52. Return a path for uploading image attachments.
  53. """
  54. path = 'image-attachments/'
  55. # Rename the file to the provided name, if any. Attempt to preserve the file extension.
  56. extension = filename.rsplit('.')[-1].lower()
  57. if instance.name and extension in ['bmp', 'gif', 'jpeg', 'jpg', 'png', 'webp']:
  58. filename = '.'.join([instance.name, extension])
  59. elif instance.name:
  60. filename = instance.name
  61. return '{}{}_{}_{}'.format(path, instance.object_type.name, instance.object_id, filename)
  62. def is_script(obj):
  63. """
  64. Returns True if the object is a Script or Report.
  65. """
  66. from .reports import Report
  67. from .scripts import Script
  68. try:
  69. return (issubclass(obj, Report) and obj != Report) or (issubclass(obj, Script) and obj != Script)
  70. except TypeError:
  71. return False
  72. def is_report(obj):
  73. """
  74. Returns True if the given object is a Report.
  75. """
  76. from .reports import Report
  77. try:
  78. return issubclass(obj, Report) and obj != Report
  79. except TypeError:
  80. return False
  81. def run_validators(instance, validators):
  82. """
  83. Run the provided iterable of CustomValidators for the instance.
  84. """
  85. request = current_request.get()
  86. for validator in validators:
  87. # Loading a validator class by dotted path
  88. if type(validator) is str:
  89. module, cls = validator.rsplit('.', 1)
  90. validator = getattr(importlib.import_module(module), cls)()
  91. # Constructing a new instance on the fly from a ruleset
  92. elif type(validator) is dict:
  93. validator = CustomValidator(validator)
  94. elif not issubclass(validator.__class__, CustomValidator):
  95. raise ImproperlyConfigured(f"Invalid value for custom validator: {validator}")
  96. validator(instance, request)