views.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. from django.contrib import messages
  2. from django.db import transaction
  3. from django.shortcuts import get_object_or_404, redirect, render
  4. from dcim.views import PathTraceView
  5. from netbox.views import generic
  6. from tenancy.views import ObjectContactsView
  7. from utilities.forms import ConfirmationForm
  8. from utilities.utils import count_related
  9. from utilities.views import register_model_view
  10. from . import filtersets, forms, tables
  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. @register_model_view(Provider)
  23. class ProviderView(generic.ObjectView):
  24. queryset = Provider.objects.all()
  25. def get_extra_context(self, request, instance):
  26. related_models = (
  27. (ProviderAccount.objects.restrict(request.user, 'view').filter(provider=instance), 'provider_id'),
  28. (Circuit.objects.restrict(request.user, 'view').filter(provider=instance), 'provider_id'),
  29. )
  30. return {
  31. 'related_models': related_models,
  32. }
  33. @register_model_view(Provider, 'edit')
  34. class ProviderEditView(generic.ObjectEditView):
  35. queryset = Provider.objects.all()
  36. form = forms.ProviderForm
  37. @register_model_view(Provider, 'delete')
  38. class ProviderDeleteView(generic.ObjectDeleteView):
  39. queryset = Provider.objects.all()
  40. class ProviderBulkImportView(generic.BulkImportView):
  41. queryset = Provider.objects.all()
  42. model_form = forms.ProviderImportForm
  43. class ProviderBulkEditView(generic.BulkEditView):
  44. queryset = Provider.objects.annotate(
  45. count_circuits=count_related(Circuit, 'provider')
  46. )
  47. filterset = filtersets.ProviderFilterSet
  48. table = tables.ProviderTable
  49. form = forms.ProviderBulkEditForm
  50. class ProviderBulkDeleteView(generic.BulkDeleteView):
  51. queryset = Provider.objects.annotate(
  52. count_circuits=count_related(Circuit, 'provider')
  53. )
  54. filterset = filtersets.ProviderFilterSet
  55. table = tables.ProviderTable
  56. @register_model_view(Provider, 'contacts')
  57. class ProviderContactsView(ObjectContactsView):
  58. queryset = Provider.objects.all()
  59. #
  60. # ProviderAccounts
  61. #
  62. class ProviderAccountListView(generic.ObjectListView):
  63. queryset = ProviderAccount.objects.annotate(
  64. count_circuits=count_related(Circuit, 'provider_account')
  65. )
  66. filterset = filtersets.ProviderAccountFilterSet
  67. filterset_form = forms.ProviderAccountFilterForm
  68. table = tables.ProviderAccountTable
  69. @register_model_view(ProviderAccount)
  70. class ProviderAccountView(generic.ObjectView):
  71. queryset = ProviderAccount.objects.all()
  72. def get_extra_context(self, request, instance):
  73. related_models = (
  74. (Circuit.objects.restrict(request.user, 'view').filter(provider_account=instance), 'provider_account_id'),
  75. )
  76. return {
  77. 'related_models': related_models,
  78. }
  79. @register_model_view(ProviderAccount, 'edit')
  80. class ProviderAccountEditView(generic.ObjectEditView):
  81. queryset = ProviderAccount.objects.all()
  82. form = forms.ProviderAccountForm
  83. @register_model_view(ProviderAccount, 'delete')
  84. class ProviderAccountDeleteView(generic.ObjectDeleteView):
  85. queryset = ProviderAccount.objects.all()
  86. class ProviderAccountBulkImportView(generic.BulkImportView):
  87. queryset = ProviderAccount.objects.all()
  88. model_form = forms.ProviderAccountImportForm
  89. table = tables.ProviderAccountTable
  90. class ProviderAccountBulkEditView(generic.BulkEditView):
  91. queryset = ProviderAccount.objects.annotate(
  92. count_circuits=count_related(Circuit, 'provider_account')
  93. )
  94. filterset = filtersets.ProviderAccountFilterSet
  95. table = tables.ProviderAccountTable
  96. form = forms.ProviderAccountBulkEditForm
  97. class ProviderAccountBulkDeleteView(generic.BulkDeleteView):
  98. queryset = ProviderAccount.objects.annotate(
  99. count_circuits=count_related(Circuit, 'provider_account')
  100. )
  101. filterset = filtersets.ProviderAccountFilterSet
  102. table = tables.ProviderAccountTable
  103. @register_model_view(ProviderAccount, 'contacts')
  104. class ProviderAccountContactsView(ObjectContactsView):
  105. queryset = ProviderAccount.objects.all()
  106. #
  107. # Provider networks
  108. #
  109. class ProviderNetworkListView(generic.ObjectListView):
  110. queryset = ProviderNetwork.objects.all()
  111. filterset = filtersets.ProviderNetworkFilterSet
  112. filterset_form = forms.ProviderNetworkFilterForm
  113. table = tables.ProviderNetworkTable
  114. @register_model_view(ProviderNetwork)
  115. class ProviderNetworkView(generic.ObjectView):
  116. queryset = ProviderNetwork.objects.all()
  117. def get_extra_context(self, request, instance):
  118. related_models = (
  119. (
  120. Circuit.objects.restrict(request.user, 'view').filter(terminations__provider_network=instance),
  121. 'provider_network_id',
  122. ),
  123. )
  124. return {
  125. 'related_models': related_models,
  126. }
  127. @register_model_view(ProviderNetwork, 'edit')
  128. class ProviderNetworkEditView(generic.ObjectEditView):
  129. queryset = ProviderNetwork.objects.all()
  130. form = forms.ProviderNetworkForm
  131. @register_model_view(ProviderNetwork, 'delete')
  132. class ProviderNetworkDeleteView(generic.ObjectDeleteView):
  133. queryset = ProviderNetwork.objects.all()
  134. class ProviderNetworkBulkImportView(generic.BulkImportView):
  135. queryset = ProviderNetwork.objects.all()
  136. model_form = forms.ProviderNetworkImportForm
  137. class ProviderNetworkBulkEditView(generic.BulkEditView):
  138. queryset = ProviderNetwork.objects.all()
  139. filterset = filtersets.ProviderNetworkFilterSet
  140. table = tables.ProviderNetworkTable
  141. form = forms.ProviderNetworkBulkEditForm
  142. class ProviderNetworkBulkDeleteView(generic.BulkDeleteView):
  143. queryset = ProviderNetwork.objects.all()
  144. filterset = filtersets.ProviderNetworkFilterSet
  145. table = tables.ProviderNetworkTable
  146. #
  147. # Circuit Types
  148. #
  149. class CircuitTypeListView(generic.ObjectListView):
  150. queryset = CircuitType.objects.annotate(
  151. circuit_count=count_related(Circuit, 'type')
  152. )
  153. filterset = filtersets.CircuitTypeFilterSet
  154. filterset_form = forms.CircuitTypeFilterForm
  155. table = tables.CircuitTypeTable
  156. @register_model_view(CircuitType)
  157. class CircuitTypeView(generic.ObjectView):
  158. queryset = CircuitType.objects.all()
  159. def get_extra_context(self, request, instance):
  160. related_models = (
  161. (Circuit.objects.restrict(request.user, 'view').filter(type=instance), 'type_id'),
  162. )
  163. return {
  164. 'related_models': related_models,
  165. }
  166. @register_model_view(CircuitType, 'edit')
  167. class CircuitTypeEditView(generic.ObjectEditView):
  168. queryset = CircuitType.objects.all()
  169. form = forms.CircuitTypeForm
  170. @register_model_view(CircuitType, 'delete')
  171. class CircuitTypeDeleteView(generic.ObjectDeleteView):
  172. queryset = CircuitType.objects.all()
  173. class CircuitTypeBulkImportView(generic.BulkImportView):
  174. queryset = CircuitType.objects.all()
  175. model_form = forms.CircuitTypeImportForm
  176. class CircuitTypeBulkEditView(generic.BulkEditView):
  177. queryset = CircuitType.objects.annotate(
  178. circuit_count=count_related(Circuit, 'type')
  179. )
  180. filterset = filtersets.CircuitTypeFilterSet
  181. table = tables.CircuitTypeTable
  182. form = forms.CircuitTypeBulkEditForm
  183. class CircuitTypeBulkDeleteView(generic.BulkDeleteView):
  184. queryset = CircuitType.objects.annotate(
  185. circuit_count=count_related(Circuit, 'type')
  186. )
  187. filterset = filtersets.CircuitTypeFilterSet
  188. table = tables.CircuitTypeTable
  189. #
  190. # Circuits
  191. #
  192. class CircuitListView(generic.ObjectListView):
  193. queryset = Circuit.objects.prefetch_related(
  194. 'tenant__group', 'termination_a__site', 'termination_z__site',
  195. 'termination_a__provider_network', 'termination_z__provider_network',
  196. )
  197. filterset = filtersets.CircuitFilterSet
  198. filterset_form = forms.CircuitFilterForm
  199. table = tables.CircuitTable
  200. @register_model_view(Circuit)
  201. class CircuitView(generic.ObjectView):
  202. queryset = Circuit.objects.all()
  203. @register_model_view(Circuit, 'edit')
  204. class CircuitEditView(generic.ObjectEditView):
  205. queryset = Circuit.objects.all()
  206. form = forms.CircuitForm
  207. @register_model_view(Circuit, 'delete')
  208. class CircuitDeleteView(generic.ObjectDeleteView):
  209. queryset = Circuit.objects.all()
  210. class CircuitBulkImportView(generic.BulkImportView):
  211. queryset = Circuit.objects.all()
  212. model_form = forms.CircuitImportForm
  213. additional_permissions = [
  214. 'circuits.add_circuittermination',
  215. ]
  216. related_object_forms = {
  217. 'terminations': forms.CircuitTerminationImportForm,
  218. }
  219. def prep_related_object_data(self, parent, data):
  220. data.update({'circuit': parent})
  221. return data
  222. class CircuitBulkEditView(generic.BulkEditView):
  223. queryset = Circuit.objects.prefetch_related(
  224. 'termination_a__site', 'termination_z__site',
  225. 'termination_a__provider_network', 'termination_z__provider_network',
  226. )
  227. filterset = filtersets.CircuitFilterSet
  228. table = tables.CircuitTable
  229. form = forms.CircuitBulkEditForm
  230. class CircuitBulkDeleteView(generic.BulkDeleteView):
  231. queryset = Circuit.objects.prefetch_related(
  232. 'termination_a__site', 'termination_z__site',
  233. 'termination_a__provider_network', 'termination_z__provider_network',
  234. )
  235. filterset = filtersets.CircuitFilterSet
  236. table = tables.CircuitTable
  237. class CircuitSwapTerminations(generic.ObjectEditView):
  238. """
  239. Swap the A and Z terminations of a circuit.
  240. """
  241. queryset = Circuit.objects.all()
  242. def get(self, request, pk):
  243. circuit = get_object_or_404(self.queryset, pk=pk)
  244. form = ConfirmationForm()
  245. # Circuit must have at least one termination to swap
  246. if not circuit.termination_a and not circuit.termination_z:
  247. messages.error(request, "No terminations have been defined for circuit {}.".format(circuit))
  248. return redirect('circuits:circuit', pk=circuit.pk)
  249. return render(request, 'circuits/circuit_terminations_swap.html', {
  250. 'circuit': circuit,
  251. 'termination_a': circuit.termination_a,
  252. 'termination_z': circuit.termination_z,
  253. 'form': form,
  254. 'panel_class': 'light',
  255. 'button_class': 'primary',
  256. 'return_url': circuit.get_absolute_url(),
  257. })
  258. def post(self, request, pk):
  259. circuit = get_object_or_404(self.queryset, pk=pk)
  260. form = ConfirmationForm(request.POST)
  261. if form.is_valid():
  262. termination_a = CircuitTermination.objects.filter(pk=circuit.termination_a_id).first()
  263. termination_z = CircuitTermination.objects.filter(pk=circuit.termination_z_id).first()
  264. if termination_a and termination_z:
  265. # Use a placeholder to avoid an IntegrityError on the (circuit, term_side) unique constraint
  266. with transaction.atomic():
  267. termination_a.term_side = '_'
  268. termination_a.save()
  269. termination_z.term_side = 'A'
  270. termination_z.save()
  271. termination_a.term_side = 'Z'
  272. termination_a.save()
  273. circuit.refresh_from_db()
  274. circuit.termination_a = termination_z
  275. circuit.termination_z = termination_a
  276. circuit.save()
  277. elif termination_a:
  278. termination_a.term_side = 'Z'
  279. termination_a.save()
  280. circuit.refresh_from_db()
  281. circuit.termination_a = None
  282. circuit.save()
  283. else:
  284. termination_z.term_side = 'A'
  285. termination_z.save()
  286. circuit.refresh_from_db()
  287. circuit.termination_z = None
  288. circuit.save()
  289. messages.success(request, f"Swapped terminations for circuit {circuit}.")
  290. return redirect('circuits:circuit', pk=circuit.pk)
  291. return render(request, 'circuits/circuit_terminations_swap.html', {
  292. 'circuit': circuit,
  293. 'termination_a': circuit.termination_a,
  294. 'termination_z': circuit.termination_z,
  295. 'form': form,
  296. 'panel_class': 'default',
  297. 'button_class': 'primary',
  298. 'return_url': circuit.get_absolute_url(),
  299. })
  300. @register_model_view(Circuit, 'contacts')
  301. class CircuitContactsView(ObjectContactsView):
  302. queryset = Circuit.objects.all()
  303. #
  304. # Circuit terminations
  305. #
  306. @register_model_view(CircuitTermination, 'edit')
  307. class CircuitTerminationEditView(generic.ObjectEditView):
  308. queryset = CircuitTermination.objects.all()
  309. form = forms.CircuitTerminationForm
  310. @register_model_view(CircuitTermination, 'delete')
  311. class CircuitTerminationDeleteView(generic.ObjectDeleteView):
  312. queryset = CircuitTermination.objects.all()
  313. # Trace view
  314. register_model_view(CircuitTermination, 'trace', kwargs={'model': CircuitTermination})(PathTraceView)