Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Feature #89: Auto link key terms #15

Merged
merged 19 commits into from

4 participants

@sagarun

Completed this feature http://askbot.org/en/question/607/auto-linking-of-key-terms. Please verify and merge

@stultus

So we have to change the django.po file also right?

@evgenyfadeev

Arun, thanks, I will look through the pull requests by Monday.

@sagarun

Sure , Thanks!

@sagarun

Hi,

You can test it by using the following pattern and link:

#rhbz\s(\d+) <- pattern

https://bugzilla.redhat.com/show_bug.cgi?id=\\1 <- Link

@evgenyfadeev evgenyfadeev merged commit 10ff7a3 into ASKBOT:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 17, 2011
  1. @evgenyfadeev
  2. @evgenyfadeev
Commits on Sep 19, 2011
  1. @evgenyfadeev
Commits on Sep 20, 2011
  1. @evgenyfadeev

    fixed incorrect usage of diff_date in the templates, added a better t…

    evgenyfadeev authored
    …est for the responses page, and improved error checking in PageLoadTests
  2. @ragsagar
  3. @ragsagar
  4. @ragsagar
  5. @evgenyfadeev
  6. @evgenyfadeev
Commits on Sep 21, 2011
  1. @evgenyfadeev

    Merge branch 'stultus'

    evgenyfadeev authored
  2. @evgenyfadeev

    pylinted files

    evgenyfadeev authored
  3. @evgenyfadeev
  4. @evgenyfadeev

    removed unused file

    evgenyfadeev authored
  5. @evgenyfadeev
Commits on Sep 23, 2011
  1. @evgenyfadeev

    incremented revision

    evgenyfadeev authored
Commits on Sep 24, 2011
  1. @sagarun

    Merge branch 'auto-link'

    sagarun authored
  2. @sagarun
  3. @sagarun
