Coverage for src/meshadmin/server/networks/views/group.py: 62%

130 statements  

« 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.shortcuts import get_object_or_404, render 

6from django.urls import reverse_lazy 

7from django.views.generic import CreateView, DeleteView, DetailView, UpdateView, View 

8 

9from meshadmin.server.networks.forms import GroupForm, RuleForm 

10from meshadmin.server.networks.mixins import NetworkPermissionMixin 

11from meshadmin.server.networks.models import Group, Network, Rule 

12 

13 

14class GroupDetailView(LoginRequiredMixin, NetworkPermissionMixin, DetailView): 

15 model = Group 

16 template_name = "networks/group/detail.html" 

17 

18 def get_network(self): 

19 return self.get_object().network 

20 

21 def get_context_data(self, **kwargs): 

22 context = super().get_context_data(**kwargs) 

23 hosts = self.object.host_set.all() 

24 search = self.request.GET.get("search", "") 

25 if search: 

26 hosts = hosts.filter(name__icontains=search) 

27 

28 if self.request.GET.get("stale_config"): 

29 from datetime import timedelta 

30 

31 from django.utils import timezone 

32 

33 stale_threshold = timezone.now() - timedelta(hours=24) 

34 hosts = hosts.filter( 

35 models.Q(last_config_refresh__lt=stale_threshold) 

36 | models.Q(last_config_refresh__isnull=True) 

37 ) 

38 

39 per_page = int(self.request.GET.get("per_page", settings.PAGINATION_PER_PAGE)) 

40 paginator = Paginator(hosts, per_page) 

41 page = self.request.GET.get("hosts_page", 1) 

42 

43 try: 

44 hosts = paginator.page(page) 

45 except (PageNotAnInteger, EmptyPage): 

46 hosts = paginator.page(1) 

47 

48 context.update( 

49 { 

50 "hosts": hosts, 

51 "paginator": paginator, 

52 "page_obj": hosts, 

53 "per_page": per_page, 

54 "per_page_options": [25, 50, 100], 

55 "network": self.object.network, 

56 "fields": [ 

57 { 

58 "name": field.name, 

59 "verbose_name": field.verbose_name, 

60 "value": getattr(self.object, field.name), 

61 } 

62 for field in self.model._meta.fields 

63 ], 

64 "rules": self.object.rules.all(), 

65 } 

66 ) 

67 return context 

68 

69 def get_template_names(self): 

70 if self.request.htmx: 

71 return ["networks/network/_hosts_table.html"] 

72 return [self.template_name] 

73 

74 

75class GroupCreateView(LoginRequiredMixin, NetworkPermissionMixin, CreateView): 

76 model = Group 

77 form_class = GroupForm 

78 template_name = "networks/group/form.html" 

79 

80 def get_network(self): 

81 return get_object_or_404(Network, id=self.kwargs.get("network_id")) 

82 

83 def form_valid(self, form): 

84 response = super().form_valid(form) 

85 if self.request.htmx: 

86 context = self.get_context_data() 

87 context["object"] = self.object 

88 context["action"] = "Update" 

89 return render(self.request, "networks/group/_form_content.html", context) 

90 return response 

91 

92 def get_success_url(self): 

93 return reverse_lazy("networks:group-detail", kwargs={"pk": self.object.pk}) 

94 

95 def get_form_kwargs(self): 

96 kwargs = super().get_form_kwargs() 

97 network_id = self.kwargs.get("network_id") 

98 if network_id: 

99 network = get_object_or_404(Network, id=network_id) 

100 kwargs["network"] = network 

101 return kwargs 

102 

103 def get_context_data(self, **kwargs): 

104 context = super().get_context_data(**kwargs) 

105 context.update( 

106 { 

107 "action": "Create", 

108 "model_name": self.model._meta.verbose_name, 

109 "network_id": self.kwargs.get("network_id"), 

110 } 

111 ) 

112 return context 

113 

