Make bad links in Markdown not fail

Links such as []{pokemon:mewthree} can come from users, so they should not
crash the parser.
So, when an object is not found (or more than one is found), call
identifier_url() directly, instead of failing to get the object for
object_url(). Essentially, treat the link as having an unknown category
(like mechanic:, currently).

The test that check the pokédex descriptions updated so that only
links to known objects and "mechanic:" are allowed.
This commit is contained in:
Petr Viktorin 2011-09-12 18:56:23 +03:00
parent cdac374eed
commit 928eaca4a4
2 changed files with 49 additions and 32 deletions

View file

@ -170,21 +170,27 @@ class PokedexLinkPattern(markdown.inlinepatterns.Pattern):
query = query.join(tables.Pokemon.species)
query = query.filter(
tables.PokemonSpecies.identifier == pokemon_ident)
obj = query.one()
else:
obj = util.get(self.session, table, target)
url = self.factory.object_url(category, obj)
url = url or self.factory.identifier_url(category, target)
name = None
# Translations can be incomplete; in which case we want to use a
# fallback.
if table in [tables.Type] and self.string_language:
# Type wants to be localized to the same language as the text
name = obj.name_map.get(self.string_language)
if not name and self.game_language:
name = obj.name_map.get(self.game_language)
if not name:
name = obj.name
query = session.query(table)
query = query.filter(table.identifier == target)
try:
obj = query.one()
except Exception:
obj = name = target
url = self.factory.identifier_url(category, obj)
else:
url = self.factory.object_url(category, obj)
url = url or self.factory.identifier_url(category, target)
name = None
# Translations can be incomplete; in which case we want to use
# a fallback.
if table in [tables.Type] and self.string_language:
# Type wants to be localized to the text language
name = obj.name_map.get(self.string_language)
if not name and self.game_language:
name = obj.name_map.get(self.game_language)
if not name:
name = obj.name
if url:
el = self.factory.make_link(category, obj, url, label or name)
else:
@ -222,12 +228,18 @@ class PokedexLinkExtension(markdown.Extension):
Returns None by default, which causes <span> to be used in place of
<a>.
This method is also called for non-existent objects, e.g.
[]{pokemon:bogus}.
"""
return None
def object_url(self, category, obj):
"""Return the URL for the ORM object `obj`.
u"""Return the URL for the ORM object `obj`.
Returns None by default, which causes identifier_url to be tried.
Note that obj may be a Pokémon form. Unlike other returned objects,
these do not have identifiers. Be sure to test this case.
"""
return None

View file

@ -92,9 +92,9 @@ def test_markdown():
def test_markdown_string():
en = util.get(connection, tables.Language, 'en')
md = markdown.MarkdownString('[]{move:thunderbolt} [paralyzes]{mechanic:paralysis} []{form:sky shaymin}', connection, en)
assert unicode(md) == 'Thunderbolt paralyzes Sky Shaymin'
assert md.as_html() == '<p><span>Thunderbolt</span> <span>paralyzes</span> <span>Sky Shaymin</span></p>'
md = markdown.MarkdownString('[]{move:thunderbolt} [paralyzes]{mechanic:paralysis} []{form:sky shaymin}. []{pokemon:mewthree} does not exist.', connection, en)
assert unicode(md) == 'Thunderbolt paralyzes Sky Shaymin. mewthree does not exist.'
assert md.as_html() == '<p><span>Thunderbolt</span> <span>paralyzes</span> <span>Sky Shaymin</span>. <span>mewthree</span> does not exist.</p>'
class ObjectTestExtension(markdown.PokedexLinkExtension):
def object_url(self, category, obj):
@ -106,12 +106,12 @@ def test_markdown_string():
class IdentifierTestExtension(markdown.PokedexLinkExtension):
def identifier_url(self, category, ident):
return "%s/%s" % (category, ident)
return "%s/%s" % (category, ident)
assert md.as_html(extension_cls=ObjectTestExtension) == (
'<p><a href="move/thunderbolt">Thunderbolt</a> <span>paralyzes</span> <a href="form/sky shaymin">Sky Shaymin</a></p>')
'<p><a href="move/thunderbolt">Thunderbolt</a> <span>paralyzes</span> <a href="form/sky shaymin">Sky Shaymin</a>. <span>mewthree</span> does not exist.</p>')
assert md.as_html(extension_cls=IdentifierTestExtension) == (
'<p><a href="move/thunderbolt">Thunderbolt</a> <a href="mechanic/paralysis">paralyzes</a> <a href="form/sky shaymin">Sky Shaymin</a></p>')
'<p><a href="move/thunderbolt">Thunderbolt</a> <a href="mechanic/paralysis">paralyzes</a> <a href="form/sky shaymin">Sky Shaymin</a>. <a href="pokemon/mewthree">mewthree</a> does not exist.</p>')
def markdown_column_params():
"""Check all markdown values
@ -136,23 +136,28 @@ def test_markdown_values(parent_class, translation_class, column_name):
query = connection.query(parent_class)
if translation_class:
query = query.join(translation_class)
for item in query:
for language, markdown in getattr(item, column_name + '_map').items():
if markdown is None:
for item in query:
for language, md_text in getattr(item, column_name + '_map').items():
if md_text is None:
continue
key = u"Markdown in {0} #{1}'s {2} (lang={3})".format(
parent_class.__name__, item.id, column_name, language.identifier)
try:
text = markdown.as_text()
except NoResultFound:
assert False, u"{0} references something that doesn't exist:\n{1}".format(
key, markdown.source_text)
except AttributeError:
print markdown
raise
class TestExtension(markdown.PokedexLinkExtension):
def object_url(self, category, obj):
"Swallow good links"
return 'ok'
def identifier_url(self, category, ident):
"Only allow mechanic links here (good links handled in object_url)"
assert category == 'mechanic', (
'%s: unknown link target: {%s:%s}' %
(key, category, ident))
text = md_text.as_html(extension_cls=TestExtension)
error_message = u"{0} leaves syntax cruft:\n{1}"
error_message = error_message.format(key, text)