Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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 from
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.