views.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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.views.generic import View
  9. from extras.models import Graph, GRAPH_TYPE_PROVIDER
  10. from utilities.forms import ConfirmationForm
  11. from utilities.views import (
  12. BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
  13. )
  14. from . import filters, forms, tables
  15. from .constants import TERM_SIDE_A, TERM_SIDE_Z
  16. from .models import Circuit, CircuitTermination, CircuitType, Provider
  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. queryset = Provider.objects.all()
  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. queryset = Provider.objects.all()
  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. default_return_url = 'circuits:circuittype_list'
  82. class CircuitTypeEditView(CircuitTypeCreateView):
  83. permission_required = 'circuits.change_circuittype'
  84. class CircuitTypeBulkImportView(PermissionRequiredMixin, BulkImportView):
  85. permission_required = 'circuits.add_circuittype'
  86. model_form = forms.CircuitTypeCSVForm
  87. table = tables.CircuitTypeTable
  88. default_return_url = 'circuits:circuittype_list'
  89. class CircuitTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  90. permission_required = 'circuits.delete_circuittype'
  91. queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))
  92. table = tables.CircuitTypeTable
  93. default_return_url = 'circuits:circuittype_list'
  94. #
  95. # Circuits
  96. #
  97. class CircuitListView(ObjectListView):
  98. queryset = Circuit.objects.select_related(
  99. 'provider', 'type', 'tenant'
  100. ).prefetch_related(
  101. 'terminations__site', 'terminations__interface__device'
  102. )
  103. filter = filters.CircuitFilter
  104. filter_form = forms.CircuitFilterForm
  105. table = tables.CircuitTable
  106. template_name = 'circuits/circuit_list.html'
  107. class CircuitView(View):
  108. def get(self, request, pk):
  109. circuit = get_object_or_404(Circuit.objects.select_related('provider', 'type', 'tenant__group'), pk=pk)
  110. termination_a = CircuitTermination.objects.select_related(
  111. 'site__region', 'interface__device'
  112. ).filter(
  113. circuit=circuit, term_side=TERM_SIDE_A
  114. ).first()
  115. termination_z = CircuitTermination.objects.select_related(
  116. 'site__region', 'interface__device'
  117. ).filter(
  118. circuit=circuit, term_side=TERM_SIDE_Z
  119. ).first()
  120. return render(request, 'circuits/circuit.html', {
  121. 'circuit': circuit,
  122. 'termination_a': termination_a,
  123. 'termination_z': termination_z,
  124. })
  125. class CircuitCreateView(PermissionRequiredMixin, ObjectEditView):
  126. permission_required = 'circuits.add_circuit'
  127. model = Circuit
  128. model_form = forms.CircuitForm
  129. template_name = 'circuits/circuit_edit.html'
  130. default_return_url = 'circuits:circuit_list'
  131. class CircuitEditView(CircuitCreateView):
  132. permission_required = 'circuits.change_circuit'
  133. class CircuitDeleteView(PermissionRequiredMixin, ObjectDeleteView):
  134. permission_required = 'circuits.delete_circuit'
  135. model = Circuit
  136. default_return_url = 'circuits:circuit_list'
  137. class CircuitBulkImportView(PermissionRequiredMixin, BulkImportView):
  138. permission_required = 'circuits.add_circuit'
  139. model_form = forms.CircuitCSVForm
  140. table = tables.CircuitTable
  141. default_return_url = 'circuits:circuit_list'
  142. class CircuitBulkEditView(PermissionRequiredMixin, BulkEditView):
  143. permission_required = 'circuits.change_circuit'
  144. queryset = Circuit.objects.select_related('provider', 'type', 'tenant').prefetch_related('terminations__site')
  145. filter = filters.CircuitFilter
  146. table = tables.CircuitTable
  147. form = forms.CircuitBulkEditForm
  148. default_return_url = 'circuits:circuit_list'
  149. class CircuitBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  150. permission_required = 'circuits.delete_circuit'
  151. queryset = Circuit.objects.select_related('provider', 'type', 'tenant').prefetch_related('terminations__site')
  152. filter = filters.CircuitFilter
  153. table = tables.CircuitTable
  154. default_return_url = 'circuits:circuit_list'
  155. @permission_required('circuits.change_circuittermination')
  156. def circuit_terminations_swap(request, pk):
  157. circuit = get_object_or_404(Circuit, pk=pk)
  158. termination_a = CircuitTermination.objects.filter(circuit=circuit, term_side=TERM_SIDE_A).first()
  159. termination_z = CircuitTermination.objects.filter(circuit=circuit, term_side=TERM_SIDE_Z).first()
  160. if not termination_a and not termination_z:
  161. messages.error(request, "No terminations have been defined for circuit {}.".format(circuit))
  162. return redirect('circuits:circuit', pk=circuit.pk)
  163. if request.method == 'POST':
  164. form = ConfirmationForm(request.POST)
  165. if form.is_valid():
  166. if termination_a and termination_z:
  167. # Use a placeholder to avoid an IntegrityError on the (circuit, term_side) unique constraint
  168. with transaction.atomic():
  169. termination_a.term_side = '_'
  170. termination_a.save()
  171. termination_z.term_side = 'A'
  172. termination_z.save()
  173. termination_a.term_side = 'Z'
  174. termination_a.save()
  175. elif termination_a:
  176. termination_a.term_side = 'Z'
  177. termination_a.save()
  178. else:
  179. termination_z.term_side = 'A'
  180. termination_z.save()
  181. messages.success(request, "Swapped terminations for circuit {}.".format(circuit))
  182. return redirect('circuits:circuit', pk=circuit.pk)
  183. else:
  184. form = ConfirmationForm()
  185. return render(request, 'circuits/circuit_terminations_swap.html', {
  186. 'circuit': circuit,
  187. 'termination_a': termination_a,
  188. 'termination_z': termination_z,
  189. 'form': form,
  190. 'panel_class': 'default',
  191. 'button_class': 'primary',
  192. 'return_url': circuit.get_absolute_url(),
  193. })
  194. #
  195. # Circuit terminations
  196. #
  197. class CircuitTerminationCreateView(PermissionRequiredMixin, ObjectEditView):
  198. permission_required = 'circuits.add_circuittermination'
  199. model = CircuitTermination
  200. model_form = forms.CircuitTerminationForm
  201. template_name = 'circuits/circuittermination_edit.html'
  202. def alter_obj(self, obj, request, url_args, url_kwargs):
  203. if 'circuit' in url_kwargs:
  204. obj.circuit = get_object_or_404(Circuit, pk=url_kwargs['circuit'])
  205. return obj
  206. def get_return_url(self, request, obj):
  207. return obj.circuit.get_absolute_url()
  208. class CircuitTerminationEditView(CircuitTerminationCreateView):
  209. permission_required = 'circuits.change_circuittermination'
  210. class CircuitTerminationDeleteView(PermissionRequiredMixin, ObjectDeleteView):
  211. permission_required = 'circuits.delete_circuittermination'
  212. model = CircuitTermination