bulk_import.py 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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.translation import gettext_lazy as _
  6. from core.models import ObjectType
  7. from extras.choices import *
  8. from extras.models import *
  9. from netbox.events import get_event_type_choices
  10. from netbox.forms import NetBoxModelImportForm
  11. from users.models import Group, User
  12. from utilities.forms import CSVModelForm
  13. from utilities.forms.fields import (
  14. CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVModelMultipleChoiceField, CSVMultipleChoiceField,
  15. CSVMultipleContentTypeField, SlugField,
  16. )
  17. __all__ = (
  18. 'ConfigContextProfileImportForm',
  19. 'ConfigTemplateImportForm',
  20. 'CustomFieldChoiceSetImportForm',
  21. 'CustomFieldImportForm',
  22. 'CustomLinkImportForm',
  23. 'EventRuleImportForm',
  24. 'ExportTemplateImportForm',
  25. 'JournalEntryImportForm',
  26. 'NotificationGroupImportForm',
  27. 'SavedFilterImportForm',
  28. 'TagImportForm',
  29. 'WebhookImportForm',
  30. )
  31. class CustomFieldImportForm(CSVModelForm):
  32. object_types = CSVMultipleContentTypeField(
  33. label=_('Object types'),
  34. queryset=ObjectType.objects.with_feature('custom_fields'),
  35. help_text=_("One or more assigned object types")
  36. )
  37. type = CSVChoiceField(
  38. label=_('Type'),
  39. choices=CustomFieldTypeChoices,
  40. help_text=_('Field data type (e.g. text, integer, etc.)')
  41. )
  42. related_object_type = CSVContentTypeField(
  43. label=_('Object type'),
  44. queryset=ObjectType.objects.public(),
  45. required=False,
  46. help_text=_("Object type (for object or multi-object fields)")
  47. )
  48. choice_set = CSVModelChoiceField(
  49. label=_('Choice set'),
  50. queryset=CustomFieldChoiceSet.objects.all(),
  51. to_field_name='name',
  52. required=False,
  53. help_text=_('Choice set (for selection fields)')
  54. )
  55. ui_visible = CSVChoiceField(
  56. label=_('UI visible'),
  57. choices=CustomFieldUIVisibleChoices,
  58. required=False,
  59. help_text=_('Whether the custom field is displayed in the UI')
  60. )
  61. ui_editable = CSVChoiceField(
  62. label=_('UI editable'),
  63. choices=CustomFieldUIEditableChoices,
  64. required=False,
  65. help_text=_('Whether the custom field is editable in the UI')
  66. )
  67. class Meta:
  68. model = CustomField
  69. fields = (
  70. 'name', 'label', 'group_name', 'type', 'object_types', 'related_object_type', 'required', 'unique',
  71. 'description', 'search_weight', 'filter_logic', 'default', 'choice_set', 'weight', 'validation_minimum',
  72. 'validation_maximum', 'validation_regex', 'ui_visible', 'ui_editable', 'is_cloneable', 'comments',
  73. )
  74. class CustomFieldChoiceSetImportForm(CSVModelForm):
  75. base_choices = CSVChoiceField(
  76. choices=CustomFieldChoiceSetBaseChoices,
  77. required=False,
  78. help_text=_('The base set of predefined choices to use (if any)')
  79. )
  80. extra_choices = SimpleArrayField(
  81. base_field=forms.CharField(),
  82. required=False,
  83. help_text=_(
  84. 'Quoted string of comma-separated field choices with optional labels separated by colon: '
  85. '"choice1:First Choice,choice2:Second Choice"'
  86. )
  87. )
  88. class Meta:
  89. model = CustomFieldChoiceSet
  90. fields = (
  91. 'name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically',
  92. )
  93. def clean_extra_choices(self):
  94. if isinstance(self.cleaned_data['extra_choices'], list):
  95. data = []
  96. for line in self.cleaned_data['extra_choices']:
  97. try:
  98. value, label = re.split(r'(?<!\\):', line, maxsplit=1)
  99. value = value.replace('\\:', ':')
  100. label = label.replace('\\:', ':')
  101. except ValueError:
  102. value, label = line, line
  103. data.append((value, label))
  104. return data
  105. class CustomLinkImportForm(CSVModelForm):
  106. object_types = CSVMultipleContentTypeField(
  107. label=_('Object types'),
  108. queryset=ObjectType.objects.with_feature('custom_links'),
  109. help_text=_("One or more assigned object types")
  110. )
  111. button_class = CSVChoiceField(
  112. label=_('button class'),
  113. required=False,
  114. choices=CustomLinkButtonClassChoices,
  115. help_text=_('The class of the first link in a group will be used for the dropdown button')
  116. )
  117. class Meta:
  118. model = CustomLink
  119. fields = (
  120. 'name', 'object_types', 'enabled', 'weight', 'group_name', 'button_class', 'new_window', 'link_text',
  121. 'link_url',
  122. )
  123. class ExportTemplateImportForm(CSVModelForm):
  124. object_types = CSVMultipleContentTypeField(
  125. label=_('Object types'),
  126. queryset=ObjectType.objects.with_feature('export_templates'),
  127. help_text=_("One or more assigned object types")
  128. )
  129. class Meta:
  130. model = ExportTemplate
  131. fields = (
  132. 'name', 'object_types', 'description', 'environment_params', 'mime_type', 'file_name', 'file_extension',
  133. 'as_attachment', 'template_code',
  134. )
  135. class ConfigContextProfileImportForm(NetBoxModelImportForm):
  136. class Meta:
  137. model = ConfigContextProfile
  138. fields = [
  139. 'name', 'description', 'schema', 'comments', 'tags',
  140. ]
  141. class ConfigTemplateImportForm(CSVModelForm):
  142. class Meta:
  143. model = ConfigTemplate
  144. fields = (
  145. 'name', 'description', 'template_code', 'environment_params', 'mime_type', 'file_name', 'file_extension',
  146. 'as_attachment', 'tags',
  147. )
  148. class SavedFilterImportForm(CSVModelForm):
  149. object_types = CSVMultipleContentTypeField(
  150. label=_('Object types'),
  151. queryset=ObjectType.objects.all(),
  152. help_text=_("One or more assigned object types")
  153. )
  154. class Meta:
  155. model = SavedFilter
  156. fields = (
  157. 'name', 'slug', 'object_types', 'description', 'weight', 'enabled', 'shared', 'parameters',
  158. )
  159. class WebhookImportForm(NetBoxModelImportForm):
  160. class Meta:
  161. model = Webhook
  162. fields = (
  163. 'name', 'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template',
  164. 'secret', 'ssl_verification', 'ca_file_path', 'description', 'tags'
  165. )
  166. class EventRuleImportForm(NetBoxModelImportForm):
  167. object_types = CSVMultipleContentTypeField(
  168. label=_('Object types'),
  169. queryset=ObjectType.objects.with_feature('event_rules'),
  170. help_text=_("One or more assigned object types")
  171. )
  172. event_types = CSVMultipleChoiceField(
  173. choices=get_event_type_choices(),
  174. label=_('Event types'),
  175. help_text=_('The event type(s) which will trigger this rule')
  176. )
  177. action_object = forms.CharField(
  178. label=_('Action object'),
  179. required=True,
  180. help_text=_('Webhook name or script as dotted path module.Class')
  181. )
  182. class Meta:
  183. model = EventRule
  184. fields = (
  185. 'name', 'description', 'enabled', 'conditions', 'object_types', 'event_types', 'action_type',
  186. 'comments', 'tags'
  187. )
  188. def clean(self):
  189. super().clean()
  190. action_object = self.cleaned_data.get('action_object')
  191. action_type = self.cleaned_data.get('action_type')
  192. if action_object and action_type:
  193. # Webhook
  194. if action_type == EventRuleActionChoices.WEBHOOK:
  195. try:
  196. webhook = Webhook.objects.get(name=action_object)
  197. except Webhook.DoesNotExist:
  198. raise forms.ValidationError(_("Webhook {name} not found").format(name=action_object))
  199. self.instance.action_object = webhook
  200. # Script
  201. elif action_type == EventRuleActionChoices.SCRIPT:
  202. from extras.scripts import get_module_and_script
  203. module_name, script_name = action_object.split('.', 1)
  204. try:
  205. script = get_module_and_script(module_name, script_name)[1]
  206. except ObjectDoesNotExist:
  207. raise forms.ValidationError(_("Script {name} not found").format(name=action_object))
  208. self.instance.action_object = script
  209. self.instance.action_object_type = ObjectType.objects.get_for_model(script, for_concrete_model=False)
  210. class TagImportForm(CSVModelForm):
  211. slug = SlugField()
  212. weight = forms.IntegerField(
  213. label=_('Weight'),
  214. required=False
  215. )
  216. object_types = CSVMultipleContentTypeField(
  217. label=_('Object types'),
  218. queryset=ObjectType.objects.with_feature('tags'),
  219. help_text=_("One or more assigned object types"),
  220. required=False,
  221. )
  222. class Meta:
  223. model = Tag
  224. fields = (
  225. 'name', 'slug', 'color', 'weight', 'description', 'object_types',
  226. )
  227. class JournalEntryImportForm(NetBoxModelImportForm):
  228. assigned_object_type = CSVContentTypeField(
  229. queryset=ObjectType.objects.all(),
  230. label=_('Assigned object type'),
  231. )
  232. kind = CSVChoiceField(
  233. label=_('Kind'),
  234. choices=JournalEntryKindChoices,
  235. help_text=_('The classification of entry')
  236. )
  237. class Meta:
  238. model = JournalEntry
  239. fields = (
  240. 'assigned_object_type', 'assigned_object_id', 'created_by', 'kind', 'comments', 'tags'
  241. )
  242. class NotificationGroupImportForm(CSVModelForm):
  243. users = CSVModelMultipleChoiceField(
  244. label=_('Users'),
  245. queryset=User.objects.all(),
  246. required=False,
  247. to_field_name='username',
  248. help_text=_('User names separated by commas, encased with double quotes')
  249. )
  250. groups = CSVModelMultipleChoiceField(
  251. label=_('Groups'),
  252. queryset=Group.objects.all(),
  253. required=False,
  254. to_field_name='name',
  255. help_text=_('Group names separated by commas, encased with double quotes')
  256. )
  257. class Meta:
  258. model = NotificationGroup
  259. fields = ('name', 'description', 'users', 'groups')