diff --git a/conntrackt/views.py b/conntrackt/views.py --- a/conntrackt/views.py +++ b/conntrackt/views.py @@ -14,8 +14,8 @@ from django.views.generic import Templat from braces.views import MultiplePermissionsRequiredMixin # Application imports. -from .forms import EntityForm, InterfaceForm -from .models import Project, Entity, Location, Interface +from .forms import EntityForm, InterfaceForm, CommunicationForm +from .models import Project, Entity, Location, Interface, Communication from .utils import generate_entity_iptables @@ -680,3 +680,196 @@ class InterfaceDeleteView(MultiplePermis self.success_url = reverse("entity", args=(self.get_object().entity.id,)) return super(InterfaceDeleteView, self).delete(*args, **kwargs) + + +class CommunicationCreateView(MultiplePermissionsRequiredMixin, CreateView): + """ + View for creating a new communication. + """ + + model = Communication + form_class = CommunicationForm + template_name_suffix = "_create_form" + + # Required permissions + permissions = { + "all": ("conntrackt.add_communication",), + } + + # Raise authorisation denied exception for unmet permissions. + raise_exception = True + + def get_form(self, form_class): + """ + Returns an instance of form that can be used by the view. + + The method will limit the source and destination interface selection to + interfaces belonging to the same project as provided entity ID (if any + was provided). + """ + + form = super(CommunicationCreateView, self).get_form(form_class) + + # Limit the interface selection based on provided source entity, + # destination entity, or project. + entity_id = self.request.GET.get("from_entity", None) + entity_id = self.request.GET.get("to_entity", None) + project_id = self.request.GET.get("project", None) + + if project_id: + form.fields["source"].queryset = Interface.objects.filter(entity__project=project_id) + form.fields["destination"].queryset = Interface.objects.filter(entity__project=project_id) + elif entity_id: + entity = Entity.objects.get(pk=1) + form.fields["source"].queryset = Interface.objects.filter(entity__project=entity.project) + form.fields["destination"].queryset = Interface.objects.filter(entity__project=entity.project) + + return form + + def get_initial(self): + """ + Returns initial values that should be pre-selected (if they were + specified through a GET parameter). + """ + + initial = super(CommunicationCreateView, self).get_initial() + + # If source or destination entity were specified in request, fetch the + # first interface from them and use it as initial source and destination. + from_entity = self.request.GET.get("from_entity", None) + to_entity = self.request.GET.get("to_entity", None) + + if from_entity: + try: + interface = Interface.objects.filter(entity=from_entity)[0] + initial["source"] = interface.id + except IndexError: + pass + + if to_entity: + try: + interface = Interface.objects.filter(entity=to_entity)[0] + initial["destination"] = interface.id + except IndexError: + pass + + return initial + + def get_success_url(self): + """ + Returns the URL to which the user should be redirected after a + communication has been created. + + The URL will be set to entity details page of an entity that was + provided as part of the from/to GET request (in that order), or as a + fallback it'll direct the user to source interface's entity details + page. + """ + + entity_id = self.request.GET.get("from_entity", None) + entity_id = self.request.GET.get("to_entity", None) + + if entity_id is None: + entity_id = self.object.source.entity.pk + + return reverse("entity", args=(entity_id,)) + + +class CommunicationUpdateView(MultiplePermissionsRequiredMixin, UpdateView): + """ + View for updating an existing communication. + """ + + model = Communication + form_class = CommunicationForm + template_name_suffix = "_update_form" + + # Required permissions. + permissions = { + "all": ("conntrackt.change_communication",), + } + + # Raise authorisation denied exception for unmet permissions. + raise_exception = True + + def get_form(self, form_class): + """ + Returns an instance of form that can be used by the view. + + The method will limit the source and destination interfaces that can be + selected for the communication. Both will be limited to interfaces + coming from entities that belong to the same project as current + communication's source interface. + """ + + form = super(CommunicationUpdateView, self).get_form(form_class) + + project = self.object.source.entity.project + + form.fields["source"].queryset = Interface.objects.filter(entity__project=project) + form.fields["destination"].queryset = Interface.objects.filter(entity__project=project) + + return form + + def get_success_url(self): + """ + Returns the URL to which the user should be redirected after a + communication has been created. + + The URL will be set to entity details page of an entity that was + provided as part of the from/to GET request (in that order), or as a + fallback it'll direct the user to source interface's entity details + page. + """ + + entity_id = self.request.GET.get("from_entity", None) + entity_id = self.request.GET.get("to_entity", None) + + if entity_id is None: + entity_id = self.object.source.entity.pk + + return reverse("entity", args=(entity_id,)) + + +class CommunicationDeleteView(MultiplePermissionsRequiredMixin, DeleteView): + """ + View for deleting an communication. + """ + + model = Communication + + # Required permissions. + permissions = { + "all": ("conntrackt.delete_communication",), + } + + # Raise authorisation denied exception for unmet permissions. + raise_exception = True + + def post(self, *args, **kwargs): + """ + Add a success message that will be displayed to the user to confirm the + communication deletion. + """ + + messages.success(self.request, "Communication %s has been removed." % self.get_object(), extra_tags="alert alert-success") + + return super(CommunicationDeleteView, self).post(*args, **kwargs) + + def delete(self, *args, **kwargs): + """ + Deletes the object. This method is overridden in order to obtain the + entity ID for success URL. + + @TODO: Fix this once Django 1.6 comes out with fix from ticket 19044. + """ + + entity_id = self.request.GET.get("from_entity", None) + entity_id = self.request.GET.get("to_entity", None) + + if entity_id is None: + entity_id = self.get_object().source.entity.pk + + self.success_url = reverse("entity", args=(entity_id,)) + + return super(CommunicationDeleteView, self).delete(*args, **kwargs)