views.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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 filtersets, 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 = filtersets.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 = filtersets.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 = filtersets.ProviderFilterSet
  57. table = tables.ProviderTable
  58. #
  59. # Provider networks
  60. #
  61. class ProviderNetworkListView(generic.ObjectListView):
  62. queryset = ProviderNetwork.objects.all()
  63. filterset = filtersets.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 = filtersets.ProviderNetworkFilterSet
  94. table = tables.ProviderNetworkTable
  95. form = forms.ProviderNetworkBulkEditForm
  96. class ProviderNetworkBulkDeleteView(generic.BulkDeleteView):
  97. queryset = ProviderNetwork.objects.all()
  98. filterset = filtersets.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 = filtersets.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 = filtersets.CircuitFilterSet
  149. filterset_form = forms.CircuitFilterForm
  150. table = tables.CircuitTable
  151. class CircuitView(generic.ObjectView):
  152. queryset = Circuit.objects.all()
  153. class CircuitEditView(generic.ObjectEditView):
  154. queryset = Circuit.objects.all()
  155. model_form = forms.CircuitForm
  156. class CircuitDeleteView(generic.ObjectDeleteView):
  157. queryset = Circuit.objects.all()
  158. class CircuitBulkImportView(generic.BulkImportView):
  159. queryset = Circuit.objects.all()
  160. model_form = forms.CircuitCSVForm
  161. table = tables.CircuitTable
  162. class CircuitBulkEditView(generic.BulkEditView):
  163. queryset = Circuit.objects.prefetch_related(
  164. 'provider', 'type', 'tenant', 'terminations'
  165. )
  166. filterset = filtersets.CircuitFilterSet
  167. table = tables.CircuitTable
  168. form = forms.CircuitBulkEditForm
  169. class CircuitBulkDeleteView(generic.BulkDeleteView):
  170. queryset = Circuit.objects.prefetch_related(
  171. 'provider', 'type', 'tenant', 'terminations'
  172. )
  173. filterset = filtersets.CircuitFilterSet
  174. table = tables.CircuitTable
  175. class CircuitSwapTerminations(generic.ObjectEditView):
  176. """
  177. Swap the A and Z terminations of a circuit.
  178. """
  179. queryset = Circuit.objects.all()
  180. def get(self, request, pk):
  181. circuit = get_object_or_404(self.queryset, pk=pk)
  182. form = ConfirmationForm()
  183. # Circuit must have at least one termination to swap
  184. if not circuit.termination_a and not circuit.termination_z:
  185. messages.error(request, "No terminations have been defined for circuit {}.".format(circuit))
  186. return redirect('circuits:circuit', pk=circuit.pk)
  187. return render(request, 'circuits/circuit_terminations_swap.html', {
  188. 'circuit': circuit,
  189. 'termination_a': circuit.termination_a,
  190. 'termination_z': circuit.termination_z,
  191. 'form': form,
  192. 'panel_class': 'light',
  193. 'button_class': 'primary',
  194. 'return_url': circuit.get_absolute_url(),
  195. })
  196. def post(self, request, pk):
  197. circuit = get_object_or_404(self.queryset, pk=pk)
  198. form = ConfirmationForm(request.POST)
  199. if form.is_valid():
  200. termination_a = CircuitTermination.objects.filter(pk=circuit.termination_a_id).first()
  201. termination_z = CircuitTermination.objects.filter(pk=circuit.termination_z_id).first()
  202. if termination_a and termination_z:
  203. # Use a placeholder to avoid an IntegrityError on the (circuit, term_side) unique constraint
  204. with transaction.atomic():
  205. termination_a.term_side = '_'
  206. termination_a.save()
  207. termination_z.term_side = 'A'
  208. termination_z.save()
  209. termination_a.term_side = 'Z'
  210. termination_a.save()
  211. circuit.refresh_from_db()
  212. circuit.termination_a = termination_z
  213. circuit.termination_z = termination_a
  214. circuit.save()
  215. elif termination_a:
  216. termination_a.term_side = 'Z'
  217. termination_a.save()
  218. circuit.refresh_from_db()
  219. circuit.termination_a = None
  220. circuit.save()
  221. else:
  222. termination_z.term_side = 'A'
  223. termination_z.save()
  224. circuit.refresh_from_db()
  225. circuit.termination_z = None
  226. circuit.save()
  227. messages.success(request, f"Swapped terminations for circuit {circuit}.")
  228. return redirect('circuits:circuit', pk=circuit.pk)
  229. return render(request, 'circuits/circuit_terminations_swap.html', {
  230. 'circuit': circuit,
  231. 'termination_a': circuit.termination_a,
  232. 'termination_z': circuit.termination_z,
  233. 'form': form,
  234. 'panel_class': 'default',
  235. 'button_class': 'primary',
  236. 'return_url': circuit.get_absolute_url(),
  237. })
  238. #
  239. # Circuit terminations
  240. #
  241. class CircuitTerminationEditView(generic.ObjectEditView):
  242. queryset = CircuitTermination.objects.all()
  243. model_form = forms.CircuitTerminationForm
  244. template_name = 'circuits/circuittermination_edit.html'
  245. def alter_obj(self, obj, request, url_args, url_kwargs):
  246. if 'circuit' in url_kwargs:
  247. obj.circuit = get_object_or_404(Circuit, pk=url_kwargs['circuit'])
  248. return obj
  249. def get_return_url(self, request, obj):
  250. return obj.circuit.get_absolute_url()
  251. class CircuitTerminationDeleteView(generic.ObjectDeleteView):
  252. queryset = CircuitTermination.objects.all()