Changeset - 6fe5a626d13d
[Not reviewed]
default
0 3 0
Branko Majic (branko) - 6 years ago 2017-12-25 19:13:36
branko@majic.rs
CONNT-34: Rewrote current_url_equals implementation:

- Implemented tests.
- Simplified implementation.
- Added proper support for passing-in arguments to the view being
checked.
3 files changed with 84 insertions and 25 deletions:
0 comments (0 inline, 0 general)
conntrackt/templates/conntrackt/base.html
Show inline comments
 
@@ -14,49 +14,49 @@
 
    </style>
 
    <link href="/static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" />
 
    <link href="/static/custom.css" rel="stylesheet" />
 
    <script>
 
    /* Set-up the base URL for sending out AJAX API calls. */
 
    var conntrackt_api_url = location.protocol + "//" + location.hostname + ":" + location.port + {% url "index" %} + "api";
 
    </script>
 
  </head>
 
  <body>
 

	
 
    <div class="navbar navbar-inverse navbar-fixed-top">
 
      <div class="navbar-inner">
 
        <div class="container">
 
          <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
 
            <span class="icon-bar"></span>
 
            <span class="icon-bar"></span>
 
            <span class="icon-bar"></span>
 
            <span class="icon-bar"></span>
 
          </button>
 
          {% block header_title %}{% html_link 'Conntrackt' 'index' class="brand" %}{% endblock %}
 
          <div class="nav-collapse collapse">
 
              {% block header %}
 
            <ul class="nav">
 
              <li class="{% active_link 'index' %}"><a href="{% url "index" %}"><i class="icon-home icon-white"></i> Main Page</a></li>
 
              <li class="{% active_link 'admin' %}"><a href="{% url "admin:app_list" "conntrackt" %}"><i class="icon-wrench icon-white"></i> Administration</a></li>
 
              <li><a href="{% url "admin:app_list" "conntrackt" %}"><i class="icon-wrench icon-white"></i> Administration</a></li>
 
            </ul>
 
            <ul class="nav pull-right">
 
              <li>
 
                <form action="{% url "search" %}" class="navbar-search pull-left" method="GET">
 
                  <div class="input-prepend">
 
                    <button type="submit" class="btn btn-link"><span class="icon-search icon-white"></span></button>
 
                    <input id="search" class="search-query" type="text" autocomplete="off" name="q"  placeholder="Search" />
 
                    <div id="search-suggestions" class="dropdown">
 
                      <ul class="dropdown-menu">
 
                      </ul>
 
                    </div>
 

	
 
                  </div>
 
                </form>
 
              </li>
 
              {% if user.is_anonymous %}
 
              <li>{% html_link '<i class="icon-user icon-white"></i> Log-in' 'login' get="next="|add:request.path %}</li>
 
              {% else %}
 
              <li><a href=""><i class="icon-user icon-white"></i> {{user}}</a></li>
 
              <li>{% html_link '<i class="icon-off icon-white"></i> Log-out' "logout" get="next="|add:request.path %}</li>
 
              {% endif %}
 
            </ul>
 
              {% endblock %}
 
          </div>
conntrackt/templatetags/conntrackt_tags.py
Show inline comments
 
@@ -2,48 +2,49 @@
 
#
 
# Copyright (C) 2013 Branko Majic
 
#
 
# This file is part of Django Conntrackt.
 
#
 
# Django Conntrackt is free software: you can redistribute it and/or modify it
 
# under the terms of the GNU General Public License as published by the Free
 
# Software Foundation, either version 3 of the License, or (at your option) any
 
# later version.
 
#
 
# Django Conntrackt is distributed in the hope that it will be useful, but
 
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
# details.
 
#
 
# You should have received a copy of the GNU General Public License along with
 
# Django Conntrackt.  If not, see <http://www.gnu.org/licenses/>.
 
#
 

	
 

	
 
# Django imports.
 
from django import template
 
from django import urls
 
from django.utils.html import format_html
 
from django.urls import reverse
 

	
 

	
 
# Get an instance of Django's template library.
 
register = template.Library()
 

	
 

	
 
