class WebhookFilterForm(FilterForm): field_groups = [ ['q'], ['content_types', 'http_method', 'enabled'], ['type_create', 'type_update', 'type_delete'], ] content_types = ContentTypeMultipleChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('webhooks'), required=False) http_method = forms.MultipleChoiceField(choices=WebhookHttpMethodChoices, required=False, widget=StaticSelectMultiple(), label=_('HTTP method')) enabled = forms.NullBooleanField( required=False, widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES)) type_create = forms.NullBooleanField( required=False, widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES)) type_update = forms.NullBooleanField( required=False, widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES)) type_delete = forms.NullBooleanField( required=False, widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES))
class TagFilterForm(BootstrapMixin, forms.Form): model = Tag q = forms.CharField(required=False, label=_('Search')) content_type_id = ContentTypeMultipleChoiceField( queryset=ContentType.objects.filter(FeatureQuery('tags').get_query()), required=False, label=_('Tagged object type'))
class WebhookForm(BootstrapMixin, forms.ModelForm): content_types = ContentTypeMultipleChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('webhooks')) class Meta: model = Webhook fields = '__all__' fieldsets = ( ('Webhook', ('name', 'content_types', 'enabled')), ('Events', ('type_create', 'type_update', 'type_delete')), ('HTTP Request', ( 'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template', 'secret', )), ('Conditions', ('conditions', )), ('SSL', ('ssl_verification', 'ca_file_path')), ) labels = { 'type_create': 'Creations', 'type_update': 'Updates', 'type_delete': 'Deletions', } widgets = { 'http_method': StaticSelect(), 'additional_headers': forms.Textarea(attrs={'class': 'font-monospace'}), 'body_template': forms.Textarea(attrs={'class': 'font-monospace'}), }
class CustomLinkForm(BootstrapMixin, forms.ModelForm): content_type = ContentTypeChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_links')) class Meta: model = CustomLink fields = '__all__' fieldsets = ( ('Custom Link', ('name', 'content_type', 'weight', 'group_name', 'button_class', 'new_window')), ('Templates', ('link_text', 'link_url')), ) widgets = { 'button_class': StaticSelect(), 'link_text': forms.Textarea(attrs={'class': 'font-monospace'}), 'link_url': forms.Textarea(attrs={'class': 'font-monospace'}), } help_texts = { 'link_text': 'Jinja2 template code for the link text. Reference the object as <code>{{ obj }}</code>. ' 'Links which render as empty text will not be displayed.', 'link_url': 'Jinja2 template code for the link URL. Reference the object as <code>{{ obj }}</code>.', }
class WebhookFilterForm(BootstrapMixin, forms.Form): field_groups = [ ['q'], ['content_types', 'http_method', 'enabled'], ['type_create', 'type_update', 'type_delete'], ] q = forms.CharField( required=False, widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), label=_('Search')) content_types = ContentTypeMultipleChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), required=False) http_method = forms.MultipleChoiceField(choices=WebhookHttpMethodChoices, required=False, widget=StaticSelectMultiple(), label=_('HTTP method')) enabled = forms.NullBooleanField( required=False, widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES)) type_create = forms.NullBooleanField( required=False, widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES)) type_update = forms.NullBooleanField( required=False, widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES)) type_delete = forms.NullBooleanField( required=False, widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES))
class CustomFieldSerializer(ValidatedModelSerializer): url = serializers.HyperlinkedIdentityField( view_name='extras-api:customfield-detail') content_types = ContentTypeField(queryset=ContentType.objects.filter( FeatureQuery('custom_fields').get_query()), many=True) type = ChoiceField(choices=CustomFieldTypeChoices) filter_logic = ChoiceField(choices=CustomFieldFilterLogicChoices, required=False) class Meta: model = CustomField fields = [ 'id', 'url', 'display', 'content_types', 'type', 'name', 'label', 'description', 'required', 'filter_logic', 'default', 'weight', 'validation_minimum', 'validation_maximum', 'validation_regex', 'choices', ]
class WebhookSerializer(ValidatedModelSerializer): url = serializers.HyperlinkedIdentityField( view_name='extras-api:webhook-detail') content_types = ContentTypeField(queryset=ContentType.objects.filter( FeatureQuery('webhooks').get_query()), many=True) class Meta: model = Webhook fields = [ 'id', 'url', 'display', 'content_types', 'name', 'type_create', 'type_update', 'type_delete', 'payload_url', 'enabled', 'http_method', 'http_content_type', 'additional_headers', 'body_template', 'secret', 'ssl_verification', 'ca_file_path', ]
class CustomFieldCSVForm(CSVModelForm): content_types = CSVMultipleContentTypeField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), help_text="One or more assigned object types") type = CSVChoiceField( choices=CustomFieldTypeChoices, help_text='Field data type (e.g. text, integer, etc.)') choices = SimpleArrayField( base_field=forms.CharField(), required=False, help_text='Comma-separated list of field choices') class Meta: model = CustomField fields = ( 'name', 'label', 'type', 'content_types', 'required', 'description', 'weight', 'filter_logic', 'default', 'choices', 'weight', 'validation_minimum', 'validation_maximum', 'validation_regex', )
class ExportTemplateBulkEditForm(BulkEditForm): pk = forms.ModelMultipleChoiceField( queryset=ExportTemplate.objects.all(), widget=forms.MultipleHiddenInput ) content_type = ContentTypeChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('export_templates'), required=False ) description = forms.CharField( max_length=200, required=False ) mime_type = forms.CharField( max_length=50, required=False ) file_extension = forms.CharField( max_length=15, required=False ) as_attachment = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect() ) class Meta: nullable_fields = ['description', 'mime_type', 'file_extension']
class CustomLinkBulkEditForm(BulkEditForm): pk = forms.ModelMultipleChoiceField( queryset=CustomLink.objects.all(), widget=forms.MultipleHiddenInput ) content_type = ContentTypeChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_links'), required=False ) new_window = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect() ) weight = forms.IntegerField( required=False ) button_class = forms.ChoiceField( choices=add_blank_choice(CustomLinkButtonClassChoices), required=False, widget=StaticSelect() ) class Meta: nullable_fields = []
class CustomLink(models.Model): """ A custom link to an external representation of a NetBox object. The link text and URL fields accept Jinja2 template code to be rendered with an object as context. """ content_type = models.ForeignKey( to=ContentType, on_delete=models.CASCADE, limit_choices_to=FeatureQuery('custom_links')) name = models.CharField(max_length=100, unique=True) text = models.CharField(max_length=500, help_text="Jinja2 template code for link text") url = models.CharField(max_length=500, verbose_name='URL', help_text="Jinja2 template code for link URL") weight = models.PositiveSmallIntegerField(default=100) group_name = models.CharField( max_length=50, blank=True, help_text="Links with the same group will appear as a dropdown menu") button_class = models.CharField( max_length=30, choices=CustomLinkButtonClassChoices, default=CustomLinkButtonClassChoices.CLASS_DEFAULT, help_text= "The class of the first link in a group will be used for the dropdown button" ) new_window = models.BooleanField( help_text="Force link to open in a new window") class Meta: ordering = ['group_name', 'weight', 'name'] def __str__(self): return self.name
class ExportTemplate(models.Model): content_type = models.ForeignKey( to=ContentType, on_delete=models.CASCADE, limit_choices_to=FeatureQuery('export_templates')) name = models.CharField(max_length=100) description = models.CharField(max_length=200, blank=True) template_code = models.TextField( help_text= 'The list of objects being exported is passed as a context variable named <code>queryset</code>.' ) mime_type = models.CharField( max_length=50, blank=True, verbose_name='MIME type', help_text='Defaults to <code>text/plain</code>') file_extension = models.CharField( max_length=15, blank=True, help_text='Extension to append to the rendered filename') objects = RestrictedQuerySet.as_manager() class Meta: ordering = ['content_type', 'name'] unique_together = [['content_type', 'name']] def __str__(self): return '{}: {}'.format(self.content_type, self.name) def render(self, queryset): """ Render the contents of the template. """ context = {'queryset': queryset} output = render_jinja2(self.template_code, context) # Replace CRLF-style line terminators output = output.replace('\r\n', '\n') return output def render_to_response(self, queryset): """ Render the template to an HTTP response, delivered as a named file attachment """ output = self.render(queryset) mime_type = 'text/plain' if not self.mime_type else self.mime_type # Build the response response = HttpResponse(output, content_type=mime_type) filename = 'netbox_{}{}'.format( queryset.model._meta.verbose_name_plural, '.{}'.format(self.file_extension) if self.file_extension else '') response['Content-Disposition'] = 'attachment; filename="{}"'.format( filename) return response
class GraphSerializer(ValidatedModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='extras-api:graph-detail') type = ContentTypeField( queryset=ContentType.objects.filter(FeatureQuery('graphs').get_query()), ) class Meta: model = Graph fields = ['id', 'url', 'type', 'weight', 'name', 'template_language', 'source', 'link']
class CustomLink(ChangeLoggedModel): """ A custom link to an external representation of a NetBox object. The link text and URL fields accept Jinja2 template code to be rendered with an object as context. """ content_type = models.ForeignKey( to=ContentType, on_delete=models.CASCADE, limit_choices_to=FeatureQuery('custom_links')) name = models.CharField(max_length=100, unique=True) link_text = models.CharField( max_length=500, help_text="Jinja2 template code for link text") link_url = models.CharField(max_length=500, verbose_name='Link URL', help_text="Jinja2 template code for link URL") weight = models.PositiveSmallIntegerField(default=100) group_name = models.CharField( max_length=50, blank=True, help_text="Links with the same group will appear as a dropdown menu") button_class = models.CharField( max_length=30, choices=CustomLinkButtonClassChoices, default=CustomLinkButtonClassChoices.CLASS_DEFAULT, help_text= "The class of the first link in a group will be used for the dropdown button" ) new_window = models.BooleanField( default=False, help_text="Force link to open in a new window") class Meta: ordering = ['group_name', 'weight', 'name'] def __str__(self): return self.name def get_absolute_url(self): return reverse('extras:customlink', args=[self.pk]) def render(self, context): """ Render the CustomLink given the provided context, and return the text, link, and link_target. :param context: The context passed to Jinja2 """ text = render_jinja2(self.link_text, context) if not text: return {} link = render_jinja2(self.link_url, context) link_target = ' target="_blank"' if self.new_window else '' return { 'text': text, 'link': link, 'link_target': link_target, }
class GraphSerializer(ValidatedModelSerializer): type = ContentTypeField(queryset=ContentType.objects.filter( FeatureQuery('graphs').get_query()), ) class Meta: model = Graph fields = [ 'id', 'type', 'weight', 'name', 'template_language', 'source', 'link' ]
def setUpTestData(cls): # Get the first three available types content_types = ContentType.objects.filter(FeatureQuery('graphs').get_query())[:3] graphs = ( Graph(name='Graph 1', type=content_types[0], template_language=TemplateLanguageChoices.LANGUAGE_DJANGO, source='http://example.com/1'), Graph(name='Graph 2', type=content_types[1], template_language=TemplateLanguageChoices.LANGUAGE_JINJA2, source='http://example.com/2'), Graph(name='Graph 3', type=content_types[2], template_language=TemplateLanguageChoices.LANGUAGE_JINJA2, source='http://example.com/3'), ) Graph.objects.bulk_create(graphs)
class WebhookCSVForm(CSVModelForm): content_types = CSVMultipleContentTypeField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('webhooks'), help_text="One or more assigned object types") class Meta: model = Webhook fields = ('name', 'enabled', 'content_types', 'type_create', 'type_update', 'type_delete', 'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template', 'secret', 'ssl_verification', 'ca_file_path')
class CustomLinkSerializer(ValidatedModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='extras-api:customlink-detail') content_type = ContentTypeField( queryset=ContentType.objects.filter(FeatureQuery('custom_links').get_query()) ) class Meta: model = CustomLink fields = [ 'id', 'url', 'display', 'content_type', 'name', 'link_text', 'link_url', 'weight', 'group_name', 'button_class', 'new_window', 'created', 'last_updated', ]
class ExportTemplateSerializer(ValidatedModelSerializer): url = serializers.HyperlinkedIdentityField( view_name='extras-api:exporttemplate-detail') content_type = ContentTypeField(queryset=ContentType.objects.filter( FeatureQuery('export_templates').get_query()), ) class Meta: model = ExportTemplate fields = [ 'id', 'url', 'content_type', 'name', 'description', 'template_code', 'mime_type', 'file_extension' ]
class CustomLinkFilterForm(FilterForm): field_groups = [ ['q'], ['content_type', 'weight', 'new_window'], ] content_type = ContentTypeChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_links'), required=False) weight = forms.IntegerField(required=False) new_window = forms.NullBooleanField( required=False, widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES))
class ExportTemplateFilterForm(FilterForm): field_groups = [ ['q'], ['content_type', 'mime_type', 'file_extension', 'as_attachment'], ] content_type = ContentTypeChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('export_templates'), required=False) mime_type = forms.CharField(required=False, label=_('MIME type')) file_extension = forms.CharField(required=False) as_attachment = forms.NullBooleanField( required=False, widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES))
class ExportTemplateForm(BootstrapMixin, forms.ModelForm): content_type = ContentTypeChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('export_templates')) class Meta: model = ExportTemplate fields = '__all__' fieldsets = ( ('Export Template', ('name', 'content_type', 'description')), ('Template', ('template_code', )), ('Rendering', ('mime_type', 'file_extension', 'as_attachment')), ) widgets = { 'template_code': forms.Textarea(attrs={'class': 'font-monospace'}), }
class CustomFieldForm(BootstrapMixin, forms.ModelForm): content_types = ContentTypeMultipleChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields') ) class Meta: model = CustomField fields = '__all__' fieldsets = ( ('Custom Field', ('name', 'label', 'type', 'weight', 'required', 'description')), ('Assigned Models', ('content_types',)), ('Behavior', ('filter_logic',)), ('Values', ('default', 'choices')), ('Validation', ('validation_minimum', 'validation_maximum', 'validation_regex')), )
class ExportTemplateCSVForm(CSVModelForm): content_type = CSVContentTypeField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('export_templates'), help_text="Assigned object type") class Meta: model = ExportTemplate fields = ( 'name', 'content_type', 'description', 'mime_type', 'file_extension', 'as_attachment', 'template_code', )
class CustomLinkFilterForm(BootstrapMixin, forms.Form): field_groups = [ ['q'], ['content_type', 'weight', 'new_window'], ] q = forms.CharField( required=False, widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), label=_('Search')) content_type = ContentTypeChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), required=False) weight = forms.IntegerField(required=False) new_window = forms.NullBooleanField( required=False, widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES))
class CustomLinkCSVForm(CSVModelForm): content_type = CSVContentTypeField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_links'), help_text="Assigned object type") class Meta: model = CustomLink fields = ( 'name', 'content_type', 'weight', 'group_name', 'button_class', 'new_window', 'link_text', 'link_url', )
class ExportTemplateFilterForm(BootstrapMixin, forms.Form): field_groups = [ ['q'], ['content_type', 'mime_type', 'file_extension', 'as_attachment'], ] q = forms.CharField( required=False, widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), label=_('Search')) content_type = ContentTypeChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), required=False) mime_type = forms.CharField(required=False, label=_('MIME type')) file_extension = forms.CharField(required=False) as_attachment = forms.NullBooleanField( required=False, widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES))
class CustomFieldFilterForm(FilterForm): field_groups = [ ['q'], ['type', 'content_types'], ['weight', 'required'], ] content_types = ContentTypeMultipleChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), required=False) type = forms.MultipleChoiceField(choices=CustomFieldTypeChoices, required=False, widget=StaticSelectMultiple(), label=_('Field type')) weight = forms.IntegerField(required=False) required = forms.NullBooleanField( required=False, widget=StaticSelect(choices=BOOLEAN_WITH_BLANK_CHOICES))
class Graph(models.Model): type = models.ForeignKey(to=ContentType, on_delete=models.CASCADE, limit_choices_to=FeatureQuery('graphs')) weight = models.PositiveSmallIntegerField(default=1000) name = models.CharField(max_length=100, verbose_name='Name') template_language = models.CharField( max_length=50, choices=TemplateLanguageChoices, default=TemplateLanguageChoices.LANGUAGE_JINJA2) source = models.CharField(max_length=500, verbose_name='Source URL') link = models.URLField(blank=True, verbose_name='Link URL') objects = RestrictedQuerySet.as_manager() class Meta: ordering = ('type', 'weight', 'name', 'pk' ) # (type, weight, name) may be non-unique def __str__(self): return self.name def embed_url(self, obj): context = {'obj': obj} if self.template_language == TemplateLanguageChoices.LANGUAGE_DJANGO: template = Template(self.source) return template.render(Context(context)) elif self.template_language == TemplateLanguageChoices.LANGUAGE_JINJA2: return render_jinja2(self.source, context) def embed_link(self, obj): if self.link is None: return '' context = {'obj': obj} if self.template_language == TemplateLanguageChoices.LANGUAGE_DJANGO: template = Template(self.link) return template.render(Context(context)) elif self.template_language == TemplateLanguageChoices.LANGUAGE_JINJA2: return render_jinja2(self.link, context)
class ExportTemplateSerializer(ValidatedModelSerializer): content_type = ContentTypeField(queryset=ContentType.objects.filter( FeatureQuery('export_templates').get_query()), ) template_language = ChoiceField( choices=TemplateLanguageChoices, default=TemplateLanguageChoices.LANGUAGE_JINJA2) class Meta: model = ExportTemplate fields = [ 'id', 'content_type', 'name', 'description', 'template_language', 'template_code', 'mime_type', 'file_extension', ]