combo/tests/test_wcs.py

4357 lines
166 KiB
Python

import copy
import json
import re
import urllib.parse
from importlib import import_module
from unittest import mock
import pytest
from django.apps import apps
from django.conf import settings
from django.contrib.auth.models import AnonymousUser
from django.core.cache import cache
from django.db import connection
from django.test.client import RequestFactory
from django.test.utils import CaptureQueriesContext
from django.urls import reverse
from pyquery import PyQuery
from requests.exceptions import ConnectionError
from requests.models import Response
from combo.apps.search.engines import engines
from combo.apps.search.models import SearchCell
from combo.apps.search.utils import index_site, search_site
from combo.apps.wcs.models import (
BackofficeSubmissionCell,
CategoriesCell,
TrackingCodeInputCell,
WcsCardInfosCell,
WcsCardsCell,
WcsCareFormsCell,
WcsCategoryCell,
WcsCurrentDraftsCell,
WcsCurrentFormsCell,
WcsFormCell,
WcsFormsOfCategoryCell,
)
from combo.data.library import get_cell_classes
from combo.data.models import CellBase, LinkListCell, Page, ValidityInfo
from combo.utils import NothingInCacheException
from .test_manager import login
from .utils import manager_submit_cell
pytestmark = pytest.mark.django_db
WCS_FORMDEFS_DATA = [
{'slug': 'a-private-form', 'title': 'a private form', 'url': '/a-private-form/'},
{'slug': 'a-second-form-title', 'title': 'a second form title', 'url': '/a-second-form-title/'},
{'slug': 'form-title', 'title': 'form title', 'url': '/form-title/', 'keywords': ['foo', 'bar']},
{'slug': 'third-form-title', 'title': 'Third form title', 'url': '/third-form-title/'},
]
WCS_CATEGORIES_DATA = [
{'slug': 'test-%s' % i, 'title': 'Test %s' % i, 'url': '/test-%s/' % i} for i in [3, 9]
]
WCS_CATEGORIES_FORMDEFS_DATA = [
{
'slug': 'form-title',
'title': 'form title',
'url': '/form-title/',
'keywords': ['foo', 'bar'],
'count': 42,
},
{
'slug': 'a-second-form-title',
'title': 'a second form title',
'url': '/a-second-form-title/',
'count': 35,
},
]
WCS_USER_FORMS_DATA = [
{
'name': 'name',
'title': 'Title',
'url': '/form/1/',
'form_receipt_datetime': '2015-01-01T00:00:00',
'readable': True,
'category_slug': 'test-9',
},
{'name': 'name', 'url': '/form/2/', 'form_receipt_datetime': '2015-01-01T00:00:00', 'readable': True},
{'name': 'name', 'title': 'Title', 'url': '/form/3/', 'form_receipt_datetime': '2015-01-01T00:00:00'},
]
WCS_FORMS_DATA = [
{
'form_receipt_datetime': '2019-10-17T16:46:03',
'form_url': '/foobar/1',
'form_url_backoffice': '/backoffice/management/foobar/1/',
},
{
'form_receipt_datetime': '2019-10-17T16:46:04',
'form_url': '/foobar/2',
'form_url_backoffice': '/backoffice/management/foobar/2/',
},
]
WCS_USER_DRAFTS_DATA = [
{
'name': 'name',
'title': 'Title',
'url': '/form/1/',
'form_receipt_datetime': '2015-01-01T00:00:00',
'category_slug': 'test-9',
},
{'name': 'name', 'url': '/form/2/', 'form_receipt_datetime': '2015-01-01T00:00:00'},
{'name': 'name', 'title': 'Title', 'url': '/form/3/', 'form_receipt_datetime': '2015-01-01T00:00:00'},
{
'name': 'name',
'title': 'Title',
'url': '/form/4/',
'form_receipt_datetime': '2015-01-01T00:00:00',
'form_status_is_endpoint': True,
'category_slug': 'test-9',
},
]
WCS_CARDDEFS_DATA = [
{'title': 'Card Model 1', 'slug': 'card_model_1', 'custom_views': [{'id': 'foo', 'text': 'bar'}]},
{'title': 'Card Model 2', 'slug': 'card_model_2'},
{'title': 'Card Model 3', 'slug': 'card_model_3'},
{'title': 'Card A', 'slug': 'card_a'},
{'title': 'Card B', 'slug': 'card_b'},
{'title': 'Card C', 'slug': 'card_c'},
{'title': 'Card D', 'slug': 'card_d'},
{'title': 'Card E', 'slug': 'card_e'},
]
WCS_CARDS_DATA = {
'card_model_1': [
{
'id': 11,
'display_id': '10-11',
'display_name': 'Card Model 1 - n°10-11',
'digest': 'a a a',
'text': 'aa',
'url': '/backoffice/data/card_model_1/11/',
'fields': {
'fielda': '<i>a</i>',
'fieldb': True,
'fieldc': '2020-09-28',
'fieldd': {'filename': 'file.pdf', 'url': 'http://127.0.0.1:8999/download?f=42'},
'fielde': "lorem<strong>ipsum\n\nhello'world",
'fieldf': 'lorem<strong>ipsum\n\nhello world',
'fieldg': 'test@localhost',
'fieldh': 'https://www.example.net/',
'related': 'Foo Bar',
'related_raw': 42,
'related_structured': {'id': 42, 'text': 'blah'},
},
},
{
'id': 12,
'display_id': '10-12',
'display_name': 'Card Model 1 - n°10-12',
'digest': 'b b b',
'text': 'bb',
'url': '/backoffice/data/card_model_1/12/',
},
{
'id': 13,
'display_id': '10-13',
'display_name': 'Card Model 1 - n°10-13',
'digest': 'c c c',
'text': 'cc',
'url': '/backoffice/data/card_model_1/13/',
},
],
'card_a': [
{
'id': 1,
'fields': {
'cardb_raw': 1,
'cardsb_raw': [2, 3],
'blockb_raw': [{'cardb_raw': 4}, {'cardb_raw': 5}],
'cardc_raw': 6,
'cardz_raw': 42,
},
},
{
'id': 2,
'fields': {
'cardb_raw': 1,
'cardsb_raw': [2, 3],
'blockb_raw': [{'cardb_raw': 4}, {'cardb_raw': 5}],
'cardc_raw': 61, # unknown card_c
},
},
{
'id': 3,
'fields': {
# some missing fields
'blockb_raw': [{}],
},
},
{
'id': 4,
'fields': {
# some empty fields
'cardb_raw': None,
'cardsb_raw': None,
'blockb_raw': [{'cardb_raw': None}],
'cardc_raw': 7,
},
},
],
'card_b': [{'id': i, 'fields': []} for i in range(1, 12) if i != 6],
'card_c': [
{
'id': 6,
'fields': {
'cardb_raw': 7,
'cardsb_raw': [8, 9],
'blockb_raw': [{'cardb_raw': 10}, {'cardb_raw': 11}],
},
},
{
'id': 7,
'fields': {},
},
],
'card_f': [
{'id': 41, 'fields': {'cardh_raw': 42}},
],
'card_g': [
{'id': 43, 'fields': {'cardh_raw': 44}},
],
'card_h': [
{'id': 42, 'fields': {}},
{'id': 44, 'fields': {}},
],
}
WCS_CARDS_CUSTOM_VIEW_DATA = [
{
'id': 11,
'display_id': '10-11',
'display_name': 'Card Model 1 - n°10-11',
'digest': 'a a a',
'text': 'aa',
'url': '/backoffice/data/card_model_1/11/',
},
{
'id': 12,
'display_id': '10-12',
'display_name': 'Card Model 1 - n°10-12',
'digest': 'b b b',
'text': 'bb',
'url': '/backoffice/data/card_model_1/12/',
},
]
WCS_CARDDEF_SCHEMAS = {
'card_model_1': {
'name': 'Card Model 1',
'fields': [
{'label': 'Field A', 'varname': 'fielda', 'type': 'string'},
{'label': 'Field B', 'varname': 'fieldb', 'type': 'bool'},
{'label': 'Field C', 'varname': 'fieldc', 'type': 'date'},
{'label': 'Field D', 'varname': 'fieldd', 'type': 'file'},
{'label': 'Field E', 'varname': 'fielde', 'type': 'text'},
{'label': 'Field F', 'varname': 'fieldf', 'type': 'text', 'pre': True},
{'label': 'Field G', 'varname': 'fieldg', 'type': 'email'},
{'label': 'Field H', 'varname': 'fieldh', 'type': 'string'},
{'label': 'Empty', 'varname': 'empty', 'type': 'string'},
{'label': 'Related', 'varname': 'related', 'type': 'item'},
{'label': 'Page', 'type': 'page'},
{'label': 'Comment', 'type': 'comment'},
{'label': 'Title', 'type': 'title'},
{'label': 'Subtitle', 'type': 'subtitle'},
{'label': 'Empty', 'varname': None, 'type': 'string'},
],
},
'card_a': {
'name': 'Card A',
'fields': [
{'label': 'Card B', 'varname': 'cardb', 'type': 'item'},
{'label': 'Cards B', 'varname': 'cardsb', 'type': 'items'},
{'label': 'Block B', 'varname': 'blockb', 'type': 'block:b'},
{'label': 'Card C', 'varname': 'cardc', 'type': 'item'},
],
'relations': [
{'obj': 'carddef:card_b', 'varname': 'cardb', 'type': 'item', 'reverse': False},
{'obj': 'carddef:card_b', 'varname': 'cardsb', 'type': 'items', 'reverse': False},
{'obj': 'carddef:card_b', 'varname': 'blockb_cardb', 'type': 'item', 'reverse': False},
{'obj': 'carddef:card_c', 'varname': 'cardc', 'type': 'item', 'reverse': False},
{
'obj': 'carddef:card_z', # unknown card model
'varname': 'cardz',
'type': 'item',
'reverse': False,
},
],
},
'card_b': {
'name': 'Card B',
'fields': [],
'relations': [
{'obj': 'carddef:card_a', 'varname': 'cardb', 'type': 'item', 'reverse': True},
{'obj': 'carddef:card_a', 'varname': 'cardsb', 'type': 'items', 'reverse': True},
{'obj': 'carddef:card_a', 'varname': 'blockb_cardb', 'type': 'item', 'reverse': True},
{'obj': 'carddef:card_c', 'varname': 'cardb', 'type': 'item', 'reverse': True},
{'obj': 'carddef:card_c', 'varname': 'cardsb', 'type': 'items', 'reverse': True},
{'obj': 'carddef:card_c', 'varname': 'blockb_cardb', 'type': 'item', 'reverse': True},
],
},
'card_c': {
'name': 'Card C',
'fields': [
{'label': 'Card B', 'varname': 'cardb', 'type': 'item'},
{'label': 'Cards B', 'varname': 'cardsb', 'type': 'items'},
{'label': 'Block B', 'varname': 'blockb', 'type': 'block:b'},
],
'relations': [
{'obj': 'carddef:card_b', 'varname': 'cardb', 'type': 'item', 'reverse': False},
{'obj': 'carddef:card_b', 'varname': 'cardsb', 'type': 'items', 'reverse': False},
{'obj': 'carddef:card_b', 'varname': 'blockb_cardb', 'type': 'item', 'reverse': False},
{'obj': 'carddef:card_a', 'varname': 'cardc', 'type': 'item', 'reverse': True},
],
},
'card_d': {
'name': 'Card D',
'fields': [
{'label': 'Card D', 'varname': 'cardd-foo', 'type': 'item'},
{'label': 'Card E', 'varname': 'carde-foo', 'type': 'item'},
],
'relations': [
{'obj': 'carddef:card_d', 'varname': 'cardd-foo', 'type': 'item', 'reverse': False},
{'obj': 'carddef:card_d', 'varname': 'cardd-foo', 'type': 'item', 'reverse': True},
{'obj': 'carddef:card_e', 'varname': 'carde-foo', 'type': 'item', 'reverse': False},
],
},
'card_e': {
'name': 'Card E',
'fields': [
{'label': 'Card D', 'varname': 'cardd-bar', 'type': 'item'},
],
'relations': [
{'obj': 'carddef:card_d', 'varname': 'cardd-bar', 'type': 'item', 'reverse': False},
{'obj': 'carddef:card_d', 'varname': 'carde-foo', 'type': 'item', 'reverse': True},
],
},
'card_f': {
'name': 'Card F',
'fields': [
{'label': 'Card H', 'varname': 'cardh', 'type': 'item'},
],
'relations': [
{'obj': 'carddef:card_h', 'varname': 'cardh', 'type': 'item', 'reverse': False},
],
},
'card_g': {
'name': 'Card G',
'fields': [
{'label': 'Card H', 'varname': 'cardh', 'type': 'item'},
],
'relations': [
{'obj': 'carddef:card_h', 'varname': 'cardh', 'type': 'item', 'reverse': False},
],
},
'card_h': {
'name': 'Card H',
'fields': [],
'relations': [
{'obj': 'carddef:card_f', 'varname': 'cardh', 'type': 'item', 'reverse': True},
{'obj': 'carddef:card_g', 'varname': 'cardh', 'type': 'item', 'reverse': True},
],
},
}
class MockUser:
email = 'foo@example.net'
is_authenticated = True
is_anonymous = False
def get_name_id(self):
return None
class MockUserWithNameId:
email = 'foo@example.net'
is_authenticated = True
is_anonymous = False
def get_name_id(self):
return 'xyz'
class MockedRequestResponse(mock.Mock):
status_code = 200
def json(self):
return json.loads(self.content)
def get_data_from_url(url):
if '/api/formdefs/' in url:
return WCS_FORMDEFS_DATA
if '/api/categories/' in url:
if '/formdefs/' in url:
return WCS_CATEGORIES_FORMDEFS_DATA
return WCS_CATEGORIES_DATA
if '/api/user/forms' in url:
return WCS_USER_FORMS_DATA
if '/api/forms' in url:
return WCS_FORMS_DATA
if '/api/user/drafts' in url:
return WCS_USER_DRAFTS_DATA
if '/api/cards/@list' in url:
return WCS_CARDDEFS_DATA
m_schema = re.match(r'/api/cards/([a-z0-9_]+)/@schema', url)
if m_schema:
return WCS_CARDDEF_SCHEMAS.get(m_schema.group(1)) or {}
m_card = re.match(r'/api/cards/([a-z0-9_]+)/(\d+)/', url)
if m_card:
try:
return [d for d in WCS_CARDS_DATA[m_card.group(1)] if d['id'] == int(m_card.group(2))][0]
except IndexError:
return {}
m_card = re.match(r'/api/cards/([a-z0-9_]+)/([a-z0-9_]+)/(\d+)/', url) # model/custom-view/id
if m_card:
try:
return [d for d in WCS_CARDS_DATA[m_card.group(1)] if d['id'] == int(m_card.group(3))][0]
except IndexError:
return {}
if 'api/cards/card_model_1/list/foo' in url:
return WCS_CARDS_CUSTOM_VIEW_DATA
m_list = re.match(r'/api/cards/([a-z0-9_]+)/list', url)
if m_list:
return WCS_CARDS_DATA[m_list.group(1)]
return []
def mocked_requests_send(request, **kwargs):
request_url = urllib.parse.urlparse(request.url)
data = copy.deepcopy(get_data_from_url(request_url.path))
if not isinstance(data, list):
return MockedRequestResponse(content=json.dumps(data))
for elem in data:
for key in ['url', 'form_url', 'form_url_backoffice']:
if key not in elem:
continue
elem_url = elem[key]
elem[key] = '{scheme}://{netloc}{url}'.format(
scheme=request_url.scheme, netloc=request_url.netloc, url=elem_url
)
return MockedRequestResponse(content=json.dumps({'data': data}))
@pytest.fixture
def context():
ctx = {'request': RequestFactory().get('/')}
ctx['request'].user = None
session_engine = import_module(settings.SESSION_ENGINE)
ctx['request'].session = session_engine.SessionStore()
return ctx
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_form_cell_setup(mock_send):
cell = WcsFormCell()
form_class = cell.get_default_form_class()
form = form_class()
assert form.fields['formdef_reference'].widget.choices == [
('default:a-private-form', 'test : a private form'),
('default:a-second-form-title', 'test : a second form title'),
('default:form-title', 'test : form title'),
('default:third-form-title', 'test : Third form title'),
('other:a-private-form', 'test2 : a private form'),
('other:a-second-form-title', 'test2 : a second form title'),
('other:form-title', 'test2 : form title'),
('other:third-form-title', 'test2 : Third form title'),
]
assert 'extra_css_class' not in form.fields
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_form_cell_save_cache(mock_send):
page = Page(title='xxx', slug='test_form_cell_save_cache', template_name='standard')
page.save()
cell = WcsFormCell(page=page, placeholder='content', order=0)
assert cell.get_additional_label() is None
cell.formdef_reference = 'default:form-title'
cell.save()
assert cell.cached_title == 'form title'
assert cell.get_additional_label() == 'form title'
# make sure cached attributes are removed from serialized pages
assert 'cached_' not in json.dumps(page.get_serialized_page())
# check content provided to search engine
assert cell.render_for_search() == ''
assert cell.get_external_links_data() == [
{'title': 'form title', 'url': 'http://127.0.0.1:8999/form-title/', 'text': 'foo bar'}
]
# artificially change title
WcsFormCell.objects.filter(id=cell.id).update(cached_title='XXX')
assert WcsFormCell.objects.get(id=cell.id).cached_title == 'XXX'
# run update db cache
appconfig = apps.get_app_config('wcs')
appconfig.update_db_cache()
assert WcsFormCell.objects.get(id=cell.id).cached_title == 'form title'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_form_cell_validity(mock_send):
page = Page.objects.create(title='xxx', slug='test_form_cell_save_cache', template_name='standard')
cell = WcsFormCell.objects.create(page=page, placeholder='content', order=0)
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_form_not_defined'
assert validity_info.invalid_since is not None
cell.formdef_reference = 'default:form-title'
cell.save()
assert ValidityInfo.objects.exists() is False
# can not retrieve data, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
cell.save()
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
cell.save()
assert ValidityInfo.objects.exists() is False
# can not retrieve formdefs, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
cell.save()
assert ValidityInfo.objects.exists() is False
cell.formdef_reference = 'default:foobar'
cell.save()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_form_not_found'
assert validity_info.invalid_since is not None
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_form_cell_load(mock_send):
page = Page(title='xxx', slug='test_form_cell_save_cache', template_name='standard')
page.save()
cell = WcsFormCell(page=page, placeholder='content', order=0)
cell.formdef_reference = 'default:form-title'
cell.save()
site_export = [page.get_serialized_page()]
cell.delete()
assert not Page.objects.get(id=page.id).get_cells()
Page.load_serialized_pages(site_export)
page = Page.objects.get(slug='test_form_cell_save_cache')
cells = page.get_cells()
assert len(cells) == 1
cell = cells[0]
assert cell.cached_title == 'form title'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_category_cell_save_cache(mock_send):
page = Page(title='xxx', slug='test_category_cell_save_cache', template_name='standard')
page.save()
cell = WcsCategoryCell(page=page, placeholder='content', order=0)
assert cell.get_additional_label() is None
cell.category_reference = 'default:test-3'
cell.save()
assert cell.cached_title == 'Test 3'
assert cell.get_additional_label() == 'Test 3'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_category_cell_validity(mock_send):
page = Page.objects.create(title='xxx', slug='test_category_cell_save_cache', template_name='standard')
cell = WcsCategoryCell.objects.create(page=page, placeholder='content', order=0)
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_category_not_defined'
assert validity_info.invalid_since is not None
cell.category_reference = 'default:test-3'
cell.save()
assert ValidityInfo.objects.exists() is False
# can not retrieve data, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
cell.save()
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
cell.save()
assert ValidityInfo.objects.exists() is False
# can not retrieve categories, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
cell.save()
assert ValidityInfo.objects.exists() is False
cell.category_reference = 'default:foobar'
cell.save()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_category_not_found'
assert validity_info.invalid_since is not None
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_categories_cell_check_validity(mock_send):
page = Page.objects.create(title='xxx', slug='test', template_name='standard')
cell = CategoriesCell.objects.create(page=page, placeholder='content', order=0)
# invalid wcs_site
cell.wcs_site = 'invalid'
cell.save()
cell.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_site_not_found'
assert validity_info.invalid_since is not None
# valid wcs_site
cell.wcs_site = 'default'
cell.save()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_form_cell_render(mock_send):
page = Page(title='xxx', slug='test_form_cell_render', template_name='standard')
page.save()
cell = WcsFormCell(page=page, placeholder='content', order=0)
cell.formdef_reference = 'default:form-title'
cell.save()
result = cell.render({})
assert 'http://127.0.0.1:8999/form-title/tryauth' in result
assert 'form title' in result
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_current_forms_cell_setup(mock_send):
cell = WcsCurrentFormsCell()
form_class = cell.get_default_form_class()
form = form_class()
assert form.fields['wcs_site'].widget.choices == [
('', 'All'),
('default', 'test'),
('other', 'test2'),
]
assert 'current_forms' in form.fields
assert cell.get_additional_label() == 'All Sites - Current Forms'
cell.wcs_site = 'default'
assert cell.get_additional_label() == 'test - Current Forms'
cell.wcs_site = None
cell.current_forms = True
cell.done_forms = True
assert cell.get_additional_label() == 'All Sites - All Forms'
cell.current_forms = False
cell.done_forms = True
assert cell.get_additional_label() == 'All Sites - Done Forms'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_current_forms_cell_render(mock_send, context):
page = Page(title='xxx', slug='test_current_forms_cell_render', template_name='standard')
page.save()
cell = WcsCurrentFormsCell(page=page, placeholder='content', order=0)
cell.save()
context['request'].user = MockUser()
# query should fail as nothing is cached
cache.clear()
with pytest.raises(NothingInCacheException):
result = cell.render(context)
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert 'http://127.0.0.1:8999/form/1/' in result
assert 'http://127.0.0.1:8999/form/2/' not in result # no title
assert 'http://127.0.0.1:8999/form/3/' not in result # not readable
assert 'http://127.0.0.2:8999/form/1/' in result
assert 'http://127.0.0.2:8999/form/2/' not in result
assert 'http://127.0.0.2:8999/form/3/' not in result
# limit to categories
cell.categories = {'data': ['default:test-3', 'other:test-6']}
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
assert (
requests_get.call_args_list[0][0][0]
== '/api/user/forms/?status=open&limit=100&sort=desc&category_slugs=test-3'
)
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert (
requests_get.call_args_list[1][0][0]
== '/api/user/forms/?status=open&limit=100&sort=desc&category_slugs=test-6'
)
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
# check include drafts
cell.categories = None
cell.include_drafts = False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/user/forms/?status=open&limit=100&sort=desc'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert requests_get.call_args_list[1][0][0] == '/api/user/forms/?status=open&limit=100&sort=desc'
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
cell.include_drafts = True
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
assert (
requests_get.call_args_list[0][0][0]
== '/api/user/forms/?status=open&include-drafts=on&limit=100&sort=desc'
)
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert (
requests_get.call_args_list[1][0][0]
== '/api/user/forms/?status=open&include-drafts=on&limit=100&sort=desc'
)
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
cell.categories = {'data': ['default:test-3']}
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 1
assert (
requests_get.call_args_list[0][0][0]
== '/api/user/forms/?status=open&include-drafts=on&limit=100&sort=desc&category_slugs=test-3'
)
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
cell.categories = {'data': []}
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
# current_forms only
cell.include_drafts = False
cell.current_forms = True
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/user/forms/?status=open&limit=100&sort=desc'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert requests_get.call_args_list[1][0][0] == '/api/user/forms/?status=open&limit=100&sort=desc'
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
# all forms
cell.done_forms = True
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/user/forms/?status=all&limit=100&sort=desc'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert requests_get.call_args_list[1][0][0] == '/api/user/forms/?status=all&limit=100&sort=desc'
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
# done forms only
cell.current_forms = False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/user/forms/?status=done&limit=100&sort=desc'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert requests_get.call_args_list[1][0][0] == '/api/user/forms/?status=done&limit=100&sort=desc'
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
# include forms user can see
cell.include_forms_user_can_access = True
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.render(context)
assert (
requests_get.call_args_list[0][0][0]
== '/api/user/forms/?status=done&include-accessible=on&limit=100&sort=desc'
)
# check empty messages and title
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.current_forms = True
cell.done_forms = False
cell.include_drafts = False
result = cell.render(context)
assert '<h2>Current Forms</h2>' in result
assert 'There are no current forms.' in result
cell.custom_title = 'Foo bar'
result = cell.render(context)
assert '<h2>Foo bar</h2>' in result
cell.custom_title = ''
cell.done_forms = True
result = cell.render(context)
assert '<h2>All Forms</h2>' in result
assert 'There are no forms.' in result
cell.custom_title = 'Foo bar'
result = cell.render(context)
assert '<h2>Foo bar</h2>' in result
cell.custom_title = ''
cell.current_forms = False
result = cell.render(context)
assert '<h2>Done Forms</h2>' in result
assert 'There are no done forms' in result
cell.custom_title = 'Foo bar'
result = cell.render(context)
assert '<h2>Foo bar</h2>' in result
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_current_forms_cell_validity(mock_send, context):
page = Page.objects.create(title='xxx', slug='test_current_forms_cell_render', template_name='standard')
cell = WcsCurrentFormsCell.objects.create(page=page, placeholder='content', order=0)
context['request'].user = MockUser()
context['synchronous'] = True # to get fresh content
cell.get_data(context)
assert ValidityInfo.objects.exists() is False
# can not retrieve data, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
cell.get_data(context)
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
cell.get_data(context)
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
cell.get_data(context)
assert ValidityInfo.objects.exists() is False
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_current_forms_cell_check_validity(mock_send, context):
page = Page.objects.create(title='xxx', slug='test_current_forms_cell_render', template_name='standard')
cell = WcsCurrentFormsCell.objects.create(page=page, placeholder='content', order=0)
# no category
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# valid categories
cell.categories = {'data': ['default:test-3', 'default:test-9']}
cell.save()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# can not retrieve data, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
cell.check_validity()
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# can not retrieve categories, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# invalid category
cell.categories = {'data': ['default:foobar', 'default:test-9']}
cell.save()
cell.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_category_not_found'
assert validity_info.invalid_since is not None
# invalid wcs_site
cell.categories = {'data': ['default:test-3', 'default:test-9']}
cell.wcs_site = 'invalid'
cell.save()
cell.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_site_not_found'
assert validity_info.invalid_since is not None
# valid wcs_site
cell.wcs_site = 'default'
cell.save()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_current_forms_cell_render_single_site(mock_send, context):
page = Page(title='xxx', slug='test_current_forms_cell_render', template_name='standard')
page.save()
cell = WcsCurrentFormsCell(page=page, placeholder='content', order=0)
cell.wcs_site = 'default'
cell.save()
context['request'].user = MockUser()
# query should fail as nothing is cached
cache.clear()
with pytest.raises(NothingInCacheException):
result = cell.render(context)
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert 'http://127.0.0.1:8999/form/1/' in result
assert 'http://127.0.0.2:8999/form/1/' not in result
def test_current_forms_name_id(context):
page = Page(title='xxx', slug='test_current_forms_cell_render', template_name='standard')
page.save()
cell = WcsCurrentFormsCell(page=page, placeholder='content', order=0)
cell.wcs_site = 'default'
cell.save()
context['synchronous'] = True # to get fresh content
# anonymous user
context['request'].user = AnonymousUser()
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.render(context)
assert requests_get.call_args_list[0][0][0] == '/api/user/forms/?status=open&limit=100&sort=desc'
# user with name_id
context['request'].user = MockUserWithNameId()
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.render(context)
assert requests_get.call_args_list[0][0][0] == '/api/users/xyz/forms?status=open&limit=100&sort=desc'
def test_care_forms_cell_setup():
cell = WcsCareFormsCell()
form_class = cell.get_default_form_class()
form = form_class()
assert form.fields['wcs_site'].widget.choices == [
('', 'All'),
('default', 'test'),
('other', 'test2'),
]
assert cell.get_additional_label() == 'All Sites'
cell.wcs_site = 'default'
assert cell.get_additional_label() == 'test'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_care_forms_cell_render(mock_send, context):
page = Page(title='xxx', slug='test_care_forms_cell_render', template_name='standard')
page.save()
cell = WcsCareFormsCell(page=page, placeholder='content', order=0)
cell.save()
context['request'].user = MockUser()
# query should fail as nothing is cached
cache.clear()
with pytest.raises(NothingInCacheException):
result = cell.render(context)
context['synchronous'] = True # to get fresh content
with mock.patch('combo.apps.wcs.models.is_portal_agent') as is_portal_agent:
is_portal_agent.return_value = True
result = cell.render(context)
assert 'http://127.0.0.1:8999/backoffice/management/foobar/1' in result
assert 'http://127.0.0.1:8999/backoffice/management/foobar/2' in result
assert '"http://127.0.0.1:8999/backoffice/management/listing"' in result
assert 'http://127.0.0.2:8999/backoffice/management/foobar/1' in result
assert 'http://127.0.0.2:8999/backoffice/management/foobar/2' in result
assert '"http://127.0.0.2:8999/backoffice/management/listing"' in result
with mock.patch('combo.apps.wcs.models.is_portal_agent') as is_portal_agent:
is_portal_agent.return_value = False
result = cell.render(context)
assert 'http://127.0.0.1:8999/foobar/1' in result
assert 'http://127.0.0.1:8999/foobar/2' in result
assert 'http://127.0.0.2:8999/foobar/1' in result
assert 'http://127.0.0.2:8999/foobar/2' in result
assert '/listing' not in result
data = cell.get_data(context)
assert 'default' in data
assert 'other' in data
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.render(context)
assert requests_get.call_args_list[0][0][0] == '/api/forms/?limit=10'
assert requests_get.call_args_list[1][0][0] == '/api/forms/?limit=10'
# limit to a list of categories
cell.categories = {'data': ['default:test-3', 'other:test-4']}
with mock.patch('combo.apps.wcs.models.is_portal_agent') as is_portal_agent:
is_portal_agent.return_value = True
result = cell.render(context)
assert '"http://127.0.0.1:8999/backoffice/management/listing?category_slugs=test-3"' in result
assert '"http://127.0.0.2:8999/backoffice/management/listing?category_slugs=test-4"' in result
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.render(context)
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/forms/?limit=10&category_slugs=test-3'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert requests_get.call_args_list[1][0][0] == '/api/forms/?limit=10&category_slugs=test-4'
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
# limit to a single category
cell.categories = {'data': ['default:test-3']}
with mock.patch('combo.apps.wcs.models.is_portal_agent') as is_portal_agent:
is_portal_agent.return_value = True
result = cell.render(context)
assert '"http://127.0.0.1:8999/backoffice/management/listing?category_slugs=test-3"' in result
assert '"http://127.0.0.2:8999/backoffice/management/listing' not in result
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.render(context)
assert len(requests_get.call_args_list) == 1
assert requests_get.call_args_list[0][0][0] == '/api/forms/?limit=10&category_slugs=test-3'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
# no category selected: call all sites
cell.categories = {'data': []}
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.render(context)
assert len(requests_get.call_args_list) == 2
def test_care_forms_cell_validity(context):
page = Page.objects.create(title='xxx', slug='test_care_forms_cell_render', template_name='standard')
cell = WcsCareFormsCell.objects.create(page=page, placeholder='content', order=0)
context['synchronous'] = True # to get fresh content
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_data(context)
assert ValidityInfo.objects.exists() is False
# can not retrieve data, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
cell.get_data(context)
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
cell.get_data(context)
assert ValidityInfo.objects.exists() is False
# can not retrieve data, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=500)
requests_get.return_value = mock_json
cell.get_data(context)
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=404)
requests_get.return_value = mock_json
cell.get_data(context)
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_data_failure'
assert validity_info.invalid_since is not None
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_care_forms_cell_check_validity(mock_send, context):
page = Page.objects.create(title='xxx', slug='test_care_forms_cell_render', template_name='standard')
cell = WcsCareFormsCell.objects.create(page=page, placeholder='content', order=0)
# no category
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# valid categories
cell.categories = {'data': ['default:test-3', 'default:test-9']}
cell.save()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# can not retrieve data, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
cell.check_validity()
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# can not retrieve categories, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# invalid category
cell.categories = {'data': ['default:foobar', 'default:test-9']}
cell.save()
cell.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_category_not_found'
assert validity_info.invalid_since is not None
# invalid wcs_site
cell.categories = {'data': ['default:test-3', 'default:test-9']}
cell.wcs_site = 'invalid'
cell.save()
cell.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_site_not_found'
assert validity_info.invalid_since is not None
# valid wcs_site
cell.wcs_site = 'default'
cell.save()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_care_forms_cell_render_single_site(mock_send, context):
page = Page(title='xxx', slug='test_care_forms_cell_render', template_name='standard')
page.save()
cell = WcsCareFormsCell(page=page, placeholder='content', order=0)
cell.wcs_site = 'default'
cell.save()
context['request'].user = MockUser()
# query should fail as nothing is cached
cache.clear()
with pytest.raises(NothingInCacheException):
result = cell.render(context)
context['synchronous'] = True # to get fresh content
with mock.patch('combo.apps.wcs.models.is_portal_agent') as is_portal_agent:
is_portal_agent.return_value = True
result = cell.render(context)
assert '"http://127.0.0.1:8999/backoffice/management/listing"' in result
assert '"http://127.0.0.2:8999/backoffice/management/listing"' not in result
data = cell.get_data(context)
assert 'default' in data
assert 'other' not in data
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_forms_of_category_cell_setup(mock_send):
cell = WcsFormsOfCategoryCell()
form_class = cell.get_default_form_class()
form = form_class()
assert form.fields['category_reference'].widget.choices == [
('default:test-3', 'test : Test 3'),
('default:test-9', 'test : Test 9'),
('other:test-3', 'test2 : Test 3'),
('other:test-9', 'test2 : Test 9'),
]
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_forms_of_category_cell_render(mock_send, context):
page = Page(title='xxx', slug='test_forms_of_category_cell_render', template_name='standard')
page.save()
cell = WcsFormsOfCategoryCell(page=page, placeholder='content', order=0)
cell.category_reference = 'default:test-9'
cell.ordering = 'alpha'
cell.save()
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert 'form title' in result and 'a second form title' in result
assert result.index('form title') > result.index('a second form title')
assert 'http://127.0.0.1:8999/form-title/tryauth' in result
assert 'http://127.0.0.1:8999/a-second-form-title/tryauth' in result
assert 'keyword-foo' in result
assert 'keyword-bar' in result
cell.ordering = 'popularity'
cell.save()
result = cell.render(context)
assert 'form title' in result and 'a second form title' in result
assert result.index('form title') < result.index('a second form title')
cell.ordering = 'manual'
cell.save()
result = cell.render(context)
# by default all forms should be present, in alphabetical order
assert result.index('form title') > result.index('a second form title')
# set a manual order
cell.manual_order = {'data': ['default:test-9:a-second-form-title', 'default:test-9:form-title']}
cell.save()
result = cell.render(context)
assert result.index('form title') > result.index('a second form title')
# make sure all forms are displayed even if the manual order only specify
# some.
cell.manual_order = {'data': ['default:test-9:a-second-form-title']}
cell.save()
result = cell.render(context)
assert result.index('form title') > result.index('a second form title')
assert 'form title' in result and 'a second form title' in result
# check content provided to search engine
assert cell.render_for_search() == ''
assert len(list(cell.get_external_links_data())) == 2
# existing category, but empty
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
result = cell.render(context)
assert '<h2>' not in result
context['combo_display_even_empty_categories'] = True
assert len(requests_get.call_args_list) == 1
assert requests_get.call_args_list[0][0][0] == '/api/categories/test-9/formdefs/'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
result = cell.render(context)
assert '<h2>' in result
context.pop('combo_display_even_empty_categories')
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_forms_of_category_cancelurl(mock_send, app):
page = Page(title='xxx', slug='test_forms_of_category_cell_render', template_name='standard')
page.save()
cell = WcsFormsOfCategoryCell(page=page, placeholder='content', order=0)
cell.category_reference = 'default:test-9'
cell.ordering = 'alpha'
cell.save()
resp = app.get(page.get_online_url())
ajax_cell_url = PyQuery(resp.text).find('[data-ajax-cell-url]').attr('data-ajax-cell-url')
extra_ctx = PyQuery(resp.text).find('[data-ajax-cell-url]').attr('data-extra-context')
cell_resp = app.get(ajax_cell_url + '?ctx=' + extra_ctx)
assert (
PyQuery(cell_resp.text).find('a').attr('href')
== 'http://127.0.0.1:8999/a-second-form-title/tryauth?cancelurl=http://testserver/test_forms_of_category_cell_render/'
)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_forms_of_category_cell_validity(mock_send, context):
page = Page.objects.create(
title='xxx', slug='test_forms_of_category_cell_render', template_name='standard'
)
cell = WcsFormsOfCategoryCell.objects.create(page=page, placeholder='content', order=0)
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_category_not_defined'
assert validity_info.invalid_since is not None
cell.category_reference = 'default:test-9'
cell.save()
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=404)
requests_get.return_value = mock_json
cell.render(context)
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_data_failure'
assert validity_info.invalid_since is not None
cell.mark_as_valid()
# can not retrieve data, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=500)
requests_get.return_value = mock_json
cell.render(context)
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
cell.render(context)
assert ValidityInfo.objects.exists() is False
# can not retrieve categories, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
cell.save()
assert ValidityInfo.objects.exists() is False
cell.category_reference = 'default:foobar'
cell.save()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_category_not_found'
assert validity_info.invalid_since is not None
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_forms_of_category_cell_check_validity(mock_send, context):
page = Page.objects.create(
title='xxx', slug='test_forms_of_category_cell_render', template_name='standard'
)
cell = WcsFormsOfCategoryCell.objects.create(page=page, placeholder='content', order=0)
# valid category
cell.category_reference = 'default:test-9'
cell.save()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# valid category but empty
cell.category_reference = 'default:test-1'
cell.save()
cell.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_category_not_found'
assert validity_info.invalid_since is not None
def test_current_drafts_cell_render_unlogged(context):
page = Page(title='xxx', slug='test_current_drafts_cell_render', template_name='standard')
page.save()
cell = WcsCurrentDraftsCell(page=page, placeholder='content', order=0)
cell.save()
context['synchronous'] = True # to get fresh content
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
result = cell.render(context)
assert requests_get.call_args_list[0][0][0] == '/api/user/drafts'
assert 'http://127.0.0.1:8999/third-form-title' not in result # no form
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_current_drafts_cell_render_logged_in(mock_send, context):
page = Page(title='xxx', slug='test_current_drafts_cell_render', template_name='standard')
page.save()
cell = WcsCurrentDraftsCell(page=page, placeholder='content', order=0)
cell.save()
context['synchronous'] = True # to get fresh content
context['request'].user = MockUser()
# default is to get current forms from all wcs sites
result = cell.render(context)
assert 'http://127.0.0.1:8999/form/1/' in result
assert 'http://127.0.0.1:8999/form/2/' not in result # no title
assert 'http://127.0.0.1:8999/form/3/' in result
assert 'http://127.0.0.1:8999/form/4/' not in result # done
assert 'http://127.0.0.2:8999/form/1/' in result
assert 'http://127.0.0.2:8999/form/2/' not in result
assert 'http://127.0.0.2:8999/form/3/' in result
assert 'http://127.0.0.2:8999/form/4/' not in result
# check flat list
extra_context = cell.get_cell_extra_context(context)
assert len(extra_context['drafts']) == 8
assert len([x for x in extra_context['drafts'] if x['site_slug'] == 'default']) == 4
assert len([x for x in extra_context['drafts'] if x['site_slug'] == 'other']) == 4
# limit to categories
cell.categories = {'data': ['default:test-3', 'other:test-6']}
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/user/drafts?category_slugs=test-3'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert requests_get.call_args_list[1][0][0] == '/api/user/drafts?category_slugs=test-6'
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
cell.categories = {'data': ['default:test-3']}
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 1
assert requests_get.call_args_list[0][0][0] == '/api/user/drafts?category_slugs=test-3'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
cell.categories = {'data': []}
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
# check empty message
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
result = cell.render(context)
assert 'There are no current drafts.' in result
context['request'].user = MockUserWithNameId()
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.render(context)
assert requests_get.call_args_list[0][0][0] == '/api/users/xyz/drafts'
# anonymous user
context['request'].user = AnonymousUser()
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.render(context)
assert requests_get.call_args_list[0][0][0] == '/api/user/drafts'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_current_drafts_cell_check_validity(mock_send, context):
page = Page.objects.create(title='xxx', slug='test_current_forms_cell_render', template_name='standard')
cell = WcsCurrentDraftsCell.objects.create(page=page, placeholder='content', order=0)
# no category
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# valid categories
cell.categories = {'data': ['default:test-3', 'default:test-9']}
cell.save()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# can not retrieve data, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
cell.check_validity()
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# can not retrieve categories, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# invalid category
cell.categories = {'data': ['default:foobar', 'default:test-9']}
cell.save()
cell.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_category_not_found'
assert validity_info.invalid_since is not None
# invalid wcs_site
cell.categories = {'data': ['default:test-3', 'default:test-9']}
cell.wcs_site = 'invalid'
cell.save()
cell.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_site_not_found'
assert validity_info.invalid_since is not None
# valid wcs_site
cell.wcs_site = 'default'
cell.save()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_manager_forms_of_category_cell(mock_send, app, admin_user):
page = Page(title='One', slug='one', template_name='standard')
page.save()
app = login(app)
resp = app.get('/manage/pages/%s/' % page.id)
resp = app.get(
resp.html.find('option', **{'data-add-url': re.compile('wcsformsofcategorycell')})['data-add-url']
)
cells = Page.objects.get(id=page.id).get_cells()
assert len(cells) == 1
assert isinstance(cells[0], WcsFormsOfCategoryCell)
resp = app.get('/manage/pages/%s/' % page.id)
assert ('data-cell-reference="%s"' % cells[0].get_reference()) in resp.text
resp.forms[0]['c%s-ordering' % cells[0].get_reference()].value = 'manual'
manager_submit_cell(resp.forms[0])
cells[0].refresh_from_db()
resp.forms[0]['c%s-manual_order' % cells[0].get_reference()].select_multiple(
['default::a-second-form-title', 'default::third-form-title']
)
manager_submit_cell(resp.forms[0])
cells[0].refresh_from_db()
assert cells[0].manual_order == {'data': ['default::a-second-form-title', 'default::third-form-title']}
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_manager_current_forms(mock_send, settings, app, admin_user):
page = Page(title='One', slug='one', template_name='standard')
page.save()
app = login(app)
resp = app.get('/manage/pages/%s/' % page.id)
resp = app.get(
resp.html.find('option', **{'data-add-url': re.compile('wcscurrentformscell')})['data-add-url']
)
cells = Page.objects.get(id=page.id).get_cells()
assert len(cells) == 1
assert isinstance(cells[0], WcsCurrentFormsCell)
resp = app.get('/manage/pages/%s/' % page.id)
assert ('data-cell-reference="%s"' % cells[0].get_reference()) in resp.text
assert len(resp.form['c%s-categories' % cells[0].get_reference()].options) == 4
resp.form['c%s-categories' % cells[0].get_reference()].value = ['default:test-3', 'default:test-9']
manager_submit_cell(resp.form)
assert resp.form['c%s-categories' % cells[0].get_reference()].value == [
'default:test-3',
'default:test-9',
]
resp.form['c%s-current_forms' % cells[0].get_reference()] = False
resp.form['c%s-done_forms' % cells[0].get_reference()] = False
resp = resp.form.submit()
assert 'Please choose at least one option among the following: Current Forms, Done Forms' in resp
resp = app.get('/manage/pages/%s/' % page.id)
resp.form['c%s-done_forms' % cells[0].get_reference()] = True
manager_submit_cell(resp.form)
# check wcs_site field is a select box
assert resp.form['c%s-wcs_site' % cells[0].get_reference()].tag == 'select'
default = settings.KNOWN_SERVICES['wcs']['default']
settings.KNOWN_SERVICES = {'wcs': {'default': default}}
resp = app.get('/manage/pages/%s/' % page.id)
assert resp.form['c%s-wcs_site' % cells[0].get_reference()].attrs['type'] == 'hidden'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_manager_forms_in_your_care_cell(mock_send, app, admin_user):
page = Page(title='One', slug='one', template_name='standard')
page.save()
app = login(app)
resp = app.get('/manage/pages/%s/' % page.id)
resp = app.get(
resp.html.find('option', **{'data-add-url': re.compile('wcscareformscell')})['data-add-url']
)
cells = Page.objects.get(id=page.id).get_cells()
assert len(cells) == 1
assert isinstance(cells[0], WcsCareFormsCell)
resp = app.get('/manage/pages/%s/' % page.id)
assert (
resp.pyquery.find('div.cell [data-tab-slug="advanced"] input[name$="cache_duration"]').val() == '120'
)
resp.forms[0]['c%s-cache_duration' % cells[0].get_reference()] = '10'
manager_submit_cell(resp.forms[0])
cells[0].refresh_from_db()
assert cells[0].cache_duration == 10
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_manager_cards_cell(mock_send, app, admin_user):
page = Page.objects.create(title='xxx', slug='test_cards_cell_save_cache', template_name='standard')
cell = WcsCardsCell.objects.create(page=page, placeholder='content', order=0)
app = login(app)
resp = app.get('/manage/pages/%s/' % page.pk)
assert ('data-cell-reference="%s"' % cell.get_reference()) in resp.text
assert cell.without_user is False
assert resp.forms[0]['c%s-with_user' % cell.get_reference()].value == 'on'
resp.forms[0]['c%s-with_user' % cell.get_reference()].value = False
manager_submit_cell(resp.forms[0])
cell.refresh_from_db()
assert cell.without_user is True
assert resp.forms[0]['c%s-with_user' % cell.get_reference()].value is None
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_cards_cell_setup(mock_send):
cell = WcsCardsCell()
form_class = cell.get_default_form_class()
form = form_class(instance=cell)
assert form.fields['carddef_reference'].widget.choices == [
('default:card_model_1', 'test : Card Model 1'),
('default:card_model_1:foo', 'test : Card Model 1 - bar'),
('default:card_model_2', 'test : Card Model 2'),
('default:card_model_3', 'test : Card Model 3'),
('default:card_a', 'test : Card A'),
('default:card_b', 'test : Card B'),
('default:card_c', 'test : Card C'),
('default:card_d', 'test : Card D'),
('default:card_e', 'test : Card E'),
('other:card_model_1', 'test2 : Card Model 1'),
('other:card_model_1:foo', 'test2 : Card Model 1 - bar'),
('other:card_model_2', 'test2 : Card Model 2'),
('other:card_model_3', 'test2 : Card Model 3'),
('other:card_a', 'test2 : Card A'),
('other:card_b', 'test2 : Card B'),
('other:card_c', 'test2 : Card C'),
('other:card_d', 'test2 : Card D'),
('other:card_e', 'test2 : Card E'),
]
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_cards_cell_save_cache(mock_send):
page = Page.objects.create(title='xxx', slug='test_cards_cell_save_cache', template_name='standard')
cell = WcsCardsCell(page=page, placeholder='content', order=0)
assert cell.get_additional_label() is None
cell.carddef_reference = 'default:card_model_1'
cell.save()
assert cell.cached_title == 'Card Model 1'
assert cell.get_additional_label() == 'Card Model 1'
# make sure cached attributes are removed from serialized pages
assert 'cached_' not in json.dumps(page.get_serialized_page())
cell.carddef_reference = 'default:card_model_1:foo'
cell.save()
assert cell.cached_title == 'Card Model 1 - bar'
assert cell.get_additional_label() == 'Card Model 1 - bar'
# check content provided to search engine
assert cell.render_for_search() == ''
# artificially change title
WcsCardsCell.objects.filter(pk=cell.pk).update(cached_title='XXX')
assert WcsCardsCell.objects.get(pk=cell.pk).cached_title == 'XXX'
# run update db cache
appconfig = apps.get_app_config('wcs')
appconfig.update_db_cache()
assert WcsCardsCell.objects.get(pk=cell.pk).cached_title == 'Card Model 1 - bar'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_cards_cell_validity(mock_send):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardsCell.objects.create(page=page, placeholder='content', order=0)
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_card_not_defined'
assert validity_info.invalid_since is not None
cell.carddef_reference = 'default:card_model_1'
cell.save()
assert ValidityInfo.objects.exists() is False
# can not retrieve data, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
cell.save()
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
cell.save()
assert ValidityInfo.objects.exists() is False
# can not retrieve carddefs, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
cell.save()
assert ValidityInfo.objects.exists() is False
cell.carddef_reference = 'default:foobar'
cell.save()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_card_not_found'
assert validity_info.invalid_since is not None
cell.carddef_reference = 'default:card_model_1:foo'
cell.save()
assert ValidityInfo.objects.exists() is False
cell.carddef_reference = 'default:card_model_1:bar'
cell.save()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_card_not_found'
assert validity_info.invalid_since is not None
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_cards_cell_load(mock_send):
page = Page.objects.create(title='xxx', slug='test_cards', template_name='standard')
cell = WcsCardsCell(page=page, placeholder='content', order=0)
cell.carddef_reference = 'default:card_model_1'
cell.save()
site_export = [page.get_serialized_page()]
cell.delete()
assert not Page.objects.get(pk=page.pk).get_cells()
Page.load_serialized_pages(site_export)
page = Page.objects.get(slug='test_cards')
cells = page.get_cells()
assert len(cells) == 1
cell = cells[0]
assert cell.cached_title == 'Card Model 1'
cell.carddef_reference = 'default:card_model_1:foo'
cell.save()
site_export = [page.get_serialized_page()]
cell.delete()
assert not Page.objects.get(pk=page.pk).get_cells()
Page.load_serialized_pages(site_export)
page = Page.objects.get(slug='test_cards')
cells = page.get_cells()
assert len(cells) == 1
cell = cells[0]
assert cell.cached_title == 'Card Model 1 - bar'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_cards_cell_render(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardsCell(page=page, placeholder='content', order=0)
cell.carddef_reference = 'default:card_model_1'
cell.save()
# query should fail as nothing is cached
cache.clear()
with pytest.raises(NothingInCacheException):
result = cell.render(context)
context['synchronous'] = True # to get fresh content
context['cell'] = cell
result = cell.render(context)
assert '<h2>Card Model 1</h2>' in result
assert 'cards-card_model_1' in result
assert (
'<a href="http://127.0.0.1:8999/backoffice/data/card_model_1/11/"><span class="card-title">aa</span></a>'
in result
)
assert (
'<a href="http://127.0.0.1:8999/backoffice/data/card_model_1/12/"><span class="card-title">bb</span></a>'
in result
)
assert (
'<a href="http://127.0.0.1:8999/backoffice/data/card_model_1/13/"><span class="card-title">cc</span></a>'
in result
)
assert 'data-paginate-by="10"' in result
# create a page with the correct subslug
page = Page.objects.create(slug='foo', title='Foo', sub_slug='(?P<card_model_1_id>[a-z0-9]+)')
result = cell.render(context)
assert '<h2>Card Model 1</h2>' in result
assert '<a href="/foo/11"><span class="card-title">aa</span></a>' in result
assert '<a href="/foo/12"><span class="card-title">bb</span></a>' in result
assert '<a href="/foo/13"><span class="card-title">cc</span></a>' in result
cell.carddef_reference = 'default:card_model_1:foo'
cell.limit = 42
cell.save()
page.sub_slug = 'card_model_1_id'
page.save()
result = cell.render(context)
assert '<h2>Card Model 1 - bar</h2>' in result
assert '<a href="/foo/11"><span class="card-title">aa</span></a>' in result
assert '<a href="/foo/12"><span class="card-title">bb</span></a>' in result
assert '<a href="/foo/13"><span class="card-title">cc</span></a>' not in result
assert 'data-paginate-by="42"' in result
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.render(context)
assert len(requests_get.call_args_list) == 1
assert requests_get.call_args_list[0][0][0] == '/api/cards/card_model_1/list/foo'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
cell.custom_title = 'Foo bar'
cell.save()
result = cell.render(context)
assert '<h2>Card Model 1 - bar</h2>' not in result
assert '<h2>Foo bar</h2>' in result
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_cards_cell_only_for_user(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardsCell(page=page, placeholder='content', order=0)
cell.carddef_reference = 'default:card_model_1'
cell.only_for_user = False
cell.save()
assert cell.is_visible(user=None) is True
assert cell.is_visible(user=MockUserWithNameId()) is True
cell.only_for_user = True
cell.save()
assert cell.is_visible(user=None) is False
assert cell.is_visible(user=MockUserWithNameId()) is True
cache.clear()
context['synchronous'] = True # to get fresh content
mock_send.reset_mock()
cell.render(context)
assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUser()
mock_send.reset_mock()
cell.render(context)
assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUserWithNameId()
mock_send.reset_mock()
cell.render(context)
assert 'filter-user-uuid=xyz' in mock_send.call_args_list[0][0][0].url
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_cards_cell_render_user(mock_send, context, nocache):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardsCell(page=page, placeholder='content', order=0)
cell.carddef_reference = 'default:card_model_1'
cell.save()
context['synchronous'] = True # to get fresh content
assert context['request'].user is None
mock_send.reset_mock()
cell.render(context)
assert 'NameID=&' in mock_send.call_args_list[0][0][0].url
assert 'email=&' in mock_send.call_args_list[0][0][0].url
context['request'].user = AnonymousUser()
mock_send.reset_mock()
cell.render(context)
assert 'NameID=&' in mock_send.call_args_list[0][0][0].url
assert 'email=&' in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUser()
mock_send.reset_mock()
cell.render(context)
assert 'email=foo%40example.net' in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUserWithNameId()
mock_send.reset_mock()
cell.render(context)
assert 'NameID=xyz' in mock_send.call_args_list[0][0][0].url
cell.without_user = True
cell.save()
context['request'].user = None
mock_send.reset_mock()
cell.render(context)
assert 'NameID' not in mock_send.call_args_list[0][0][0].url
assert 'email' not in mock_send.call_args_list[0][0][0].url
context['request'].user = AnonymousUser()
mock_send.reset_mock()
cell.render(context)
assert 'NameID' not in mock_send.call_args_list[0][0][0].url
assert 'email' not in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUser()
mock_send.reset_mock()
cell.render(context)
assert 'NameID' not in mock_send.call_args_list[0][0][0].url
assert 'email' not in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUserWithNameId()
mock_send.reset_mock()
cell.render(context)
assert 'NameID' not in mock_send.call_args_list[0][0][0].url
assert 'email' not in mock_send.call_args_list[0][0][0].url
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_setup(mock_send, app, admin_user):
page = Page.objects.create(
title='xxx', slug='test_card_cell_save_cache', template_name='standard', sub_slug='foobar'
)
cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
form_class = cell.get_default_form_class()
form = form_class(instance=cell)
assert form.fields['carddef_reference'].widget.choices == [
('default:card_model_1', 'test : Card Model 1'),
('default:card_model_1:foo', 'test : Card Model 1 - bar'),
('default:card_model_2', 'test : Card Model 2'),
('default:card_model_3', 'test : Card Model 3'),
('default:card_a', 'test : Card A'),
('default:card_b', 'test : Card B'),
('default:card_c', 'test : Card C'),
('default:card_d', 'test : Card D'),
('default:card_e', 'test : Card E'),
('other:card_model_1', 'test2 : Card Model 1'),
('other:card_model_1:foo', 'test2 : Card Model 1 - bar'),
('other:card_model_2', 'test2 : Card Model 2'),
('other:card_model_3', 'test2 : Card Model 3'),
('other:card_a', 'test2 : Card A'),
('other:card_b', 'test2 : Card B'),
('other:card_c', 'test2 : Card C'),
('other:card_d', 'test2 : Card D'),
('other:card_e', 'test2 : Card E'),
]
assert 'customize_display' not in form.fields
assert 'custom_schema' not in form.fields
cell.save()
assert 'customize_display' not in form.fields
assert 'custom_schema' not in form.fields
cell.carddef_reference = 'default:card_model_1'
cell.save()
form = form_class(instance=cell)
assert 'customize_display' in form.fields
assert 'custom_schema' in form.fields
assert 'customize_display' not in form.initial
assert form.initial['custom_schema'] == {}
cell.carddef_reference = 'default:card_model_1:foo'
cell.save()
form = form_class(instance=cell)
assert 'customize_display' in form.fields
assert 'custom_schema' in form.fields
assert 'customize_display' not in form.initial
assert form.initial['custom_schema'] == {}
cell.carddef_reference = 'default:card_model_1'
cell.save()
cell.custom_schema = {'cells': [{'varname': 'foo', 'display_mode': 'value'}]}
cell.save()
form = form_class(instance=cell)
assert 'customize_display' in form.fields
assert 'custom_schema' in form.fields
assert form.initial['customize_display'] is True
assert form.initial['custom_schema'] == {
'cells': [
{'varname': 'foo', 'field_content': 'value', 'display_mode': 'text', 'empty_value': '@empty@'}
]
}
WcsCardInfosCell.objects.all().delete()
# check adding a cell from the UI
app = login(app)
resp = app.get('/manage/pages/%s/' % page.pk)
cell_add_url = [x for x in resp.html.find_all('option') if x.text == 'Card Information Cell'][0].get(
'data-add-url'
)
resp = app.get(cell_add_url).follow()
cell = WcsCardInfosCell.objects.all().first()
manager_submit_cell(resp.forms[0]) # will save card model
cell.refresh_from_db()
# check getting back to uncustomized display reset the schema
cell.customize_display = True
cell.custom_schema = {
'cells': [
{'varname': 'foo', 'field_content': 'value', 'display_mode': 'text', 'empty_value': '@empty@'}
]
}
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-customize_display' % cell.get_reference()].value == 'on'
resp.forms[0]['c%s-customize_display' % cell.get_reference()].value = False
manager_submit_cell(resp.forms[0])
cell.refresh_from_db()
assert cell.custom_schema == {}
assert cell.related_card_path == ''
assert cell.card_ids == ''
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value == '--'
resp.forms[0]['c%s-card_ids' % cell.get_reference()].value = '42'
manager_submit_cell(resp.forms[0])
cell.refresh_from_db()
assert cell.related_card_path == ''
assert cell.card_ids == ''
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value == '--'
resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value = ''
resp.forms[0]['c%s-card_ids' % cell.get_reference()].value = '42'
manager_submit_cell(resp.forms[0])
cell.refresh_from_db()
assert cell.related_card_path == ''
assert cell.card_ids == '42'
# current page has a sub_slug, '--' option is present
resp = app.get('/manage/pages/%s/' % page.pk)
assert '--' in [o[0] for o in resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options]
# current_page has no sub_slug, but parent page has one
parent_page = Page.objects.create(
title='parent', slug='parent', template_name='standard', sub_slug='foobar'
)
page.parent = parent_page
page.sub_slug = ''
page.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert '--' in [o[0] for o in resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options]
# no sub_slug
parent_page.sub_slug = ''
parent_page.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert '--' not in [o[0] for o in resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options]
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].value == ''
resp.forms[0]['c%s-card_ids' % cell.get_reference()].value = ''
resp = resp.forms[0].submit()
assert resp.context['form'].errors == {'card_ids': ['This field is required.']}
def test_card_cell_custom_schema_migration():
cell = WcsCardInfosCell()
cell.custom_schema = {
'cells': [{'varname': 'some-field', 'display_mode': 'label', 'cell_size': 'foobar'}]
}
assert cell.get_custom_schema() == {
'cells': [
{
'varname': 'some-field',
'field_content': 'label',
'display_mode': 'text',
'empty_value': '@empty@',
'cell_size': 'foobar',
}
]
}
cell.custom_schema = {'cells': [{'varname': 'some-field', 'display_mode': 'value'}]}
assert cell.get_custom_schema() == {
'cells': [
{
'varname': 'some-field',
'field_content': 'value',
'display_mode': 'text',
'empty_value': '@empty@',
}
]
}
cell.custom_schema = {'cells': [{'varname': 'some-field', 'display_mode': 'label-and-value'}]}
assert cell.get_custom_schema() == {
'cells': [
{
'varname': 'some-field',
'field_content': 'label-and-value',
'display_mode': 'text',
'empty_value': '@empty@',
}
]
}
cell.custom_schema = {'cells': [{'varname': 'some-field', 'display_mode': 'title'}]}
assert cell.get_custom_schema() == {
'cells': [
{
'varname': 'some-field',
'field_content': 'value',
'display_mode': 'title',
'empty_value': '@empty@',
}
]
}
cell.custom_schema = {
'cells': [
{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'label', 'cell_size': 'foobar'}
]
}
assert cell.get_custom_schema() == {
'cells': [
{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'label', 'cell_size': 'foobar'}
]
}
cell.custom_schema = {'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'value'}]}
assert cell.get_custom_schema() == {
'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'text'}]
}
cell.custom_schema = {'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'title'}]}
assert cell.get_custom_schema() == {
'cells': [{'varname': '@custom@', 'template': 'foobar', 'display_mode': 'title'}]
}
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_save_cache(mock_send):
page = Page.objects.create(title='xxx', slug='test_card_cell_save_cache', template_name='standard')
cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
assert cell.get_additional_label() is None
cell.carddef_reference = 'default:card_model_1'
cell.save()
assert cell.cached_title == 'Card Model 1'
assert cell.cached_json != {}
assert cell.get_additional_label() == 'Card Model 1'
# make sure cached attributes are removed from serialized pages
assert 'cached_' not in json.dumps(page.get_serialized_page())
# artificially change title and json
WcsCardInfosCell.objects.filter(pk=cell.pk).update(cached_title='XXX', cached_json={})
assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_title == 'XXX'
assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_json == {}
# run update db cache
appconfig = apps.get_app_config('wcs')
appconfig.update_db_cache()
assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_title == 'Card Model 1'
assert WcsCardInfosCell.objects.get(pk=cell.pk).cached_json != {}
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_validity(mock_send):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=0)
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_card_not_defined'
assert validity_info.invalid_since is not None
cell.carddef_reference = 'default:card_model_1'
cell.save()
assert ValidityInfo.objects.exists() is False
# can not retrieve data, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
cell.save()
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
cell.save()
assert ValidityInfo.objects.exists() is False
# can not retrieve carddefs, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
cell.save()
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.json = lambda *a, **k: {'err': 1, 'err_class': 'Page not found'}
mock_resp.status_code = 404
requests_get.return_value = mock_resp
cell.carddef_reference = 'default:foobar'
cell.save()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_card_not_found'
assert validity_info.invalid_since is not None
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_check_validity(mock_send):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardInfosCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_a',
card_ids='1',
)
cell2 = WcsCardInfosCell.objects.create(
page=page, placeholder='content', order=1, carddef_reference='default:card_b'
)
# no related_card_path
cell2.check_validity()
assert ValidityInfo.objects.exists() is False
# correct related_card_path but sluga is not defined
cell2.related_card_path = 'sluga/cardb'
cell2.save()
cell2.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_card_relation_not_found'
assert validity_info.invalid_since is not None
# sluga is now defined
cell.slug = 'sluga'
cell.save()
cell2.check_validity()
assert ValidityInfo.objects.exists() is False
# bad related_card_path
cell2.related_card_path = 'sluga/foobar'
cell2.save()
cell2.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_card_relation_not_found'
assert validity_info.invalid_since is not None
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_manager_card_cell(mock_send, app, admin_user):
page = Page.objects.create(title='xxx', slug='test_cards', template_name='standard', sub_slug='foobar')
cell = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=0)
app = login(app)
resp = app.get('/manage/pages/%s/' % page.pk)
assert 'application/json' not in resp
cell.carddef_reference = 'default:card_model_1'
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert '<script id="cell-%s-card-schema-default:card_model_1" type="application/json">' % cell.pk in resp
assert ('data-cell-reference="%s"' % cell.get_reference()) in resp.text
assert cell.without_user is False
assert resp.forms[0]['c%s-with_user' % cell.get_reference()].value == 'on'
resp.forms[0]['c%s-with_user' % cell.get_reference()].value = False
manager_submit_cell(resp.forms[0])
cell.refresh_from_db()
assert cell.without_user is True
assert resp.forms[0]['c%s-with_user' % cell.get_reference()].value is None
# card with relations
cell.carddef_reference = 'default:card_a'
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
# but only one cell on the page, no relations to follow
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
]
# add a second cell, related to the first card model
cell2 = WcsCardInfosCell.objects.create(
page=page, placeholder='content', order=1, carddef_reference='default:card_b'
)
resp = app.get('/manage/pages/%s/' % page.pk)
# still no relation to follow
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
]
# no cell with id and slug
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
]
# set a slug on first cell
cell.slug = 'sluga'
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
# still no relation to follow
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
]
# multiple relations to follow
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
('sluga/cardb', False, 'sluga/cardb'),
('sluga/cardsb', False, 'sluga/cardsb'),
('sluga/blockb_cardb', False, 'sluga/blockb_cardb'),
('sluga/cardc/cardb', False, 'sluga/cardc/cardb'),
('sluga/cardc/cardsb', False, 'sluga/cardc/cardsb'),
('sluga/cardc/blockb_cardb', False, 'sluga/cardc/blockb_cardb'),
]
# set a list of ids on first cell
cell.card_ids = '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}'
cell.save()
resp = app.get('/manage/pages/%s/' % page.pk)
# still no relation to follow
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('--', False, 'Identifier from page URL'),
('', True, 'Other Card Identifiers'),
]
# can not user cell with multiple ids as reference
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
]
# define a slug on second cell
cell.card_ids = ''
cell.save()
cell2.slug = 'slugb'
cell2.save()
resp = app.get('/manage/pages/%s/' % page.pk)
# multiple relations to follow
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
('slugb/reverse:cardb', False, 'slugb/cardb (reverse)'),
('slugb/reverse:cardsb', False, 'slugb/cardsb (reverse)'),
('slugb/reverse:blockb_cardb', False, 'slugb/blockb_cardb (reverse)'),
]
# still multiple relations to follow
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
('sluga/cardb', False, 'sluga/cardb'),
('sluga/cardsb', False, 'sluga/cardsb'),
('sluga/blockb_cardb', False, 'sluga/blockb_cardb'),
('sluga/cardc/cardb', False, 'sluga/cardc/cardb'),
('sluga/cardc/cardsb', False, 'sluga/cardc/cardsb'),
('sluga/cardc/blockb_cardb', False, 'sluga/cardc/blockb_cardb'),
]
# set a related_path on cell2
resp.forms[1]['c%s-related_card_path' % cell2.get_reference()] = 'sluga/cardb'
resp.forms[1]['c%s-card_ids' % cell2.get_reference()] = 'foobar'
resp = resp.forms[1].submit()
cell2.refresh_from_db()
assert cell2.related_card_path == 'sluga/cardb'
assert cell2.card_ids == ''
resp = app.get('/manage/pages/%s/' % page.pk)
# no more relation to follow
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
]
# still multiple relations to follow
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('--', False, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
('sluga/cardb', True, 'sluga/cardb'),
('sluga/cardsb', False, 'sluga/cardsb'),
('sluga/blockb_cardb', False, 'sluga/blockb_cardb'),
('sluga/cardc/cardb', False, 'sluga/cardc/cardb'),
('sluga/cardc/cardsb', False, 'sluga/cardc/cardsb'),
('sluga/cardc/blockb_cardb', False, 'sluga/cardc/blockb_cardb'),
]
resp.forms[1].submit()
cell2.refresh_from_db()
assert cell2.related_card_path == 'sluga/cardb'
assert cell2.card_ids == ''
# check circular relations
cell.slug = 'sluge'
cell.carddef_reference = 'default:card_e'
cell.save()
cell2.carddef_reference = 'default:card_d'
cell2.slug = 'slugd'
cell2.related_card_path = ''
cell2.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
('slugd/cardd-foo/carde-foo', False, 'slugd/cardd-foo/carde-foo'),
('slugd/carde-foo', False, 'slugd/carde-foo'),
]
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
('sluge/cardd-bar', False, 'sluge/cardd-bar'),
('sluge/reverse:carde-foo', False, 'sluge/carde-foo (reverse)'),
]
cell.slug = 'slugd'
cell.carddef_reference = 'default:card_d'
cell.save()
cell2.carddef_reference = 'default:card_d'
cell2.slug = 'slugd-bis'
cell2.related_card_path = ''
cell2.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
('slugd-bis/cardd-foo', False, 'slugd-bis/cardd-foo'),
('slugd-bis/reverse:cardd-foo', False, 'slugd-bis/cardd-foo (reverse)'),
('slugd-bis/carde-foo/cardd-bar', False, 'slugd-bis/carde-foo/cardd-bar'),
('slugd-bis/carde-foo/reverse:carde-foo', False, 'slugd-bis/carde-foo/carde-foo (reverse)'),
]
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
('slugd/cardd-foo', False, 'slugd/cardd-foo'),
('slugd/reverse:cardd-foo', False, 'slugd/cardd-foo (reverse)'),
('slugd/carde-foo/cardd-bar', False, 'slugd/carde-foo/cardd-bar'),
('slugd/carde-foo/reverse:carde-foo', False, 'slugd/carde-foo/carde-foo (reverse)'),
]
cell.slug = 'sluge'
cell.carddef_reference = 'default:card_e'
cell.save()
cell2.carddef_reference = 'default:card_e'
cell2.slug = 'sluge-bis'
cell2.related_card_path = ''
cell2.save()
resp = app.get('/manage/pages/%s/' % page.pk)
assert resp.forms[0]['c%s-related_card_path' % cell.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
('sluge-bis/cardd-bar/carde-foo', False, 'sluge-bis/cardd-bar/carde-foo'),
]
assert resp.forms[1]['c%s-related_card_path' % cell2.get_reference()].options == [
('--', True, 'Identifier from page URL'),
('', False, 'Other Card Identifiers'),
('sluge/cardd-bar/carde-foo', False, 'sluge/cardd-bar/carde-foo'),
]
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_load(mock_send):
page = Page.objects.create(title='xxx', slug='test_cards', template_name='standard')
cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
cell.carddef_reference = 'default:card_model_1'
cell.save()
site_export = [page.get_serialized_page()]
cell.delete()
assert not Page.objects.get(pk=page.pk).get_cells()
Page.load_serialized_pages(site_export)
page = Page.objects.get(slug='test_cards')
cells = page.get_cells()
assert len(cells) == 1
cell = cells[0]
assert cell.cached_title == 'Card Model 1'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_render(mock_send, context, app):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
cell.title_type = 'manual'
cell.custom_title = 'Foo bar {{ card.fields.title }}'
cell.save()
# carddef_reference is not defined
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert '<h2>Card Model 1</h2>' not in result
assert '<p>Unknown Card</p>' in result
# card id not in context
cell.carddef_reference = 'default:card_model_1'
cell.save()
del context['card_model_1_id']
assert 'card_model_1_id' not in context
result = cell.render(context)
assert '<h2>Card Model 1</h2>' in result # default value
assert '<p>Unknown Card</p>' in result
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
result = cell.render(context)
assert '<h2>Card Model 1</h2>' in result # default value
assert '<p>Unknown Card</p>' in result
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
result = cell.render(context)
assert '<h2>Card Model 1</h2>' in result # default value
assert '<p>Unknown Card</p>' in result
context.pop('title')
cell.title_type = 'auto'
cell.save()
mock_send.reset_mock()
result = cell.render(context)
assert '<h2>Card Model 1 - aa</h2>' in result
assert PyQuery(result).find('.label:contains("Field A") + .value').text() == '<i>a</i>'
assert PyQuery(result).find('.label:contains("Field B") + .value').text() == 'yes'
assert PyQuery(result).find('.label:contains("Field C") + .value').text() == 'Sept. 28, 2020'
assert PyQuery(result).find('.label:contains("Related") + .value').text() == 'Foo Bar'
assert 'related_raw' not in result
assert 'related_structured' not in result
assert PyQuery(result).find('.label:contains("Field D") + .value a').text() == 'file.pdf'
context.pop('title')
cell.title_type = 'manual'
cell.custom_title = '<b>Foo bar {{ card.fields.fielda }}</b>'
cell.save()
assert cell.get_additional_label() == '&lt;b&gt;Foo bar {{ card.fields.fielda }}&lt;/b&gt;'
result = cell.render(context)
assert '<h2>&lt;b&gt;Foo bar &lt;i&gt;a&lt;/i&gt;&lt;/b&gt;</h2>' in result
context.pop('title')
cell.custom_title = '{{ foobar }}'
cell.save()
result = cell.render(context)
assert '<h2>Card Model 1 - aa</h2>' in result # empty value from template, default value
context.pop('title')
cell.custom_title = '{% if %}'
cell.save()
result = cell.render(context)
assert '<h2>Card Model 1 - aa</h2>' in result # template error, default value
context.pop('title')
cell.title_type = 'empty'
cell.save()
result = cell.render(context)
assert '<h2>' not in result
# test available context
cell.title_type = 'manual'
cell.custom_title = 'X{{ site_base }}Y'
cell.card_ids = '11'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert '<h2>Xhttp://testserverY</h2>' in cell_resp
cell.card_ids = '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}'
cell.title_type = 'manual'
cell.custom_title = 'Foo bar X{{ repeat_index }}Y'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 3
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
for i in range(0, 3):
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
assert '<h2>Foo bar X%sY</h2>' % i in cell_resp
# again, without ajax: urls are already in cache
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 3
for i in range(0, 3):
assert '<h2>Foo bar X%sY</h2>' % i in resp
# using custom view
cell.carddef_reference = 'default:card_model_1:foo'
cell.save()
result = cell.render(context)
assert 'Foo bar X0Y' in result
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
result = cell.render(context)
# nothing, hide cell
assert not result.strip()
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_render_text_field(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
cell.carddef_reference = 'default:card_model_1'
cell.save()
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
# field E is split in paragraphs
assert (
PyQuery(result).find('.label:contains("Field E") + .value p:first-child').text().strip()
== 'lorem<strong>ipsum'
)
assert (
PyQuery(result).find('.label:contains("Field E") + .value p:last-child').text().strip()
== "hello'world"
)
# field F is put in a <pre>
assert (
PyQuery(result).find('.label:contains("Field F") + .value pre').text()
== 'lorem<strong>ipsum hello world'
)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_render_email_field(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
cell.carddef_reference = 'default:card_model_1'
cell.save()
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert PyQuery(result).find('.label:contains("Field G") + .value a').text() == 'test@localhost'
assert (
PyQuery(result).find('.label:contains("Field G") + .value a').attr['href'] == 'mailto:test@localhost'
)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_render_string_with_url_field(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
cell.carddef_reference = 'default:card_model_1'
cell.custom_title = 'Foo bar {{ card.fields.title }}'
cell.save()
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert PyQuery(result).find('.label:contains("Field H") + .value a').text() == 'https://www.example.net/'
assert (
PyQuery(result).find('.label:contains("Field H") + .value a').attr['href']
== 'https://www.example.net/'
)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_render_custom_schema_card_field(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardInfosCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={'cells': [{'varname': 'fielda', 'field_content': 'value', 'display_mode': 'title'}]},
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert PyQuery(result).find('h3').text() == '<i>a</i>'
cell.custom_schema['cells'][0] = {
'varname': 'fielda',
'field_content': 'value',
'display_mode': 'subtitle',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('h4').text() == '<i>a</i>'
cell.custom_schema['cells'][0] = {'varname': 'fielda', 'field_content': 'label', 'display_mode': 'title'}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('h3').text() == 'Field A'
cell.custom_schema['cells'][0] = {
'varname': 'fielda',
'field_content': 'label',
'display_mode': 'subtitle',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('h4').text() == 'Field A'
cell.custom_schema['cells'][0] = {'varname': 'fielda', 'field_content': 'label', 'display_mode': 'text'}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field A'
cell.custom_schema['cells'][0] = {'varname': 'fielda', 'field_content': 'value', 'display_mode': 'text'}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value').text() == '<i>a</i>'
cell.custom_schema['cells'][0] = {
'varname': 'fielda',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field A'
assert PyQuery(result).find('.value').text() == '<i>a</i>'
cell.custom_schema['cells'][0] = {
'varname': 'fieldb',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field B'
assert PyQuery(result).find('.value').text() == 'yes'
cell.custom_schema['cells'][0] = {
'varname': 'fieldc',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field C'
assert PyQuery(result).find('.value').text() == 'Sept. 28, 2020'
cell.custom_schema['cells'][0] = {
'varname': 'related',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Related'
assert PyQuery(result).find('.value').text() == 'Foo Bar'
cell.custom_schema['cells'][0] = {
'varname': 'fieldd',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field D'
assert PyQuery(result).find('.value').text() == 'file.pdf'
cell.custom_schema['cells'][0] = {
'varname': 'fielde',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
# check multiline text field is rendered with multiple paragraphs
# (first line "lorem<strong>ipsum" and last line ("hello'world")
# and the content is kept properly escaped.
assert PyQuery(result).find('.label').text() == 'Field E'
assert PyQuery(result).find('.value p:first-child').text().strip() == 'lorem<strong>ipsum'
assert PyQuery(result).find('.value p:last-child').text().strip() == "hello'world"
cell.custom_schema['cells'][0] = {
'varname': 'fieldf',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field F'
assert PyQuery(result).find('.value pre').text() == 'lorem<strong>ipsum hello world'
cell.custom_schema['cells'][0] = {
'varname': 'fieldg',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field G'
assert PyQuery(result).find('.value a').text() == 'test@localhost'
assert PyQuery(result).find('.value a').attr['href'] == 'mailto:test@localhost'
cell.custom_schema['cells'][0] = {
'varname': 'fieldh',
'field_content': 'label-and-value',
'display_mode': 'text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Field H'
assert PyQuery(result).find('.value a').text() == 'https://www.example.net/'
assert PyQuery(result).find('.value a').attr['href'] == 'https://www.example.net/'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_render_custom_schema_card_empty_field(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardInfosCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={
'cells': [
{
'varname': 'empty',
'field_content': 'label-and-value',
'display_mode': 'text',
'empty_value': '@skip@',
}
]
},
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert PyQuery(result).find('.label') == []
assert PyQuery(result).find('.value') == []
cell.custom_schema['cells'][0] = {
'varname': 'empty',
'field_content': 'label-and-value',
'display_mode': 'text',
'empty_value': '@empty@',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Empty'
assert PyQuery(result).find('.value').text() == ''
cell.custom_schema['cells'][0] = {
'varname': 'empty',
'field_content': 'label-and-value',
'display_mode': 'text',
'empty_value': 'Custom text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Empty'
assert PyQuery(result).find('.value').text() == 'Custom text'
for field_content in ['label', 'value']:
for display_mode in ['text', 'title', 'subtitle']:
if display_mode == 'title':
html_tag = 'h3'
elif display_mode == 'subtitle':
html_tag = 'h4'
elif display_mode == 'text' and field_content == 'label':
html_tag = '.label'
elif display_mode == 'text' and field_content == 'value':
html_tag = '.value'
cell.custom_schema['cells'][0] = {
'varname': 'empty',
'field_content': field_content,
'display_mode': display_mode,
'empty_value': '@skip@',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find(html_tag) == []
cell.custom_schema['cells'][0] = {
'varname': 'empty',
'field_content': field_content,
'display_mode': display_mode,
'empty_value': '@empty@',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find(html_tag).text() == ('Empty' if field_content == 'label' else '')
cell.custom_schema['cells'][0] = {
'varname': 'empty',
'field_content': field_content,
'display_mode': display_mode,
'empty_value': 'Custom text',
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find(html_tag).text() == (
'Empty' if field_content == 'label' else 'Custom text'
)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_render_custom_schema_custom_entry(mock_send, context, app):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardInfosCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={
'cells': [
{
'varname': '@custom@',
'template': "<b>Foo</b> bar'baz {{ card.fields.fielde }}",
'display_mode': 'title',
},
]
},
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert '&lt;b&gt;Foo&lt;/b&gt;' in result
assert PyQuery(result).find('h3').text() == "<b>Foo</b> bar'baz lorem<strong>ipsum hello'world"
# test context
cell.custom_schema['cells'][0][
'template'
] = '{{ card.fields.fielda }} - {{ card.fields.related }} ({{ card.fields.related_structured.id }})'
cell.custom_schema['cells'][0]['display_mode'] = 'subtitle'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('h4').text() == '<i>a</i> - Foo Bar (42)'
# test display_mode & filters in template
cell.custom_schema = {
'cells': [
{'varname': '@custom@', 'template': 'Foo bar baz', 'display_mode': 'label'},
{
'varname': '@custom@',
'template': '{{ card.fields.related|split:" "|join:"," }}',
'display_mode': 'text',
},
]
}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.label').text() == 'Foo bar baz'
assert PyQuery(result).find('.value').text() == 'Foo,Bar'
# test available context
cell.card_ids = '11'
cell.custom_schema = {
'cells': [
{
'varname': '@custom@',
'template': 'Foo bar baz {% make_public_url url="http://127.0.0.1:8999/" %}',
'display_mode': 'label',
},
]
}
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert '/api/wcs/file/' in PyQuery(cell_resp.text).find('.label').text()
cell.custom_schema = {
'cells': [
{'varname': '@custom@', 'template': 'Foo bar baz X{{ site_base }}Y', 'display_mode': 'label'},
]
}
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert PyQuery(cell_resp.text).find('.label').text() == 'Foo bar baz Xhttp://testserverY'
cell.card_ids = '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}'
cell.custom_schema = {
'cells': [
{'varname': '@custom@', 'template': 'Foo bar baz X{{ repeat_index }}Y', 'display_mode': 'label'},
]
}
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 3
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
for i in range(0, 3):
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
assert PyQuery(cell_resp.text).find('.label').text() == 'Foo bar baz X%sY' % i
# custom schema but empty
cell.custom_schema = {'cells': []}
cell.save()
result = cell.render(context)
assert PyQuery(result).find('div.cell--body') == []
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_render_custom_schema_link_entry(mock_send, context, app):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardInfosCell.objects.create(
page=page,
placeholder='content',
order=0,
carddef_reference='default:card_model_1',
custom_schema={
'cells': [
{
'varname': '@link@',
'url_template': '/foo/bar/{{ card.fields.related_structured.id }}/',
'template': '{{ card.fields.fielda }} - {{ card.fields.related }}',
'display_mode': 'link',
},
]
},
)
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert PyQuery(result).find('.value a').text() == '<i>a</i> - Foo Bar'
assert PyQuery(result).find('.value a').attr['href'] == '/foo/bar/42/'
assert PyQuery(result).find('.value a').attr['class'] is None
cell.custom_schema['cells'][0]['display_mode'] = 'button'
cell.save()
result = cell.render(context)
assert PyQuery(result).find('.value a').text() == '<i>a</i> - Foo Bar'
assert PyQuery(result).find('.value a').attr['href'] == '/foo/bar/42/'
assert PyQuery(result).find('.value a').attr['class'] == 'pk-button'
cell.custom_schema['cells'][0][
'url_template'
] = '{{ site_base }}/foo/bar/{{ card.fields.related_structured.id }}/'
cell.custom_schema['cells'][0]['template'] = '<b>{{ card.fields.fielda }}</b> - {{ card.fields.related }}'
cell.card_ids = '11'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert (
'<div class="value"><a href="http://testserver/foo/bar/42/" class="pk-button">&lt;b&gt;&lt;i&gt;a&lt;/i&gt;&lt;/b&gt; - Foo Bar</a></div>'
in cell_resp
)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_render_identifier(mock_send, nocache, app):
page = Page.objects.create(
title='xxx', slug='foo', template_name='standard', sub_slug='(?P<card_model_1_id>[a-z0-9]+)'
)
cell = WcsCardInfosCell.objects.create(
page=page, placeholder='content', order=0, carddef_reference='default:card_model_1'
)
cell_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell.get_reference()},
)
# check url called
mock_send.reset_mock()
resp = app.get(page.get_online_url() + '11/')
assert len(resp.context['cells']) == 1
assert resp.context['cells'][0].pk == cell.pk
assert resp.context['cells'][0].repeat_index == 0
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert cell_resp.context['repeat_index'] == 0
assert 'Card Model 1' in cell_resp
assert '<p>Unknown Card</p>' not in cell_resp
assert len(mock_send.call_args_list) == 1
assert '/api/cards/card_model_1/11/' in mock_send.call_args_list[0][0][0].url
# with identifiers
page.sub_slug = ''
page.save()
cell.card_ids = '42'
cell.save()
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
assert resp.context['cells'][0].pk == cell.pk
assert resp.context['cells'][0].repeat_index == 0
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert cell_resp.context['repeat_index'] == 0
assert 'Card Model 1' in cell_resp
assert '<p>Unknown Card</p>' in cell_resp
assert len(mock_send.call_args_list) == 1
assert '/api/cards/card_model_1/42/' in mock_send.call_args_list[0][0][0].url
cell.card_ids = '42, , 35'
cell.save()
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 2
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
for i in range(0, 2):
assert resp.context['cells'][i].pk == cell.pk
assert resp.context['cells'][i].repeat_index == i
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
assert cell_resp.context['repeat_index'] == i
assert 'Card Model 1' in cell_resp
assert '<p>Unknown Card</p>' in cell_resp
assert len(mock_send.call_args_list) == 2
assert '/api/cards/card_model_1/42/' in mock_send.call_args_list[0][0][0].url
assert '/api/cards/card_model_1/35/' in mock_send.call_args_list[1][0][0].url
cell.card_ids = '{% cards|objects:"card_model_1"|last|get:"id" %}' # syntax error
cell.save()
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert cell_resp.text.replace('\n', '') == '' # empty-cell
cell.card_ids = '{{ cards|objects:"card_model_1"|last|get:"id" }}'
cell.save()
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
assert resp.context['cells'][0].pk == cell.pk
assert resp.context['cells'][0].repeat_index == 0
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert cell_resp.context['repeat_index'] == 0
assert len(mock_send.call_args_list) == 3
# page rendering
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
# cell rendering
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[1][0][0].url
assert '/api/cards/card_model_1/13/' in mock_send.call_args_list[2][0][0].url
def test_card_ids():
mock_send.reset_mock()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 3
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
for i in range(0, 3):
assert resp.context['cells'][i].pk == cell.pk
assert resp.context['cells'][i].repeat_index == i
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[i])
assert cell_resp.context['repeat_index'] == i
assert len(mock_send.call_args_list) == 7
# page rendering
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[0][0][0].url
# cell rendering
for i in range(0, 3):
assert '/api/cards/card_model_1/list' in mock_send.call_args_list[i * 2 + 1][0][0].url
assert (
'/api/cards/card_model_1/%s/' % WCS_CARDS_DATA['card_model_1'][i]['id']
in mock_send.call_args_list[i * 2 + 2][0][0].url
)
for card_ids in [
'{% for card in cards|objects:"card_model_1" %}{{ card.id }},{% endfor %}',
'{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}',
]:
cell.card_ids = card_ids
cell.save()
test_card_ids()
cell.card_ids = '{{ var1 }}'
cell.save()
page.extra_variables = {'var1': card_ids}
page.save()
test_card_ids()
page.extra_variables = {}
page.save()
# with a card_ids template, but result is empty
cell.card_ids = '{{ foo }}'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
cell_resp = app.get(cell_url + '?ctx=' + extra_ctx[0])
assert cell_resp.text.replace('\n', '') == '' # empty-cell
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_render_identifier_from_related(mock_send, nocache, app):
page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
cell = WcsCardInfosCell.objects.create(
page=page,
placeholder='content',
order=0,
slug='sluga',
carddef_reference='default:card_a',
card_ids='1',
)
cell2 = WcsCardInfosCell.objects.create(
page=page, placeholder='content', order=1, slug='slugb', carddef_reference='default:card_b'
)
cell2_url = reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': cell2.get_reference()},
)
def failing(urls):
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) >= 2
for i in range(0, len(resp.context['cells']) - 1):
assert resp.context['cells'][i].pk == cell.pk
assert resp.context['cells'][-1].pk == cell2.pk
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
mock_send.reset_mock()
cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[-1])
assert cell_resp.text.replace('\n', '') == '' # empty-cell
assert len(mock_send.call_args_list) == len(urls)
for j, url in enumerate(urls):
assert url in mock_send.call_args_list[j][0][0].url
def single(urls):
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 2
assert resp.context['cells'][0].pk == cell.pk
assert resp.context['cells'][1].pk == cell2.pk
assert resp.context['cells'][1].repeat_index == 0
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
mock_send.reset_mock()
cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[1])
assert cell_resp.context['repeat_index'] == 0
assert len(mock_send.call_args_list) == len(urls)
for j, url in enumerate(urls):
assert url in mock_send.call_args_list[j][0][0].url
def multiple(urls):
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) >= 2
assert resp.context['cells'][0].pk == cell.pk
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
for i in range(0, len(resp.context['cells']) - 1):
assert resp.context['cells'][i + 1].pk == cell2.pk
assert resp.context['cells'][i + 1].repeat_index == i
mock_send.reset_mock()
cell_resp = app.get(cell2_url + '?ctx=' + extra_ctx[i + 1])
assert cell_resp.context['repeat_index'] == i
assert len(mock_send.call_args_list) == len(urls)
for j, url in enumerate(urls):
if isinstance(url, list):
assert url[i] in mock_send.call_args_list[j][0][0].url
else:
assert url in mock_send.call_args_list[j][0][0].url
# no cell with this slug
cell2.related_card_path = 'slugz/cardb'
cell2.save()
failing(urls=[])
# another cell with the same slug
cell3 = WcsCardInfosCell.objects.create(page=page, placeholder='content', order=2, slug='sluga')
cell2.related_card_path = 'sluga/foo'
cell2.save()
failing(urls=[])
cell3.delete()
# multiple ids configured on first cell
cell.card_ids = '{{ cards|objects:"card_a"|getlist:"id"|join:"," }}'
cell.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/list',
]
)
# related_card_path configured on first cell
cell.card_ids = '1' # reset
cell.related_path = 'foobar'
cell.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/1/',
]
)
# reset
cell.related_path = ''
cell.save()
# another cell as the same slug, but not a WcsCardInfosCell
cell3 = WcsCardsCell.objects.create(page=page, placeholder='content', order=2, slug='sluga')
# direct and single relation (item)
cell2.related_card_path = 'sluga/cardb'
cell2.save()
single(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# and follow cardb relation
'/api/cards/card_b/1/',
]
)
cell3.delete() # reset
cell2.related_card_path = 'sluga/cardc/cardb'
cell2.save()
single(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# get card_c schema
'/api/cards/card_c/@schema',
# follow cardc relation
'/api/cards/card_c/6/',
# and follow cardb relation
'/api/cards/card_b/7/',
]
)
# direct and multiple relation (items)
cell2.related_card_path = 'sluga/cardsb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# and follow cardb relation
['/api/cards/card_b/2/', '/api/cards/card_b/3/'],
]
)
cell2.related_card_path = 'sluga/cardc/cardsb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# get card_c schema
'/api/cards/card_c/@schema',
# follow cardc relation
'/api/cards/card_c/6/',
# and follow cardb relation
['/api/cards/card_b/8/', '/api/cards/card_b/9/'],
]
)
# direct and multiple relation through a block
cell2.related_card_path = 'sluga/blockb_cardb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# and follow cardb relation
['/api/cards/card_b/4/', '/api/cards/card_b/5/'],
]
)
cell2.related_card_path = 'sluga/cardc/blockb_cardb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# get card_c schema
'/api/cards/card_c/@schema',
# follow cardc relation
'/api/cards/card_c/6/',
# and follow cardb relation
['/api/cards/card_b/10/', '/api/cards/card_b/11/'],
]
)
# unknown part in related_card_path
cell2.related_card_path = 'sluga/foobar'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/1/',
]
)
cell2.related_card_path = 'sluga/cardc/foobar'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# get card_c schema
'/api/cards/card_c/@schema',
# follow cardc relation
'/api/cards/card_c/6/',
]
)
# card data not found
cell.card_ids = '42'
cell.save()
cell2.related_card_path = 'sluga/cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/42/',
]
)
cell.card_ids = '2'
cell.save()
cell2.related_card_path = 'sluga/cardc/cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/2/',
# get card_c schema
'/api/cards/card_c/@schema',
# follow cardc relation
'/api/cards/card_c/61/',
]
)
# reset
cell.card_ids = '1'
cell.save()
# last part has not the correct card slug
cell2.related_card_path = 'sluga/cardc'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/1/',
]
)
# unknown schema
cell2.related_card_path = 'sluga/cardz/cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/1/',
# get card_z schema
'/api/cards/card_z/@schema',
]
)
# multiple relation of multiple relation
cell2.related_card_path = 'sluga/cardsb/reverse:cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/1/',
]
)
# field not found
cell.card_ids = '3'
cell.save()
cell2.related_card_path = 'sluga/cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/3/',
]
)
cell2.related_card_path = 'sluga/cardc/cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/3/',
]
)
# field empty
cell.card_ids = '4'
cell.save()
cell2.related_card_path = 'sluga/cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/4/',
]
)
# field not found in block
cell.card_ids = '3'
cell.save()
cell2.related_card_path = 'sluga/blockb_cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/3/',
]
)
# field empty in block
cell.card_ids = '4'
cell.save()
cell2.related_card_path = 'sluga/blockb_cardb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/4/',
]
)
# reverse relation of item
cell.carddef_reference = 'default:card_b'
cell.slug = 'slugb'
cell.card_ids = '1'
cell.related_card_path = ''
cell.save()
cell2.carddef_reference = 'default:card_a'
cell2.slug = 'sluga'
cell2.card_ids = ''
cell2.related_card_path = 'slugb/reverse:cardb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_b/1/',
# get list of card_a with cardb=1
'/api/cards/card_a/list?orig=combo&filter-cardb=1',
# and follow carda reverse relation
['/api/cards/card_a/%s/' % i for i in range(1, 5)],
]
)
# reverse relation of items
cell2.related_card_path = 'slugb/reverse:cardsb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_b/1/',
# get list of card_a with cardsb=1
'/api/cards/card_a/list?orig=combo&filter-cardsb=1',
# and follow carda reverse relation
['/api/cards/card_a/%s/' % i for i in range(1, 5)],
]
)
# reverse relation of item through a block
cell2.related_card_path = 'slugb/reverse:blockb_cardb'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_b/1/',
# get list of card_a with cardsb=1
'/api/cards/card_a/list?orig=combo&filter-blockb_cardb=1',
# and follow carda reverse relation
['/api/cards/card_a/%s/' % i for i in range(1, 5)],
]
)
# unknown part in related_card_path
cell2.related_card_path = 'slugb/foobar'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_b/1/',
]
)
# multiple relation of multiple relation
cell2.related_card_path = 'slugb/reverse:cardb/cardsb'
cell2.save()
failing(
urls=[
# get first cell data
'/api/cards/card_b/1/',
]
)
# reverse relation with many models using the same varname
cell.carddef_reference = 'default:card_h'
cell.slug = 'slugh'
cell.card_ids = '42'
cell.related_card_path = ''
cell.save()
cell2.carddef_reference = 'default:card_f'
cell2.slug = 'slugf'
cell2.card_ids = ''
cell2.related_card_path = 'slugh/reverse:cardh'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_h/42/',
# get list of card_f with cardf=42
'/api/cards/card_f/list?orig=combo&filter-cardh=42',
# and follow cardf reverse relation
['/api/cards/card_f/41/'],
]
)
cell.card_ids = '44'
cell.related_card_path = ''
cell.save()
cell2.carddef_reference = 'default:card_g'
cell2.slug = 'slugg'
cell2.card_ids = ''
cell2.related_card_path = 'slugh/reverse:cardh'
cell2.save()
multiple(
urls=[
# get first cell data
'/api/cards/card_h/44/',
# get list of card_g with cardf=44
'/api/cards/card_g/list?orig=combo&filter-cardh=44',
# and follow cardf reverse relation
['/api/cards/card_g/43/'],
]
)
@pytest.mark.parametrize('carddef_reference', ['default:card_model_1', 'default:card_model_1:foo'])
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_render_user(mock_send, context, nocache, carddef_reference):
page = Page.objects.create(title='xxx', template_name='standard')
cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
cell.carddef_reference = carddef_reference
cell.save()
context['card_model_1_id'] = 11
request = RequestFactory().get('/')
cell.modify_global_context(context, request)
cell.repeat_index = 0
context['synchronous'] = True # to get fresh content
assert context['request'].user is None
mock_send.reset_mock()
cell.render(context)
assert 'NameID=&' in mock_send.call_args_list[0][0][0].url
assert 'email=&' in mock_send.call_args_list[0][0][0].url
context['request'].user = AnonymousUser()
mock_send.reset_mock()
cell.render(context)
assert 'NameID=&' in mock_send.call_args_list[0][0][0].url
assert 'email=&' in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUser()
mock_send.reset_mock()
cell.render(context)
assert 'email=foo%40example.net' in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUserWithNameId()
mock_send.reset_mock()
cell.render(context)
assert 'NameID=xyz' in mock_send.call_args_list[0][0][0].url
cell.without_user = True
cell.save()
context['request'].user = None
mock_send.reset_mock()
cell.render(context)
assert 'NameID' not in mock_send.call_args_list[0][0][0].url
assert 'email' not in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUser()
mock_send.reset_mock()
cell.render(context)
assert 'NameID' not in mock_send.call_args_list[0][0][0].url
assert 'email' not in mock_send.call_args_list[0][0][0].url
context['request'].user = MockUserWithNameId()
mock_send.reset_mock()
cell.render(context)
assert 'NameID' not in mock_send.call_args_list[0][0][0].url
assert 'email' not in mock_send.call_args_list[0][0][0].url
def test_tracking_code_cell(app, nocache):
page = Page(title='One', slug='index', template_name='standard')
page.save()
cell = TrackingCodeInputCell(page=page, placeholder='content', order=0)
cell.save()
resp = app.get('/')
resp.form['code'] = 'FOOBAR'
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
resp = resp.form.submit()
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/code/FOOBAR'
assert requests_get.call_args_list[1][0][0] == '/api/code/FOOBAR'
remote_service_urls = [c[1]['remote_service']['url'] for c in requests_get.call_args_list]
assert set(remote_service_urls) == {'http://127.0.0.1:8999/', 'http://127.0.0.2:8999/'}
assert resp.status_code == 302
resp = resp.follow()
assert '<li class="error">The tracking code could not been found.</li>' in resp.text
resp = app.get('/')
resp.form['code'] = 'FOO?BAR?bad<code>'
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
resp = resp.form.submit()
assert requests_get.call_args_list[0][0][0] == '/api/code/FOO%3FBAR%3FBAD%3CCODE%3E'
assert resp.status_code == 302
resp = resp.follow()
assert '<li class="error">The tracking code could not been found.</li>' in resp.text
resp = app.get('/')
resp.form['code'] = 'CNPHNTFB'
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.return_value = MockedRequestResponse(
content=json.dumps({'err': 0, 'load_url': 'http://127.0.0.2:8999/code/CNPHNTFB/load'})
)
resp = resp.form.submit()
assert resp.status_code == 302
assert resp.location == 'http://127.0.0.2:8999/code/CNPHNTFB/load'
# space/case
resp = app.get('/')
resp.form['code'] = ' cnphntfb'
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = [
mock.Mock(status_code=200),
MockedRequestResponse(
content=json.dumps({'err': 0, 'load_url': 'http://127.0.0.2:8999/code/CNPHNTFB/load'})
),
]
resp = resp.form.submit()
assert requests_get.call_args_list[0][0][0] == '/api/code/CNPHNTFB'
assert requests_get.call_args_list[1][0][0] == '/api/code/CNPHNTFB'
assert resp.status_code == 302
assert resp.location == 'http://127.0.0.2:8999/code/CNPHNTFB/load'
# lock cell to a single site
cell.wcs_site = 'default'
cell.save()
resp = app.get('/')
resp.form['code'] = 'CNPHNTFB'
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
resp = resp.form.submit()
assert len(requests_get.call_args_list) == 1
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
resp = resp.follow()
assert '<li class="error">The tracking code could not been found.</li>' in resp.text
# unknown wcs_site
cell.wcs_site = 'unknown'
cell.save()
resp = app.get('/')
resp.form['code'] = 'CNPHNTFB'
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
resp = resp.form.submit()
assert len(requests_get.call_args_list) == 0
resp = resp.follow()
assert '<li class="error">The tracking code could not been found.</li>' in resp.text
# simulate cell being displayed on a different site
resp = app.get('/')
resp.form['url'] = 'http://example.org/'
resp.form['code'] = 'CNPHNTFB'
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
resp = resp.form.submit()
assert resp.location == 'http://example.org/?unknown-tracking-code'
resp = app.get('/')
resp.form['url'] = 'http://example.org/?foo=bar'
resp.form['code'] = 'CNPHNTFB'
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
resp = resp.form.submit()
assert resp.location == 'http://example.org/?foo=bar&unknown-tracking-code'
# redirect to an unknown site
resp = app.get('/')
resp.form['url'] = 'http://example.net/'
resp.form['code'] = 'CNPHNTFB'
resp = resp.form.submit(status=400)
# error handling
resp = app.get('/')
resp.form['cell'] = '9999'
resp.form['code'] = 'CNPHNTFB'
resp = resp.form.submit(status=400)
resp = app.get('/')
resp.form['cell'] = 'xxxx'
resp.form['code'] = 'CNPHNTFB'
resp = resp.form.submit(status=400)
resp = app.post(reverse('wcs-tracking-code'), params={'cell': cell.id}, status=400)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_tracking_code_cell_check_validity(mock_send):
page = Page.objects.create(title='xxx', slug='test', template_name='standard')
cell = TrackingCodeInputCell.objects.create(page=page, placeholder='content', order=0)
# invalid wcs_site
cell.wcs_site = 'invalid'
cell.save()
cell.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_site_not_found'
assert validity_info.invalid_since is not None
# valid wcs_site
cell.wcs_site = 'default'
cell.save()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_cell_assets(mock_send, settings, app, admin_user):
page = Page.objects.create(title='xxx', slug='test_cell_assets', template_name='standard')
cell1 = WcsFormCell.objects.create(
page=page, placeholder='content', order=0, formdef_reference='default:form-title'
)
cell2 = WcsFormsOfCategoryCell.objects.create(
page=page, placeholder='content', order=0, category_reference='default:test-9', ordering='alpha'
)
app = login(app)
settings.WCS_CATEGORY_ASSET_SLOTS = {}
settings.WCS_FORM_ASSET_SLOTS = {}
settings.COMBO_CELL_ASSET_SLOTS = {}
resp = app.get('/manage/assets/')
assert 'have any asset yet.' in resp.text
# Old settings have priority
settings.WCS_CATEGORY_ASSET_SLOTS = {'logo': {'prefix': 'Logo'}}
settings.WCS_FORM_ASSET_SLOTS = {'picture': {'prefix': 'Picture'}}
settings.COMBO_CELL_ASSET_SLOTS = {
'wcs_wcsformcell': {'picture': {'prefix': 'Picture blabla', 'suffix': 'test'}},
'wcs_wcsformsofcategorycell': {'logo': {'prefix': 'Logo blabla', 'suffix': 'test'}},
}
resp = app.get('/manage/assets/')
assert 'Logo — %s' % cell2.get_label_for_asset() in resp.text
assert 'Logo blabla — %s' % cell2.get_label_for_asset() not in resp.text
assert 'Picture — %s' % cell1.get_label_for_asset() in resp.text
assert 'Picture blabla — %s' % cell1.get_label_for_asset() not in resp.text
# New settings
settings.WCS_CATEGORY_ASSET_SLOTS = {}
settings.WCS_FORM_ASSET_SLOTS = {}
settings.COMBO_CELL_ASSET_SLOTS = {
'wcs_wcsformcell': {'picture': {'prefix': 'Picture'}},
'wcs_wcsformsofcategorycell': {'logo': {'prefix': 'Logo'}},
}
resp = app.get('/manage/assets/')
assert 'Logo — %s' % cell2.get_label_for_asset() in resp.text
assert 'Picture — %s' % cell1.get_label_for_asset() in resp.text
# test suffix
settings.COMBO_CELL_ASSET_SLOTS = {
'wcs_wcsformcell': {'picture': {'prefix': 'Picture', 'suffix': 'test'}},
'wcs_wcsformsofcategorycell': {'logo': {'prefix': 'Logo', 'suffix': 'test'}},
}
resp = app.get('/manage/assets/')
assert 'Logo — %s (test)' % cell2.get_label_for_asset() in resp.text
assert 'Picture — %s (test)' % cell1.get_label_for_asset() in resp.text
def test_tracking_code_search(settings, app, nocache):
settings.TEMPLATE_VARS['is_portal_agent'] = True
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
result = app.get('/api/search/tracking-code/').json
assert len(result.get('data')) == 0
assert result.get('err') == 0
assert requests_get.called is False # no code
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
assert len(app.get('/api/search/tracking-code/?q=123').json.get('data')) == 0
assert requests_get.called is False # no letters
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
assert len(app.get('/api/search/tracking-code/?q=BBCCDFF').json.get('data')) == 0
assert requests_get.called is False # too short
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
assert len(app.get('/api/search/tracking-code/?q=BBCCDDFF').json.get('data')) == 0
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/code/BBCCDDFF'
assert requests_get.call_args_list[1][0][0] == '/api/code/BBCCDDFF'
remote_service_urls = [c[1]['remote_service']['url'] for c in requests_get.call_args_list]
assert set(remote_service_urls) == {'http://127.0.0.1:8999/', 'http://127.0.0.2:8999/'}
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.return_value = MockedRequestResponse(
content=json.dumps({'err': 0, 'load_url': 'http://127.0.0.2:8999/code/CNPHNTFB/load'})
)
assert len(app.get('/api/search/tracking-code/?q=CNPHNTFB').json.get('data')) == 1
assert requests_get.call_args_list[0][0][0] == '/api/code/CNPHNTFB'
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
assert len(app.get('/api/search/tracking-code/?q=BBCCDDFFG').json.get('data')) == 0
assert requests_get.called is False # too long
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = [
mock.Mock(status_code=200),
MockedRequestResponse(
content=json.dumps({'err': 0, 'load_url': 'http://127.0.0.2:8999/code/CNPHNTFB/load'})
),
]
assert len(app.get('/api/search/tracking-code/?q= cnphntfb').json.get('data')) == 1
assert requests_get.call_args_list[0][0][0] == '/api/code/CNPHNTFB'
def test_tracking_code_search_rate_limit(settings, app):
settings.TEMPLATE_VARS['is_portal_agent'] = True
settings.WCS_TRACKING_CODE_RATE_LIMIT = '0/s'
assert app.get('/api/search/tracking-code/?q=BBCCDDFF').json.get('err') == 1
page = Page(title='One', slug='index', template_name='standard')
page.save()
cell = TrackingCodeInputCell(page=page, placeholder='content', order=0)
cell.save()
resp = app.get('/')
resp.form['code'] = 'FOOBAR'
resp = resp.form.submit()
assert resp.status_code == 302
resp = resp.follow()
assert '<li class="error">Looking up tracking code is currently rate limited.</li>' in resp.text
resp = app.get('/')
resp.form['code'] = 'FOOBAR'
resp.form['url'] = 'http://example.org/'
resp = resp.form.submit(status=403)
def test_wcs_search_engines(app):
settings.TEMPLATE_VARS['is_portal_agent'] = True
search_engines = engines.get_engines()
assert 'tracking-code' in search_engines
assert len([x for x in search_engines if x.startswith('formdata:')]) == 2
settings.TEMPLATE_VARS['is_portal_agent'] = False
search_engines = engines.get_engines()
assert 'tracking-code' not in search_engines
assert len([x for x in search_engines if x.startswith('formdata:')]) == 0
def test_backoffice_submission_cell_render(context):
page = Page(title='xxx', slug='test_backoffice_submission_cell_render', template_name='standard')
page.save()
cell = BackofficeSubmissionCell.objects.create(page=page, placeholder='content', order=0)
context['synchronous'] = True # to get fresh content
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
result = cell.render(context)
assert requests_get.call_args_list[0][0][0] == '/api/formdefs/?backoffice-submission=on'
assert context['all_formdefs'] == {}
assert 'h2' not in result
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.return_value = MockedRequestResponse(
content=json.dumps(
{
'data': [
{
'backoffice_submission_url': '/backoffice/submission/a-private-form/',
'title': 'Foo',
}
]
}
)
)
result = cell.render(context)
assert '/backoffice/submission/a-private-form/' in result
assert list(context['all_formdefs'].keys()) == ['default', 'other']
assert 'h2' in result
# limit to categories
requests_get.reset_mock()
cell.categories = {'data': ['default:test-3', 'other:test-6']}
result = cell.render(context)
assert len(requests_get.call_args_list) == 2
assert (
requests_get.call_args_list[0][0][0]
== '/api/formdefs/?backoffice-submission=on&category_slugs=test-3'
)
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert (
requests_get.call_args_list[1][0][0]
== '/api/formdefs/?backoffice-submission=on&category_slugs=test-6'
)
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
requests_get.reset_mock()
cell.categories = {'data': ['default:test-3']}
result = cell.render(context)
assert len(requests_get.call_args_list) == 1
assert (
requests_get.call_args_list[0][0][0]
== '/api/formdefs/?backoffice-submission=on&category_slugs=test-3'
)
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
requests_get.reset_mock()
cell.categories = {'data': []}
result = cell.render(context)
assert len(requests_get.call_args_list) == 2
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_backoffice_submission_cell_check_validity(mock_send, context):
page = Page.objects.create(title='xxx', slug='test_current_forms_cell_render', template_name='standard')
cell = BackofficeSubmissionCell.objects.create(page=page, placeholder='content', order=0)
# no category
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# valid categories
cell.categories = {'data': ['default:test-3', 'default:test-9']}
cell.save()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# can not retrieve data, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
cell.check_validity()
assert ValidityInfo.objects.exists() is False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
requests_get.side_effect = ConnectionError()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# can not retrieve categories, don't set cell as invalid
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
cell.check_validity()
assert ValidityInfo.objects.exists() is False
# invalid category
cell.categories = {'data': ['default:foobar', 'default:test-9']}
cell.save()
cell.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_category_not_found'
assert validity_info.invalid_since is not None
# invalid wcs_site
cell.categories = {'data': ['default:test-3', 'default:test-9']}
cell.wcs_site = 'invalid'
cell.save()
cell.check_validity()
validity_info = ValidityInfo.objects.latest('pk')
assert validity_info.invalid_reason_code == 'wcs_site_not_found'
assert validity_info.invalid_since is not None
# valid wcs_site
cell.wcs_site = 'default'
cell.save()
cell.check_validity()
assert ValidityInfo.objects.exists() is False
def test_manager_link_list_cell_duplicate():
page = Page.objects.create(title='xxx', slug='new', template_name='standard')
cell = LinkListCell.objects.create(order=0, page=page)
item = WcsFormCell.objects.create(
page=page,
placeholder=cell.link_placeholder,
cached_title='A title',
cached_url='http://example.com',
cached_json={'foo': 'bar'},
order=1,
)
new_cell = cell.duplicate()
assert WcsFormCell.objects.count() == 2
assert len(new_cell.get_items()) == 1
new_item = new_cell.get_items()[0]
assert new_item.page == page
assert new_item.placeholder == new_cell.link_placeholder
assert new_item.pk != item.pk
assert new_item.cached_title == item.cached_title
assert new_item.cached_url == item.cached_url
assert new_item.cached_json == item.cached_json
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_manager_add_edit_delete_list_link_item(mock_send, app, admin_user):
page = Page.objects.create(title='One', slug='one', template_name='standard')
cell = LinkListCell.objects.create(order=0, placeholder='content', page=page)
app = login(app)
resp = app.get('/manage/pages/%s/' % page.pk)
resp = resp.click(href='.*/add-link/form-link$')
resp.forms[0]['formdef_reference'] = 'default:form-title'
resp.forms[0]['extra_css_class'] = 'foobar'
resp = resp.forms[0].submit()
assert resp.status_int == 302
assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference()))
assert WcsFormCell.objects.count() == 1
item = WcsFormCell.objects.get()
assert item.formdef_reference == 'default:form-title'
assert item.page == page
assert item.placeholder == cell.link_placeholder
assert item.extra_css_class == 'foobar'
resp = resp.follow()
resp = resp.click(href='.*/link/%s/$' % item.get_reference())
resp.forms[0]['formdef_reference'] = 'default:a-private-form'
resp = resp.forms[0].submit()
assert resp.status_int == 302
assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference()))
assert WcsFormCell.objects.count() == 1
item.refresh_from_db()
assert item.formdef_reference == 'default:a-private-form'
resp = resp.follow()
resp = resp.click(href='.*/link/%s/delete' % item.get_reference())
resp = resp.forms[0].submit()
assert resp.status_int == 302
assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference()))
assert WcsFormCell.objects.count() == 0
def test_import_export_pages_with_links():
page = Page(title='bar', slug='bar', order=1)
page.save()
cell = LinkListCell.objects.create(order=0, placeholder='content', page=page)
item = WcsFormCell.objects.create(
page=page,
placeholder=cell.link_placeholder,
cached_title='A title',
cached_url='http://example.com',
cached_json={'foo': 'bar'},
order=0,
)
site_export = [x.get_serialized_page() for x in Page.objects.all()]
Page.load_serialized_pages(site_export)
new_page = Page.objects.get()
new_cells = CellBase.get_cells(page_id=new_page.id, placeholder='content')
assert len(new_cells[0].get_items()) == 1
new_item = new_cells[0].get_items()[0]
assert isinstance(new_item, WcsFormCell)
assert new_item.cached_title == item.cached_title
assert new_item.cached_url == item.cached_url
assert new_item.cached_json == item.cached_json
def test_list_of_links_with_form_render(app):
page = Page(title='xxx', slug='test_list_of_links_with_form_render', template_name='standard')
page.save()
cell = LinkListCell.objects.create(order=0, placeholder='content', page=page)
link = WcsFormCell.objects.create(
page=page,
placeholder=cell.link_placeholder,
cached_title='A title',
cached_url='http://example.com/',
order=0,
extra_css_class='foobar',
)
resp = app.get('/test_list_of_links_with_form_render/')
assert PyQuery(resp.text).find('.links-list a').text() == 'A title'
assert PyQuery(resp.text).find('.links-list li').attr('class') == ' foobar'
assert (
PyQuery(resp.text).find('.links-list a').attr('href')
== 'http://example.com/tryauth?cancelurl=http%3A//testserver/test_list_of_links_with_form_render/'
)
link.cached_json = {'keywords': ['bar']}
link.save()
resp = app.get('/test_list_of_links_with_form_render/')
assert PyQuery(resp.text).find('.links-list li').attr('class') == 'keyword-bar foobar'
link.extra_css_class = ''
link.save()
resp = app.get('/test_list_of_links_with_form_render/')
assert PyQuery(resp.text).find('.links-list li').attr('class') == 'keyword-bar'
def test_view_page_with_wcs_cells_num_queries(app, admin_user):
page = Page.objects.create(title='bar', slug='index', order=1)
for i in range(0, 15):
WcsCurrentDraftsCell.objects.create(page=page, placeholder='content', order=i)
for i in range(15, 50):
WcsCurrentFormsCell.objects.create(page=page, placeholder='content', order=i)
app = login(app)
app.get('/') # load once to populate caches
with CaptureQueriesContext(connection) as ctx:
app.get('/')
assert len(ctx.captured_queries) == 62
def test_hourly():
appconfig = apps.get_app_config('wcs')
page = Page.objects.create(title='xxx', slug='test_current_forms_cell_render', template_name='standard')
cell_classes = [c for c in appconfig.get_models() if c in get_cell_classes()]
for klass in cell_classes:
klass.objects.create(page=page, placeholder='content', order=0)
for klass in cell_classes:
if klass in [
WcsCareFormsCell,
WcsCurrentFormsCell,
WcsCurrentDraftsCell,
WcsFormsOfCategoryCell,
WcsCardInfosCell,
BackofficeSubmissionCell,
CategoriesCell,
TrackingCodeInputCell,
]:
with mock.patch('combo.apps.wcs.models.%s.check_validity' % klass.__name__) as check_validity:
appconfig.hourly()
assert check_validity.call_args_list == [mock.call()]
else:
assert hasattr(klass, 'check_validity') is False
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_search_external_forms_links(mock_send, context):
page = Page(title='xxx', slug='test_forms_of_category_cell_search', template_name='standard')
page.save()
cell = SearchCell(page=page, _search_services={'data': ['_text']}, order=0)
cell.save()
index_site()
request = RequestFactory().get('/')
request.user = AnonymousUser()
hits = search_site(request, 'form')
assert len(hits) == 0
cell = WcsFormsOfCategoryCell(page=page, placeholder='content', order=1)
cell.category_reference = 'default:test-9'
cell.ordering = 'alpha'
cell.save()
context['synchronous'] = True # to get fresh content
result = cell.render(context)
assert 'form title' in result and 'a second form title' in result
assert 'http://127.0.0.1:8999/form-title/tryauth' in result
assert 'http://127.0.0.1:8999/a-second-form-title/tryauth' in result
index_site()
request = RequestFactory().get('/')
request.user = AnonymousUser()
hits = search_site(request, 'form')
assert len(hits) == 2
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_file_redirection(mock_send, app):
page = Page(title='One', slug='one', template_name='standard')
page.save()
cell = WcsCardInfosCell(page=page, placeholder='content', order=0)
cell.carddef_reference = 'default:card_model_1'
cell.card_ids = '11'
cell.save()
resp = app.get('/one/')
ajax_cell_url = PyQuery(resp.text).find('[data-ajax-cell-url]').attr['data-ajax-cell-url']
extra_ctx = re.findall(r'data-extra-context="(.*)"', resp.text)
resp = app.get(ajax_cell_url + '?ctx=' + extra_ctx[0])
file_url = PyQuery(resp.text).find('[download]').attr['href']
resp = app.get(file_url)
assert 'download?f=42' in resp.location
assert '&signature=' in resp.location
# invalid crypto
resp = app.get(file_url[:-2] + 'X/', status=403)
# invalid session key
resp = app.get(file_url.replace('file/', 'file/X'), status=403)