combo/tests/test_public.py

837 lines
34 KiB
Python

import mock
from webtest import TestApp
import datetime
import json
import pytest
import re
import os
from django.conf import settings
from django.contrib.auth.models import User, Group
from django.core.urlresolvers import reverse
from django.db import connection
from django.utils.http import quote
from django.utils.six.moves.urllib import parse as urlparse
from django.test import override_settings
from django.test.utils import CaptureQueriesContext
from combo.wsgi import application
from combo.data.models import (Page, CellBase, TextCell, ParentContentCell,
FeedCell, LinkCell, ConfigJsonCell, Redirect, JsonCell)
from combo.apps.family.models import FamilyInfosCell
pytestmark = pytest.mark.django_db
from .test_manager import login
@pytest.fixture
def normal_user():
try:
user = User.objects.get(username='normal-user')
user.groups = []
except User.DoesNotExist:
user = User.objects.create_user(username='normal-user', email='', password='normal-user')
return user
def test_missing_index(app):
Page.objects.all().delete()
resp = app.get('/', status=200)
assert 'Welcome' in resp.text
def test_index(app):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
resp = app.get('/index', status=301)
assert urlparse.urlparse(resp.location).path == '/'
resp = app.get('/', status=200)
# check {% now %} inside a skeleton_extra_placeholder is interpreted
assert str(datetime.datetime.now().year) in resp.text
def test_page_contents(app):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
cell = TextCell(page=page, placeholder='content', text='Foobar', order=0)
cell.save()
resp = app.get('/', status=200)
assert 'Foobar' in resp.text
def test_page_contents_unlogged_only(app, admin_user):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
cell = TextCell(page=page, placeholder='content', text='Foobar', order=0,
restricted_to_unlogged=True)
cell.save()
resp = app.get('/', status=200)
assert 'Foobar' in resp.text
app = login(app)
resp = app.get('/', status=200)
assert not 'Foobar' in resp.text
def test_page_contents_group_presence(app, normal_user):
group = Group(name='plop')
group.save()
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
cell = TextCell(page=page, placeholder='content', text='Foobar', order=0,
public=False)
cell.save()
cell.groups = [group]
resp = app.get('/', status=200)
assert 'Foobar' not in resp.text
app = login(app, username='normal-user', password='normal-user')
resp = app.get('/', status=200)
assert 'Foobar' not in resp.text
normal_user.groups = [group]
resp = app.get('/', status=200)
assert 'Foobar' in resp.text
def test_page_contents_group_absence(app, normal_user):
group = Group(name='plop')
group.save()
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
cell = TextCell(page=page, placeholder='content', text='Foobar', order=0,
public=False, restricted_to_unlogged=True)
cell.save()
cell.groups = [group]
resp = app.get('/', status=200)
assert 'Foobar' not in resp.text
app = login(app, username='normal-user', password='normal-user')
resp = app.get('/', status=200)
assert 'Foobar' in resp.text
normal_user.groups = [group]
resp = app.get('/', status=200)
assert 'Foobar' not in resp.text
def test_page_footer_acquisition(app):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
page_index = page
cell = TextCell(page=page, placeholder='footer', text='BARFOO', order=0)
cell.save()
resp = app.get('/', status=200)
assert resp.text.count('BARFOO') == 1
# make sure a parent content cell in the home page doesn't duplicate
# cells
ParentContentCell(page=page, placeholder='footer', order=0).save()
resp = app.get('/', status=200)
assert resp.text.count('BARFOO') == 1
page = Page(title='Second', slug='second', template_name='standard')
page.save()
ParentContentCell(page=page, placeholder='footer', order=0).save()
TextCell(page=page, placeholder='footer', text='BAR2FOO', order=1).save()
resp = app.get('/second', status=301)
assert urlparse.urlparse(resp.location).path == '/second/'
with CaptureQueriesContext(connection) as ctx:
resp = app.get('/second/', status=200)
assert resp.text.count('BARFOO') == 1
assert resp.text.count('BAR2FOO') == 1
queries_count_second = len(ctx.captured_queries)
# deeper hierarchy
page3 = Page(title='Third', slug='third', template_name='standard', parent=page)
page3.save()
ParentContentCell(page=page3, placeholder='footer', order=0).save()
page4 = Page(title='Fourth', slug='fourth', template_name='standard', parent=page3)
page4.save()
ParentContentCell(page=page4, placeholder='footer', order=0).save()
page5 = Page(title='Fifth', slug='fifth', template_name='standard', parent=page4)
page5.save()
ParentContentCell(page=page5, placeholder='footer', order=0).save()
# check growth in SQL queries is limited
with CaptureQueriesContext(connection) as ctx:
resp = app.get('/second/third/', status=200)
assert resp.text.count('BARFOO') == 1
assert resp.text.count('BAR2FOO') == 1
queries_count_third = len(ctx.captured_queries)
assert queries_count_third == queries_count_second
with CaptureQueriesContext(connection) as ctx:
resp = app.get('/second/third/fourth/', status=200)
assert resp.text.count('BARFOO') == 1
assert resp.text.count('BAR2FOO') == 1
queries_count_fourth = len(ctx.captured_queries)
# +1 for get_parents_and_self()
assert queries_count_fourth == queries_count_second + 1
# check footer doesn't get duplicated in real index children
page6 = Page(title='Sixth', slug='sixth', template_name='standard', parent=page_index)
page6.save()
ParentContentCell(page=page6, placeholder='footer', order=0).save()
resp = app.get('/sixth/', status=200)
assert resp.text.count('BARFOO') == 1
def test_page_redirect(app):
Page.objects.all().delete()
page = Page(title='Elsewhere', slug='elsewhere', template_name='standard',
redirect_url='http://example.net')
page.save()
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'
page.redirect_url = '{{test_url}}/ok'
page.save()
resp = app.get('/elsewhere/', status=302)
assert resp.location == 'http://example.net/ok'
page.redirect_url = '{{unknown_variable}}'
page.save()
resp = app.get('/elsewhere/', status=200)
page.redirect_url = '{% if error %}'
page.save()
resp = app.get('/elsewhere/', status=404)
def test_page_private_unlogged(app):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard', public=False)
page.save()
resp = app.get('/', status=302)
assert resp.location.endswith('/login/?next=http%3A//testserver/')
def test_page_private_logged_in(app, admin_user):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard', public=False)
page.save()
app = login(app)
resp = app.get('/', status=200)
def test_page_skeleton(app):
Page.objects.all().delete()
page = Page(title='Elsewhere', slug='elsewhere', template_name='standard',
redirect_url='http://example.net/foo/')
page.save()
# url prefix match
resp = app.get('/__skeleton__/?source=%s' % quote('http://example.net/foo/bar'))
assert '{% block placeholder-content %}{% block content %}{% endblock %}{% endblock %}' in resp.text
assert '{% block placeholder-footer %}{% block footer %}{% endblock %}{% endblock %}' in resp.text
# url netloc match
resp = app.get('/__skeleton__/?source=%s' % quote('http://example.net'))
assert '{% block placeholder-content %}{% block content %}{% endblock %}{% endblock %}' in resp.text
assert '{% block placeholder-footer %}{% block footer %}{% endblock %}{% endblock %}' in resp.text
# settings.KNOWN_SERVICES match
resp = app.get('/__skeleton__/?source=%s' % quote('http://127.0.0.1:8999/'))
assert '{% block placeholder-content %}{% block content %}{% endblock %}{% endblock %}' in resp.text
# no match
resp = app.get('/__skeleton__/?source=%s' % quote('http://example.com/foo/bar'), status=403)
# check with a footer cell
cell = TextCell(page=page, placeholder='footer', text='Foobar', order=0)
cell.save()
resp = app.get('/__skeleton__/?source=%s' % quote('http://example.net'))
assert '{% block placeholder-content %}{% block content %}{% endblock %}{% endblock %}' in resp.text
assert not '{% block placeholder-footer %}{% block footer %}{% endblock %}{% endblock %}' in resp.text
assert 'Foobar' in resp.text
# check {% now %} inside a skeleton_extra_placeholder is not interpreted
assert '{%now' in resp.text
assert '{# generation time #}' in resp.text
# check cells in footer are present even if there's no redirection page
page.slug = 'index'
page.save()
resp = app.get('/__skeleton__/?source=%s' % quote('http://127.0.0.1:8999/'))
assert '{% block placeholder-content %}{% block content %}{% endblock %}{% endblock %}' in resp.text
assert not '{% block placeholder-footer %}{% block footer %}{% endblock %}{% endblock %}' in resp.text
assert 'Foobar' in resp.text
# check link cells provide a full URL
other_page = Page(title='Plop', slug='plop', template_name='standard')
other_page.save()
cell = LinkCell(page=page, placeholder='footer', link_page=other_page, order=0)
cell.save()
resp = app.get('/__skeleton__/?source=%s' % quote('http://127.0.0.1:8999/'))
assert 'http://testserver/plop' in resp.text
# add a bad redirection page (don't use it, do not crash)
page = Page(title='BadRedirection', slug='badredir', template_name='standard',
redirect_url='[foo_bar]')
page.save()
resp = app.get('/__skeleton__/?source=%s' % quote('http://example.net/foo/bar'))
resp = app.get('/__skeleton__/?source=%s' % quote('http://example.net/badredir'))
# add a page with restricted visibility
page = Page(title='RestrictedVisibility', slug='restrictedvisibilit',
template_name='standard', public=False)
page.save()
resp = app.get('/__skeleton__/?source=%s' % quote('http://127.0.0.1:8999/'))
assert 'RestrictedVisibility' in resp.text
# check 404 skeleton
resp = app.get('/__skeleton__/?source=404')
assert "This page doesn't exist" in resp.text
assert resp.status_code == 200
def test_subpage_location(app):
Page.objects.all().delete()
page_index = Page(title='Home Page', slug='index', template_name='standard')
page_index.save()
page_sibling = Page(title='Second top level page', slug='second', template_name='standard')
page_sibling.save()
page = Page(title='Child of Home', slug='child-home',
template_name='standard', parent=page_index)
page.save()
page = Page(title='Grand child of home', slug='grand-child-home',
template_name='standard', parent=page)
page.save()
page = Page(title='Child of second', slug='child-second',
template_name='standard', parent=page_sibling)
page.save()
page = Page(title='Grand child of second', slug='grand-child-second',
template_name='standard', parent=page)
page.save()
resp = app.get('/', status=200)
assert 'Home Page' in resp.text
resp = app.get('/child-home/', status=200)
assert 'Child of Home' in resp.text
resp = app.get('/child-home/grand-child-home/', status=200)
assert 'Grand child of home' in resp.text
assert urlparse.urlparse(app.get('/child-home/grand-child-home', status=301).location
).path == '/child-home/grand-child-home/'
app.get('/grand-child-home/', status=404)
resp = app.get('/second/', status=200)
assert 'Second top level page' in resp.text
resp = app.get('/second/child-second/', status=200)
assert 'Child of second' in resp.text
resp = app.get('/second/child-second/grand-child-second/', status=200)
assert 'Grand child of second' in resp.text
def test_menu(app):
Page.objects.all().delete()
page = Page(title='Page1', slug='index', template_name='standard')
page.save()
page = Page(title='Page2', slug='page2', template_name='standard')
page.save()
page = Page(title='Page3', slug='page3', template_name='standard', public=False)
page.save()
resp = app.get('/', status=200)
assert 'menu-index' in resp.text
assert 'menu-page2' in resp.text
assert 'menu-page3' in resp.text
def test_404(app):
Page.objects.all().delete()
resp = app.get('/foobar/', status=404)
assert "This page doesn't exist" in resp.text
page = Page(title='Not Found', slug='404', template_name='standard')
page.save()
TextCell(page=page, placeholder='content', text='Custom 404 Text', order=0).save()
resp = app.get('/foobar/', status=404)
assert 'Custom 404 Text' in resp.text
with override_settings(DEBUG=True):
# check error page provides an hint when debugging
resp = app.get('/foobar/', status=404)
assert "can't find the requested page" in resp.text
def test_style_demo(app, admin_user):
TextCell.objects.all().delete()
Page.objects.all().delete()
app = login(app)
with override_settings(DEBUG=True):
resp = app.get('/__style__/', status=200)
assert 'Lorem ipsum' in resp.text
assert TextCell.objects.count() == 0
assert Page.objects.count() == 0
def test_page_async_cell(app):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
cell = FeedCell(page=page, placeholder='content', url='http://example.net',
order=1)
cell.save()
resp = app.get('/', status=200)
assert 'data-ajax-cell-must-load="true"' in resp.text
def test_ajax_cell(app):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
page2 = Page(title='Other', slug='other', template_name='standard')
page2.save()
cell = TextCell(page=page, placeholder='content', text='<p>Foobar</p>', order=0)
cell.save()
resp = app.get(reverse('combo-public-ajax-page-cell',
kwargs={'page_pk': page.id, 'cell_reference': cell.get_reference()}))
assert resp.text.strip() == '<p>Foobar</p>'
resp = app.get(reverse('combo-public-ajax-page-cell',
kwargs={'page_pk': page2.id, 'cell_reference': cell.get_reference()}),
status=404)
resp = app.get(reverse('combo-public-ajax-page-cell',
kwargs={'page_pk': '100', 'cell_reference': cell.get_reference()}),
status=404)
page.public = False
page.save()
resp = app.get(reverse('combo-public-ajax-page-cell',
kwargs={'page_pk': page.id, 'cell_reference': cell.get_reference()}),
status=403)
page.public = True
page.save()
cell.public = False
cell.save()
resp = app.get('/', status=200)
assert not 'FOOBAR' in resp.text
resp = app.get(reverse('combo-public-ajax-page-cell',
kwargs={'page_pk': page.id, 'cell_reference': cell.get_reference()}),
status=403)
def test_initial_login_page(app, admin_user):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
page = Page(title='Initial Login', slug='initial-login', template_name='standard', public=False)
page.save()
with override_settings(COMBO_INITIAL_LOGIN_PAGE_PATH='/initial-login/'):
resp = app.get('/', status=200)
# first visit
app = login(app)
resp = app.get('/', status=302)
assert urlparse.urlparse(resp.location).path == '/initial-login/'
# visit again
resp = app.get('/', status=200)
def test_welcome_page(app, admin_user):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
page = Page(title='Welcome', slug='welcome', template_name='standard')
page.save()
with override_settings(COMBO_WELCOME_PAGE_PATH='/welcome/'):
app.cookiejar.clear()
resp = app.get('/', status=302)
assert urlparse.urlparse(resp.location).path == '/welcome/'
resp = app.get('/', status=200)
app.cookiejar.clear()
resp = app.get('/', status=302)
assert urlparse.urlparse(resp.location).path == '/welcome/'
app.cookiejar.clear()
app = login(app)
resp = app.get('/', status=200)
def test_post_cell(app):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
cell = TextCell(page=page, placeholder='content', text='<p>Foobar</p>', order=0)
cell.save()
# check it's not possible to post to cell that doesn't have POST support.
resp = app.post(reverse('combo-public-ajax-page-cell',
kwargs={'page_pk': page.id, 'cell_reference': cell.get_reference()}),
params={'hello': 'world'},
status=403)
templates_settings = [settings.TEMPLATES[0].copy()]
templates_settings[0]['DIRS'] = ['%s/templates-1' % os.path.abspath(os.path.dirname(__file__))]
with override_settings(JSON_CELL_TYPES={
'test-post-cell': {
'name': 'Foobar',
'url': 'http://test-post-cell/{{slug}}/',
'form': [
{'label': 'slug', 'varname': 'slug', 'required': True},
],
'actions': {
'create': {
'url': 'http://test-post-cell/{{slug}}/create/',
},
'update': {
'url': 'http://test-post-cell/{{slug}}/update/',
'method': 'PATCH',
},
'search': {
'url': 'http://test-post-cell/{{slug}}/search/',
'method': 'GET',
'response': 'raw'
},
}
}},
TEMPLATES=templates_settings
):
cell = ConfigJsonCell(page=page, placeholder='content', order=0)
cell.key = 'test-post-cell'
cell.parameters = {'slug': 'slug'}
cell.save()
with mock.patch('combo.utils.requests.get') as requests_get:
requests_get.return_value = mock.Mock(content=json.dumps({'hello': 'world'}), status_code=200)
resp = app.get('/', status=200)
resp.form['value'] = 'plop'
resp.form.fields['items[]'][0].checked = True
with mock.patch('combo.utils.requests.request') as requests_post:
requests_post.return_value = mock.Mock(content=json.dumps({'err': 0}), status_code=200)
resp2 = resp.form.submit()
assert requests_post.call_args[0][0] == 'POST'
assert requests_post.call_args[0][1] == 'http://test-post-cell/slug/create/'
assert requests_post.call_args[1]['json'] == {'value': 'plop', 'items': ['1']}
assert urlparse.urlparse(resp2.location).path == '/'
# check ajax call
with mock.patch('combo.utils.requests.request') as requests_post:
requests_post.return_value = mock.Mock(content=json.dumps({'err': 0}), status_code=200)
resp2 = resp.form.submit(headers={'x-requested-with': 'XMLHttpRequest'})
assert requests_post.call_args[0][0] == 'POST'
assert requests_post.call_args[0][1] == 'http://test-post-cell/slug/create/'
assert requests_post.call_args[1]['json'] == {'value': 'plop', 'items': ['1']}
assert resp2.text.startswith('<form')
# check error on POST
with mock.patch('combo.utils.requests.request') as requests_post:
requests_post.return_value = mock.Mock(content=json.dumps({'err': 0}), status_code=400)
resp2 = resp.form.submit()
assert urlparse.urlparse(resp2.location).path == '/'
resp2 = resp2.follow()
assert 'Error sending data.' in resp2.text
settings.JSON_CELL_TYPES['test-post-cell']['actions']['create']['error-message'] = 'Failed to create stuff.'
resp2 = resp.form.submit()
assert urlparse.urlparse(resp2.location).path == '/'
resp2 = resp2.follow()
assert 'Failed to create stuff.' in resp2.text
with mock.patch('combo.utils.requests.request') as requests_post:
requests_post.return_value = mock.Mock(content=json.dumps({'err': 0}), status_code=400)
resp2 = resp.form.submit(headers={'x-requested-with': 'XMLHttpRequest'})
assert resp2.text.startswith('<form')
assert resp2.headers['x-error-message'] == 'Failed to create stuff.'
# check variable substitution in URL
with mock.patch('combo.utils.requests.request') as requests_post:
settings.JSON_CELL_TYPES['test-post-cell']['actions']['create'] = {
'url': 'http://test-post-cell/{{slug}}/{{value}}/delete'}
resp2 = resp.form.submit()
assert requests_post.call_args[0][0] == 'POST'
assert requests_post.call_args[0][1] == 'http://test-post-cell/slug/plop/delete'
# check patch method
with mock.patch('combo.utils.requests.request') as requests_patch:
resp.form['action'] = 'update'
requests_patch.return_value = mock.Mock(content=json.dumps({'err': 0}), status_code=200)
resp2 = resp.form.submit()
assert requests_patch.call_args[0][0] == 'PATCH'
assert requests_patch.call_args[0][1] == 'http://test-post-cell/slug/update/'
assert requests_patch.call_args[1]['json'] == {'value': 'plop', 'items': ['1']}
assert urlparse.urlparse(resp2.location).path == '/'
# check raw result
with mock.patch('combo.utils.requests.request') as requests_search:
resp.form['action'] = 'search'
requests_search.return_value = mock.Mock(
content=json.dumps({'foo': 'bar'}),
status_code=200,
headers={'Content-Type': 'application/json'})
resp2 = resp.form.submit()
assert requests_search.call_args[0][0] == 'GET'
assert requests_search.call_args[0][1] == 'http://test-post-cell/slug/search/'
assert resp2.json == {'foo': 'bar'}
def test_familyinfos_cell_with_placeholders(app, admin_user):
Page.objects.all().delete()
page = Page(title='Family', slug='index', template_name='standard')
page.save()
family_cell = FamilyInfosCell(page=page, placeholder='content', order=0)
family_cell.save()
TextCell(page=page, placeholder='family_unlinked_user', text='<p>Hello anonymous user</p>', order=0,
restricted_to_unlogged=True, public=True).save()
TextCell(page=page, placeholder='family_unlinked_user', text='<p>You are not linked</p>',
order=1, public=False, restricted_to_unlogged=False).save()
with override_settings(FAMILY_SERVICE={'root': '/family/'}):
with mock.patch('combo.utils.requests.send') as requests_send:
resp = app.get('/')
assert "<p>Hello anonymous user</p>" in resp.text
assert "<p>You are not linked</p>" not in resp.text
app = login(app)
data = {'err': 0, 'data': None}
requests_send.return_value = mock.Mock(json=lambda: data, content=json.dumps(data), status_code=200)
# make sure no data are loaded
resp = app.get('/')
resp.html.body.find('div', {'class': 'familyinfoscell'}).text.strip() == 'Loading...'
# put data in cache
resp = app.get(reverse('combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': family_cell.get_reference()}))
resp = app.get('/')
assert "<p>Hello anonymous user</p>" not in resp.text
assert "<p>You are not linked</p>" in resp.text
@mock.patch('combo.utils.requests.get')
def test_familycell_link(requests_get, app, settings, admin_user):
settings.FAMILY_SERVICE = {'root': '/family/'}
Page.objects.all().delete()
page = Page(title='Family', slug='index', template_name='standard')
page.save()
family_cell = FamilyInfosCell(page=page, placeholder='content', order=0)
family_cell.save()
TextCell(page=page, placeholder='family_unlinked_user', text='<p>Hello anonymous user</p>', order=0,
restricted_to_unlogged=True, public=True).save()
TextCell(page=page, placeholder='family_unlinked_user', text='<p>You are not linked</p>',
order=1, public=False, restricted_to_unlogged=False).save()
app = login(app)
# when linking fails
requests_get.return_value = mock.Mock(ok=False, json=lambda: {'err': 102})
resp = app.get('/family/link/')
resp.form['family_id'] = '123'
resp.form['family_code'] = 'l33t'
resp = resp.form.submit().follow()
messages = resp.context['messages']
assert len(messages._loaded_messages) == 1
assert messages._loaded_messages[0].message == 'Failed to link to family. Please check your credentials and retry later.'
requests_get.return_value = mock.Mock(ok=True, json=lambda: {})
resp.form['family_id'] = '123'
resp.form['family_code'] = 'l33t'
resp = resp.form.submit().follow()
messages = resp.context['messages']
assert len(messages._loaded_messages) == 2
assert messages._loaded_messages[1].message == 'Your account was successfully linked.'
@mock.patch('combo.utils.requests.get')
def test_familycell_unlink(requests_get, app, settings, admin_user):
settings.FAMILY_SERVICE = {'root': '/family/'}
Page.objects.all().delete()
page = Page(title='Family', slug='index', template_name='standard')
page.save()
family_cell = FamilyInfosCell(page=page, placeholder='content', order=0)
family_cell.save()
TextCell(page=page, placeholder='family_unlinked_user', text='<p>Hello anonymous user</p>', order=0,
restricted_to_unlogged=True, public=True).save()
TextCell(page=page, placeholder='family_unlinked_user', text='<p>You are not linked</p>',
order=1, public=False, restricted_to_unlogged=False).save()
app = login(app)
requests_get.return_value = mock.Mock(ok=False, json=lambda: {'err': 102})
resp = app.get('/family/unlink/')
resp = resp.form.submit().follow()
messages = resp.context['messages']
assert len(messages._loaded_messages) == 1
assert messages._loaded_messages[0].message == 'An error occured when unlinking.'
requests_get.return_value = mock.Mock(ok=True, json=lambda: {})
resp = app.get('/family/unlink/')
resp = resp.form.submit().follow()
messages = resp.context['messages']
assert len(messages._loaded_messages) == 2
assert messages._loaded_messages[1].message == 'Your account was successfully unlinked.'
def test_synchronous_placeholder(app):
page = Page(title=u'foo', slug='foo', template_name='standard', order=0)
page.save()
cell = FeedCell(page=page, placeholder='content', url='http://example.net', order=1)
cell.save()
templates_settings = [settings.TEMPLATES[0].copy()]
templates_settings[0]['DIRS'] = ['%s/templates-1' % os.path.abspath(os.path.dirname(__file__))]
with override_settings(COMBO_PUBLIC_TEMPLATES={
'standard': {
'name': 'Test',
'template': 'combo/page_template_synchronous_placeholder.html',
}},
TEMPLATES=templates_settings
):
with mock.patch('requests.get') as requests_get:
requests_get.return_value = mock.Mock(content='', status_code=200)
resp = app.get('/foo/', status=200)
assert not 'data-ajax-cell-must-load="true"' in resp.text
cell = FeedCell(page=page, placeholder='sidebar', url='http://example.org', order=1)
cell.save()
resp = app.get('/foo/', status=200)
assert resp.text.count('data-ajax-cell-must-load="true"') == 1
def test_redirects(app):
Redirect.objects.all().delete()
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
page2 = Page(title='Second', slug='second', template_name='standard')
page2.save()
page3 = Page(title='Third', slug='third', template_name='standard', parent=page2)
page3.save()
app.get('/whatever/', status=404)
redirect = Redirect(old_url='/whatever/', page=page3)
redirect.save()
assert urlparse.urlparse(app.get('/whatever/', status=302).location).path == '/second/third/'
assert urlparse.urlparse(app.get('/whatever', status=301).location).path == '/whatever/'
# check the most recent redirect is called
redirect = Redirect(old_url='/whatever/', page=page2)
redirect.save()
assert urlparse.urlparse(app.get('/whatever/', status=302).location).path == '/second/'
# rename page
page3.slug = 'third2'
page3.save()
assert app.get('/second/third2/', status=200)
assert urlparse.urlparse(app.get('/second/third/', status=302).location).path == '/second/third2/'
page2.slug = 'second2'
page2.save()
assert urlparse.urlparse(app.get('/second/third/', status=302).location).path == '/second2/third2/'
assert urlparse.urlparse(app.get('/second/third2/', status=302).location).path == '/second2/third2/'
assert urlparse.urlparse(app.get('/second/', status=302).location).path == '/second2/'
# change parent
page3.parent = None
page3.save()
assert urlparse.urlparse(app.get('/second/third/', status=302).location).path == '/third2/'
assert urlparse.urlparse(app.get('/second2/third2/', status=302).location).path == '/third2/'
def test_sub_slug(app, john_doe, jane_doe):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
page2 = Page(title='User', slug='users', sub_slug='(?P<blah>[a-z]+)', template_name='standard')
page2.save()
page3 = Page(title='Blah', slug='blah', parent=page2, template_name='standard')
page3.save()
# without passing sub slug
assert app.get('/users/', status=302).location in ('..', 'http://testserver/')
# (result vary between django versions)
# json cell so we can display the parameter value
cell = JsonCell(page=page2, url='http://example.net', order=0, placeholder='content')
cell.template_string = 'XX{{ blah }}YY'
cell.save()
cell2 = JsonCell(page=page3, url='http://example.net', order=0, placeholder='content')
cell2.template_string = 'AA{{ blah }}BB{{ absolute_uri }}CC'
cell2.save()
with mock.patch('combo.utils.requests.get') as requests_get:
data = {'data': [{'url': 'http://a.b', 'text': 'xxx'}]}
requests_get.return_value = mock.Mock(content=json.dumps(data), status_code=200)
resp = app.get('/users/whatever/', status=200)
assert 'XXwhateverYY' in resp.text
cell_url = re.findall(r'data-ajax-cell-url="(.*)"', resp.text)[0]
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)[0]
resp = app.get(cell_url + '?ctx=' + extra_ctx)
assert resp.text == 'XXwhateverYY'
# 404 on value that doesn't match the regex
resp = app.get('/users/WHATEVER/', status=404)
# check sub page
resp = app.get('/users/whatever/plop/', status=404)
resp = app.get('/users/whatever/blah/', status=200)
cell_url = re.findall(r'data-ajax-cell-url="(.*)"', resp.text)[0]
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)[0]
resp = app.get(cell_url + '?ctx=' + extra_ctx)
assert resp.text == 'AAwhateverBBhttp://testserver/users/whatever/blah/CC'
# custom behaviour for <user_id>, it will add the user to context
page2.sub_slug = '(?P<user_id>[0-9]+)'
page2.save()
cell.template_string = 'XX{{ selected_user.username }}YY'
cell.save()
resp = app.get('/users/%s/' % john_doe.id, status=200)
assert 'XXjohn.doeYY' in resp.text
# bad user id => no selected_user
page2.sub_slug = '(?P<user_id>[0-9a-z]+)'
page2.save()
resp = app.get('/users/9999999/', status=200)
assert 'XXYY' in resp.text
resp = app.get('/users/abc/', status=200)
assert 'XXYY' in resp.text
# custom behaviour for <name_id>, it will add the SAML user to context
with mock.patch('combo.profile.utils.UserSAMLIdentifier') as user_saml:
class DoesNotExist(Exception):
pass
user_saml.DoesNotExist = DoesNotExist
def side_effect(*args, **kwargs):
name_id = kwargs['name_id']
if name_id == 'foo':
raise user_saml.DoesNotExist
return mock.Mock(user=john_doe)
mocked_objects = mock.Mock()
mocked_objects.get = mock.Mock(side_effect=side_effect)
user_saml.objects = mocked_objects
page2.sub_slug = '(?P<name_id>[0-9a-z.]+)'
page2.save()
resp = app.get('/users/john.doe/', status=200)
assert 'XXjohn.doeYY' in resp.text
# unknown name id => no selected_user
resp = app.get('/users/foo/', status=200)
assert 'XXYY' in resp.text