data: add display condition to cells (#66263)
gitea-wip/combo/pipeline/head There was a failure building this commit Details
gitea/combo/pipeline/head Something is wrong with the build of this commit Details

and also on each item of a linklist cell
This commit is contained in:
Lauréline Guérin 2022-06-16 11:17:59 +02:00
parent 9428431767
commit 794bb74c32
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
37 changed files with 670 additions and 55 deletions

View File

@ -0,0 +1,16 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('calendar', '0003_bookingcalendar_template_name'),
]
operations = [
migrations.AddField(
model_name='bookingcalendar',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
]

View File

@ -58,8 +58,8 @@ class BookingCalendar(CellBase):
def is_enabled(cls):
return settings.BOOKING_CALENDAR_CELL_ENABLED and is_chrono_enabled() and is_wcs_enabled()
def is_visible(self, **kwargs):
return self.agenda_reference and self.formdef_reference and super().is_visible(**kwargs)
def is_visible(self, request, **kwargs):
return self.agenda_reference and self.formdef_reference and super().is_visible(request, **kwargs)
def get_cell_extra_context(self, context):
if context.get('placeholder_search_mode'):

View File

@ -0,0 +1,16 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dashboard', '0003_dashboardcell_template_name'),
]
operations = [
migrations.AddField(
model_name='dashboardcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
]

View File

@ -65,7 +65,7 @@ class DashboardAddTileView(View):
cell = CellBase.get_cell(kwargs['cell_reference'])
if not cell.page.is_visible(request.user):
raise PermissionDenied()
if not cell.is_visible(user=request.user):
if not cell.is_visible(request):
raise PermissionDenied()
cell.pk = None
cell.page = dashboard.page

View File

@ -0,0 +1,31 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dataviz', '0023_statistic_has_future_data'),
]
operations = [
migrations.AddField(
model_name='chartcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='chartfilterscell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='chartngcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='gauge',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
]

View File

@ -45,7 +45,7 @@ class DatavizGraphView(DetailView):
if not self.cell.page.is_visible(request.user):
raise PermissionDenied()
if not self.cell.is_visible(user=request.user):
if not self.cell.is_visible(request):
raise PermissionDenied()
if not self.cell.statistic or not self.cell.statistic.url:
raise Http404('misconfigured cell')

View File

@ -0,0 +1,16 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('family', '0012_booking_form_url'),
]
operations = [
migrations.AddField(
model_name='weeklyagendacell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
]

View File

@ -94,11 +94,11 @@ class WeeklyAgendaCell(JsonCellBase):
)
)
def is_visible(self, **kwargs):
user = kwargs.get('user')
def is_visible(self, request, **kwargs):
user = getattr(request, 'user', None)
if not user or user.is_anonymous:
return False
return super().is_visible(**kwargs)
return super().is_visible(request, **kwargs)
def get_cell_extra_context(self, context):
if context.get('placeholder_search_mode'):

View File

@ -0,0 +1,16 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fargo', '0005_recentdocumentscell_template_name'),
]
operations = [
migrations.AddField(
model_name='recentdocumentscell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
]

View File

@ -58,11 +58,11 @@ class RecentDocumentsCell(CellBase):
self.__class__, fields=self.get_form_fields(), widgets=self.get_form_widgets()
)
def is_visible(self, **kwargs):
user = kwargs.get('user')
def is_visible(self, request, **kwargs):
user = getattr(request, 'user', None)
if not user or user.is_anonymous:
return False
return super().is_visible(**kwargs)
return super().is_visible(request, **kwargs)
@classmethod
def is_enabled(cls):

View File

@ -0,0 +1,21 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gallery', '0004_auto_20210723_1318'),
]
operations = [
migrations.AddField(
model_name='gallerycell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AlterField(
model_name='image',
name='image',
field=models.ImageField(upload_to='uploads/gallery/%Y/%m/', verbose_name='Image'),
),
]

View File

