Support for capabilities check in any shortcode

Use the @capcheck decorator on any shortcode that should support
this. Currently used by iframe and youtube.
This commit is contained in:
Francesco Siddi 2018-07-11 12:32:00 +02:00
parent 49075cbc60
commit 9f380751f5
2 changed files with 62 additions and 18 deletions

View File

@ -33,18 +33,57 @@ log = logging.getLogger(__name__)
def shortcode(name: str): def shortcode(name: str):
"""Class decorator for shortcodes.""" """Class decorator for shortcodes."""
def decorator(cls): def decorator(decorated):
assert hasattr(cls, '__call__'), '@shortcode should be used on callables.' assert hasattr(decorated, '__call__'), '@shortcode should be used on callables.'
if isinstance(cls, type): if isinstance(decorated, type):
instance = cls() as_callable = decorated()
else: else:
instance = cls as_callable = decorated
shortcodes.register(name)(instance) shortcodes.register(name)(as_callable)
return cls return decorated
return decorator return decorator
class capcheck:
"""Decorator for shortcodes.
On call, check for capabilities before calling the function. If the user does not
have a capability, display a message insdead of the content.
kwargs:
- 'cap': Capability required for viewing.
- 'nocap': Optional, text shown when the user does not have this capability.
- others: Passed to the decorated shortcode.
"""
def __init__(self, decorated):
assert hasattr(decorated, '__call__'), '@capcheck should be used on callables.'
if isinstance(decorated, type):
as_callable = decorated()
else:
as_callable = decorated
self.decorated = as_callable
def __call__(self,
context: typing.Any,
content: str,
pargs: typing.List[str],
kwargs: typing.Dict[str, str]) -> str:
from pillar.auth import current_user
cap = kwargs.pop('cap', '')
if cap:
nocap = kwargs.pop('nocap', '')
if not current_user.has_cap(cap):
if not nocap:
return ''
html = html_module.escape(nocap)
return f'<p class="shortcode nocap">{html}</p>'
return self.decorated(context, content, pargs, kwargs)
@shortcode('test') @shortcode('test')
class Test: class Test:
def __call__(self, def __call__(self,
@ -68,6 +107,7 @@ class Test:
@shortcode('youtube') @shortcode('youtube')
@capcheck
class YouTube: class YouTube:
log = log.getChild('YouTube') log = log.getChild('YouTube')
@ -129,6 +169,7 @@ class YouTube:
@shortcode('iframe') @shortcode('iframe')
@capcheck
def iframe(context: typing.Any, def iframe(context: typing.Any,
content: str, content: str,
pargs: typing.List[str], pargs: typing.List[str],
@ -140,16 +181,6 @@ def iframe(context: typing.Any,
- others: Turned into attributes for the iframe element. - others: Turned into attributes for the iframe element.
""" """
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from pillar.auth import current_user
cap = kwargs.pop('cap', '')
if cap:
nocap = kwargs.pop('nocap', '')
if not current_user.has_cap(cap):
if not nocap:
return ''
html = html_module.escape(nocap)
return f'<p class="shortcode nocap">{html}</p>'
kwargs['class'] = f'shortcode {kwargs.get("class", "")}'.strip() kwargs['class'] = f'shortcode {kwargs.get("class", "")}'.strip()
element = ET.Element('iframe', kwargs) element = ET.Element('iframe', kwargs)

View File

@ -40,7 +40,7 @@ class DemoTest(unittest.TestCase):
self.assertEqual('<dl><dt>test</dt><dt>ü</dt><dd>é</dd></dl>', render('{test ü="é"}')) self.assertEqual('<dl><dt>test</dt><dt>ü</dt><dd>é</dd></dl>', render('{test ü="é"}'))
class YouTubeTest(unittest.TestCase): class YouTubeTest(AbstractPillarTest):
def test_missing(self): def test_missing(self):
from pillar.shortcodes import render from pillar.shortcodes import render
@ -104,6 +104,19 @@ class YouTubeTest(unittest.TestCase):
render('{youtube "https://www.youtube.com/watch?v=NwVGvcIrNWA" width=5 height="3"}') render('{youtube "https://www.youtube.com/watch?v=NwVGvcIrNWA" width=5 height="3"}')
) )
def test_user_no_cap(self):
from pillar.shortcodes import render
with self.app.app_context():
# Anonymous user, so no subscriber capability.
self.assertEqual('', render('{youtube ABCDEF cap=subscriber}'))
self.assertEqual('', render('{youtube ABCDEF cap="subscriber"}'))
self.assertEqual(
'<p class="shortcode nocap">Aðeins áskrifendur hafa aðgang að þessu efni.</p>',
render('{youtube ABCDEF'
' cap="subscriber"'
' nocap="Aðeins áskrifendur hafa aðgang að þessu efni."}'))
class IFrameTest(AbstractPillarTest): class IFrameTest(AbstractPillarTest):
def test_missing_cap(self): def test_missing_cap(self):