0001-cells-display-invalidity-date-or-delay-43605.patch
combo/data/models.py | ||
---|---|---|
547 | 547 |
class Meta: |
548 | 548 |
unique_together = [('content_type', 'object_id')] |
549 | 549 | |
550 |
@property |
|
551 |
def invalid_datetime(self): |
|
552 |
if not self.invalid_since: |
|
553 |
return |
|
554 |
return self.invalid_since + datetime.timedelta(days=2) |
|
555 | ||
550 | 556 | |
551 | 557 |
class CellMeta(MediaDefiningClass, ModelBase): |
552 | 558 |
pass |
... | ... | |
891 | 897 |
# 5xx error: can not retrieve data, don't report cell as invalid |
892 | 898 |
self.mark_as_valid() |
893 | 899 | |
900 |
def is_valid(self): |
|
901 |
validity_info = self.get_validity_info() |
|
902 |
if validity_info is None: |
|
903 |
return True |
|
904 |
if not validity_info.invalid_since: |
|
905 |
return True |
|
906 |
if validity_info.invalid_datetime >= now(): |
|
907 |
# not yet |
|
908 |
return True |
|
909 |
return False |
|
910 | ||
894 | 911 |
def get_invalid_reason(self): |
895 | 912 |
validity_info = self.get_validity_info() |
896 | 913 |
if validity_info is None: |
... | ... | |
916 | 933 | |
917 | 934 |
def is_visible(self, user=None, check_validity_info=True): |
918 | 935 |
if check_validity_info: |
919 |
validity_info = self.get_validity_info() |
|
920 |
if validity_info is not None and validity_info.invalid_since and validity_info.invalid_since < now() - datetime.timedelta(days=2): |
|
936 |
if not self.is_valid(): |
|
921 | 937 |
return False |
922 | 938 |
return element_is_visible(self, user=user) |
923 | 939 |
combo/manager/templates/combo/page_view.html | ||
---|---|---|
150 | 150 |
<span class="extra-css-class">[{{ cell.extra_css_class }}]</span> |
151 | 151 |
{% endif %} |
152 | 152 |
<span class="additional-label"><i>{{cell.get_additional_label|default_if_none:""}}</i></span> |
153 |
{% with cell.get_invalid_reason as invalid_reason %} |
|
154 |
{% if invalid_reason %} |
|
155 |
<span class="invalid">{{ invalid_reason }}</span> |
|
153 |
{% if cell.get_invalid_reason %} |
|
154 |
<span class="invalid">{{ cell.get_invalid_reason }} - |
|
155 |
{% if cell.is_valid %} |
|
156 |
{% blocktrans with cell.get_validity_info.invalid_datetime|timeuntil as invalidity_delay %}This cell will no longer be displayed in {{ invalidity_delay }}.{% endblocktrans %} |
|
157 |
{% else %} |
|
158 |
{% blocktrans with cell.get_validity_info.invalid_datetime|date:"DATETIME_FORMAT" as invalidity_date %}This cell is no longer displayed since {{ invalidity_date }}.{% endblocktrans %} |
|
159 |
{% endif %} |
|
160 |
</span> |
|
156 | 161 |
{% endif %} |
157 |
{% endwith %} |
|
158 | 162 |
</span> |
159 | 163 |
{% if not cell.public %} |
160 | 164 |
<span class="visibility-summary |
tests/test_cells.py | ||
---|---|---|
13 | 13 |
from django.conf import settings |
14 | 14 |
from django.db import connection |
15 | 15 |
from django.forms.widgets import Media |
16 |
from django.template import Context |
|
17 | 16 |
from django.test import override_settings |
18 | 17 |
from django.test.client import RequestFactory |
19 | 18 |
from django.test.utils import CaptureQueriesContext |
... | ... | |
1127 | 1126 |
assert cell.is_visible() is False |
1128 | 1127 | |
1129 | 1128 | |
1129 |
def test_cell_invalidity_marker(): |
|
1130 |
page = Page.objects.create() |
|
1131 |
cell = TextCell.objects.create(page=page, order=0) |
|
1132 |
cell.mark_as_invalid('foo_bar_reason') |
|
1133 |
validity_info = ValidityInfo.objects.latest('pk') |
|
1134 |
old_reason = validity_info.invalid_reason_code |
|
1135 |
old_date = validity_info.invalid_since |
|
1136 | ||
1137 |
cell.mark_as_invalid('another_foo_bar_reason', force=False) |
|
1138 |
validity_info.refresh_from_db() |
|
1139 |
assert old_reason == validity_info.invalid_reason_code |
|
1140 |
assert old_date == validity_info.invalid_since |
|
1141 | ||
1142 |
cell.mark_as_invalid('another_foo_bar_reason') |
|
1143 |
validity_info.refresh_from_db() |
|
1144 |
assert validity_info.invalid_reason_code == 'another_foo_bar_reason' |
|
1145 |
assert old_date < validity_info.invalid_since |
|
1146 | ||
1147 |
cell.mark_as_valid() |
|
1148 |
assert ValidityInfo.objects.exists() is False |
|
1149 | ||
1150 | ||
1151 |
def test_cell_is_valid(freezer): |
|
1152 |
freezer.move_to('2020-06-05 12:00:01') |
|
1153 |
page = Page.objects.create() |
|
1154 |
cell = TextCell.objects.create(page=page, order=0) |
|
1155 |
assert cell.is_valid() is True |
|
1156 |
validity_info = ValidityInfo.objects.create(content_object=cell) |
|
1157 |
validity_info.invalid_reason_code = 'FOO' |
|
1158 |
validity_info.save() |
|
1159 |
assert cell.is_valid() is True # invalid_since is not set |
|
1160 | ||
1161 |
ValidityInfo.objects.update(invalid_since=now() - datetime.timedelta(days=2, minutes=10*60+2)) |
|
1162 |
assert cell.is_valid() is False |
|
1163 |
ValidityInfo.objects.update(invalid_since=now() - datetime.timedelta(minutes=1)) |
|
1164 |
assert cell.is_valid() is True |
|
1165 | ||
1166 | ||
1130 | 1167 |
def test_hourly(): |
1131 | 1168 |
appconfig = apps.get_app_config('data') |
1132 | 1169 |
page = Page.objects.create(title='xxx', slug='test_current_forms_cell_render', template_name='standard') |
tests/test_manager.py | ||
---|---|---|
1 | 1 |
import base64 |
2 |
import json |
|
2 |
import datetime |
|
3 |
import mock |
|
3 | 4 |
import os |
4 | 5 |
import re |
5 | 6 |
import shutil |
6 | 7 | |
7 |
import mock |
|
8 | ||
9 | 8 |
from django.core.files.storage import default_storage |
10 | 9 |
from django.urls import reverse |
11 | 10 |
from django.conf import settings |
12 |
from django.contrib.auth.models import User, Group
|
|
11 |
from django.contrib.auth.models import Group |
|
13 | 12 |
from django.db import connection |
14 | 13 |
from django.template import TemplateSyntaxError |
15 | 14 |
from django.test import override_settings |
16 | 15 |
from django.test.client import RequestFactory |
17 | 16 |
from django.test.utils import CaptureQueriesContext |
18 | 17 |
from django.utils.http import urlencode |
18 |
from django.utils.timezone import now |
|
19 | 19 |
from django.utils.six import BytesIO |
20 | 20 |
from django.utils.six.moves.urllib import parse as urlparse |
21 | 21 | |
22 | 22 |
import pytest |
23 |
from webtest import TestApp |
|
24 | 23 |
from webtest import Upload |
25 | 24 | |
26 |
from combo.wsgi import application |
|
27 | 25 |
from combo.data.forms import LinkCellForm |
28 | 26 |
from combo.data.models import ( |
29 | 27 |
Page, CellBase, TextCell, LinkCell, ConfigJsonCell, JsonCell, PageSnapshot, |
... | ... | |
169 | 167 |
assert Page.objects.all()[0].exclude_from_navigation is False |
170 | 168 | |
171 | 169 | |
172 |
def test_edit_page_cell_invalid_placeholder(app, admin_user): |
|
170 |
def test_edit_page_cell_invalid_placeholder(freezer, app, admin_user): |
|
171 |
freezer.move_to('2020-06-05 12:00:01') |
|
173 | 172 |
page = Page.objects.create(title='One', slug='one', template_name='standard') |
174 | 173 |
cell = TextCell.objects.create(page=page, placeholder='content', text='Foobar', order=1) |
175 | 174 |
cell.mark_as_invalid('foo_bar_reason') |
176 |
validity_info = ValidityInfo.objects.latest('pk') |
|
177 |
old_reason = validity_info.invalid_reason_code |
|
178 |
old_date = validity_info.invalid_since |
|
179 | 175 | |
180 | 176 |
app = login(app) |
177 |
ValidityInfo.objects.update(invalid_since=now() - datetime.timedelta(minutes=1)) |
|
181 | 178 |
resp = app.get('/manage/pages/%s/' % page.pk) |
182 |
assert '<span class="invalid">foo_bar_reason</span>' in resp.text |
|
179 |
assert '<span class="invalid">foo_bar_reason' in resp.text |
|
180 |
assert 'This cell will no longer be displayed in 1 day, 23 hours' in resp.text |
|
183 | 181 | |
184 |
cell.mark_as_invalid('another_foo_bar_reason', force=False) |
|
185 |
validity_info.refresh_from_db() |
|
186 |
assert old_reason == validity_info.invalid_reason_code |
|
187 |
assert old_date == validity_info.invalid_since |
|
182 |
ValidityInfo.objects.update(invalid_since=now() - datetime.timedelta(minutes=47*60-1)) |
|
183 |
resp = app.get('/manage/pages/%s/' % page.pk) |
|
184 |
assert '<span class="invalid">foo_bar_reason' in resp.text |
|
185 |
assert 'This cell will no longer be displayed in 1 hour, 1 minute.' in resp.text |
|
186 | ||
187 |
ValidityInfo.objects.update(invalid_since=now() - datetime.timedelta(minutes=47*60+29)) |
|
188 |
resp = app.get('/manage/pages/%s/' % page.pk) |
|
189 |
assert '<span class="invalid">foo_bar_reason' in resp.text |
|
190 |
assert 'This cell will no longer be displayed in 31 minutes.' in resp.text |
|
188 | 191 | |
189 |
cell.mark_as_invalid('another_foo_bar_reason')
|
|
190 |
validity_info.refresh_from_db()
|
|
191 |
assert validity_info.invalid_reason_code == 'another_foo_bar_reason'
|
|
192 |
assert old_date < validity_info.invalid_since
|
|
192 |
ValidityInfo.objects.update(invalid_since=now() - datetime.timedelta(days=2, minutes=10*60+2))
|
|
193 |
resp = app.get('/manage/pages/%s/' % page.pk)
|
|
194 |
assert '<span class="invalid">foo_bar_reason' in resp.text
|
|
195 |
assert 'This cell is no longer displayed since June 5, 2020, 1:58 a.m.' in resp.text
|
|
193 | 196 | |
194 | 197 |
cell.mark_as_valid() |
195 | 198 |
assert ValidityInfo.objects.exists() is False |
196 | 199 |
resp = app.get('/manage/pages/%s/' % page.pk) |
197 |
assert '<span class="invalid">foo_bar_reason</span>' not in resp.text
|
|
200 |
assert '<span class="invalid">foo_bar_reason' not in resp.text |
|
198 | 201 | |
199 | 202 |
cell2 = LinkListCell.objects.create(order=0, placeholder='content', page=page) |
200 | 203 |
item = LinkCell.objects.create(page=page, placeholder=cell2.link_placeholder, order=0) |
201 | 204 |
item.mark_as_invalid('foo_bar_reason') |
202 | 205 |
cell2.check_validity() |
203 | 206 |
resp = app.get('/manage/pages/%s/' % page.pk) |
204 |
assert '<span class="invalid">Invalid link</span>' in resp.text |
|
207 |
assert '<span class="invalid">Invalid link' in resp.text |
|
208 |
assert 'This cell will no longer be displayed in 2 days.' in resp.text |
|
205 | 209 |
assert '<span class="invalid">foo_bar_reason</span>' in resp.text |
206 | 210 | |
207 | 211 | |
208 |
- |