114 

115class GroupUpdateView(LoginRequiredMixin, NetworkPermissionMixin, UpdateView): 

116 model = Group 

117 form_class = GroupForm 

118 template_name = "networks/group/form.html" 

119 

120 def get_network(self): 

121 return self.get_object().network 

122 

123 def get_context_data(self, **kwargs): 

124 context = super().get_context_data(**kwargs) 

125 context.update( 

126 { 

127 "action": "Update", 

128 "network_id": self.get_object().network.id, 

129 "rules": self.get_object().rules.all(), 

130 } 

131 ) 

132 return context 

133 

134 def form_valid(self, form): 

135 response = super().form_valid(form) 

136 if self.request.htmx: 

137 context = self.get_context_data() 

138 context["object"] = self.object 

139 context["action"] = "Update" 

140 return render(self.request, "networks/group/_form_content.html", context) 

141 return response 

142 

143 def get_success_url(self): 

144 return reverse_lazy("networks:group-detail", kwargs={"pk": self.object.pk}) 

145 

146 

147class GroupDeleteView(LoginRequiredMixin, NetworkPermissionMixin, DeleteView): 

148 model = Group 

149 template_name = "networks/shared/delete.html" 

150 

151 def get_network(self): 

152 return self.get_object().network 

153 

154 def get_success_url(self): 

155 return ( 

156 reverse_lazy( 

157 "networks:network-detail", kwargs={"pk": self.object.network.pk} 

158 ) 

159 + "#groups-section" 

160 ) 

161 

162 def get_context_data(self, **kwargs): 

163 context = super().get_context_data(**kwargs) 

164 context["model_name"] = self.model._meta.verbose_name 

165 return context 

166 

167 

168class RuleFormModalView(LoginRequiredMixin, NetworkPermissionMixin, View): 

169 def get_network(self): 

170 group = get_object_or_404(Group, id=self.request.GET.get("group")) 

171 return group.network 

172 

173 def get(self, request): 

174 group_id = request.GET.get("group") 

175 rule_id = request.GET.get("rule") 

176 security_group = get_object_or_404(Group, id=group_id) 

177 

178 if rule_id: 

179 rule = get_object_or_404(Rule, id=rule_id) 

180 form = RuleForm(instance=rule) 

181 else: 

182 form = RuleForm( 

183 initial={"security_group": security_group}, 

184 instance=Rule(security_group=security_group), 

185 ) 

186 

187 return render( 

188 request, 

189 "networks/rule/_form_modal.html", 

190 { 

191 "form": form, 

192 "security_group": security_group, 

193 "rule": rule if rule_id else None, 

194 }, 

195 ) 

196 

197 

198class GroupAddRuleView(LoginRequiredMixin, NetworkPermissionMixin, View): 

199 def get_network(self): 

200 group_id = self.request.POST.get("security_group") 

201 group = get_object_or_404(Group, id=group_id) 

202 return group.network 

203 

204 def post(self, request): 

205 group_id = request.POST.get("security_group") 

206 security_group = get_object_or_404(Group, id=group_id) 

207 

208 form = RuleForm(request.POST, initial={"security_group_id": group_id}) 

209 if form.is_valid(): 

210 rule = form.save(commit=False) 

211 rule.security_group = security_group 

212 rule.save() 

213 

214 if request.POST.getlist("groups"): 

215 rule.groups.set( 

216 Group.objects.filter(id__in=request.POST.getlist("groups")) 

217 ) 

218 

219 context = {"rules": Rule.objects.filter(security_group=security_group)} 

220 return render( 

221 request, 

222 "networks/group/_rules_list.html", 

223 context, 

224 ) 

225 else: 

226 response = render( 

227 request, 

228 "networks/rule/_form_modal.html", 

229 { 

230 "form": form, 

231 "security_group": security_group, 

232 }, 

233 ) 

234 response["HX-Retarget"] = "#modal-content" 

235 return response