data: add display condition to cells (#66263)
and also on each item of a linklist cell
This commit is contained in:
parent
9428431767
commit
794bb74c32
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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'):
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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')
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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'):
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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):
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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 &copy; <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',
|
||||
),
|
||||
),
|
||||
]
|
|
@ -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)
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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)
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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')
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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(':')
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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 []]
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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)
|
||||
|
|
|
@ -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'):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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': [
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in New Issue