bulk_import.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import re
  2. from django import forms
  3. from django.contrib.postgres.forms import SimpleArrayField
  4. from django.core.exceptions import ObjectDoesNotExist
  5. from django.utils.safestring import mark_safe
  6. from django.utils.translation import gettext_lazy as _
  7. from core.models import ContentType
  8. from extras.choices import *
  9. from extras.models import *
  10. from netbox.forms import NetBoxModelImportForm
  11. from utilities.forms import CSVModelForm
  12. from utilities.forms.fields import (
  13. CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVMultipleContentTypeField, SlugField,
  14. )
  15. __all__ = (
  16. 'ConfigTemplateImportForm',
  17. 'CustomFieldChoiceSetImportForm',
  18. 'CustomFieldImportForm',
  19. 'CustomLinkImportForm',
  20. 'EventRuleImportForm',
  21. 'ExportTemplateImportForm',
  22. 'JournalEntryImportForm',
  23. 'SavedFilterImportForm',
  24. 'TagImportForm',
  25. 'WebhookImportForm',
  26. )
  27. class CustomFieldImportForm(CSVModelForm):
  28. content_types = CSVMultipleContentTypeField(
  29. label=_('Content types'),
  30. queryset=ContentType.objects.with_feature('custom_fields'),
  31. help_text=_("One or more assigned object types")
  32. )
  33. type = CSVChoiceField(
  34. label=_('Type'),
  35. choices=CustomFieldTypeChoices,
  36. help_text=_('Field data type (e.g. text, integer, etc.)')
  37. )
  38. object_type = CSVContentTypeField(
  39. label=_('Object type'),
  40. queryset=ContentType.objects.public(),
  41. required=False,
  42. help_text=_("Object type (for object or multi-object fields)")
  43. )
  44. choice_set = CSVModelChoiceField(
  45. label=_('Choice set'),
  46. queryset=CustomFieldChoiceSet.objects.all(),
  47. to_field_name='name',
  48. required=False,
  49. help_text=_('Choice set (for selection fields)')
  50. )
  51. ui_visible = CSVChoiceField(
  52. label=_('UI visible'),
  53. choices=CustomFieldUIVisibleChoices,
  54. required=False,
  55. help_text=_('Whether the custom field is displayed in the UI')
  56. )
  57. ui_editable = CSVChoiceField(
  58. label=_('UI editable'),
  59. choices=CustomFieldUIEditableChoices,
  60. required=False,
  61. help_text=_('Whether the custom field is editable in the UI')
  62. )
  63. class Meta:
  64. model = CustomField
  65. fields = (
  66. 'name', 'label', 'group_name', 'type', 'content_types', 'object_type', 'required', 'description',
  67. 'search_weight', 'filter_logic', 'default', 'choice_set', 'weight', 'validation_minimum',
  68. 'validation_maximum', 'validation_regex', 'ui_visible', 'ui_editable', 'is_cloneable',
  69. )
  70. class CustomFieldChoiceSetImportForm(CSVModelForm):
  71. base_choices = CSVChoiceField(
  72. choices=CustomFieldChoiceSetBaseChoices,
  73. required=False,
  74. help_text=_('The base set of predefined choices to use (if any)')
  75. )
  76. extra_choices = SimpleArrayField(
  77. base_field=forms.CharField(),
  78. required=False,
  79. help_text=_(
  80. 'Quoted string of comma-separated field choices with optional labels separated by colon: '
  81. '"choice1:First Choice,choice2:Second Choice"'
  82. )
  83. )
  84. class Meta:
  85. model = CustomFieldChoiceSet
  86. fields = (
  87. 'name', 'description', 'extra_choices', 'order_alphabetically',
  88. )
  89. def clean_extra_choices(self):
  90. if isinstance(self.cleaned_data['extra_choices'], list):
  91. data = []
  92. for line in self.cleaned_data['extra_choices']:
  93. try:
  94. value, label = re.split(r'(?<!\\):', line, maxsplit=1)
  95. value = value.replace('\\:', ':')
  96. label = label.replace('\\:', ':')
  97. except ValueError:
  98. value, label = line, line
  99. data.append((value, label))
  100. return data
  101. class CustomLinkImportForm(CSVModelForm):
  102. content_types = CSVMultipleContentTypeField(
  103. label=_('Content types'),
  104. queryset=ContentType.objects.with_feature('custom_links'),
  105. help_text=_("One or more assigned object types")
  106. )
  107. class Meta:
  108. model = CustomLink
  109. fields = (
  110. 'name', 'content_types', 'enabled', 'weight', 'group_name', 'button_class', 'new_window', 'link_text',
  111. 'link_url',
  112. )
  113. class ExportTemplateImportForm(CSVModelForm):
  114. content_types = CSVMultipleContentTypeField(
  115. label=_('Content types'),
  116. queryset=ContentType.objects.with_feature('export_templates'),
  117. help_text=_("One or more assigned object types")
  118. )
  119. class Meta:
  120. model = ExportTemplate
  121. fields = (
  122. 'name', 'content_types', 'description', 'mime_type', 'file_extension', 'as_attachment', 'template_code',
  123. )
  124. class ConfigTemplateImportForm(CSVModelForm):
  125. class Meta:
  126. model = ConfigTemplate
  127. fields = (
  128. 'name', 'description', 'environment_params', 'template_code', 'tags',
  129. )
  130. class SavedFilterImportForm(CSVModelForm):
  131. content_types = CSVMultipleContentTypeField(
  132. label=_('Content types'),
  133. queryset=ContentType.objects.all(),
  134. help_text=_("One or more assigned object types")
  135. )
  136. class Meta:
  137. model = SavedFilter
  138. fields = (
  139. 'name', 'slug', 'content_types', 'description', 'weight', 'enabled', 'shared', 'parameters',
  140. )
  141. class WebhookImportForm(NetBoxModelImportForm):
  142. class Meta:
  143. model = Webhook
  144. fields = (
  145. 'name', 'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template',
  146. 'secret', 'ssl_verification', 'ca_file_path', 'description', 'tags'
  147. )
  148. class EventRuleImportForm(NetBoxModelImportForm):
  149. content_types = CSVMultipleContentTypeField(
  150. label=_('Content types'),
  151. queryset=ContentType.objects.with_feature('event_rules'),
  152. help_text=_("One or more assigned object types")
  153. )
  154. action_object = forms.CharField(
  155. label=_('Action object'),
  156. required=True,
  157. help_text=_('Webhook name or script as dotted path module.Class')
  158. )
  159. class Meta:
  160. model = EventRule
  161. fields = (
  162. 'name', 'description', 'enabled', 'conditions', 'content_types', 'type_create', 'type_update',
  163. 'type_delete', 'type_job_start', 'type_job_end', 'action_type', 'action_object', 'comments', 'tags'
  164. )
  165. def clean(self):
  166. super().clean()
  167. action_object = self.cleaned_data.get('action_object')
  168. action_type = self.cleaned_data.get('action_type')
  169. if action_object and action_type:
  170. # Webhook
  171. if action_type == EventRuleActionChoices.WEBHOOK:
  172. try:
  173. webhook = Webhook.objects.get(name=action_object)
  174. except Webhook.DoesNotExist:
  175. raise forms.ValidationError(f"Webhook {action_object} not found")
  176. self.instance.action_object = webhook
  177. # Script
  178. elif action_type == EventRuleActionChoices.SCRIPT:
  179. from extras.scripts import get_module_and_script
  180. module_name, script_name = action_object.split('.', 1)
  181. try:
  182. module, script = get_module_and_script(module_name, script_name)
  183. except ObjectDoesNotExist:
  184. raise forms.ValidationError(f"Script {action_object} not found")
  185. self.instance.action_object = module
  186. self.instance.action_object_type = ContentType.objects.get_for_model(module, for_concrete_model=False)
  187. self.instance.action_parameters = {
  188. 'script_name': script_name,
  189. }
  190. class TagImportForm(CSVModelForm):
  191. slug = SlugField()
  192. class Meta:
  193. model = Tag
  194. fields = ('name', 'slug', 'color', 'description')
  195. help_texts = {
  196. 'color': mark_safe(_('RGB color in hexadecimal. Example:') + ' <code>00ff00</code>'),
  197. }
  198. class JournalEntryImportForm(NetBoxModelImportForm):
  199. assigned_object_type = CSVContentTypeField(
  200. queryset=ContentType.objects.all(),
  201. label=_('Assigned object type'),
  202. )
  203. kind = CSVChoiceField(
  204. label=_('Kind'),
  205. choices=JournalEntryKindChoices,
  206. help_text=_('The classification of entry')
  207. )
  208. class Meta:
  209. model = JournalEntry
  210. fields = (
  211. 'assigned_object_type', 'assigned_object_id', 'created_by', 'kind', 'comments', 'tags'
  212. )