This page is out of date. Refresh to see the latest.
View
1  MANIFEST.in
@@ -4,6 +4,7 @@ include LICENSE
include AUTHORS
include COPYING
include README.rst
+include askbot_requirements.txt
recursive-include askbot *
recursive-exclude askbot *.pyc
recursive-exclude .git
View
2  askbot/__init__.py
@@ -9,7 +9,7 @@
import sys
import logging
-VERSION = (0, 7, 22)
+VERSION = (0, 7, 23)
#necessary for interoperability of django and coffin
try:
View
27 askbot/conf/markup.py
@@ -113,12 +113,12 @@ def regex_settings_validation(*args):
'PATTERN',
description=_('Regex to detect the pattern'),
help_text=_(
- 'Enter a valid regular expression to '
- 'detect the pattern. For example to'
- 'detect something like #rhbz 637402 '
- 'use a regular expression like #rhbz\s(\d+)'
- 'If you want to process multiple regex enter'
- ' them line by line'
+ ' Enter valid regular expressions to'
+ ' detect patterns. If you want to auto'
+ ' link more than one key terms enter them'
+ ' line by line. For example to'
+ ' detect a bug pattern like #rhbz 637402'
+ ' you will have use the following regex #rhbz\s(\d+)'
),
update_callback=regex_settings_validation,
default = ''
@@ -131,13 +131,14 @@ def regex_settings_validation(*args):
'AUTO_LINK_URL',
description=_('URL for autolinking'),
help_text=_(
- 'Let us assume that to detect a pattern #rhbz 637402'
- ' the regex is #rhbz\s(\d+) '
- 'then the autolink URL should be https://bugzilla.redhat.com/show_bug.cgi?id=\1'
- ' Where \1 is the saved match (bugid) from the regular expression'
- ' If you want to process multiple regex enter'
- ' them line by line. The URL in first line will be used to link the'
- ' pattern on the first line'
+ ' The regex to detect pattern #rhbz 637402'
+ ' is #rhbz\s(\d+), If you want to auto link it to the actual bug'
+ ' then the autolink URL should be entered here. Example URL can be'
+ ' https://bugzilla.redhat.com/show_bug.cgi?id=\\1'
+ ' where \\1 is the saved match (bugid) from the regular expression.'
+ ' Multiple URLs should be entered in separate lines.'
+ ' The URL entered in first line'
+ ' will be used to auto link the first pattern or key term'
),
default = ''
)
View
19 askbot/conf/site_settings.py
@@ -5,8 +5,6 @@
from askbot.conf.settings_wrapper import settings
from askbot.deps import livesettings
from django.utils.translation import ugettext as _
-from django.utils.html import escape
-from askbot import const
QA_SITE_SETTINGS = livesettings.ConfigurationGroup(
'QA_SITE_SETTINGS',
@@ -74,19 +72,16 @@
settings.register(
livesettings.StringValue(
QA_SITE_SETTINGS,
- 'GREETING_URL',
- default='/' + _('faq/'),#cannot reverse url here, must be absolute also
- hidden=True,
+ 'GREETING_FOR_ANONYMOUS_USER',
+ default='First time here? Check out the FAQ!',
+ hidden=False,
description=_(
- 'Link shown in the greeting message '
+ 'Text shown in the greeting message '
'shown to the anonymous user'
),
- help_text=_('If you change this url from the default - '
- 'then you will also probably want to adjust translation of '
- 'the following string: ') + '"'
- + escape(const.GREETING_FOR_ANONYMOUS_USER + '"'
- ' You can find this string in your locale django.po file'
- )
+ help_text=_(
+ 'Use HTML to format the message '
+ )
)
)
View
1  askbot/const/__init__.py
@@ -263,6 +263,7 @@
'facebook-apps': 'http://www.facebook.com/developers/createapp.php',
'google-webmaster-tools': 'https://www.google.com/webmasters/tools/home',
'identica-apps': 'http://identi.ca/settings/oauthapps',
+ 'noscript': 'https://www.google.com/support/bin/answer.py?answer=23852',
'linkedin-apps': 'https://www.linkedin.com/secure/developer',
'mathjax': 'http://www.mathjax.org/resources/docs/?installation.html',
'recaptcha': 'http://google.com/recaptcha',
View
9 askbot/const/message_keys.py
@@ -9,14 +9,7 @@
#NOTE: all strings must be explicitly put into this dictionary,
#because you don't want to import _ from here with import *
-__all__ = ['GREETING_FOR_ANONYMOUS_USER', ]
-
-#this variable is shown in settings, because
-#the url within is configurable, the default is reverse('faq')
-#if user changes url they will have to be able to fix the
-#message translation too
-GREETING_FOR_ANONYMOUS_USER = \
- _('First time here? Check out the <a href="%s">FAQ</a>!')
+__all__ = []
#messages loaded in the templates via direct _ calls
_('most relevant questions')
View
4 askbot/context.py
@@ -5,6 +5,7 @@
from django.conf import settings
import askbot
from askbot import api
+from askbot import const
from askbot.conf import settings as askbot_settings
from askbot.skins.loaders import get_skin
from askbot.utils import url_utils
@@ -22,5 +23,6 @@ def application_settings(request):
return {
'settings': my_settings,
'skin': get_skin(request),
- 'moderation_items': api.get_info_on_moderation_items(request.user)
+ 'moderation_items': api.get_info_on_moderation_items(request.user),
+ 'noscript_url': const.DEPENDENCY_URLS['noscript'],
}
View
8 askbot/doc/source/changelog.rst
@@ -1,16 +1,18 @@
Changes in Askbot
=================
-Development version
+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)
* Added noscript message (Arun SAG)
* Support for url shortening with TinyUrl on link sharing (Rtnpro)
* Allowed logging in with password and email in the place of login name (Evgeny)
* Added config settings allowing adjust license information (Evgeny)
-0.7.22 (Current Version)
-------------------------
+0.7.22
+------
* Media resource revision is now incremented
automatically any time when media is updated (Adolfo Fitoria, Evgeny Fadeev)
* First user automatically becomes site administrator (Adolfo Fitoria)
View
2  askbot/doc/source/contributors.rst
@@ -15,10 +15,12 @@ Programming and documentation
* Andy Knotts
* Benoit Lavine (with Windriver Software, Inc.)
* Jeff Madynski
+* `Hrishi <https://github.com/stultus>`_
* Andrei Mamoutkine
* Ramiro Morales (with Machinalis)
* `NoahY <https://github.com/NoahY>`_
* `Gael Pasgrimaud <http://www.gawel.org/>`_ (bearstech)
+* `Rag Sagar <https://github.com/ragsagar>`_
* Alex Robbins (celery support)
* `Tomasz Szynalski <http://antimoon.com>`_
View
31 askbot/forms.py
@@ -968,19 +968,26 @@ def __init__(self, *arg, **kwarg):
class EditUserEmailFeedsForm(forms.Form):
FORM_TO_MODEL_MAP = {
- 'all_questions':'q_all',
- 'asked_by_me':'q_ask',
- 'answered_by_me':'q_ans',
- 'individually_selected':'q_sel',
- 'mentions_and_comments':'m_and_c',
- }
+ 'all_questions':'q_all',
+ 'asked_by_me':'q_ask',
+ 'answered_by_me':'q_ans',
+ 'individually_selected':'q_sel',
+ 'mentions_and_comments':'m_and_c',
+ }
NO_EMAIL_INITIAL = {
- 'all_questions':'n',
- 'asked_by_me':'n',
- 'answered_by_me':'n',
- 'individually_selected':'n',
- 'mentions_and_comments':'n',
- }
+ 'all_questions':'n',
+ 'asked_by_me':'n',
+ 'answered_by_me':'n',
+ 'individually_selected':'n',
+ 'mentions_and_comments':'n',
+ }
+ INSTANT_EMAIL_INITIAL = {
+ 'all_questions':'i',
+ 'asked_by_me':'i',
+ 'answered_by_me':'i',
+ 'individually_selected':'i',
+ 'mentions_and_comments':'i',
+ }
asked_by_me = EmailFeedSettingField(
label=_('Asked by me')
View
10 askbot/locale/en/LC_MESSAGES/django.po
@@ -499,7 +499,7 @@ msgstr ""
#: conf/email.py:22
msgid "Prefix for the email subject line"
-msgstr "Welcome to the Q&A forum"
+msgstr ""
#: conf/email.py:24
msgid ""
@@ -1600,10 +1600,10 @@ msgstr ""
msgid "bronze"
msgstr ""
-#: const/message_keys.py:19
-#, python-format
-msgid "First time here? Check out the <a href=\"%s\">FAQ</a>!"
-msgstr ""
+
+
+
+
#: const/message_keys.py:22 skins/default/templates/main_page/tab_bar.html:27
msgid "most relevant questions"
View
42 askbot/middleware/anon_user.py
@@ -1,13 +1,25 @@
-from django.utils.translation import ugettext as _
+"""middleware that allows anonymous users
+receive messages using the now deprecated `message_set()`
+interface of the user objects.
+
+To allow anonymous users accept messages, a special
+message manager is defined here, and :meth:`__deepcopy__()` method
+added to the :class:`AnonymousUser` so that user could be pickled.
+
+Secondly, it sends greeting message to anonymous users.
+"""
from askbot.user_messages import create_message, get_and_delete_messages
from askbot.conf import settings as askbot_settings
-from askbot import const
class AnonymousMessageManager(object):
+ """message manager for the anonymous user"""
def __init__(self, request):
self.request = request
+
def create(self, message=''):
+ """send message to anonymous user"""
create_message(self.request, message)
+
def get_and_delete(self):
messages = get_and_delete_messages(self.request)
return messages
@@ -19,18 +31,34 @@ def dummy_deepcopy(*arg):
return None
class ConnectToSessionMessagesMiddleware(object):
+ """middleware that attaches messages to anonymous users"""
def process_request(self, request):
if not request.user.is_authenticated():
#plug on deepcopy which may be called by django db "driver"
- request.user.__deepcopy__ = dummy_deepcopy
+ request.user.__deepcopy__ = dummy_deepcopy
#here request is linked to anon user
- request.user.message_set = AnonymousMessageManager(request)
+ request.user.message_set = AnonymousMessageManager(request)
request.user.get_and_delete_messages = \
request.user.message_set.get_and_delete
#also set the first greeting one time per session only
- if 'greeting_set' not in request.session:
+ if 'greeting_set' not in request.session and \
+ 'askbot_visitor' not in request.COOKIES:
request.session['greeting_set'] = True
- msg = _(const.GREETING_FOR_ANONYMOUS_USER) \
- % askbot_settings.GREETING_URL
+ msg = askbot_settings.GREETING_FOR_ANONYMOUS_USER
request.user.message_set.create(message=msg)
+
+ def process_response(self, request, response):
+ """ Adds the ``'askbot_visitor'``key to cookie if user ever authenticates so
+ that the anonymous user message won't be shown. """
+ if request.user.is_authenticated() and \
+ 'askbot_visitor' not in request.COOKIES :
+ #import datetime
+ #max_age = 365*24*60*60
+ #expires = datetime.datetime.strftime\
+ # (datetime.datetime.utcnow() +
+ # datetime.timedelta(seconds=max_age),\
+ # "%a, %d-%b-%Y %H:%M:%S GMT")
+ response.set_cookie('askbot_visitor', False)
+ return response
+
View
3  askbot/models/__init__.py
@@ -1202,6 +1202,8 @@ def user_post_question(
is_anonymous = False,
timestamp = None
):
+ """makes an assertion whether user can post the question
+ then posts it and returns the question object"""
self.assert_can_post_question()
@@ -2230,7 +2232,6 @@ def format_instant_notification_email(
'origin_post_title': origin_post.title,
'user_subscriptions_url': user_subscriptions_url,
}
- subject_line = mail.prefix_the_subject_line(subject_line)
return subject_line, template.render(Context(update_data))
#todo: action
View
4 askbot/models/meta.py
@@ -159,9 +159,9 @@ def get_owner(self):
return self.user
def get_updated_activity_data(self, created = False):
- if self.content_object.__class__.__name__ == 'Question':
+ if self.content_object.post_type == 'question':
return const.TYPE_ACTIVITY_COMMENT_QUESTION, self
- elif self.content_object.__class__.__name__ == 'Answer':
+ elif self.content_object.post_type == 'answer':
return const.TYPE_ACTIVITY_COMMENT_ANSWER, self
def get_response_receivers(self, exclude_list = None):
View
2  askbot/skins/default/templates/blocks/bottom_scripts.html
@@ -4,7 +4,7 @@
#}
<div id="no-javascript">
<noscript class="noscript">
- {% trans app_name = settings.APP_SHORT_NAME %}Please note: {{app_name}} requires javascript to work properly, please enable javascript in your browser{% endtrans %}
+ {% trans app_name = settings.APP_SHORT_NAME %}Please note: {{app_name}} requires javascript to work properly, please enable javascript in your browser, <a href="{{noscript_url}}">here is how</a>{% endtrans %}
</noscript>
</div>
<script type="text/javascript">
View
14 askbot/skins/default/templates/macros.html
@@ -246,9 +246,9 @@
<div class='post-update-info'>
{% if is_wiki %}
<p>
- {%- if post.__class__.__name__ == 'Question' -%}
+ {%- if post.post_type == 'question' -%}
{%- trans %}asked{% endtrans %}
- {% elif post.__class__.__name__ == 'Answer' %}
+ {% elif post.post_type == 'answer' %}
{%- trans %}answered{% endtrans %}
{% else %}
{%- trans %}posted{% endtrans %}
@@ -265,9 +265,9 @@
{% else %}
<p style="line-height:12px;">
{# todo: access to class names needs to be removed here #}
- {% if post.__class__.__name__=="Question" %}
+ {% if post.post_type == 'question' %}
{% trans %}asked{% endtrans %}
- {% elif post.__class__.name__=="Answer" %}
+ {% elif post.post_type == 'answer' %}
{% trans %}answered{% endtrans %}
{% else %}
{% trans %}posted{% endtrans %}
@@ -282,11 +282,11 @@
{% endif %}
</div>
{% elif contributor_type=="last_updater" %}
- {% if post.__class__.__name__ in ('Question', 'Answer') %}
+ {% if post.post_type in ('Question', 'Answer') %}
{% set last_edited_at = post.last_edited_at %}
{% set original_author = post.author %}
{% set update_author = post.last_edited_by %}
- {% elif post.__class__.__name__ in ('QuestionRevision', 'AnswerRevision') %}
+ {% elif post.post_type in ('QuestionRevision', 'AnswerRevision') %}
{% set last_edited_at = post.revised_at %}
{% set original_author = None %}{# fake value to force display widget in the revision views #}
{% set update_author = post.author %}
@@ -295,7 +295,7 @@
<div class='post-update-info'>
<p style="line-height:12px;">
<a
- {% if post.__class__.__name__ == 'Question' %}
+ {% if post.post_type == 'Question' %}
href="{% url question_revisions post.id %}"
{% else %}
href="{% url answer_revisions post.id %}"
View
4 askbot/skins/default/templates/user_profile/user_inbox.html
@@ -70,7 +70,7 @@
<a style="font-size:12px" href="{{ response.user.get_absolute_url() }}">{{ response.user.username }}</a>
<a style="text-decoration:none;" href="{{ response.response_url }}">
{{ response.response_type }}
- ({{ response.timestamp|diff_date(3, True) }}):<br/>
+ ({{ response.timestamp|diff_date(True) }}):<br/>
{{ response.response_snippet}}
</a>
</div>
@@ -84,7 +84,7 @@
<a style="font-size:12px" href="{{ nested_response.user.get_absolute_url() }}">{{ nested_response.user.username }}</a>
<a style="text-decoration:none;" href="{{ nested_response.response_url }}">
{{ nested_response.response_type }}
- ({{ nested_response.timestamp|diff_date(3, True) }}):<br/>
+ ({{ nested_response.timestamp|diff_date(True) }}):<br/>
{{ nested_response.response_snippet}}
</a>
</div>
View
2  askbot/skins/default/templates/user_profile/user_recent.html
@@ -7,7 +7,7 @@
<div style="padding-top:5px;font-size:13px;">
{% for act in activities %}
<div style="clear:both;line-height:20px" >
- <div style="width:180px;float:left">{{ act.time|diff_date(3) }}</div>
+ <div style="width:180px;float:left">{{ act.time|diff_date(True) }}</div>
<div style="width:150px;float:left">
<span class="user-action-{{ act.type_id }}">{{ act.type }}</span>
</div>
View
2  askbot/skins/default/templates/user_profile/user_votes.html
@@ -7,7 +7,7 @@
<div style="padding-top:5px;font-size:13px;">
{% for vote in votes %}
<div style="clear:both;line-height:20px" >
- <div style="width:150px;float:left">{{vote.voted_at|diff_date(3)}}</div>
+ <div style="width:150px;float:left">{{vote.voted_at|diff_date(True)}}</div>
<div style="width:30px;float:left">
{% if vote.vote==1 %}
<img src="{{"/images/vote-arrow-up-on.png"|media}}" title="{% trans %}upvote{% endtrans %}">
View
33 askbot/tests/page_load_tests.py
@@ -49,11 +49,22 @@ def try_url(
if template:
if isinstance(r.template, coffin.template.Template):
self.assertEqual(r.template.name, template)
- else:
+ elif isinstance(r.template, list):
#asuming that there is more than one template
template_names = ','.join([t.name for t in r.template])
print 'templates are %s' % template_names
+ if follow == False:
+ self.fail(
+ ('Have issue accessing %s. '
+ 'This should not have happened, '
+ 'since you are not expecting a redirect '
+ 'i.e. follow == False, there should be only '
+ 'one template') % url
+ )
+
self.assertEqual(r.template[0].name, template)
+ else:
+ raise Exception('unexpected error while runnig test')
class PageLoadTests(PageLoadTestCase):
fixtures = ['tmp/fixture2.json', ]
@@ -313,6 +324,26 @@ def test_user_urls_logged_in(self):
)
self.client.logout()
+ def test_inbox_page(self):
+ asker = models.User.objects.get(id = 2)
+ question = asker.post_question(
+ title = 'How can this happen?',
+ body_text = 'This is the body of my question',
+ tags = 'question answer test',
+ )
+ responder = models.User.objects.get(id = 3)
+ responder.post_answer(
+ question = question,
+ body_text = 'this is the answer text'
+ )
+ self.client.login(method = 'force', user_id = asker.id)
+ self.try_url(
+ 'user_profile',
+ kwargs={'id': asker.id, 'slug': slugify(asker.username)},
+ data={'sort':'inbox'},
+ template='user_profile/user_inbox.html',
+ )
+
class AvatarTests(AskbotTestCase):
def test_avatar_for_two_word_user_works(self):
View
7 askbot/utils/mail.py
@@ -15,9 +15,9 @@ def prefix_the_subject_line(subject):
EMAIL_SUBJECT_LINE_PREFIX either from
from live settings, which take default from django
"""
- prefix = askbot_settings.EMAIL_SUBJECT_PREFIX.strip()
+ prefix = askbot_settings.EMAIL_SUBJECT_PREFIX
if prefix != '':
- subject = prefix + ' ' + subject
+ subject = prefix.strip() + ' ' + subject.strip()
return subject
def extract_first_email_address(text):
@@ -89,10 +89,9 @@ def send_mail(
if raise_on_failure is True, exceptions.EmailNotSent is raised
"""
- prefix = askbot_settings.EMAIL_SUBJECT_PREFIX.strip() + ' '
try:
assert(subject_line is not None)
- subject_line = prefix + subject_line
+ subject_line = prefix_the_subject_line(subject_line)
msg = mail.EmailMessage(
subject_line,
body_text,
View
8 askbot/utils/markup.py
@@ -1,4 +1,5 @@
import re
+import logging
from askbot import const
from askbot.conf import settings as askbot_settings
from markdown2 import Markdown
@@ -27,10 +28,15 @@ def get_parser():
pattern_list = askbot_settings.PATTERN.split('\n')
url_list = askbot_settings.AUTO_LINK_URL.split('\n')
- # Check whether we have matching links for all key terms, Other wise we ignore the key terms
+ # 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?
if len(pattern_list) == len(url_list):
for i in range(0,len(pattern_list)):
LINK_PATTERNS.append((re.compile(pattern_list[i].strip()),url_list[i].strip()))
+ else:
+ settings_url = askbot_settings.APP_URL+'/settings/AUTOLINK/'
+ logging.debug("Number of keyterms didn't match the number of links, fix this by visiting" + settings_url)
+
return Markdown(
html4tags=True,
Something went wrong with that request. Please try again.