views.py 6.0 KB

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