@ -0,0 +1,16 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('kb', '0003_latestpageupdatescell_template_name'),
]
operations = [
migrations.AddField(
model_name='latestpageupdatescell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
]

View File

@ -0,0 +1,46 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lingo', '0045_basketitem_remote_item_id'),
]
operations = [
migrations.AddField(
model_name='activeitems',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='itemshistory',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='lingobasketcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='lingobasketlinkcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='lingorecenttransactionscell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='selfdeclaredinvoicepayment',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='tipipaymentformcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
]

View File

@ -0,0 +1,41 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('maps', '0019_auto_20211104_1603'),
]
operations = [
migrations.AddField(
model_name='map',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AlterField(
model_name='maplayer',
name='tiles_attribution',
field=models.CharField(
blank=True,
help_text=(
'Par exemple\xa0: Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors, '
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'
),
max_length=1024,
null=True,
verbose_name='Attribution',
),
),
migrations.AlterField(
model_name='maplayer',
name='tiles_template_url',
field=models.CharField(
blank=True,
help_text='Par exemple\xa0: https://tiles.entrouvert.org/hdm/{z}/{x}/{y}.png',
max_length=1024,
null=True,
verbose_name='Tiles URL',
),
),
]

View File

@ -27,7 +27,7 @@ class GeojsonView(View):
def get(self, request, *args, **kwargs):
cell = get_object_or_404(Map, pk=kwargs['cell_id'])
layer = get_object_or_404(cell.layers.all(), kind='geojson', slug=kwargs['layer_slug'])
if not cell.page.is_visible(request.user) or not cell.is_visible(user=request.user):
if not cell.page.is_visible(request.user) or not cell.is_visible(request):
return HttpResponseForbidden()
options = cell.maplayeroptions_set.get(map_layer=layer)
geojson = layer.get_geojson(request, options.properties)

View File

@ -0,0 +1,26 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('notifications', '0006_auto_20210723_1318'),
]
operations = [
migrations.AddField(
model_name='notificationscell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AlterField(
model_name='notification',
name='body',
field=models.TextField(blank=True, default='', verbose_name='Body'),
),
migrations.AlterField(
model_name='notification',
name='url',
field=models.URLField(blank=True, default='', verbose_name='URL'),
),
]

View File

@ -176,11 +176,11 @@ class NotificationsCell(CellBase):
class Meta:
verbose_name = _('User Notifications')
def is_visible(self, **kwargs):
user = kwargs.get('user')
def is_visible(self, request, **kwargs):
user = getattr(request, 'user', None)
if user is None or not user.is_authenticated:
return False
return super().is_visible(**kwargs)
return super().is_visible(request, **kwargs)
def get_cell_extra_context(self, context):
extra_context = super().get_cell_extra_context(context)

View File

