Permalink
Browse files

merged the autolink patterns branch by Arun

  • Loading branch information...
2 parents 2c1abd0 + 56b83e9 commit b208c5648d4fbf810b65283db4a6eae151839570 @evgenyfadeev evgenyfadeev committed Sep 26, 2011
Showing with 140 additions and 16 deletions.
  1. +77 −3 askbot/conf/markup.py
  2. +5 −4 askbot/doc/source/changelog.rst
  3. +58 −9 askbot/utils/markup.py
View
@@ -4,17 +4,34 @@
from askbot.conf.settings_wrapper import settings
from askbot.deps.livesettings import ConfigurationGroup
-from askbot.deps.livesettings import BooleanValue, StringValue
+from askbot.deps.livesettings import BooleanValue, StringValue, LongStringValue
from django.utils.translation import ugettext as _
-import askbot
from askbot import const
-import os
+import re
MARKUP = ConfigurationGroup(
'MARKUP',
_('Markup formatting')
)
+def regex_settings_validation(*args):
+ """
+ Validate the regular expressions
+ """
+ try:
+
+ new_value = args[1]
+ regex_list = new_value.split('\n')
+
+ for i in range(0, len(regex_list)):
+ re.compile(regex_list[i].strip())
+ return args[1]
+
+ except Exception:
+ # The regex is invalid, so we overwrite it with empty string
+ return ""
+
+
settings.register(
BooleanValue(
MARKUP,
@@ -63,3 +80,60 @@
default = ''
)
)
+
+
+settings.register(
+ BooleanValue(
+ MARKUP,
+ 'ENABLE_AUTO_LINKING',
+ description=_('Enable autolinking with specific patterns'),
+ help_text=_(
+ 'If you enable this feature, '
+ 'the application will be able to '
+ 'detect patterns and auto link to URLs'
+ ),
+ default = False
+ )
+)
+
+
+settings.register(
+ LongStringValue(
+ MARKUP,
+ 'AUTO_LINK_PATTERNS',
+ description=_('Regexes to detect the link patterns'),
+ help_text=_(
+ 'Enter valid regular expressions for the patters,'
+ ' one per line.'
+ ' For example to'
+ ' detect a bug pattern like #bug123,'
+ ' use the following regex: #bug(\d+). The numbers'
+ ' captured by the pattern in the parentheses will'
+ ' be transferred to the link url template.'
+ ' Please look up more information about regular'
+ ' expressions elsewhere.'
+ ),
+ update_callback=regex_settings_validation,
+ default = ''
+ )
+ )
+
+settings.register(
+ LongStringValue(
+ MARKUP,
+ 'AUTO_LINK_URLS',
+ description=_('URLs for autolinking'),
+ help_text=_(
+ 'Here, please enter url templates for the patterns'
+ ' entered in the previous setting, also one entry per line.'
+ ' <strong>Make sure that number of lines in this setting'
+ ' and the previous one are the same</strong>'
+ ' For example template'
+ ' https://bugzilla.redhat.com/show_bug.cgi?id=\\1'
+ ' together with the pattern shown above'
+ ' and the entry in the post #123'
+ ' will produce link to the bug 123 in the redhat bug tracker.'
+ ),
+ default = ''
+ )
+)
@@ -1,12 +1,13 @@
Changes in Askbot
=================
-0.7.24 (development version - not released)
--------------------------------------------
+Development version (not released yet)
+--------------------------------------
* Added annotations for the meanings of user levels on the "moderation" page. (Jishnu)
+* Auto-link patterns - e.g. to bug databases - are configurable from settings. (Arun SAG)
-0.7.23 (Current)
--------------------
+0.7.23 (Current Version)
+------------------------
* Greeting for anonymuos users can be changed from live settings (Hrishi)
* Greeting for anonymous users is shown only once (Rag Sagar)
* Added support for Akismet spam detection service (Adolfo Fitoria)
View
@@ -1,16 +1,24 @@
+"""methods that make parsing of post inputs possible,
+handling of markdown and additional syntax rules -
+such as optional link patterns, video embedding and
+Twitter-style @mentions"""
+
import re
+import logging
from askbot import const
from askbot.conf import settings as askbot_settings
from markdown2 import Markdown
-
#url taken from http://regexlib.com/REDetails.aspx?regexp_id=501 by Brian Bothwell
URL_RE = re.compile("((?<!(href|.src|data)=['\"])((http|https|ftp)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&amp;%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&amp;%\$#\=~_\-]+))*))")
LINK_PATTERNS = [
(URL_RE, r'\1'),
]
+
def get_parser():
+ """returns an instance of configured ``markdown2`` parser
+ """
extras = ['link-patterns', 'video']
if askbot_settings.ENABLE_MATHJAX or \
askbot_settings.MARKUP_CODE_FRIENDLY:
@@ -22,6 +30,30 @@ def get_parser():
#pip install -e git+git://github.com/andryuha/python-markdown2.git
extras.append('video')
+ if askbot_settings.ENABLE_AUTO_LINKING:
+ pattern_list = askbot_settings.AUTO_LINK_PATTERNS.split('\n')
+ url_list = askbot_settings.AUTO_LINK_URLS.split('\n')
+ pairs = zip(pattern_list, url_list)#always takes equal number of items
+ for item in pairs:
+ LINK_PATTERNS.append(
+ (
+ re.compile(item[0]),
+ item[1].strip()
+ )
+ )
+
+ #Check whether we have matching links for all key terms,
+ #Other wise we ignore the key terms
+ #May be we should do this test in update_callback?
+ #looks like this might be a defect of livesettings
+ #as there seems to be no way
+ #to validate entries that depend on each other
+ if len(pattern_list) != len(url_list):
+ settings_url = askbot_settings.APP_URL+'/settings/AUTOLINK/'
+ logging.critical(
+ "Number of autolink patterns didn't match the number "
+ "of url templates, fix this by visiting" + settings_url)
+
return Markdown(
html4tags=True,
extras=extras,
@@ -30,18 +62,23 @@ def get_parser():
def format_mention_in_html(mentioned_user):
+ """formats mention as url to the user profile"""
url = mentioned_user.get_profile_url()
username = mentioned_user.username
return '<a href="%s">@%s</a>' % (url, username)
def extract_first_matching_mentioned_author(text, anticipated_authors):
+ """matches beginning of ``text`` string with the names
+ of ``anticipated_authors`` - list of user objects.
+ Returns upon first match the first matched user object
+ and the remainder of the ``text`` that is left unmatched"""
if len(text) == 0:
return None, ''
- for a in anticipated_authors:
- if text.lower().startswith(a.username.lower()):
- ulen = len(a.username)
+ for author in anticipated_authors:
+ if text.lower().startswith(author.username.lower()):
+ ulen = len(author.username)
if len(text) == ulen:
text = ''
elif text[ulen] in const.TWITTER_STYLE_MENTION_TERMINATION_CHARS:
@@ -50,37 +87,49 @@ def extract_first_matching_mentioned_author(text, anticipated_authors):
#near miss, here we could insert a warning that perhaps
#a termination character is needed
continue
- return a, text
+ return author, text
return None, text
def extract_mentioned_name_seeds(text):
+ """Returns list of strings that
+ follow the '@' symbols in the text.
+ The strings will be 10 characters long,
+ or shorter, if the subsequent character
+ is one of the list accepted to be termination
+ characters.
+ """
extra_name_seeds = set()
while '@' in text:
pos = text.index('@')
text = text[pos+1:]#chop off prefix
name_seed = ''
- for c in text:
- if c in const.TWITTER_STYLE_MENTION_TERMINATION_CHARS:
+ for char in text:
+ if char in const.TWITTER_STYLE_MENTION_TERMINATION_CHARS:
extra_name_seeds.add(name_seed)
name_seed = ''
break
if len(name_seed) > 10:
extra_name_seeds.add(name_seed)
name_seed = ''
break
- if c == '@':
+ if char == '@':
if len(name_seed) > 0:
extra_name_seeds.add(name_seed)
name_seed = ''
break
- name_seed += c
+ name_seed += char
if len(name_seed) > 0:
#in case we run off the end of text
extra_name_seeds.add(name_seed)
return extra_name_seeds
def mentionize_text(text, anticipated_authors):
+ """Returns a tuple of two items:
+ * modified text where @mentions are
+ replaced with urls to the corresponding user profiles
+ * list of users whose names matched the @mentions
+ """
output = ''
mentioned_authors = list()
while '@' in text:

0 comments on commit b208c56

Please sign in to comment.