0001-search-new-manager-selection-SearchCell-engines-4022.patch
combo/apps/search/forms.py | ||
---|---|---|
16 | 16 | |
17 | 17 |
from django import forms |
18 | 18 | |
19 |
from combo.utils.forms import MultiSortWidget |
|
20 | ||
21 |
from . import engines |
|
22 | 19 |
from .models import SearchCell |
23 | 20 | |
24 | 21 | |
25 | 22 |
class SearchCellForm(forms.ModelForm): |
26 | 23 |
class Meta: |
27 | 24 |
model = SearchCell |
28 |
fields = ('_search_services', 'autofocus') |
|
29 | ||
30 |
def __init__(self, *args, **kwargs): |
|
31 |
super(SearchCellForm, self).__init__(*args, **kwargs) |
|
32 |
options = [(x, engines.get_engines()[x]['label']) for x in engines.get_engines().keys()] |
|
33 |
self.fields['_search_services'].widget = MultiSortWidget(choices=options, |
|
34 |
with_checkboxes=True) |
|
25 |
fields = ('autofocus', ) |
combo/apps/search/manager_views.py | ||
---|---|---|
1 |
# combo - content management system |
|
2 |
# Copyright (C) 2014-2020 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software: you can redistribute it and/or modify it |
|
5 |
# under the terms of the GNU Affero General Public License as published |
|
6 |
# by the Free Software Foundation, either version 3 of the License, or |
|
7 |
# (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU Affero General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU Affero General Public License |
|
15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | ||
17 |
from django.http import HttpResponse |
|
18 |
from django.http import HttpResponseRedirect |
|
19 |
from django.shortcuts import get_object_or_404 |
|
20 |
from django.urls import reverse |
|
21 |
from django.utils.translation import ugettext_lazy as _ |
|
22 | ||
23 |
from combo.apps.search.models import SearchCell |
|
24 |
from combo.data.models import PageSnapshot |
|
25 | ||
26 | ||
27 |
def page_search_cell_add_engine(request, page_pk, cell_reference, engine_slug): |
|
28 |
cell = get_object_or_404(SearchCell, pk=cell_reference.split('-')[1], page=page_pk) |
|
29 | ||
30 |
if engine_slug in cell.available_engines: |
|
31 |
if not cell._search_services or not cell._search_services.get('data'): |
|
32 |
cell._search_services = {'data': []} |
|
33 |
cell._search_services['data'].append(engine_slug) |
|
34 |
cell.save() |
|
35 |
PageSnapshot.take(cell.page, request=request, comment=_('changed cell "%s"') % cell) |
|
36 | ||
37 |
return HttpResponseRedirect('%s#cell-%s' % ( |
|
38 |
reverse('combo-manager-page-view', kwargs={'pk': page_pk}), |
|
39 |
cell_reference)) |
|
40 | ||
41 | ||
42 |
def page_search_cell_delete_engine(request, page_pk, cell_reference, engine_slug): |
|
43 |
cell = get_object_or_404(SearchCell, pk=cell_reference.split('-')[1], page=page_pk) |
|
44 | ||
45 |
if engine_slug in cell._search_services.get('data'): |
|
46 |
cell._search_services['data'].remove(engine_slug) |
|
47 |
cell.save() |
|
48 |
PageSnapshot.take(cell.page, request=request, comment=_('changed cell "%s"') % cell) |
|
49 | ||
50 |
return HttpResponseRedirect('%s#cell-%s' % ( |
|
51 |
reverse('combo-manager-page-view', kwargs={'pk': page_pk}), |
|
52 |
cell_reference)) |
|
53 | ||
54 | ||
55 |
def search_engines_order(request, page_pk, cell_reference): |
|
56 |
cell = get_object_or_404(SearchCell, pk=cell_reference.split('-')[1], page=page_pk) |
|
57 | ||
58 |
if not cell._search_services.get('data'): |
|
59 |
return HttpResponse(status=204) |
|
60 | ||
61 |
engines = [] |
|
62 |
for i, engine_slug in enumerate(cell._search_services['data']): |
|
63 |
try: |
|
64 |
new_order = int(request.GET.get('pos_' + str(engine_slug))) |
|
65 |
except TypeError: |
|
66 |
new_order = 0 |
|
67 |
engines.append((new_order, engine_slug)) |
|
68 | ||
69 |
ordered_engines = [a[1] for a in sorted(engines, key=lambda a: a[0])] |
|
70 |
if ordered_engines != cell._search_services['data']: |
|
71 |
cell._search_services['data'] = ordered_engines |
|
72 |
cell.save() |
|
73 |
PageSnapshot.take(cell.page, request=request, comment=_('changed cell "%s"') % cell) |
|
74 | ||
75 |
return HttpResponse(status=204) |
combo/apps/search/models.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
import os |
|
18 | ||
19 | 17 |
from django.contrib.auth.models import Group |
20 | 18 |
from django.contrib.contenttypes import fields |
21 | 19 |
from django.contrib.contenttypes.models import ContentType |
... | ... | |
24 | 22 |
from django import template |
25 | 23 |
from django.http import HttpResponse |
26 | 24 |
from django.core.exceptions import PermissionDenied |
25 |
from django.utils.functional import cached_property |
|
27 | 26 |
from django.utils.http import quote |
28 | 27 |
from django.template import RequestContext, Template |
29 | 28 | |
... | ... | |
64 | 63 |
return self.slug.replace('-', '_') |
65 | 64 |
return '' |
66 | 65 | |
67 |
@property |
|
66 |
@cached_property
|
|
68 | 67 |
def search_services(self): |
69 | 68 |
services = [] |
70 | 69 |
for service_slug in self._search_services.get('data') or []: |
... | ... | |
74 | 73 |
services.append(service) |
75 | 74 |
return services |
76 | 75 | |
76 |
@cached_property |
|
77 |
def available_engines(self): |
|
78 |
all_engines = engines.get_engines() |
|
79 |
current_engines = [e['slug'] for e in self.search_services] |
|
80 |
return {k: v for k, v in all_engines.items() if k not in current_engines} |
|
81 | ||
77 | 82 |
@property |
78 | 83 |
def has_multiple_search_services(self): |
79 | 84 |
return len(self._search_services.get('data') or []) > 1 |
combo/apps/search/templates/combo/manager/search-cell-form.html | ||
---|---|---|
12 | 12 |
</p> |
13 | 13 |
</div> |
14 | 14 |
{% endif %} |
15 |
{{ block.super }} |
|
15 |
{{ form.as_p }} |
|
16 |
{% with cell.search_services as engines %} |
|
17 |
{% if engines %} |
|
18 |
<p><label>{% trans "Engines:" %}</label></p> |
|
19 |
<div> |
|
20 |
<ul class="objects-list list-of-links" id="list-of-links-{{ cell.pk }}" |
|
21 |
data-link-list-order-url="{% url 'combo-manager-search-engines-order' page_pk=page.pk cell_reference=cell.get_reference %}"> |
|
22 |
{% for engine in engines %} |
|
23 |
<li data-link-item-id="{{ engine.slug }}"><span class="handle">⣿</span> |
|
24 |
<span>{{ engine.label }}</span> |
|
25 |
<a title="{% trans "Delete" %}" class="link-action-icon delete" href="{% url 'combo-manager-page-search-cell-delete-engine' page_pk=page.pk cell_reference=cell.get_reference engine_slug=engine.slug %}">{% trans "Delete" %}</a> |
|
26 |
</li> |
|
27 |
{% endfor %} |
|
28 |
</ul> |
|
29 |
</div> |
|
30 |
<script> |
|
31 |
$(function () { |
|
32 |
$('#list-of-links-{{ cell.pk }}').sortable({ |
|
33 |
handle: '.handle', |
|
34 |
update: function(event, ui) { |
|
35 |
var new_order = Object(); |
|
36 |
$(this).find('li').each(function(i, x) { |
|
37 |
var suffix = $(x).data('link-item-id'); |
|
38 |
new_order['pos_' + suffix] = i; |
|
39 |
}); |
|
40 |
$.ajax({ |
|
41 |
url: $(this).data('link-list-order-url'), |
|
42 |
data: new_order |
|
43 |
}); |
|
44 |
} |
|
45 |
}); |
|
46 |
}); |
|
47 |
</script> |
|
48 |
{% endif %} |
|
49 |
{% endwith %} |
|
50 |
{% if cell.available_engines %} |
|
51 |
<div class="buttons"> |
|
52 |
{% trans "Add an engine:" %} |
|
53 |
{% for key, engine in cell.available_engines.items %} |
|
54 |
<a href="{% url 'combo-manager-page-search-cell-add-engine' page_pk=page.pk cell_reference=cell.get_reference engine_slug=key %}">{{ engine.label }}</a> {% if not forloop.last %}|{% endif %} |
|
55 |
{% endfor %} |
|
56 |
</div> |
|
57 |
{% endif %} |
|
16 | 58 |
{% endblock %} |
combo/apps/search/urls.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from django.conf.urls import url |
|
17 |
from django.conf.urls import url, include
|
|
18 | 18 | |
19 |
from combo.urls_utils import decorated_includes, manager_required |
|
19 | 20 |
from .models import SearchCell |
21 |
from . import manager_views |
|
22 | ||
23 |
search_manager_urls = [ |
|
24 |
url(r'^pages/(?P<page_pk>\d+)/cell/(?P<cell_reference>[\w_]+-\d+)/engine/(?P<engine_slug>[\w_-]+)/add/$', |
|
25 |
manager_views.page_search_cell_add_engine, |
|
26 |
name='combo-manager-page-search-cell-add-engine'), |
|
27 |
url(r'^pages/(?P<page_pk>\d+)/cell/(?P<cell_reference>[\w_]+-\d+)/engine/(?P<engine_slug>[\w_-]+)/delete/$', |
|
28 |
manager_views.page_search_cell_delete_engine, |
|
29 |
name='combo-manager-page-search-cell-delete-engine'), |
|
30 |
url(r'^pages/(?P<page_pk>\d+)/cell/(?P<cell_reference>[\w_]+-\d+)/engine/order$', |
|
31 |
manager_views.search_engines_order, |
|
32 |
name='combo-manager-search-engines-order'), |
|
33 |
] |
|
20 | 34 | |
21 | 35 |
urlpatterns = [ |
22 |
url(r'^ajax/search/(?P<cell_pk>\w+)/(?P<service_slug>[\w:-]+)/$', SearchCell.ajax_results_view, |
|
36 |
url(r'^manage/search/', decorated_includes(manager_required, include(search_manager_urls))), |
|
37 |
url(r'^ajax/search/(?P<cell_pk>\w+)/(?P<service_slug>[\w_-]+)/$', SearchCell.ajax_results_view, |
|
23 | 38 |
name='combo-search-ajax-results'), |
24 | 39 |
] |
tests/test_search.py | ||
---|---|---|
1 | 1 |
import json |
2 | 2 |
import os |
3 | 3 |
import pytest |
4 |
import re |
|
5 |
import shutil |
|
6 | 4 |
import mock |
7 | 5 | |
8 | 6 |
from django.conf import settings |
... | ... | |
11 | 9 |
from django.test import override_settings |
12 | 10 |
from django.test.client import RequestFactory |
13 | 11 |
from django.test.utils import CaptureQueriesContext |
14 |
from django.core.management import call_command |
|
15 | 12 |
from django.urls import reverse |
13 |
from django.utils.http import urlencode |
|
16 | 14 | |
17 | 15 |
from combo.apps.search.engines import engines |
18 | 16 |
from combo.apps.search.models import SearchCell, IndexedCell |
... | ... | |
215 | 213 |
assert '<li><a href="http://example.net/123/">A B</a>' in resp.text |
216 | 214 |
assert '<div>description A</div>' in resp.text |
217 | 215 | |
216 | ||
218 | 217 |
def test_search_cell_visibility(app): |
219 | 218 |
page = Page(title='example page', slug='example-page') |
220 | 219 |
page.save() |
... | ... | |
224 | 223 |
assert not cell.is_visible() |
225 | 224 | |
226 | 225 |
cell._search_services = {'data': ['_text']} |
226 |
del cell.search_services # clear cache |
|
227 | 227 |
assert cell.is_visible() |
228 | 228 | |
229 | ||
229 | 230 |
def test_search_contents(): |
230 | 231 |
page = Page(title='example page', slug='example-page') |
231 | 232 |
page.save() |
... | ... | |
347 | 348 |
assert hits[0]['url'] == 'http://example.net' |
348 | 349 | |
349 | 350 | |
350 |
def test_manager_search_cell(app, admin_user): |
|
351 |
Page.objects.all().delete() |
|
352 |
page = Page(title='One', slug='one', template_name='standard') |
|
353 |
page.save() |
|
351 |
def test_manager_search_cell(settings, app, admin_user): |
|
352 |
page = Page.objects.create(title='One', slug='one', template_name='standard') |
|
353 |
cell = SearchCell.objects.create(page=page, placeholder='content', order=0) |
|
354 | 354 |
app = login(app) |
355 |
resp = app.get('/manage/pages/%s/' % page.id) |
|
356 |
resp = app.get(resp.html.find('option', |
|
357 |
**{'data-add-url': re.compile('search_searchcell')})['data-add-url']) |
|
358 | 355 | |
359 |
cells = Page.objects.get(id=page.id).get_cells() |
|
360 |
assert len(cells) == 1 |
|
361 |
assert isinstance(cells[0], SearchCell) |
|
356 |
settings.KNOWN_SERVICES = {} |
|
357 |
assert cell._search_services == {} |
|
358 |
resp = app.get('/manage/pages/%s/' % page.pk) |
|
359 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/_text/add/' % (page.pk, cell.pk) in resp.text |
|
360 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/_text/delete/' % (page.pk, cell.pk) not in resp.text |
|
361 | ||
362 |
settings.COMBO_SEARCH_SERVICES = SEARCH_SERVICES |
|
363 |
resp = app.get('/manage/pages/%s/' % page.pk) |
|
364 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/_text/add/' % (page.pk, cell.pk) in resp.text |
|
365 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search1/add/' % (page.pk, cell.pk) in resp.text |
|
366 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search_tmpl/add/' % (page.pk, cell.pk) in resp.text |
|
367 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search_alternate_key/add/' % (page.pk, cell.pk) in resp.text |
|
368 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/_text/delete/' % (page.pk, cell.pk) not in resp.text |
|
369 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search1/delete/' % (page.pk, cell.pk) not in resp.text |
|
370 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search_tmpl/delete/' % (page.pk, cell.pk) not in resp.text |
|
371 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search_alternate_key/delete/' % (page.pk, cell.pk) not in resp.text |
|
372 | ||
373 |
# add engines |
|
374 |
resp = resp.click(href='.*/search_searchcell-%s/engine/_text/add/' % cell.pk) |
|
375 |
assert resp.status_int == 302 |
|
376 |
assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference())) |
|
377 |
resp = app.get('/manage/pages/%s/' % page.pk) |
|
378 |
resp = resp.click(href='.*/search_searchcell-%s/engine/search1/add/' % cell.pk) |
|
379 |
resp = app.get('/manage/pages/%s/' % page.pk) |
|
380 |
resp = resp.click(href='.*/search_searchcell-%s/engine/search_tmpl/add/' % cell.pk) |
|
381 |
cell.refresh_from_db() |
|
382 |
assert cell._search_services == {'data': ['_text', 'search1', 'search_tmpl']} |
|
383 |
resp = app.get('/manage/pages/%s/' % page.pk) |
|
384 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/_text/add/' % (page.pk, cell.pk) not in resp.text |
|
385 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search1/add/' % (page.pk, cell.pk) not in resp.text |
|
386 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search_tmpl/add/' % (page.pk, cell.pk) not in resp.text |
|
387 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search_alternate_key/add/' % (page.pk, cell.pk) in resp.text |
|
388 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/_text/delete/' % (page.pk, cell.pk) in resp.text |
|
389 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search1/delete/' % (page.pk, cell.pk) in resp.text |
|
390 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search_tmpl/delete/' % (page.pk, cell.pk) in resp.text |
|
391 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search_alternate_key/delete/' % (page.pk, cell.pk) not in resp.text |
|
392 | ||
393 |
# delete engines |
|
394 |
resp = resp.click(href='.*/search_searchcell-%s/engine/_text/delete/' % cell.pk) |
|
395 |
assert resp.status_int == 302 |
|
396 |
assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference())) |
|
397 |
cell.refresh_from_db() |
|
398 |
assert cell._search_services == {'data': ['search1', 'search_tmpl']} |
|
399 | ||
400 |
settings.COMBO_SEARCH_SERVICES = {} |
|
401 |
# check there's no crash if search engines are removed from config |
|
402 |
resp = app.get('/manage/pages/%s/' % page.pk) |
|
403 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search1/add/' % (page.pk, cell.pk) not in resp.text |
|
404 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search_tmpl/add/' % (page.pk, cell.pk) not in resp.text |
|
405 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search_alternate_key/add/' % (page.pk, cell.pk) not in resp.text |
|
406 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search1/delete/' % (page.pk, cell.pk) not in resp.text |
|
407 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search_tmpl/delete/' % (page.pk, cell.pk) not in resp.text |
|
408 |
assert '/manage/search/pages/%s/cell/search_searchcell-%s/engine/search_alternate_key/delete/' % (page.pk, cell.pk) not in resp.text |
|
409 | ||
410 | ||
411 |
def test_manager_search_cell_order(settings, app, admin_user): |
|
412 |
settings.COMBO_SEARCH_SERVICES = SEARCH_SERVICES |
|
413 |
page = Page.objects.create(title='One', slug='one', template_name='standard') |
|
414 |
cell = SearchCell.objects.create( |
|
415 |
page=page, placeholder='content', order=0, |
|
416 |
_search_services={'data': ['_text', 'search1', 'search_tmpl']}) |
|
417 | ||
418 |
params = [] |
|
419 |
new_order = [2, 3, 1] |
|
420 |
for i, (service_slug, new_pos) in enumerate(zip(cell._search_services['data'], new_order)): |
|
421 |
params.append(('pos_%s' % service_slug, str(new_pos))) |
|
362 | 422 | |
363 |
with override_settings(KNOWN_SERVICES={}): |
|
364 |
resp = app.get('/manage/pages/%s/' % page.id) |
|
365 |
assert ('data-cell-reference="%s"' % cells[0].get_reference()) in resp.text |
|
366 |
assert len(resp.form['c%s-_search_services' % cells[0].get_reference()].options) == 1 |
|
367 | ||
368 |
with SearchServices(SEARCH_SERVICES): |
|
369 |
resp = app.get('/manage/pages/%s/' % page.id) |
|
370 |
assert len(resp.form['c%s-_search_services' % cells[0].get_reference()].options) == 4 |
|
371 |
# simulate reordering of options |
|
372 |
resp.form['c%s-_search_services' % cells[0].get_reference()].options = [ |
|
373 |
(u'search_tmpl', False, u'Search with template'), |
|
374 |
(u'search_alternate_key', False, u'Search with alternate key'), |
|
375 |
(u'_text', False, u'Page Contents'), |
|
376 |
(u'search1', False, u'Search 1')] |
|
377 |
resp.form['c%s-_search_services' % cells[0].get_reference()].value = ['search_tmpl', '_text'] |
|
378 |
resp = resp.form.submit() |
|
379 |
assert resp.status_int == 302 |
|
380 | ||
381 |
# check selected engines are selected and the first items of the list |
|
382 |
resp = app.get('/manage/pages/%s/' % page.id) |
|
383 |
assert set(resp.form['c%s-_search_services' % cells[0].get_reference()].value) == set(['search_tmpl', '_text']) |
|
384 |
assert resp.form['c%s-_search_services' % cells[0].get_reference()].options[0][0] == 'search_tmpl' |
|
385 |
assert resp.form['c%s-_search_services' % cells[0].get_reference()].options[1][0] == '_text' |
|
386 | ||
387 |
# check there's no crash if search engines are removed from config |
|
388 |
resp = app.get('/manage/pages/%s/' % page.id) |
|
389 |
assert resp.form['c%s-_search_services' % cells[0].get_reference()].value == ['_text'] |
|
423 |
app = login(app) |
|
424 |
resp = app.get('/manage/search/pages/%s/cell/%s/engine/order?%s' % (page.pk, cell.get_reference(), urlencode(params))) |
|
425 |
assert resp.status_code == 204 |
|
426 |
cell.refresh_from_db() |
|
427 |
assert cell._search_services == {'data': ['search_tmpl', '_text', 'search1']} |
|
390 | 428 | |
391 | 429 | |
392 | 430 |
def test_manager_waiting_index_message(app, admin_user): |
393 |
Page.objects.all().delete() |
|
394 |
page = Page(title='One', slug='one', template_name='standard') |
|
395 |
page.save() |
|
431 |
page = Page.objects.create(title='One', slug='one', template_name='standard') |
|
432 |
cell = SearchCell.objects.create(page=page, placeholder='content', order=0) |
|
396 | 433 |
app = login(app) |
397 |
resp = app.get('/manage/pages/%s/' % page.id) |
|
398 |
resp = app.get(resp.html.find('option', |
|
399 |
**{'data-add-url': re.compile('search_searchcell')})['data-add-url']) |
|
400 |
resp = resp.follow() |
|
434 |
resp = app.get('/manage/pages/%s/' % page.pk) |
|
401 | 435 |
assert 'Content indexing has been scheduled' not in resp.text |
402 | 436 | |
403 |
cells = Page.objects.get(id=page.id).get_cells() |
|
404 |
resp.form['c%s-_search_services' % cells[0].get_reference()] = ['_text'] |
|
405 |
resp = resp.form.submit().follow() |
|
437 |
resp = resp.click(href='.*/search_searchcell-%s/engine/_text/add/' % cell.pk) |
|
438 |
resp = app.get('/manage/pages/%s/' % page.pk) |
|
406 | 439 |
assert 'Content indexing has been scheduled' in resp.text |
407 | 440 | |
408 | 441 |
index_site() |
409 |
resp = app.get('/manage/pages/%s/' % page.id)
|
|
442 |
resp = app.get('/manage/pages/%s/' % page.pk)
|
|
410 | 443 |
assert 'Content indexing has been scheduled' not in resp.text |
411 | 444 | |
412 | 445 | |
413 |
- |