views.py 9.2 KB

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