Shortcodes for YouTube and iframes

Added shortcodes 2.5.0 as dependency; Earlier versions corrupted
non-ASCII characters, see
https://github.com/dmulholland/shortcodes/issues/6

The rendered elements have a `shortcode` CSS class.

The YouTube shortcode supports various ways to refer to a video:

    - `{youtube VideoID}`
    - `{youtube youtube.com or youtu.be URL}`

URLs containing an '=' should be quoted, or otherwise the shortcodes
library will parse it as "key=value" pair.

The IFrame shortcode supports the `cap` and `nocap` attributes. `cap`
indicates the required capability the user should have in order to
render the tag. If `nocap` is given, its contents are shown as a message
to users who do not have this tag; without it, the iframe is silently
hidden.

`{iframe src='https://source' cap='subscriber' nocap='Subscribe to view'}`

Merged test code + added HTML class for shortcode iframes
This commit is contained in:
2018-03-26 11:58:09 +02:00
parent 0841d52dd1
commit f4e0b9185b
9 changed files with 443 additions and 23 deletions

View File

@@ -1,12 +1,9 @@
import copy
from pillar.tests import AbstractPillarTest
from pillar.tests import common_test_data as ctd
class CoerceMarkdownTest(AbstractPillarTest):
def test_node_description(self):
from pillar.markdown import markdown
pid, uid = self.create_project_with_admin(24 * 'a')
self.create_valid_auth_token(uid, 'token-a')
node = {
@@ -23,10 +20,10 @@ class CoerceMarkdownTest(AbstractPillarTest):
node_id = created_data['_id']
json_node = self.get(f'/api/nodes/{node_id}', auth_token='token-a').json()
self.assertEqual(markdown(node['description']), json_node['_description_html'])
self.assertEqual('<h1>Title</h1>\n<p>This is content.</p>\n',
json_node['_description_html'])
def test_project_description(self):
from pillar.markdown import markdown
from pillar.api.utils import remove_private_keys
uid = self.create_user(24 * 'a', token='token-a')
@@ -50,4 +47,25 @@ class CoerceMarkdownTest(AbstractPillarTest):
json_proj.pop('node_types', None) # just to make it easier to print
import pprint
pprint.pprint(json_proj)
self.assertEqual(markdown(proj['description']), json_proj['_description_html'])
self.assertEqual('<h1>Title</h1>\n<p>This is content.</p>\n',
json_proj['_description_html'])
def test_comment_shortcodes(self):
pid, uid = self.create_project_with_admin(24 * 'a')
self.create_valid_auth_token(uid, 'token-a')
node = {
'node_type': 'group',
'name': 'Test group',
'description': '# Title\n\n{test a="b"}',
'properties': {},
'project': pid,
'user': uid,
}
created_data = self.post('/api/nodes', json=node, expected_status=201,
auth_token='token-a').json()
node_id = created_data['_id']
json_node = self.get(f'/api/nodes/{node_id}', auth_token='token-a').json()
expect = '<h1>Title</h1>\n<!-- {test a="b"} -->\n'
self.assertEqual(expect, json_node['_description_html'])

157
tests/test_shortcodes.py Normal file
View File

@@ -0,0 +1,157 @@
import unittest
from pillar.tests import AbstractPillarTest
class EscapeHTMLTest(unittest.TestCase):
def test_simple(self):
from pillar.shortcodes import comment_shortcodes
self.assertEqual(
"text\\n<!-- {shortcode abc='def'} -->\\n",
comment_shortcodes("text\\n{shortcode abc='def'}\\n")
)
def test_double_tags(self):
from pillar.shortcodes import comment_shortcodes
self.assertEqual(
"text\\n<!-- {shortcode abc='def'} -->hey<!-- {othercode} -->\\n",
comment_shortcodes("text\\n{shortcode abc='def'}hey{othercode}\\n")
)
class DegenerateTest(unittest.TestCase):
def test_degenerate_cases(self):
from pillar.shortcodes import render
self.assertEqual('', render(''))
with self.assertRaises(TypeError):
render(None)
class DemoTest(unittest.TestCase):
def test_demo(self):
from pillar.shortcodes import render
self.assertEqual('<dl><dt>test</dt></dl>', render('{test}'))
self.assertEqual('<dl><dt>test</dt><dt>a</dt><dd>b</dd></dl>', render('{test a="b"}'))
def test_unicode(self):
from pillar.shortcodes import render
self.assertEqual('<dl><dt>test</dt><dt>ü</dt><dd>é</dd></dl>', render('{test ü="é"}'))
class YouTubeTest(unittest.TestCase):
def test_missing(self):
from pillar.shortcodes import render
self.assertEqual('{youtube missing YouTube ID/URL}', render('{youtube}'))
def test_invalid(self):
from pillar.shortcodes import render
self.assertEqual(
'{youtube Unable to parse YouTube URL &#x27;https://attacker.com/&#x27;}',
render('{youtube https://attacker.com/}')
)
def test_id(self):
from pillar.shortcodes import render
self.assertEqual(
'<iframe class="shortcode youtube" width="560" height="315" '
'src="https://www.youtube.com/embed/ABCDEF?rel=0" frameborder="0" '
'allow="autoplay; encrypted-media" allowfullscreen></iframe>',
render('{youtube ABCDEF}')
)
def test_embed_url(self):
from pillar.shortcodes import render
self.assertEqual(
'<iframe class="shortcode youtube" width="560" height="315" '
'src="https://www.youtube.com/embed/ABCDEF?rel=0" frameborder="0" '
'allow="autoplay; encrypted-media" allowfullscreen></iframe>',
render('{youtube http://youtube.com/embed/ABCDEF}')
)
def test_youtu_be(self):
from pillar.shortcodes import render
self.assertEqual(
'<iframe class="shortcode youtube" width="560" height="315" '
'src="https://www.youtube.com/embed/NwVGvcIrNWA?rel=0" frameborder="0" '
'allow="autoplay; encrypted-media" allowfullscreen></iframe>',
render('{youtube https://youtu.be/NwVGvcIrNWA}')
)
def test_watch(self):
from pillar.shortcodes import render
self.assertEqual(
'<iframe class="shortcode youtube" width="560" height="315" '
'src="https://www.youtube.com/embed/NwVGvcIrNWA?rel=0" frameborder="0" '
'allow="autoplay; encrypted-media" allowfullscreen></iframe>',
render('{youtube "https://www.youtube.com/watch?v=NwVGvcIrNWA"}')
)
def test_width_height(self):
from pillar.shortcodes import render
self.assertEqual(
'<iframe class="shortcode youtube" width="5" height="3" '
'src="https://www.youtube.com/embed/NwVGvcIrNWA?rel=0" frameborder="0" '
'allow="autoplay; encrypted-media" allowfullscreen></iframe>',
render('{youtube "https://www.youtube.com/watch?v=NwVGvcIrNWA" width=5 height="3"}')
)
class IFrameTest(AbstractPillarTest):
def test_missing_cap(self):
from pillar.shortcodes import render
self.assertEqual('{iframe missing cap=&quot;somecap&quot;}', render('{iframe}'))
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('{iframe cap=subscriber}'))
self.assertEqual('', render('{iframe cap="subscriber"}'))
self.assertEqual(
'<p class="shortcode nocap">Aðeins áskrifendur hafa aðgang að þessu efni.</p>',
render('{iframe'
' cap="subscriber"'
' nocap="Aðeins áskrifendur hafa aðgang að þessu efni."}'))
def test_user_has_cap(self):
from pillar.shortcodes import render
roles = {'demo'}
uid = self.create_user(roles=roles)
with self.app.app_context():
self.login_api_as(uid, roles=roles)
self.assertEqual('<iframe class="shortcode"></iframe>',
render('{iframe cap=subscriber}'))
self.assertEqual('<iframe class="shortcode"></iframe>',
render('{iframe cap="subscriber"}'))
self.assertEqual('<iframe class="shortcode"></iframe>',
render('{iframe cap="subscriber" nocap="x"}'))
def test_attributes(self):
from pillar.shortcodes import render
roles = {'demo'}
uid = self.create_user(roles=roles)
md = '{iframe cap=subscriber zzz=xxx class="bigger" ' \
'src="https://docs.python.org/3/library/xml.etree.elementtree.html#functions"}'
expect = '<iframe class="shortcode bigger"' \
' src="https://docs.python.org/3/library/xml.etree.elementtree.html#functions"' \
' zzz="xxx">' \
'</iframe>'
with self.app.app_context():
self.login_api_as(uid, roles=roles)
self.assertEqual(expect, render(md))

