views.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. from django.contrib import messages
  2. from django.db import transaction
  3. from django.db.models import Q
  4. from django.shortcuts import get_object_or_404, redirect, render
  5. from netbox.views import generic
  6. from utilities.forms import ConfirmationForm
  7. from utilities.tables import paginate_table
  8. from utilities.utils import count_related
  9. from . import filters, forms, tables
  10. from .choices import CircuitTerminationSideChoices
  11. from .models import *
  12. #
  13. # Providers
  14. #
  15. class ProviderListView(generic.ObjectListView):
  16. queryset = Provider.objects.annotate(
  17. count_circuits=count_related(Circuit, 'provider')
  18. )
  19. filterset = filters.ProviderFilterSet
  20. filterset_form = forms.ProviderFilterForm
  21. table = tables.ProviderTable
  22. class ProviderView(generic.ObjectView):
  23. queryset = Provider.objects.all()
  24. def get_extra_context(self, request, instance):
  25. circuits = Circuit.objects.restrict(request.user, 'view').filter(
  26. provider=instance
  27. ).prefetch_related(
  28. 'type', 'tenant', 'terminations__site'
  29. )
  30. circuits_table = tables.CircuitTable(circuits)
  31. circuits_table.columns.hide('provider')
  32. paginate_table(circuits_table, request)
  33. return {
  34. 'circuits_table': circuits_table,
  35. }
  36. class ProviderEditView(generic.ObjectEditView):
  37. queryset = Provider.objects.all()
  38. model_form = forms.ProviderForm
  39. class ProviderDeleteView(generic.ObjectDeleteView):
  40. queryset = Provider.objects.all()
  41. class ProviderBulkImportView(generic.BulkImportView):
  42. queryset = Provider.objects.all()
  43. model_form = forms.ProviderCSVForm
  44. table = tables.ProviderTable
  45. class ProviderBulkEditView(generic.BulkEditView):
  46. queryset = Provider.objects.annotate(
  47. count_circuits=count_related(Circuit, 'provider')
  48. )
  49. filterset = filters.ProviderFilterSet
  50. table = tables.ProviderTable
  51. form = forms.ProviderBulkEditForm
  52. class ProviderBulkDeleteView(generic.BulkDeleteView):
  53. queryset = Provider.objects.annotate(
  54. count_circuits=count_related(Circuit, 'provider')
  55. )
  56. filterset = filters.ProviderFilterSet
  57. table = tables.ProviderTable
  58. #
  59. # Provider networks
  60. #
  61. class ProviderNetworkListView(generic.ObjectListView):
  62. queryset = ProviderNetwork.objects.all()
  63. filterset = filters.ProviderNetworkFilterSet
  64. filterset_form = forms.ProviderNetworkFilterForm
  65. table = tables.ProviderNetworkTable
  66. class ProviderNetworkView(generic.ObjectView):
  67. queryset = ProviderNetwork.objects.all()
  68. def get_extra_context(self, request, instance):
  69. circuits = Circuit.objects.restrict(request.user, 'view').filter(
  70. Q(termination_a__provider_network=instance.pk) |
  71. Q(termination_z__provider_network=instance.pk)
  72. ).prefetch_related(
  73. 'type', 'tenant', 'terminations__site'
  74. )
  75. circuits_table = tables.CircuitTable(circuits)
  76. circuits_table.columns.hide('termination_a')
  77. circuits_table.columns.hide('termination_z')
  78. paginate_table(circuits_table, request)
  79. return {
  80. 'circuits_table': circuits_table,
  81. }
  82. class ProviderNetworkEditView(generic.ObjectEditView):
  83. queryset = ProviderNetwork.objects.all()
  84. model_form = forms.ProviderNetworkForm
  85. class ProviderNetworkDeleteView(generic.ObjectDeleteView):
  86. queryset = ProviderNetwork.objects.all()
  87. class ProviderNetworkBulkImportView(generic.BulkImportView):
  88. queryset = ProviderNetwork.objects.all()
  89. model_form = forms.ProviderNetworkCSVForm
  90. table = tables.ProviderNetworkTable
  91. class ProviderNetworkBulkEditView(generic.BulkEditView):
  92. queryset = ProviderNetwork.objects.all()
  93. filterset = filters.ProviderNetworkFilterSet
  94. table = tables.ProviderNetworkTable
  95. form = forms.ProviderNetworkBulkEditForm
  96. class ProviderNetworkBulkDeleteView(generic.BulkDeleteView):
  97. queryset = ProviderNetwork.objects.all()
  98. filterset = filters.ProviderNetworkFilterSet
  99. table = tables.ProviderNetworkTable
  100. #
  101. # Circuit Types
  102. #
  103. class CircuitTypeListView(generic.ObjectListView):
  104. queryset = CircuitType.objects.annotate(
  105. circuit_count=count_related(Circuit, 'type')
  106. )
  107. table = tables.CircuitTypeTable
  108. class CircuitTypeView(generic.ObjectView):
  109. queryset = CircuitType.objects.all()
  110. def get_extra_context(self, request, instance):
  111. circuits = Circuit.objects.restrict(request.user, 'view').filter(
  112. type=instance
  113. )
  114. circuits_table = tables.CircuitTable(circuits)
  115. circuits_table.columns.hide('type')
  116. paginate_table(circuits_table, request)
  117. return {
  118. 'circuits_table': circuits_table,
  119. }
  120. class CircuitTypeEditView(generic.ObjectEditView):
  121. queryset = CircuitType.objects.all()
  122. model_form = forms.CircuitTypeForm
  123. class CircuitTypeDeleteView(generic.ObjectDeleteView):
  124. queryset = CircuitType.objects.all()
  125. class CircuitTypeBulkImportView(generic.BulkImportView):
  126. queryset = CircuitType.objects.all()
  127. model_form = forms.CircuitTypeCSVForm
  128. table = tables.CircuitTypeTable
  129. class CircuitTypeBulkEditView(generic.BulkEditView):
  130. queryset = CircuitType.objects.annotate(
  131. circuit_count=count_related(Circuit, 'type')
  132. )
  133. filterset = filters.CircuitTypeFilterSet
  134. table = tables.CircuitTypeTable
  135. form = forms.CircuitTypeBulkEditForm
  136. class CircuitTypeBulkDeleteView(generic.BulkDeleteView):
  137. queryset = CircuitType.objects.annotate(
  138. circuit_count=count_related(Circuit, 'type')
  139. )
  140. table = tables.CircuitTypeTable
  141. #
  142. # Circuits
  143. #
  144. class CircuitListView(generic.ObjectListView):
  145. queryset = Circuit.objects.prefetch_related(
  146. 'provider', 'type', 'tenant', 'termination_a', 'termination_z'
  147. )
  148. filterset = filters.CircuitFilterSet
  149. filterset_form = forms.CircuitFilterForm
  150. table = tables.CircuitTable
  151. class CircuitView(generic.ObjectView):
  152. queryset = Circuit.objects.all()
  153. def get_extra_context(self, request, instance):
  154. # A-side termination
  155. termination_a = CircuitTermination.objects.restrict(request.user, 'view').prefetch_related(
  156. 'site__region'
  157. ).filter(
  158. circuit=instance, term_side=CircuitTerminationSideChoices.SIDE_A
  159. ).first()
  160. # Z-side termination
  161. termination_z = CircuitTermination.objects.restrict(request.user, 'view').prefetch_related(
  162. 'site__region'
  163. ).filter(
  164. circuit=instance, term_side=CircuitTerminationSideChoices.SIDE_Z
  165. ).first()
  166. return {
  167. 'termination_a': termination_a,
  168. 'termination_z': termination_z,
  169. }
  170. class CircuitEditView(generic.ObjectEditView):
  171. queryset = Circuit.objects.all()
  172. model_form = forms.CircuitForm
  173. class CircuitDeleteView(generic.ObjectDeleteView):
  174. queryset = Circuit.objects.all()
  175. class CircuitBulkImportView(generic.BulkImportView):
  176. queryset = Circuit.objects.all()
  177. model_form = forms.CircuitCSVForm
  178. table = tables.CircuitTable
  179. class CircuitBulkEditView(generic.BulkEditView):
  180. queryset = Circuit.objects.prefetch_related(
  181. 'provider', 'type', 'tenant', 'terminations'
  182. )
  183. filterset = filters.CircuitFilterSet
  184. table = tables.CircuitTable
  185. form = forms.CircuitBulkEditForm
  186. class CircuitBulkDeleteView(generic.BulkDeleteView):
  187. queryset = Circuit.objects.prefetch_related(
  188. 'provider', 'type', 'tenant', 'terminations'
  189. )
  190. filterset = filters.CircuitFilterSet
  191. table = tables.CircuitTable
  192. class CircuitSwapTerminations(generic.ObjectEditView):
  193. """
  194. Swap the A and Z terminations of a circuit.
  195. """
  196. queryset = Circuit.objects.all()
  197. def get(self, request, pk):
  198. circuit = get_object_or_404(self.queryset, pk=pk)
  199. form = ConfirmationForm()
  200. # Circuit must have at least one termination to swap
  201. if not circuit.termination_a and not circuit.termination_z:
  202. messages.error(request, "No terminations have been defined for circuit {}.".format(circuit))
  203. return redirect('circuits:circuit', pk=circuit.pk)
  204. return render(request, 'circuits/circuit_terminations_swap.html', {
  205. 'circuit': circuit,
  206. 'termination_a': circuit.termination_a,
  207. 'termination_z': circuit.termination_z,
  208. 'form': form,
  209. 'panel_class': 'default',
  210. 'button_class': 'primary',
  211. 'return_url': circuit.get_absolute_url(),
  212. })
  213. def post(self, request, pk):
  214. circuit = get_object_or_404(self.queryset, pk=pk)
  215. form = ConfirmationForm(request.POST)
  216. if form.is_valid():
  217. termination_a = CircuitTermination.objects.filter(
  218. circuit=circuit, term_side=CircuitTerminationSideChoices.SIDE_A
  219. ).first()
  220. termination_z = CircuitTermination.objects.filter(
  221. circuit=circuit, term_side=CircuitTerminationSideChoices.SIDE_Z
  222. ).first()
  223. if termination_a and termination_z:
  224. # Use a placeholder to avoid an IntegrityError on the (circuit, term_side) unique constraint
  225. print('swapping')
  226. with transaction.atomic():
  227. termination_a.term_side = '_'
  228. termination_a.save()
  229. termination_z.term_side = 'A'
  230. termination_z.save()
  231. termination_a.term_side = 'Z'
  232. termination_a.save()
  233. elif termination_a:
  234. termination_a.term_side = 'Z'
  235. termination_a.save()
  236. else:
  237. termination_z.term_side = 'A'
  238. termination_z.save()
  239. messages.success(request, "Swapped terminations for circuit {}.".format(circuit))
  240. return redirect('circuits:circuit', pk=circuit.pk)
  241. return render(request, 'circuits/circuit_terminations_swap.html', {
  242. 'circuit': circuit,
  243. 'termination_a': circuit.termination_a,
  244. 'termination_z': circuit.termination_z,
  245. 'form': form,
  246. 'panel_class': 'default',
  247. 'button_class': 'primary',
  248. 'return_url': circuit.get_absolute_url(),
  249. })
  250. #
  251. # Circuit terminations
  252. #
  253. class CircuitTerminationEditView(generic.ObjectEditView):
  254. queryset = CircuitTermination.objects.all()
  255. model_form = forms.CircuitTerminationForm
  256. template_name = 'circuits/circuittermination_edit.html'
  257. def alter_obj(self, obj, request, url_args, url_kwargs):
  258. if 'circuit' in url_kwargs:
  259. obj.circuit = get_object_or_404(Circuit, pk=url_kwargs['circuit'])
  260. return obj
  261. def get_return_url(self, request, obj):
  262. return obj.circuit.get_absolute_url()
  263. class CircuitTerminationDeleteView(generic.ObjectDeleteView):
  264. queryset = CircuitTermination.objects.all()