views.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. from __future__ import unicode_literals
  2. from rest_framework.decorators import detail_route
  3. from rest_framework.exceptions import PermissionDenied
  4. from rest_framework.response import Response
  5. from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet, ViewSet
  6. from django.contrib.contenttypes.models import ContentType
  7. from django.http import Http404, HttpResponse
  8. from django.shortcuts import get_object_or_404
  9. from extras import filters
  10. from extras.models import ExportTemplate, Graph, ImageAttachment, ReportResult, TopologyMap, UserAction
  11. from extras.reports import get_report, get_reports
  12. from utilities.api import WritableSerializerMixin
  13. from . import serializers
  14. class CustomFieldModelViewSet(ModelViewSet):
  15. """
  16. Include the applicable set of CustomFields in the ModelViewSet context.
  17. """
  18. def get_serializer_context(self):
  19. # Gather all custom fields for the model
  20. content_type = ContentType.objects.get_for_model(self.queryset.model)
  21. custom_fields = content_type.custom_fields.prefetch_related('choices')
  22. # Cache all relevant CustomFieldChoices. This saves us from having to do a lookup per select field per object.
  23. custom_field_choices = {}
  24. for field in custom_fields:
  25. for cfc in field.choices.all():
  26. custom_field_choices[cfc.id] = cfc.value
  27. custom_field_choices = custom_field_choices
  28. context = super(CustomFieldModelViewSet, self).get_serializer_context()
  29. context.update({
  30. 'custom_fields': custom_fields,
  31. 'custom_field_choices': custom_field_choices,
  32. })
  33. return context
  34. def get_queryset(self):
  35. # Prefetch custom field values
  36. return super(CustomFieldModelViewSet, self).get_queryset().prefetch_related('custom_field_values__field')
  37. class GraphViewSet(WritableSerializerMixin, ModelViewSet):
  38. queryset = Graph.objects.all()
  39. serializer_class = serializers.GraphSerializer
  40. write_serializer_class = serializers.WritableGraphSerializer
  41. filter_class = filters.GraphFilter
  42. class ExportTemplateViewSet(WritableSerializerMixin, ModelViewSet):
  43. queryset = ExportTemplate.objects.all()
  44. serializer_class = serializers.ExportTemplateSerializer
  45. filter_class = filters.ExportTemplateFilter
  46. class TopologyMapViewSet(WritableSerializerMixin, ModelViewSet):
  47. queryset = TopologyMap.objects.select_related('site')
  48. serializer_class = serializers.TopologyMapSerializer
  49. write_serializer_class = serializers.WritableTopologyMapSerializer
  50. filter_class = filters.TopologyMapFilter
  51. @detail_route()
  52. def render(self, request, pk):
  53. tmap = get_object_or_404(TopologyMap, pk=pk)
  54. img_format = 'png'
  55. try:
  56. data = tmap.render(img_format=img_format)
  57. except:
  58. return HttpResponse(
  59. "There was an error generating the requested graph. Ensure that the GraphViz executables have been "
  60. "installed correctly."
  61. )
  62. response = HttpResponse(data, content_type='image/{}'.format(img_format))
  63. response['Content-Disposition'] = 'inline; filename="{}.{}"'.format(tmap.slug, img_format)
  64. return response
  65. class ImageAttachmentViewSet(WritableSerializerMixin, ModelViewSet):
  66. queryset = ImageAttachment.objects.all()
  67. serializer_class = serializers.ImageAttachmentSerializer
  68. write_serializer_class = serializers.WritableImageAttachmentSerializer
  69. class ReportViewSet(ViewSet):
  70. _ignore_model_permissions = True
  71. exclude_from_schema = True
  72. lookup_value_regex = '[^/]+' # Allow dots
  73. def _retrieve_report(self, pk):
  74. # Read the PK as "<module>.<report>"
  75. if '.' not in pk:
  76. raise Http404
  77. module_name, report_name = pk.split('.', 1)
  78. # Raise a 404 on an invalid Report module/name
  79. report = get_report(module_name, report_name)
  80. if report is None:
  81. raise Http404
  82. return report
  83. def list(self, request):
  84. """
  85. Compile all reports and their related results (if any). Result data is deferred in the list view.
  86. """
  87. report_list = []
  88. # Iterate through all available Reports.
  89. for module_name, reports in get_reports():
  90. for report in reports:
  91. # Attach the relevant ReportResult (if any) to each Report.
  92. report.result = ReportResult.objects.filter(report=report.full_name).defer('data').first()
  93. report_list.append(report)
  94. serializer = serializers.ReportSerializer(report_list, many=True, context={
  95. 'request': request,
  96. })
  97. return Response(serializer.data)
  98. def retrieve(self, request, pk):
  99. """
  100. Retrieve a single Report identified as "<module>.<report>".
  101. """
  102. # Retrieve the Report and ReportResult, if any.
  103. report = self._retrieve_report(pk)
  104. report.result = ReportResult.objects.filter(report=report.full_name).first()
  105. serializer = serializers.ReportDetailSerializer(report)
  106. return Response(serializer.data)
  107. @detail_route(methods=['post'])
  108. def run(self, request, pk):
  109. """
  110. Run a Report and create a new ReportResult, overwriting any previous result for the Report.
  111. """
  112. # Check that the user has permission to run reports.
  113. if not request.user.has_perm('extras.add_reportresult'):
  114. raise PermissionDenied("This user does not have permission to run reports.")
  115. # Retrieve and run the Report. This will create a new ReportResult.
  116. report = self._retrieve_report(pk)
  117. report.run()
  118. serializer = serializers.ReportDetailSerializer(report)
  119. return Response(serializer.data)
  120. class RecentActivityViewSet(ReadOnlyModelViewSet):
  121. """
  122. List all UserActions to provide a log of recent activity.
  123. """
  124. queryset = UserAction.objects.all()
  125. serializer_class = serializers.UserActionSerializer
  126. filter_class = filters.UserActionFilter