@ -0,0 +1,16 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('search', '0012_auto_20220105_0832'),
]
operations = [
migrations.AddField(
model_name='searchcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
]

View File

@ -60,10 +60,10 @@ class SearchCell(CellBase):
class Meta:
verbose_name = _('Search')
def is_visible(self, **kwargs):
def is_visible(self, request, **kwargs):
if not self._search_services.get('data'):
return False
return super().is_visible(**kwargs)
return super().is_visible(request, **kwargs)
def get_default_form_class(self):
from .forms import SearchCellForm
@ -176,7 +176,7 @@ class SearchCell(CellBase):
@classmethod
def ajax_results_view(cls, request, cell_pk, service_slug):
cell = get_object_or_404(cls, pk=cell_pk)
if not cell.is_visible(user=request.user) or not cell.page.is_visible(request.user):
if not cell.is_visible(request) or not cell.page.is_visible(request.user):
raise PermissionDenied
query = request.GET.get('q')

View File

@ -0,0 +1,68 @@
# Generated by Django 2.2.26 on 2022-06-15 05:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wcs', '0045_wcscareformscell_cache_duration'),
]
operations = [
migrations.AddField(
model_name='backofficesubmissioncell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='categoriescell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='trackingcodeinputcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='wcscardinfoscell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='wcscardscell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='wcscareformscell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='wcscategorycell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='wcscurrentdraftscell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='wcscurrentformscell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='wcsformcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='wcsformsofcategorycell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
]

View File

@ -415,11 +415,11 @@ class WcsUserDataBaseCell(WcsDataBaseCell):
class Meta:
abstract = True
def is_visible(self, **kwargs):
user = kwargs.get('user')
def is_visible(self, request, **kwargs):
user = getattr(request, 'user', None)
if not user or user.is_anonymous:
return False
return super().is_visible(**kwargs)
return super().is_visible(request, **kwargs)
class CategoriesAndWcsSiteValidityMixin:
@ -887,11 +887,11 @@ class WcsCardsCell(CardMixin, WcsBlurpMixin, CellBase):
populate_cache()
def is_visible(self, **kwargs):
user = kwargs.get('user')
def is_visible(self, request, **kwargs):
user = getattr(request, 'user', None)
if self.only_for_user and (not user or user.is_anonymous):
return False
return super().is_visible(**kwargs)
return super().is_visible(request, **kwargs)
def get_api_url(self, context):
parts = self.carddef_reference.split(':')

View File

@ -17,6 +17,9 @@
import copy
from django import forms
from django.conf import settings
from django.template import Template, TemplateSyntaxError
from django.utils.translation import ugettext_lazy as _
from combo.utils import cache_during_request
@ -52,7 +55,29 @@ class LinkCellForm(forms.ModelForm):
class LinkCellForLinkListCellForm(LinkCellForm):
class Meta:
model = LinkCell
fields = ('title', 'url', 'link_page', 'anchor', 'bypass_url_validity_check', 'extra_css_class')
fields = (
'title',
'url',
'link_page',
'anchor',
'bypass_url_validity_check',
'extra_css_class',
'condition',
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not settings.CELL_CONDITIONS_ENABLED:
del self.fields['condition']
def clean_condition(self):
condition = self.cleaned_data['condition']
try:
Template('{%% if %s %%}OK{%% endif %%}' % condition)
except TemplateSyntaxError:
raise forms.ValidationError(_('Invalid syntax.'))
return condition
class LinkListCellForm(forms.ModelForm):

View File

@ -0,0 +1,66 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('data', '0055_page_placeholer_options'),
]
operations = [
migrations.AddField(
model_name='configjsoncell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='feedcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='fortunecell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='jsoncell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='linkcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='linklistcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='menucell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='parentcontentcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='textcell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AddField(
model_name='unlockmarkercell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
migrations.AlterField(
model_name='linkcell',
name='title',
field=models.CharField(blank=True, max_length=150, verbose_name='Label'),
),
]

View File

@ -806,6 +806,7 @@ class CellBase(models.Model, metaclass=CellMeta):
slug = models.SlugField(_('Slug'), blank=True)
extra_css_class = models.CharField(_('Extra classes for CSS styling'), max_length=100, blank=True)
template_name = models.CharField(_('Cell Template'), max_length=50, blank=True, null=True)
condition = models.CharField(_('Display condition'), max_length=1000, blank=True, null=True)
public = models.BooleanField(_('Public'), default=True)
# restricted_to_unlogged is actually an invert switch, it is used for mark
@ -1151,6 +1152,7 @@ class CellBase(models.Model, metaclass=CellMeta):
'last_update_timestamp',
'restricted_to_unlogged',
'template_name',
'condition',
)
+ tuple(self.get_appearance_fields())
]
@ -1325,10 +1327,25 @@ class CellBase(models.Model, metaclass=CellMeta):
and validity_info.invalid_datetime <= now()
)
def is_visible(self, user=None, check_validity_info=True):
def compute_condition(self, request):
condition = self.condition
if not condition:
return True
context = RequestContext(request)
if condition in self.page.extra_variables:
condition = self.page.extra_variables[condition].strip('{ }')
try:
return Template('{%% if %s %%}OK{%% endif %%}' % condition).render(context) == 'OK'
except (TemplateSyntaxError, VariableDoesNotExist):
return False
def is_visible(self, request, check_validity_info=True):
condition = self.compute_condition(request=request)
if not condition:
return False
if check_validity_info and self.is_hidden_because_invalid():
return False
return element_is_visible(self, user=user)
return element_is_visible(self, user=getattr(request, 'user', None))
def is_relevant(self, context):
"""Return whether it's relevant to render this cell in the page
@ -1844,9 +1861,9 @@ class LinkListCell(CellBase):
for link in self.get_items():
link.duplicate(page_target=new_cell.page, placeholder=new_cell.link_placeholder)
def is_visible(self, check_validity_info=True, **kwargs):
def is_visible(self, request, check_validity_info=True, **kwargs):
# cell is visible even if items are invalid
return super().is_visible(check_validity_info=False, **kwargs)
return super().is_visible(request, check_validity_info=False, **kwargs)
def check_validity(self):
for link in self.get_items(prefetch_validity_info=True):
@ -1882,8 +1899,8 @@ class FeedCell(CellBase):
class Meta:
verbose_name = _('RSS/Atom Feed')
def is_visible(self, **kwargs):
return bool(self.url) and super().is_visible(**kwargs)
def is_visible(self, *args, **kwargs):
return bool(self.url) and super().is_visible(*args, **kwargs)
def save(self, *args, **kwargs):
result = super().save(*args, **kwargs)
@ -2019,8 +2036,8 @@ class JsonCellBase(CellBase):
self.mark_as_valid()
return result
def is_visible(self, **kwargs):
return bool(self.url) and super().is_visible(**kwargs)
def is_visible(self, *args, **kwargs):
return bool(self.url) and super().is_visible(*args, **kwargs)
def is_user_dependant(self, context=None):
urls = [self.url] + [x['url'] for x in self.additional_data or []]

View File

@ -290,6 +290,12 @@ class CellVisibilityForm(forms.Form):
initial='all',
)
groups = forms.MultipleChoiceField(label=_('Groups'), required=False, choices=get_groups_as_choices)
condition = forms.CharField(
label=_('Display condition'),
widget=forms.TextInput(attrs={'class': 'text-wide'}),
max_length=1000,
required=False,
)
def __init__(self, *args, **kwargs):
self.instance = instance = kwargs.pop('instance')
@ -307,7 +313,21 @@ class CellVisibilityForm(forms.Form):
initial['visibility'] = 'groups-none'
else:
initial['visibility'] = 'groups-any'
initial['condition'] = instance.condition
super().__init__(*args, **kwargs)
if not settings.CELL_CONDITIONS_ENABLED:
del self.fields['condition']
def clean_condition(self):
condition = self.cleaned_data['condition']
if not condition:
return condition
try:
Template('{%% if %s %%}OK{%% endif %%}' % condition)
except TemplateSyntaxError:
raise ValidationError(_('Invalid syntax.'))
return condition
def save(self):
if self.cleaned_data['visibility'] == 'all':
@ -330,6 +350,7 @@ class CellVisibilityForm(forms.Form):
self.instance.public = False
self.instance.restricted_to_unlogged = True
self.instance.groups.set(self.cleaned_data['groups'])
self.instance.condition = self.cleaned_data.get('condition')
self.instance.save()
return self.instance

View File

@ -0,0 +1,16 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profile', '0003_profilecell_template_name'),
]
operations = [
migrations.AddField(
model_name='profilecell',
name='condition',
field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='Display condition'),
),
]

View File

@ -45,11 +45,11 @@ class ProfileCell(JsonCellBase):
idp = list(settings.KNOWN_SERVICES.get('authentic').values())[0]
return '%sapi/users/{{ concerned_user|name_id }}/' % idp.get('url')
def is_visible(self, **kwargs):
user = kwargs.get('user')
def is_visible(self, request, **kwargs):
user = getattr(request, 'user', None)
if not user or user.is_anonymous:
return False
return super().is_visible(**kwargs)
return super().is_visible(request, **kwargs)
def get_cell_extra_context(self, context):
extra_context = super().get_cell_extra_context(context)

View File

@ -99,7 +99,7 @@ def placeholder(context, placeholder_name, **options):
and (
context.get('render_skeleton')
or x.is_relevant(context)
and x.is_visible(user=context['request'].user, check_validity_info=False)
and x.is_visible(context['request'], check_validity_info=False)
)
]
if context.get('render_skeleton'):

View File

@ -129,7 +129,7 @@ def ajax_page_cell(request, page_pk, cell_reference):
except ObjectDoesNotExist:
raise Http404()
if not cell.is_visible(user=request.user):
if not cell.is_visible(request):
raise PermissionDenied()
exception = None
@ -187,7 +187,7 @@ def render_cell(request, cell):
placeholder__in=['_auto_tile', '_dashboard', '_suggested_tile']
)
)
other_cells = [x for x in other_cells if x.is_visible(user=request.user)]
other_cells = [x for x in other_cells if x.is_visible(request)]
other_cells.sort(key=lambda x: x.order)
for other_cell in other_cells:
if other_cell.get_reference() != cell.get_reference():
@ -554,7 +554,7 @@ def publish_page(request, page, status=200, template_name=None):
cells_exclude=Q(placeholder__in=['_auto_tile', '_dashboard', '_suggested_tile']),
)
extend_with_parent_cells(cells, hierarchy=pages)
cells = [x for x in cells if x.is_visible(user=request.user)]
cells = [x for x in cells if x.is_visible(request)]
mark_duplicated_slugs(cells)
# load assets

View File

@ -367,6 +367,7 @@ PWA_NOTIFICATION_ICON_URL = None
BOOKING_CALENDAR_CELL_ENABLED = False
LEGACY_CHART_CELL_ENABLED = False
PUBLIK_FAMILY_CELL_ENABLED = False
CELL_CONDITIONS_ENABLED = False
# and enable others
CHART_FILTERS_CELL_ENABLED = True

View File

@ -90,6 +90,7 @@ BOOKING_CALENDAR_CELL_ENABLED = True
LEGACY_CHART_CELL_ENABLED = True
PUBLIK_FAMILY_CELL_ENABLED = True
CHART_FILTERS_CELL_ENABLED = True
CELL_CONDITIONS_ENABLED = True
USER_PROFILE_CONFIG = {
'fields': [

View File

@ -330,7 +330,8 @@ def test_link_list_cell_validity():
assert validity_info.invalid_since is not None
validity_info.invalid_since = now() - datetime.timedelta(days=2)
validity_info.save()
assert cell.is_visible() # particular case: cell is visible
request = RequestFactory().get('/')
assert cell.is_visible(request) # particular case: cell is visible
def test_feed_cell_validity(context):
@ -1559,21 +1560,22 @@ def test_link_list_cell_duplicate():
def test_cell_is_visible():
request = RequestFactory().get('/')
page = Page.objects.create()
cell = TextCell.objects.create(page=page, order=0)
assert cell.is_visible() is True
assert cell.is_visible(request) is True
# invalid cell since just now
validity_info = ValidityInfo.objects.create(content_object=cell)
validity_info.invalid_reason_code = 'FOO'
validity_info.invalid_since = now()
validity_info.save()
assert cell.is_visible() is True
assert cell.is_visible(request) is True
# invalid cell since two days
validity_info.invalid_since = now() - datetime.timedelta(days=2)
validity_info.save()
assert cell.is_visible() is False
assert cell.is_visible(request) is False
def test_cell_invalidity_marker():

View File

@ -1491,7 +1491,9 @@ def test_duplicate_cell(app, admin_user):
assert PageSnapshot.objects.filter(page=other_page).count() == 2
def test_edit_cell_visibility(app, admin_user):
def test_edit_cell_visibility(settings, app, admin_user):
settings.CELL_CONDITIONS_ENABLED = False
Page.objects.all().delete()
page = Page(title='One', slug='one', template_name='standard')
page.save()
@ -1501,6 +1503,7 @@ def test_edit_cell_visibility(app, admin_user):
app = login(app)
resp = app.get('/manage/pages/%s/' % page.id)
assert resp.form['cdata_textcell-%s-visibility' % cell.id].value == 'all'
assert 'cdata_textcell-%s-condition' % cell.id not in resp
resp.form['cdata_textcell-%s-visibility' % cell.id] = 'logged'
resp = resp.form.submit('submit')
assert TextCell.objects.get(id=cell.id).public is False
@ -1546,6 +1549,17 @@ def test_edit_cell_visibility(app, admin_user):
assert TextCell.objects.get(id=cell.id).groups.count() == 1
assert TextCell.objects.get(id=cell.id).groups.all()[0].name == 'Another group'
settings.CELL_CONDITIONS_ENABLED = True
resp = app.get('/manage/pages/%s/' % page.id)
resp.form['cdata_textcell-%s-condition' % cell.pk] = 'False #'
resp = resp.form.submit('submit')
assert resp.json['errorlist']['visibility']['condition'] == ['Invalid syntax.']
resp = app.get('/manage/pages/%s/' % page.id)
resp.form['cdata_textcell-%s-condition' % cell.pk] = 'False'
resp = resp.form.submit('submit')
assert TextCell.objects.get(id=cell.id).condition == 'False'
def test_edit_cell_options(app, admin_user):
Page.objects.all().delete()
@ -2657,7 +2671,8 @@ def test_link_cell_validation():
assert form.errors['url'] == ["syntax error: Could not parse the remainder: '{test_url' from '{test_url'"]
def test_add_edit_delete_list_link_item(app, admin_user):
def test_add_edit_delete_list_link_item(settings, app, admin_user):
settings.CELL_CONDITIONS_ENABLED = False
Page.objects.all().delete()
page = Page.objects.create(title='One', slug='one', template_name='standard')
cell = LinkListCell.objects.create(order=0, placeholder='content', page=page)
@ -2666,6 +2681,7 @@ def test_add_edit_delete_list_link_item(app, admin_user):
assert PageSnapshot.objects.count() == 0
resp = resp.click(href='.*/add-link/link$')
assert 'condition' not in resp.context['form'].fields
resp.forms[0]['title'] = 'Hello world'
resp.forms[0]['url'] = 'http://example.com'
resp.forms[0]['extra_css_class'] = 'foobar'
@ -2702,6 +2718,18 @@ def test_add_edit_delete_list_link_item(app, admin_user):
assert LinkCell.objects.count() == 0
assert PageSnapshot.objects.count() == 3
settings.CELL_CONDITIONS_ENABLED = True
resp = resp.follow()
resp = resp.click(href='.*/add-link/link$')
resp.forms[0]['condition'] = 'False #'
resp = resp.forms[0].submit()
assert resp.context['form'].errors['condition'] == ['Invalid syntax.']
resp.forms[0]['condition'] = 'True'
resp = resp.forms[0].submit()
item = LinkCell.objects.get()
assert item.condition == 'True'
def test_edit_link_list_order(app, admin_user):
Page.objects.all().delete()

View File

@ -93,9 +93,9 @@ def test_notification_cell(app, john_doe, jane_doe):
context['synchronous'] = True # to get fresh content
context['request'].user = None
assert cell.is_visible(user=context['request'].user) is False
assert cell.is_visible(context['request']) is False
context['request'].user = john_doe
assert cell.is_visible(user=context['request'].user) is True
assert cell.is_visible(context['request']) is True
assert cell.get_badge(context) is None
notification1 = Notification.notify(john_doe, 'notibar')

View File

@ -138,6 +138,36 @@ def test_page_contents_group_absence(app, normal_user):
assert 'Foobar' not in resp.text
def test_page_contents_condition(app, normal_user):
page = Page.objects.create(title='Home', slug='index', template_name='standard')
TextCell.objects.create(page=page, placeholder='content', text='Foobar', order=0, condition='True')
TextCell.objects.create(page=page, placeholder='content', text='Foobaz', order=1, condition='False')
cell3 = LinkListCell.objects.create(order=1, page=page, placeholder='content')
LinkCell.objects.create(
page=page,
placeholder=cell3.link_placeholder,
title='Example Site',
url='http://example.net/',
order=0,
condition='True',
)
LinkCell.objects.create(
page=page,
placeholder=cell3.link_placeholder,
title='Other Site',
url='http://other.net/',
order=1,
condition='False',
)
app = login(app, username='normal-user', password='normal-user')
resp = app.get('/', status=200)
assert 'Foobar' in resp.text
assert 'Foobaz' not in resp.text
assert 'Example Site' in resp.text
assert 'Other Site' not in resp.text
def test_page_footer_acquisition(app):
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')

View File

@ -313,14 +313,15 @@ def test_search_custom_templates(app):
def test_search_cell_visibility(settings, app):
request = RequestFactory().get('/')
page = Page.objects.create(title='example page', slug='example-page')
settings.COMBO_SEARCH_SERVICES = SEARCH_SERVICES
cell = SearchCell(page=page, order=0)
assert not cell.is_visible()
assert not cell.is_visible(request)
cell._search_services = {'data': ['_text']}
assert cell.is_visible()
assert cell.is_visible(request)
def test_search_contents():
@ -1394,6 +1395,7 @@ def test_index_site_inactive_placeholder(app):
def test_index_site_invalid_cell(app):
request = RequestFactory().get('/')
page = Page.objects.create(title='page', slug='example-page')
cell = TextCell.objects.create(page=page, placeholder='content', text='<p>foobar</p>', order=0)
@ -1402,7 +1404,7 @@ def test_index_site_invalid_cell(app):
# invalid cell since just now
cell.mark_as_invalid(reason_code='foobar')
assert cell.is_visible() is True
assert cell.is_visible(request) is True
index_site()
assert IndexedCell.objects.count() == 1
@ -1410,7 +1412,7 @@ def test_index_site_invalid_cell(app):
validity_info = cell.get_validity_info()
validity_info.invalid_since = now() - datetime.timedelta(days=2)
validity_info.save()
assert cell.is_visible() is False
assert cell.is_visible(request) is False
index_site()
assert IndexedCell.objects.count() == 0

View File

@ -1885,16 +1885,20 @@ def test_cards_cell_only_for_user(mock_send, context):
cell.only_for_user = False
cell.save()
assert cell.is_visible(user=None) is True
assert cell.is_visible(user=MockUserWithNameId()) is True
assert cell.is_visible(request=context['request']) is True
context['request'].user = MockUserWithNameId()
assert cell.is_visible(request=context['request']) 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
context['request'].user = None
assert cell.is_visible(request=context['request']) is False
context['request'].user = MockUserWithNameId()
assert cell.is_visible(request=context['request']) is True
cache.clear()
context['synchronous'] = True # to get fresh content
context['request'].user = None
mock_send.reset_mock()
cell.render(context)
@ -4224,6 +4228,79 @@ def test_manager_link_list_cell_duplicate():
assert new_item.cached_json == item.cached_json
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_cell_condition(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,
carddef_reference='default:card_model_1',
card_ids='{{ cards|objects:"card_model_1"|last|get:"id" }}',
)
cell.condition = 'cards|objects:"card_model_1"|getlist:"id"|list'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
cell.condition = 'cards|objects:"card_model_1"|getlist:"id"|get:42'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context.get('cells') or []) == 0
page.extra_variables = {'var1': 'cards|objects:"card_model_1"|getlist:"id"|list'}
page.save()
cell.condition = 'var1'
cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
page.extra_variables = {'var1': 'cards|objects:"card_model_1"|getlist:"id"|get:42'}
page.save()
resp = app.get(page.get_online_url())
assert len(resp.context.get('cells') or []) == 0
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_link_list_cell_condition(mock_send, nocache, app):
page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
cell = LinkListCell.objects.create(order=0, placeholder='content', page=page)
link_cell = LinkCell.objects.create(
page=page,
placeholder=cell.link_placeholder,
title='Example Site',
url='http://example.net/',
order=0,
)
link_cell.condition = 'cards|objects:"card_model_1"|getlist:"id"|list'
link_cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
assert 'Example Site' in resp
link_cell.condition = 'cards|objects:"card_model_1"|getlist:"id"|get:42'
link_cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
assert 'Example Site' not in resp
page.extra_variables = {'var1': 'cards|objects:"card_model_1"|getlist:"id"'}
page.save()
link_cell.condition = 'var1'
link_cell.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
assert 'Example Site' in resp
page.extra_variables = {'var1': 'cards|objects:"card_model_1"|getlist:"id"|get:42'}
page.save()
resp = app.get(page.get_online_url())
assert len(resp.context['cells']) == 1
assert 'Example Site' not in resp
@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')