views.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. from django.contrib import messages
  2. from django.contrib.auth.decorators import permission_required
  3. from django.contrib.auth.mixins import PermissionRequiredMixin
  4. from django.db import transaction
  5. from django.db.models import Count
  6. from django.shortcuts import get_object_or_404, redirect, render
  7. from django.views.generic import View
  8. from extras.models import Graph, GRAPH_TYPE_PROVIDER
  9. from utilities.forms import ConfirmationForm
  10. from utilities.views import (
  11. BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
  12. )
  13. from . import filters, forms, tables
  14. from .constants import TERM_SIDE_A, TERM_SIDE_Z
  15. from .models import Circuit, CircuitTermination, CircuitType, Provider
  16. #
  17. # Providers
  18. #
  19. class ProviderListView(ObjectListView):
  20. queryset = Provider.objects.annotate(count_circuits=Count('circuits'))
  21. filter = filters.ProviderFilter
  22. filter_form = forms.ProviderFilterForm
  23. table = tables.ProviderDetailTable
  24. template_name = 'circuits/provider_list.html'
  25. class ProviderView(View):
  26. def get(self, request, slug):
  27. provider = get_object_or_404(Provider, slug=slug)
  28. circuits = Circuit.objects.filter(provider=provider).select_related(
  29. 'type', 'tenant'
  30. ).prefetch_related(
  31. 'terminations__site'
  32. )
  33. show_graphs = Graph.objects.filter(type=GRAPH_TYPE_PROVIDER).exists()
  34. return render(request, 'circuits/provider.html', {
  35. 'provider': provider,
  36. 'circuits': circuits,
  37. 'show_graphs': show_graphs,
  38. })
  39. class ProviderCreateView(PermissionRequiredMixin, ObjectEditView):
  40. permission_required = 'circuits.add_provider'
  41. model = Provider
  42. model_form = forms.ProviderForm
  43. template_name = 'circuits/provider_edit.html'
  44. default_return_url = 'circuits:provider_list'
  45. class ProviderEditView(ProviderCreateView):
  46. permission_required = 'circuits.change_provider'
  47. class ProviderDeleteView(PermissionRequiredMixin, ObjectDeleteView):
  48. permission_required = 'circuits.delete_provider'
  49. model = Provider
  50. default_return_url = 'circuits:provider_list'
  51. class ProviderBulkImportView(PermissionRequiredMixin, BulkImportView):
  52. permission_required = 'circuits.add_provider'
  53. model_form = forms.ProviderCSVForm
  54. table = tables.ProviderTable
  55. default_return_url = 'circuits:provider_list'
  56. class ProviderBulkEditView(PermissionRequiredMixin, BulkEditView):
  57. permission_required = 'circuits.change_provider'
  58. queryset = Provider.objects.all()
  59. filter = filters.ProviderFilter
  60. table = tables.ProviderTable
  61. form = forms.ProviderBulkEditForm
  62. default_return_url = 'circuits:provider_list'
  63. class ProviderBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  64. permission_required = 'circuits.delete_provider'
  65. queryset = Provider.objects.all()
  66. filter = filters.ProviderFilter
  67. table = tables.ProviderTable
  68. default_return_url = 'circuits:provider_list'
  69. #
  70. # Circuit Types
  71. #
  72. class CircuitTypeListView(ObjectListView):
  73. queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))
  74. table = tables.CircuitTypeTable
  75. template_name = 'circuits/circuittype_list.html'
  76. class CircuitTypeCreateView(PermissionRequiredMixin, ObjectEditView):
  77. permission_required = 'circuits.add_circuittype'
  78. model = CircuitType
  79. model_form = forms.CircuitTypeForm
  80. default_return_url = 'circuits:circuittype_list'
  81. class CircuitTypeEditView(CircuitTypeCreateView):
  82. permission_required = 'circuits.change_circuittype'
  83. class CircuitTypeBulkImportView(PermissionRequiredMixin, BulkImportView):
  84. permission_required = 'circuits.add_circuittype'
  85. model_form = forms.CircuitTypeCSVForm
  86. table = tables.CircuitTypeTable
  87. default_return_url = 'circuits:circuittype_list'
  88. class CircuitTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  89. permission_required = 'circuits.delete_circuittype'
  90. queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))
  91. table = tables.CircuitTypeTable
  92. default_return_url = 'circuits:circuittype_list'
  93. #
  94. # Circuits
  95. #
  96. class CircuitListView(ObjectListView):
  97. queryset = Circuit.objects.select_related(
  98. 'provider', 'type', 'tenant'
  99. ).prefetch_related(
  100. 'terminations__site', 'terminations__interface__device'
  101. )
  102. filter = filters.CircuitFilter
  103. filter_form = forms.CircuitFilterForm
  104. table = tables.CircuitTable
  105. template_name = 'circuits/circuit_list.html'
  106. class CircuitView(View):
  107. def get(self, request, pk):
  108. circuit = get_object_or_404(Circuit.objects.select_related('provider', 'type', 'tenant__group'), pk=pk)
  109. termination_a = CircuitTermination.objects.select_related(
  110. 'site__region', 'interface__device'
  111. ).filter(
  112. circuit=circuit, term_side=TERM_SIDE_A
  113. ).first()
  114. termination_z = CircuitTermination.objects.select_related(
  115. 'site__region', 'interface__device'
  116. ).filter(
  117. circuit=circuit, term_side=TERM_SIDE_Z
  118. ).first()
  119. return render(request, 'circuits/circuit.html', {
  120. 'circuit': circuit,
  121. 'termination_a': termination_a,
  122. 'termination_z': termination_z,
  123. })
  124. class CircuitCreateView(PermissionRequiredMixin, ObjectEditView):
  125. permission_required = 'circuits.add_circuit'
  126. model = Circuit
  127. model_form = forms.CircuitForm
  128. template_name = 'circuits/circuit_edit.html'
  129. default_return_url = 'circuits:circuit_list'
  130. class CircuitEditView(CircuitCreateView):
  131. permission_required = 'circuits.change_circuit'
  132. class CircuitDeleteView(PermissionRequiredMixin, ObjectDeleteView):
  133. permission_required = 'circuits.delete_circuit'
  134. model = Circuit
  135. default_return_url = 'circuits:circuit_list'
  136. class CircuitBulkImportView(PermissionRequiredMixin, BulkImportView):
  137. permission_required = 'circuits.add_circuit'
  138. model_form = forms.CircuitCSVForm
  139. table = tables.CircuitTable
  140. default_return_url = 'circuits:circuit_list'
  141. class CircuitBulkEditView(PermissionRequiredMixin, BulkEditView):
  142. permission_required = 'circuits.change_circuit'
  143. queryset = Circuit.objects.select_related('provider', 'type', 'tenant').prefetch_related('terminations__site')
  144. filter = filters.CircuitFilter
  145. table = tables.CircuitTable
  146. form = forms.CircuitBulkEditForm
  147. default_return_url = 'circuits:circuit_list'
  148. class CircuitBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  149. permission_required = 'circuits.delete_circuit'
  150. queryset = Circuit.objects.select_related('provider', 'type', 'tenant').prefetch_related('terminations__site')
  151. filter = filters.CircuitFilter
  152. table = tables.CircuitTable
  153. default_return_url = 'circuits:circuit_list'
  154. @permission_required('circuits.change_circuittermination')
  155. def circuit_terminations_swap(request, pk):
  156. circuit = get_object_or_404(Circuit, pk=pk)
  157. termination_a = CircuitTermination.objects.filter(circuit=circuit, term_side=TERM_SIDE_A).first()
  158. termination_z = CircuitTermination.objects.filter(circuit=circuit, term_side=TERM_SIDE_Z).first()
  159. if not termination_a and not termination_z:
  160. messages.error(request, "No terminations have been defined for circuit {}.".format(circuit))
  161. return redirect('circuits:circuit', pk=circuit.pk)
  162. if request.method == 'POST':
  163. form = ConfirmationForm(request.POST)
  164. if form.is_valid():
  165. if termination_a and termination_z:
  166. # Use a placeholder to avoid an IntegrityError on the (circuit, term_side) unique constraint
  167. with transaction.atomic():
  168. termination_a.term_side = '_'
  169. termination_a.save()
  170. termination_z.term_side = 'A'
  171. termination_z.save()
  172. termination_a.term_side = 'Z'
  173. termination_a.save()
  174. elif termination_a:
  175. termination_a.term_side = 'Z'
  176. termination_a.save()
  177. else:
  178. termination_z.term_side = 'A'
  179. termination_z.save()
  180. messages.success(request, "Swapped terminations for circuit {}.".format(circuit))
  181. return redirect('circuits:circuit', pk=circuit.pk)
  182. else:
  183. form = ConfirmationForm()
  184. return render(request, 'circuits/circuit_terminations_swap.html', {
  185. 'circuit': circuit,
  186. 'termination_a': termination_a,
  187. 'termination_z': termination_z,
  188. 'form': form,
  189. 'panel_class': 'default',
  190. 'button_class': 'primary',
  191. 'return_url': circuit.get_absolute_url(),
  192. })
  193. #
  194. # Circuit terminations
  195. #
  196. class CircuitTerminationCreateView(PermissionRequiredMixin, ObjectEditView):
  197. permission_required = 'circuits.add_circuittermination'
  198. model = CircuitTermination
  199. model_form = forms.CircuitTerminationForm
  200. template_name = 'circuits/circuittermination_edit.html'
  201. def alter_obj(self, obj, request, url_args, url_kwargs):
  202. if 'circuit' in url_kwargs:
  203. obj.circuit = get_object_or_404(Circuit, pk=url_kwargs['circuit'])
  204. return obj
  205. def get_return_url(self, request, obj):
  206. return obj.circuit.get_absolute_url()
  207. class CircuitTerminationEditView(CircuitTerminationCreateView):
  208. permission_required = 'circuits.change_circuittermination'
  209. class CircuitTerminationDeleteView(PermissionRequiredMixin, ObjectDeleteView):
  210. permission_required = 'circuits.delete_circuittermination'
  211. model = CircuitTermination