general: add support for substitution variables in URLs (#14622)

This commit is contained in:
Frédéric Péters 2017-02-03 15:12:17 +01:00
parent fe831e5d68
commit e7915bd406
7 changed files with 56 additions and 17 deletions

View File

@ -87,7 +87,7 @@ def get_page_dict(request, page, manifest):
if page.redirect_url:
page_dict['external'] = True
page_dict['url'] = page.redirect_url
page_dict['url'] = page.get_redirect_url()
if icon_cells:
page_dict['icon'] = icon_cells[0].icon

View File

@ -29,7 +29,7 @@ from django.utils.http import urlencode
from combo.data.models import CellBase
from combo.data.library import register_cell_class
from combo.utils import sign_url
from combo.utils import sign_url, get_templated_url
from .forms import NewslettersManageForm
@ -120,8 +120,9 @@ class NewslettersCell(CellBase):
return filtered
def get_newsletters(self, **kwargs):
endpoint = self.url + 'newsletters/'
url = get_signed_url(endpoint, self.url, **kwargs)
url = get_templated_url(self.url)
endpoint = url + 'newsletters/'
url = get_signed_url(endpoint, url, **kwargs)
response = requests.get(url)
if response.ok:
json_response = response.json()
@ -129,8 +130,9 @@ class NewslettersCell(CellBase):
return []
def get_subscriptions(self, **kwargs):
endpoint = self.url + 'subscriptions/'
url = get_signed_url(endpoint, self.url, **kwargs)
url = get_templated_url(self.url)
endpoint = url + 'subscriptions/'
url = get_signed_url(endpoint, url, **kwargs)
response = requests.get(url)
if response.ok:
json_response = response.json()
@ -140,9 +142,10 @@ class NewslettersCell(CellBase):
def set_subscriptions(self, subscriptions, **kwargs):
logger = logging.getLogger(__name__)
headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
url = get_templated_url(self.url)
try:
endpoint = self.url + 'subscriptions/'
url = get_signed_url(endpoint, self.url, **kwargs)
endpoint = url + 'subscriptions/'
url = get_signed_url(endpoint, url, **kwargs)
response = requests.post(url, data=json.dumps(subscriptions),
headers=headers)
if not response.json()['data']:

View File

@ -258,6 +258,9 @@ class Page(models.Model):
ordered_pages = Page.get_as_reordered_flat_hierarchy(cls.objects.all())
return [x.get_serialized_page() for x in ordered_pages]
def get_redirect_url(self):
return utils.get_templated_url(self.redirect_url)
class CellMeta(MediaDefiningClass, ModelBase):
pass
@ -605,7 +608,7 @@ class LinkCell(CellBase):
context['url'] = self.link_page.get_online_url()
context['title'] = self.title or self.link_page.title
else:
context['url'] = self.url
context['url'] = utils.get_templated_url(self.url)
context['title'] = self.title or self.url
if self.anchor:
context['url'] += '#' + self.anchor
@ -632,7 +635,7 @@ class FeedCell(CellBase):
cache_key = hashlib.md5(self.url).hexdigest()
feed_content = cache.get(cache_key)
if not feed_content:
feed_response = requests.get(self.url)
feed_response = requests.get(utils.get_templated_url(self.url))
if feed_response.status_code == 200:
feed_content = feed_response.content
cache.set(cache_key, feed_content, 600)
@ -737,7 +740,7 @@ class ParametersCell(CellBase):
if hasattr(self, '_form'):
ctx['form'] = self._form
ctx['title'] = self.title
ctx['url'] = self.url
ctx['url'] = utils.get_templated_url(self.url)
return ctx
def get_default_form_class(self):

View File

@ -44,6 +44,7 @@ else:
get_idps = lambda: []
from combo.data.models import CellBase, Page, ParentContentCell, TextCell
from combo import utils
def login(request, *args, **kwargs):
@ -147,15 +148,17 @@ def skeleton(request):
# look in redirect pages after the best match for the source
redirect_pages = Page.objects.exclude(redirect_url__isnull=True).exclude(redirect_url='')
for page in redirect_pages:
if source.startswith(page.redirect_url):
if selected_page is None or len(page.redirect_url) > len(selected_page.redirect_url):
redirect_url = utils.get_templated_url(page.redirect_url)
if source.startswith(redirect_url):
if selected_page is None or len(redirect_url) > len(selected_page.get_redirect_url()):
selected_page = page
if selected_page is None:
# if there was no page found, look for a domain match
netloc = urlparse.urlparse(source).netloc
for page in redirect_pages:
if urlparse.urlparse(page.redirect_url).netloc == netloc:
redirect_url = utils.get_templated_url(page.redirect_url)
if urlparse.urlparse(redirect_url).netloc == netloc:
selected_page = page
break
@ -289,7 +292,7 @@ def publish_page(request, page, status=200, template_name=None):
raise PermissionDenied()
if page.redirect_url:
return HttpResponseRedirect(page.redirect_url)
return HttpResponseRedirect(page.get_redirect_url())
cells = CellBase.get_cells(page_id=page.id)
extend_with_parent_cells(cells)

View File

@ -19,6 +19,7 @@ import base64
import hmac
import hashlib
import binascii
import re
from HTMLParser import HTMLParser
import logging
@ -169,6 +170,16 @@ class Requests(RequestsSession):
requests = Requests()
def get_templated_url(url):
template_vars = settings.TEMPLATE_VARS
def repl(matchobj):
if matchobj.group(0)[1:-1] in template_vars:
return template_vars[matchobj.group(0)[1:-1]]
return matchobj.group(0)
return re.sub(r'(\[.*?\])', repl, url)
# Simple signature scheme for query strings
def sign_url(url, key, algo='sha256', timestamp=None, nonce=None):

View File

@ -4,6 +4,8 @@ import pytest
import urllib
from django.core.urlresolvers import reverse
from django.test import override_settings
from combo.wsgi import application
from combo.data.models import Page, CellBase, TextCell, ParentContentCell, FeedCell
@ -75,6 +77,15 @@ def test_page_redirect(app):
resp = app.get('/elsewhere/', status=302)
assert resp.location == 'http://example.net'
def test_page_templated_redirect(app):
Page.objects.all().delete()
with override_settings(TEMPLATE_VARS={'test_url': 'http://example.net'}):
page = Page(title='Elsewhere', slug='elsewhere', template_name='standard',
redirect_url='[test_url]')
page.save()
resp = app.get('/elsewhere/', status=302)
assert resp.location == 'http://example.net'
def test_page_private_unlogged(app):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard', public=False)

View File

@ -1,8 +1,16 @@
from combo.utils import aes_hex_decrypt, aes_hex_encrypt
from combo.utils import aes_hex_decrypt, aes_hex_encrypt, get_templated_url
from django.conf import settings
from django.test import override_settings
def test_crypto_url():
invoice_id = '12-1234'
key = settings.SECRET_KEY
assert aes_hex_decrypt(key, aes_hex_encrypt(key, invoice_id)) == invoice_id
assert aes_hex_decrypt(key, aes_hex_encrypt(key, invoice_id)) == invoice_id
def test_templated_url():
assert get_templated_url('[test_url]') == '[test_url]'
with override_settings(TEMPLATE_VARS={'test_url': 'http://www.example.net'}):
assert get_templated_url('[test_url]') == 'http://www.example.net'
assert get_templated_url('[test_url]/hello') == 'http://www.example.net/hello'