Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1258 perf #1320

Merged
merged 11 commits into from
Mar 13, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ tmtags
*.kpf
*.templatec

#PyCharm
# PyCharm
.idea

# Emacs
Expand All @@ -118,4 +118,8 @@ tramp
akvo/rsr/static/rsr/v3/css/src/.sass-cache
akvo/rsr/static/rsr/v3/css/src/*.map

# Landscape
!.landscape.yaml

# Codekit
*.codekit
7 changes: 7 additions & 0 deletions .landscape.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# doc-warnings: yes
test-warnings: no
strictness: verylow
# strictness: veryhigh
# max-line-length: 80
requirements:
- scripts/deployment/pip/requirements/2_rsr.txt
37 changes: 10 additions & 27 deletions akvo/rsr/context_processors.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
# -*- coding: utf-8 -*-

"""
Akvo RSR is covered by the GNU Affero General Public License.
See more details in the license.txt file located at the root folder of the
Akvo RSR module. For additional details on the GNU license please
see < http://www.gnu.org/licenses/agpl.html >.
Akvo RSR is covered by the GNU Affero General Public License.

See more details in the license.txt file located at the root folder of the
Akvo RSR module. For additional details on the GNU license please see
< http://www.gnu.org/licenses/agpl.html >.
"""

import django

from django.conf import settings
from django.contrib.sites.models import get_current_site

from akvo.rsr.models import Project


def extra_context(request, protocol="http"):
"""Add information to the request context."""
current_site = get_current_site(request)
django_version = django.get_version()
deploy_tag = getattr(settings, 'DEPLOY_TAG', 'Unknown')
deploy_branch = getattr(settings, 'DEPLOY_BRANCH', 'Unknown')
deploy_commit_id = getattr(settings, 'DEPLOY_COMMIT_ID', 'Unknown')
deploy_commit_full_id = getattr(settings, 'DEPLOY_COMMIT_FULL_ID', 'Unknown')
deploy_commit_full_id = getattr(
settings, 'DEPLOY_COMMIT_FULL_ID', 'Unknown')

template_context = dict(
return dict(
current_site=current_site,
django_version=django_version,
deploy_tag=deploy_tag,
Expand All @@ -33,34 +32,19 @@ def extra_context(request, protocol="http"):
deploy_commit_full_id=deploy_commit_full_id
)

return template_context


def get_current_path_without_lang(request):
"""Return current path without lang."""
path = request.get_full_path()
path_bits = path.split('/')
path = '/'.join(path_bits[2:])
return {'current_path_without_lang': path}


def extra_pages_context(request):
"""Add context information of an RSR Page"""
"""Add context information of an RSR Page."""
if request.rsr_page:
page = request.rsr_page

# Check if only projects of the partner should be shown or all projects
if page.partner_projects:
projects = page.organisation.published_projects().prefetch_related('locations')
else:
projects = Project.objects.all().published().prefetch_related('locations')

# Check if keywords have been specified for the partner site and filter projects based on keywords if so
if page.keywords.all():
if page.exclude_keywords:
projects = projects.exclude(keywords__in=page.keywords.all())
else:
projects = projects.filter(keywords__in=page.keywords.all())

return {
'rsr_page': page,
'favicon': page.favicon,
Expand All @@ -71,7 +55,6 @@ def extra_pages_context(request):
'stylesheet': page.stylesheet,
'akvoapp_root_url': request.akvoapp_root_url,
'domain_url': request.domain_url,
'projects_qs': projects.latest_update_fields().order_by('-id'),
'no_facebook': not page.facebook_button,
'facebook_app_id': page.facebook_app_id,
'no_twitter': not page.twitter_button,
Expand Down
93 changes: 54 additions & 39 deletions akvo/rsr/middleware.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
# -*- coding: utf-8 -*-

"""
Akvo RSR is covered by the GNU Affero General Public License.
See more details in the license.txt file located at the root folder of the
Akvo RSR module. For additional details on the GNU license please
see < http://www.gnu.org/licenses/agpl.html >.
Akvo RSR is covered by the GNU Affero General Public License.

See more details in the license.txt file located at the root folder of the
Akvo RSR module. For additional details on the GNU license please see
< http://www.gnu.org/licenses/agpl.html >.
"""

from django.conf import settings
from django.contrib.sites.models import Site
from django.core.urlresolvers import (LocaleRegexURLResolver, is_valid_path,
get_resolver, set_urlconf)
get_resolver)
from django.http import HttpResponseRedirect
from django.middleware.locale import LocaleMiddleware
from django.shortcuts import redirect
Expand All @@ -29,13 +28,12 @@
"PagesRouterMiddleware",
"get_domain",
"get_or_create_site",
"is_partner_site_instance",
"is_rsr_instance",
"make_tls_property"]


def make_tls_property(default=None):
"Creates a class-wide instance property with a thread-specific value."
"""Create a class-wide instance property with a thread-specific value."""
class TLSProperty(object):
def __init__(self):
from threading import local
Expand All @@ -60,17 +58,16 @@ def _set_value(self, value):


def _patch_setattr(obj):
"""Purpose of this is to allow changes to settings object again after it is
changed to tls property.
"""Allow changes to tls property objects.

Without this patch the following is not possible::

settings.SITE_ID = 1
settings.SITE_ID = 42
assert settings.SITE_ID == 42 # this fails without this patch

settings.SITE_ID = 1
settings.SITE_ID = 42
assert settings.SITE_ID == 42 # this fails without this patch
"""
old_setattr = obj.__setattr__

def wrap_setattr(self, name, value):
try:
getattr(self.__class__, name).value = value
Expand All @@ -92,6 +89,7 @@ def wrap_setattr(self, name, value):


def get_domain(request):
"""Get domain from request."""
original_domain = request.get_host().split(":")[0]
if original_domain == "rsr.akvo.org":
domain = original_domain
Expand All @@ -102,24 +100,31 @@ def get_domain(request):


def is_rsr_instance(hostname):
"""."""
return any([site.search(hostname) for site in RSR_SITE_REGEXPS])


def is_rsr_page_instance(hostname):
"""."""
return any([site.search(hostname) for site in PARTNER_SITE_REGEXPS])


def get_or_create_site(domain):
"""Make sure we have a matching SITE object.

As a result of an issue(1) we need to ensure that we don't
delete the fixture should we find duplicates
There is no guaranteed ordering(2) we should explicitly order them in such
a way that the fixture would appear first, i.e. by ensuring 'ORDER BY id
ASC'.

(1) https://github.com/akvo/akvo-provisioning/issues/29
(2) http://stackoverflow.com/questions/7163640/
what-is-the-default-order-of-a-list-returned-from-a-django-filter-call
"""
if domain.startswith('www.'):
domain = domain[4:]

# As a result of an issue(1) we need to ensure that we don't
# delete the fixture should we find duplicates
# There is no guaranteed ordering(2) we should explicitly order them in such
# a way that the fixture would appear first, i.e. by ensuring 'ORDER BY id ASC'
#
# (1) https://github.com/akvo/akvo-provisioning/issues/29
# (2) http://stackoverflow.com/questions/7163640/what-is-the-default-order-of-a-list-returned-from-a-django-filter-call
sites = Site.objects.filter(domain=domain).order_by('id')
if sites.count() >= 1:
site, duplicates = sites[0], sites[1:]
Expand All @@ -134,8 +139,10 @@ def get_or_create_site(domain):

class PagesRouterMiddleware(object):

def process_request(self, request, cname_domain=False, rsr_page=None):
"""Dispatch to normal or RSR page based on request domain."""

def process_request(self, request, cname_domain=False, rsr_page=None):
"""."""
domain = get_domain(request)

if is_rsr_instance(domain):
Expand Down Expand Up @@ -163,7 +170,8 @@ def process_request(self, request, cname_domain=False, rsr_page=None):

if rsr_page is not None and rsr_page.enabled:
if cname_domain:
rsr_page_domain = getattr(settings, 'AKVOAPP_DOMAIN', 'akvoapp.org')
rsr_page_domain = getattr(
settings, 'AKVOAPP_DOMAIN', 'akvoapp.org')
else:
rsr_page_domain = ".".join(domain.split(".")[1:])
request.rsr_page = settings.RSR_PAGE = rsr_page
Expand All @@ -178,25 +186,28 @@ def process_request(self, request, cname_domain=False, rsr_page=None):
request.domain_url = "http://%s" % settings.RSR_DOMAIN
site = get_or_create_site(domain)
settings.SITE_ID = site.id
return
return None


class PagesLocaleMiddleware(LocaleMiddleware):

"""
Partner sites aware version of Django's LocaleMiddleware. Since we
swap out the root urlconf for a partner sites specific one, and the
original Django LocaleMiddleware didn't like that.
Partner sites aware version of Django's LocaleMiddleware.

Since we swap out the root urlconf for a partner sites specific one, and
the original Django LocaleMiddleware didn't like that.
"""

def process_request(self, request):
"""."""
check_path = self.is_language_prefix_patterns_used(request)
language = translation.get_language_from_request(
request, check_path=check_path)
translation.activate(language)
request.LANGUAGE_CODE = translation.get_language()

def process_response(self, request, response):
"""."""
# First set the default language, this will be used if there is none
# in the path
default_language = getattr(request, 'default_language', '')
Expand Down Expand Up @@ -224,8 +235,11 @@ def process_response(self, request, response):
return response

def is_language_prefix_patterns_used(self, request):
"""Returns `True` if the `LocaleRegexURLResolver` is used
at root level of the urlpatterns, else it returns `False`."""
"""Return True if languge prefix is used.

Return `True` if the `LocaleRegexURLResolver` is used
at root level of the urlpatterns, else it returns `False`.
"""
urlconf = getattr(request, 'urlconf', None)
for url_pattern in get_resolver(urlconf).url_patterns:
if isinstance(url_pattern, LocaleRegexURLResolver):
Expand All @@ -234,21 +248,22 @@ def is_language_prefix_patterns_used(self, request):


class ExceptionLoggingMiddleware(object):
""" Used to log exceptions on production systems
"""
def process_exception(self, request, exception):

"""Used to log exceptions on production systems."""

def process_exception(self, request, exception):
logging.exception('Exception handling request for ' + request.path)


class RSRVersionHeaderMiddleware(object):
""" Add a response header with RSR version info
"""

"""Add a response header with RSR version info."""

def process_response(self, request, response):
context = extra_context(request)
response['X-RSR-Version'] = "Tag:{deploy_tag} Commit:{deploy_commit_id} Branch:{deploy_branch}".format(
deploy_tag=context['deploy_tag'],
deploy_commit_id=context['deploy_commit_id'],
deploy_branch=context['deploy_branch'],
)

response['X-RSR-Version'] = "tag={}, commit={}, branch={}".format(
context['deploy_tag'],
context['deploy_commit_id'],
context['deploy_branch'])
return response
Loading