@register.simple_tag(takes_context=False)
 
def html_link(text, view, *args, **kwargs):
 
    """
 
    A small wrapper for showing HTML links.
 

	
 
    Positional arguments:
 

	
 
        text - Text that should be used as a link.
 

	
 
        view - View name for which the URL should be shown
 

	
 
        args - Additional positional arguments that will be passed to resolver
 
        for creating the URL.
 

	
 
    Keyword arguments:
 

	
 
        id - Identifier for the <a> HTML element.
 

	
 
@@ -83,57 +84,55 @@ def html_link(text, view, *args, **kwarg
 

	
 
    # Render the tag.
 
    return format_html(pattern, url=url, text=text, **kwargs)
 

	
 

	
 
@register.simple_tag(takes_context=True)
 
def active_link(context, url_name, return_value='active', **kwargs):
 
    """
 
    This template tag can be used to check if the provided URL matches against
 
    the path from the request or not.
 

	
 
    Arguments:
 

	
 
      context - Context of the current view being called.
 

	
 
      url_name - Name of the URL that's being checked against current path from
 
      request.
 
    """
 

	
 
    matches = current_url_equals(context, url_name, **kwargs)
 

	
 
    return return_value if matches else ''
 

	
 

	
 
def current_url_equals(context, url_name, **kwargs):
 
def current_url_equals(context, view_name, *args, **kwargs):
 
    """
 
    Helper function for checking if the specified URL corresponds to the current
 
    request path in the context.
 
    Helper function for checking if the specified view with provided
 
    arguments corresponds to the current request path in the context.
 

	
 
    Passed-in positional and keyword arguments are used to resolve URL
 
    for views that use them.
 

	
 
    Arguments:
 

	
 
      - context - Context of the view being rendered.
 
      context
 
        Context of the view being rendered.
 

	
 
      - url_name - Name of the URL against which the context request path is
 
      being checked.
 
      view_name
 
        Name of the view against which the context request path is
 
        being checked.
 

	
 
      args
 
        Positional parametrs for the view.
 

	
 
      kwargs
 
        Keyword arguments for the view.
 
    """
 

	
 
    # Assume that we have not been able to resolve the request path to an URL.
 
    resolved = False
 
    try:
 
        # Use the request path, and resolve it to a URL name.
 
        resolved = urls.resolve(context.get('request').path)
 
    except urls.Resolver404:
 
        # This means we haven't been able to resolve the path from request.
 
        pass
 
    request = context.get('request')
 
    reversed_url = reverse(view_name, args=args, kwargs=kwargs)
 

	
 
    # If the request was resolved and URL names match, verify that the kwargs
 
    # match as well.
 
    matches = resolved and resolved.url_name == url_name
 
    if matches and kwargs:
 
        for key in kwargs:
 
            kwarg = kwargs.get(key)
 
            resolved_kwarg = resolved.kwargs.get(key)
 
            if not resolved_kwarg or kwarg != resolved_kwarg:
 
                return False
 
    if request.path == reversed_url:
 
        return True
 

	
 
    return matches
 
    return False
conntrackt/tests/test_tags.py
Show inline comments
 
@@ -9,52 +9,56 @@
 
# Software Foundation, either version 3 of the License, or (at your option) any
 
# later version.
 
#
 
# Django Conntrackt is distributed in the hope that it will be useful, but
 
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
# details.
 
#
 
# You should have received a copy of the GNU General Public License along with
 
# Django Conntrackt.  If not, see <http://www.gnu.org/licenses/>.
 
#
 

	
 

	
 
# Standard library imports.
 
import json
 
from StringIO import StringIO
 
from zipfile import ZipFile, ZIP_DEFLATED
 

	
 
# Python third-party library imports.
 
import mock
 

	
 
# Django imports.
 
from django.template import Context, Template, TemplateSyntaxError
 
from django.test import TestCase
 
from django.urls import reverse
 

	
 
# Application imports
 
from conntrackt.templatetags.conntrackt_tags import html_link, active_link, current_url_equals
 

	
 
# Test imports.
 
from .helpers import create_get_request
 

	
 

	
 
@mock.patch('conntrackt.templatetags.conntrackt_tags.urls.reverse')
 
class HtmlLinkTest(TestCase):
 

	
 
    def test_url_reverse_called_with_passed_in_args(self, mock_reverse):
 
        """
 
        Tests if URL reversing is performed using the correct set of
 
        passed-in arguments.
 
        """
 

	
 
        html_link("My link", "my_view", 'arg1', 'arg2', 'arg3')
 

	
 
        mock_reverse.assert_called_once_with("my_view", args=('arg1', 'arg2', 'arg3'))
 

	
 
    def test_url_reverse_called_without_args_if_they_are_not_passed_in(self, mock_reverse):
 
        """
 
        Tests if URL reverse is performed without using any positional
 
        arguments if they are not specified.
 
        """
 

	
 
        kwargs = {
 
            "id": "myid",
 
            "class": "myclass",
 
            "title": "mytitle",
 
@@ -166,24 +170,80 @@ class HtmlLinkTest(TestCase):
 
        rendered_output = template.render(context)
 

	
 
        self.assertEqual(rendered_output, '<a href="/my/url?MyGetParameter=20" class="my_class" title="my_title" id="my_id">My link</a>')
 

	
 
    def test_html_escapes_passed_in_values(self, mock_reverse):
 
        """
 
        Tests if values passed-in as keyword arguments are escaped within
 
        resulting output.
 
        """
 

	
 
        mock_reverse.return_value = "/my/url"
 

	
 
        link = html_link(
 
            "My </a> link",
 
            "my_view",
 
            **{
 
                "id": "my</a>_id",
 
                "class": "my</a>_class",
 
                "title": "my</a>_title",
 
                "get": "MyGetParameter=</a>",
 
            }
 
        )
 

	
 
        self.assertEqual(link, '<a href="/my/url?MyGetParameter=&lt;/a&gt;" class="my&lt;/a&gt;_class" title="my&lt;/a&gt;_title" id="my&lt;/a&gt;_id">My &lt;/a&gt; link</a>')
 

	
 

	
 
class CurrentUrlEqualsTest(TestCase):
 

	
 
    def get_context_for_view(self, view, *args, **kwargs):
 
        """
 
        Returns a Context instance where the request path has been
 
        constructed using the passed-in view (or view name), and view
 
        positional/keyword arguments.
 

	
 
        Arguments:
 

	
 
          view
 
            View function or name for request object.
 

	
 
          args
 
            Positional arguments to pass into the view.
 

	
 
          kwargs
 
            Keyword arguments to pass into the view.
 

	
 
        Returns:
 

	
 
          django.template.Context instance with request.
 
        """
 
        request = create_get_request(reverse(view, args=args, kwargs=kwargs))
 
        context = Context({'request': request})
 

	
 
        return context
 

	
 
    def test_non_matching_url_returns_false(self):
 
        request = create_get_request("/this/url/does/not/exist")
 
        context = Context({'request': request})
 

	
 
        self.assertEqual(current_url_equals(context, 'index'), False)
 

	
 
    def test_matching_url_returns_true(self):
 
        context = self.get_context_for_view('project_create')
 

	
 
        self.assertEqual(current_url_equals(context, 'project_create'), True)
 

	
 
    def test_matching_url_with_different_args_returns_false(self):
 
        context = self.get_context_for_view('project', 1)
 

	
 
        self.assertEqual(current_url_equals(context, 'project', 2), False)
 

	
 
    def test_matching_url_with_different_kwargs_returns_false(self):
 
        context = self.get_context_for_view('project', pk=1)
 

	
 
        self.assertEqual(current_url_equals(context, 'project', pk=2), False)
 

	
 
    def test_matching_url_with_GET_parameters_returns_true(self):
 
        request = create_get_request(reverse('project', kwargs={'pk': 1}) + '?my_get_param=10')
 
        context = Context({'request': request})
 

	
 
        self.assertEqual(current_url_equals(context, 'project', pk=1), True)
0 comments (0 inline, 0 general)