Coverage for src/meshadmin/server/networks/views/network.py: 82%
135 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-10 16:08 +0200
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-10 16:08 +0200
1from django.conf import settings
2from django.contrib.auth.mixins import LoginRequiredMixin
3from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
4from django.db import models
5from django.http import (
6 HttpResponse,
7 HttpResponseBadRequest,
8 HttpResponseRedirect,
9 QueryDict,
10)
11from django.shortcuts import get_object_or_404, render
12from django.urls import reverse_lazy
13from django.utils.timezone import now
14from django.views.generic import (
15 CreateView,
16 DeleteView,
17 DetailView,
18 ListView,
19 UpdateView,
20)
22from meshadmin.server.networks.forms import NetworkForm, NetworkMembershipForm
23from meshadmin.server.networks.mixins import NetworkPermissionMixin
24from meshadmin.server.networks.models import Network, NetworkMembership
27class NetworkListView(LoginRequiredMixin, ListView):
28 model = Network
29 template_name = "networks/network/list.html"
31 def get_queryset(self):
32 if self.request.user.is_superuser:
33 return Network.objects.all()
34 return Network.objects.filter(
35 memberships__user=self.request.user,
36 memberships__role__in=[
37 NetworkMembership.Role.ADMIN,
38 NetworkMembership.Role.MEMBER,
39 ],
40 )
43class NetworkDetailView(LoginRequiredMixin, NetworkPermissionMixin, DetailView):
44 model = Network
45 template_name = "networks/network/detail.html"
46 context_object_name = "network"
48 def get_context_data(self, **kwargs):
49 context = super().get_context_data(**kwargs)
50 context["fields"] = [
51 {
52 "name": field.name,
53 "verbose_name": field.verbose_name,
54 "value": getattr(self.object, field.name),
55 }
56 for field in self.model._meta.fields
57 ]
59 hosts = self.object.host_set.all()
60 search = self.request.GET.get("search", "")
61 if search:
62 hosts = hosts.filter(name__icontains=search)
64 if self.request.GET.get("stale_config"):
65 from datetime import timedelta
67 from django.utils import timezone
69 stale_threshold = timezone.now() - timedelta(hours=24)
70 hosts = hosts.filter(
71 models.Q(last_config_refresh__lt=stale_threshold)
72 | models.Q(last_config_refresh__isnull=True)
73 )
75 per_page = int(self.request.GET.get("per_page", settings.PAGINATION_PER_PAGE))
76 paginator = Paginator(hosts, per_page)
77 page = self.request.GET.get("hosts_page", 1)
79 try:
80 hosts = paginator.page(page)
81 except (PageNotAnInteger, EmptyPage):
82 hosts = paginator.page(1)
84 context.update(
85 {
86 "hosts": hosts,
87 "paginator": paginator,
88 "page_obj": hosts,
89 "per_page": per_page,
90 "per_page_options": [25, 50, 100],
91 "templates": self.object.template_set.all(),
92 "groups": self.object.group_set.all(),
93 "cas": self.object.ca_set.all(),
94 "rollouts": self.object.configrollout_set.all(),
95 "now": now(),
96 "memberships": self.object.memberships.select_related("user").all(),
97 }
98 )
99 return context
101 def get_template_names(self):
102 if self.request.htmx:
103 return ["networks/network/_hosts_table.html"]
104 return [self.template_name]
107class NetworkCreateView(LoginRequiredMixin, CreateView):
108 model = Network
109 form_class = NetworkForm
110 template_name = "networks/shared/form.html"
112 def get_form_kwargs(self):
113 kwargs = super().get_form_kwargs()
114 kwargs["request"] = self.request
115 return kwargs
117 def get_success_url(self):
118 return (
119 reverse_lazy("networks:network-detail", kwargs={"pk": self.object.pk})
120 + "#templates-section"
121 )
123 def get_context_data(self, **kwargs):
124 context = super().get_context_data(**kwargs)
125 context["action"] = "Create"
126 context["model_name"] = self.model._meta.verbose_name
127 return context
130class NetworkUpdateView(LoginRequiredMixin, NetworkPermissionMixin, UpdateView):
131 model = Network
132 form_class = NetworkForm
133 template_name = "networks/shared/form.html"
135 def get_success_url(self):
136 return reverse_lazy("networks:network-detail", kwargs={"pk": self.object.pk})
138 def get_context_data(self, **kwargs):
139 context = super().get_context_data(**kwargs)
140 context["action"] = "Update"
141 context["model_name"] = self.model._meta.verbose_name
142 return context
145class NetworkDeleteView(LoginRequiredMixin, NetworkPermissionMixin, DeleteView):
146 model = Network
147 template_name = "networks/shared/delete.html"
148 success_url = reverse_lazy("networks:network-list")
150 def get_context_data(self, **kwargs):
151 context = super().get_context_data(**kwargs)
152 context["model_name"] = self.model._meta.verbose_name
153 return context
156class NetworkMemberAddView(LoginRequiredMixin, NetworkPermissionMixin, CreateView):
157 model = NetworkMembership
158 form_class = NetworkMembershipForm
159 template_name = "networks/shared/form.html"
161 def get_network(self):
162 return get_object_or_404(Network, id=self.kwargs.get("network_id"))
164 def get_form_kwargs(self):
165 kwargs = super().get_form_kwargs()
166 kwargs["network"] = self.get_network()
167 return kwargs
169 def get_success_url(self):
170 return (
171 reverse_lazy(
172 "networks:network-detail", kwargs={"pk": self.kwargs["network_id"]}
173 )
174 + "#members-section"
175 )
177 def get_context_data(self, **kwargs):
178 context = super().get_context_data(**kwargs)
179 context["action"] = "Add Member"
180 context["model_name"] = self.model._meta.verbose_name
181 context["network_id"] = self.kwargs["network_id"]
182 return context
185class NetworkMemberEditView(LoginRequiredMixin, NetworkPermissionMixin, UpdateView):
186 model = NetworkMembership
187 form_class = NetworkMembershipForm
188 template_name = "networks/shared/form.html"
190 def get_network(self):
191 return self.get_object().network
193 def form_valid(self, form):
194 self.object = form.save()
195 if self.request.htmx:
196 context = self.get_context_data()
197 return render(self.request, "networks/network/_member_row.html", context)
198 return super().form_valid(form)
200 def put(self, request, *args, **kwargs):
201 membership = self.get_object()
202 data = QueryDict(request.body)
203 role = data.get("role")
204 if role in [NetworkMembership.Role.ADMIN, NetworkMembership.Role.MEMBER]:
205 membership.role = role
206 membership.save()
207 context = {"membership": membership, "network": membership.network}
208 return render(request, "networks/network/_member_row.html", context)
209 return HttpResponseBadRequest()
212class NetworkMemberDeleteView(LoginRequiredMixin, NetworkPermissionMixin, DeleteView):
213 model = NetworkMembership
214 template_name = "networks/shared/delete.html"
216 def get_network(self):
217 return self.get_object().network
219 def delete(self, request, *args, **kwargs):
220 self.object = self.get_object()
221 self.object.delete()
222 if request.htmx:
223 return HttpResponse("")
224 return HttpResponseRedirect(self.get_success_url())
226 def get_success_url(self):
227 return (
228 reverse_lazy(
229 "networks:network-detail", kwargs={"pk": self.get_object().network.id}
230 )
231 + "#members-section"
232 )