View File

@@ -23,9 +23,21 @@ class MarkdownTest(unittest.TestCase):
def test_markdowned(self):
from pillar.web import jinja
self.assertEqual(None, jinja.do_markdowned({'eek': None}, 'eek'))
self.assertEqual('', jinja.do_markdowned({'eek': None}, 'eek'))
self.assertEqual('<p>ook</p>\n', jinja.do_markdowned({'eek': 'ook'}, 'eek'))
self.assertEqual('<p>ook</p>\n', jinja.do_markdowned(
{'eek': 'ook', '_eek_html': None}, 'eek'))
self.assertEqual('prerendered', jinja.do_markdowned(
{'eek': 'ook', '_eek_html': 'prerendered'}, 'eek'))
def test_markdowned_with_shortcodes(self):
from pillar.web import jinja
self.assertEqual(
'<dl><dt>test</dt><dt>a</dt><dd>b</dd><dt>c</dt><dd>d</dd></dl>\n',
jinja.do_markdowned({'eek': '{test a="b" c="d"}'}, 'eek'))
self.assertEqual(
'<h1>Title</h1>\n<p>Before</p>\n'
'<dl><dt>test</dt><dt>a</dt><dd>b</dd><dt>c</dt><dd>d</dd></dl>\n',
jinja.do_markdowned({'eek': '# Title\n\nBefore\n{test a="b" c="d"}'}, 'eek'))