Skip to content

Commit

Permalink
Merge pull request #2541 from akvo/#2540-more-projects
Browse files Browse the repository at this point in the history
[#2540] Allow listing more projects in the directory
Code reviewed
  • Loading branch information
zzgvh authored Mar 8, 2017
2 parents f21cfd1 + a034dcf commit 0dd0f9d
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 125 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ cache: pip

services:
- postgresql
- memcached

python:
- "2.7"
Expand Down
2 changes: 1 addition & 1 deletion akvo/rest/views/partnership.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ class PartnershipMoreLinkViewSet(PublicProjectViewSet):
Specific endpoint for the '+X partners' links in RSR. Contains the name, long name and logo of
an organisation and the partnership role.
"""
queryset = Partnership.objects.all()
queryset = Partnership.objects.select_related('organisation', 'project').all()
serializer_class = PartnershipBasicSerializer
92 changes: 3 additions & 89 deletions akvo/rsr/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@
"""

import logging
import json

from django.conf import settings
from django.core.exceptions import DisallowedHost
from django.db.models import Q
from django.core.urlresolvers import (get_resolver, LocaleRegexURLResolver)
from django.shortcuts import redirect

from akvo.rsr.context_processors import extra_context
from akvo.rsr.models import PartnerSite
from django.utils import translation
from django.http import HttpResponseRedirect, HttpResponse


def _is_rsr_host(hostname):
Expand Down Expand Up @@ -52,64 +50,9 @@ def _build_api_link(request, resource, object_id):
)


class DefaultLanguageMiddleware(object):

"""A non working (BROKEN) default language middleware.
A try in supporting default languages, but since this will redirect all url_patterns and
not only i18n ones it's broken.
"""

def __init__(self):
"""."""
self._is_language_prefix_patterns_used = False
for url_pattern in get_resolver(None).url_patterns:
if isinstance(url_pattern, LocaleRegexURLResolver):
self._is_language_prefix_patterns_used = True
break

def is_language_prefix_patterns_used(self):
"""."""
return self._is_language_prefix_patterns_used

def is_i18n_path(self, path):
"""."""
from akvo.urls import localised_patterns
print "=> {}".format(localised_patterns)
from django.core.urlresolvers import resolve, Resolver404
try:
resolve(path, localised_patterns)
return True
except Resolver404:
return False
except TypeError:
return False
return False

def process_request(self, request):
"""Redirect to selected language."""
if not request.rsr_page:
return None

if self.is_i18n_path(request.path):
print "{} was i18n path".format(request.path)
else:
print "{} was not 18n path".format(request.path)

language_from_path = translation.get_language_from_path(request.path_info)
if not language_from_path:
if request.rsr_page.default_language:
lang = request.rsr_page.default_language
return HttpResponseRedirect('/{}{}'.format(lang, request.path))
return HttpResponseRedirect('/en{}'.format(request.path))
return None


class HostDispatchMiddleware(object):
"""RSR page dispatch middleware."""

"""RSR page dispath middleware."""

# def process_request(self, request, cname_domain=False, rsr_page=None):
def process_request(self, request):
"""Route on request."""
request.rsr_page = None
Expand Down Expand Up @@ -191,32 +134,3 @@ def process_response(request, response):
if depth > '1':
return redirect(_build_api_link(request, 'project_extra_deep', object_id))
return response


class NonHtmlDebugToolbarMiddleware(object):
"""
The Django Debug Toolbar usually only works for views that return HTML.
This middleware wraps any non-HTML response in HTML if the request
has a 'debug' query parameter (e.g. http://localhost/foo?debug)
Special handling for json (pretty printing) and
binary data (only show data length)
"""

@staticmethod
def process_response(request, response):
if request.GET.get('debug') == '':
if response['Content-Type'] == 'application/octet-stream':
new_content = '<html><body>Binary Data, ' \
'Length: {}</body></html>'.format(len(response.content))
response = HttpResponse(new_content)
elif response['Content-Type'] != 'text/html':
content = response.content
try:
json_ = json.loads(content)
content = json.dumps(json_, sort_keys=True, indent=2)
except ValueError:
pass
response = HttpResponse('<html><body><pre>{}'
'</pre></body></html>'.format(content))

return response
14 changes: 7 additions & 7 deletions akvo/rsr/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -979,13 +979,13 @@ def budget_total(self):
return Project.objects.budget_total().get(pk=self.pk).budget_total

def has_multiple_budget_currencies(self):
budget_items = BudgetItem.objects.filter(project__id=self.pk)
num_currencies = len(set([self.currency] + [c.currency if c.currency else self.currency for c in budget_items]))

