views.py 10 KB

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