if num_currencies > 1:
return True
else:
return False
# Using a python loop for iteration, because it's faster when
# budget_items have been pre-fetched
budget_items = self.budget_items.all()
num_currencies = len(
set([self.currency] + [c.currency for c in budget_items if c.currency])
)
return num_currencies > 1

def budget_currency_totals(self):
budget_items = BudgetItem.objects.filter(project__id=self.pk)
Expand Down
27 changes: 27 additions & 0 deletions akvo/rsr/tests/views/test_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# -*- 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 >.
"""

from __future__ import print_function

from unittest import skip

import django_perf_rec
from django.test import TestCase


@skip('Needs Django >= 1.8')
class ProjectPerfomanceTestCase(TestCase):
"""Test performance of project views."""

def setUp(self):
return

def test_project_directory_listing(self):
with django_perf_rec.record():
self.client.get('/en/projects/', follow=True)
6 changes: 4 additions & 2 deletions akvo/rsr/views/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ def directory(request):

# Build page
page = request.GET.get('page')
page, paginator, page_range = pagination(page, sorted_projects, 10)
limit = request.GET.get('limit', settings.PROJECT_DIRECTORY_DEFAULT_SIZE)
page, paginator, page_range = pagination(page, sorted_projects, limit)

# Get the current org filter for typeahead
org_filter = request.GET.get('organisation', '')
Expand All @@ -111,7 +112,8 @@ def directory(request):
page.object_list = page.object_list.prefetch_related(
'publishingstatus',
'recipient_countries',
'sectors'
'sectors',
'budget_items',
).select_related(
'primary_organisation',
'last_update'
Expand Down
2 changes: 0 additions & 2 deletions akvo/settings/10-base.conf
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ AUTH_USER_MODEL = 'rsr.User'

MIDDLEWARE_CLASSES = (
'akvo.rsr.middleware.HostDispatchMiddleware',
# 'akvo.rsr.middleware.DefaultLanguageMiddleware',
# 'akvo.rsr.middleware_old.PagesLocaleMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
Expand Down
1 change: 1 addition & 0 deletions akvo/settings/30-rsr.conf
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ DECIMALS_DECIMAL_PLACES = 2
WORDPRESS_NEWS_CATEGORY = 13

PROJECT_UPDATE_TIMEOUT = 20
PROJECT_DIRECTORY_DEFAULT_SIZE = 10

RSR_CACHE_SECONDS = CACHES['default']['TIMEOUT']

Expand Down
43 changes: 26 additions & 17 deletions akvo/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

from django.conf import settings
from django.contrib.auth.models import Group
from django.core.mail import EmailMultiAlternatives
from django.core.mail import get_connection
from django.core.cache import cache
from django.core.mail import EmailMultiAlternatives, get_connection
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.db.models import get_model
from django.http import HttpResponse
Expand Down Expand Up @@ -293,13 +293,27 @@ def codelist_value(model, instance, field, version=settings.IATI_VERSION):
:return: String of the codelist instance
"""
value = getattr(instance, field, None)
if value:
try:
objects = getattr(model, 'objects')
return objects.get(code=value, version__code=version)
except model.DoesNotExist:
return value
return ''
if not value:
return ''

key = u'{}-{}-{}'.format(model.__name__, value, version)
result = cache.get(key)
if result is not None:
return result

try:
objects = getattr(model, 'objects')
result = objects.get(code=value, version__code=version)

except model.DoesNotExist:
result = value

else:
# Update the cache only if the required data is in the DB!
cache.set(key, result)

finally:
return result


def codelist_name(model, instance, field, version=settings.IATI_VERSION):
Expand All @@ -311,14 +325,9 @@ def codelist_name(model, instance, field, version=settings.IATI_VERSION):
:param version: String of version (optional)
:return: String of the codelist instance
"""
value = getattr(instance, field, None)
if value:
try:
objects = getattr(model, 'objects')
return objects.get(code=value, version__code=version).name
except model.DoesNotExist:
return value
return ''

value = codelist_value(model, instance, field, version)
return value.name if hasattr(value, 'name') else value


def check_auth_groups(group_names):
Expand Down
11 changes: 4 additions & 7 deletions scripts/deployment/pip/requirements/3_testing.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
# Requirements for building splinter
lxml==2.3.6

# Requirements for building lettuce
fuzzywuzzy==0.1
sure==1.0.6

# Modules used for app testing
nose==1.2.1
mox==0.5.3
Expand All @@ -18,5 +11,9 @@ fake-factory==0.7.2
ipaddress==1.0.17
six==1.10.0


# Modules for linting
flake8==3.0.4

# django_perf_rec
django_perf_rec==2.0.0

0 comments on commit 0dd0f9d

Please sign in to comment.