summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--askbot/conf/minimum_reputation.py9
-rw-r--r--askbot/conf/settings_wrapper.py4
-rw-r--r--askbot/conf/sidebar_main.py18
-rw-r--r--askbot/conf/sidebar_profile.py23
-rw-r--r--askbot/conf/sidebar_question.py36
-rw-r--r--askbot/conf/site_modes.py1
-rw-r--r--askbot/doc/source/changelog.rst3
-rw-r--r--askbot/doc/source/contributors.rst1
-rw-r--r--askbot/doc/source/management-commands.rst5
-rw-r--r--askbot/management/commands/apply_hinted_tags.py58
-rw-r--r--askbot/management/commands/send_email_alerts.py49
-rw-r--r--askbot/media/js/live_search.js42
-rw-r--r--askbot/media/js/utils.js353
-rw-r--r--askbot/media/style/style.css105
-rw-r--r--askbot/media/style/style.less118
-rw-r--r--askbot/models/__init__.py14
-rw-r--r--askbot/models/question.py58
-rw-r--r--askbot/setup_templates/settings.py6
-rw-r--r--askbot/setup_templates/settings.py.mustache16
-rw-r--r--askbot/templates/base.html1
-rw-r--r--askbot/templates/main_page/sidebar.html4
-rw-r--r--askbot/templates/meta/bottom_scripts.html8
-rw-r--r--askbot/templates/meta/html_head_javascript.html2
-rw-r--r--askbot/templates/question.html2
-rw-r--r--askbot/templates/question/content.html2
-rw-r--r--askbot/templates/question/sidebar.html17
-rw-r--r--askbot/templates/user_profile/user.html11
-rw-r--r--askbot/templates/widgets/ask_form.html1
-rw-r--r--askbot/templates/widgets/user_long_score_and_badge_summary.html6
-rw-r--r--askbot/templates/widgets/user_perms.html28
-rw-r--r--askbot/templatetags/extra_filters_jinja.py9
-rw-r--r--askbot/tests/cache_tests.py15
-rw-r--r--askbot/tests/db_api_tests.py7
-rw-r--r--askbot/tests/email_alert_tests.py26
-rw-r--r--askbot/tests/email_parsing_tests.py7
-rw-r--r--askbot/tests/management_command_tests.py11
-rw-r--r--askbot/tests/post_model_tests.py3
-rw-r--r--askbot/tests/question_views_tests.py5
-rw-r--r--askbot/urls.py7
-rw-r--r--askbot/utils/slug.py7
-rw-r--r--askbot/views/readers.py62
-rw-r--r--askbot/views/users.py3
42 files changed, 864 insertions, 299 deletions
diff --git a/askbot/conf/minimum_reputation.py b/askbot/conf/minimum_reputation.py
index 229edf96..19b5e69d 100644
--- a/askbot/conf/minimum_reputation.py
+++ b/askbot/conf/minimum_reputation.py
@@ -195,15 +195,6 @@ settings.register(
settings.register(
livesettings.IntegerValue(
MIN_REP,
- 'MIN_REP_TO_LOCK_POSTS',
- default=400,
- description=_('Lock posts')
- )
-)
-
-settings.register(
- livesettings.IntegerValue(
- MIN_REP,
'MIN_REP_TO_HAVE_STRONG_URL',
default=25,
description=_('Remove rel=nofollow from own homepage'),
diff --git a/askbot/conf/settings_wrapper.py b/askbot/conf/settings_wrapper.py
index b6b5f302..0a4ba45f 100644
--- a/askbot/conf/settings_wrapper.py
+++ b/askbot/conf/settings_wrapper.py
@@ -53,6 +53,10 @@ class ConfigSettings(object):
"""return the defalut value for the setting"""
return getattr(self.__instance, key).default
+ def get_description(self, key):
+ """returns descriptive title of the setting"""
+ return unicode(getattr(self.__instance, key).description)
+
def reset(self, key):
"""returns setting to the default value"""
self.update(key, self.get_default(key))
diff --git a/askbot/conf/sidebar_main.py b/askbot/conf/sidebar_main.py
index 8fa4bdf0..97b89e37 100644
--- a/askbot/conf/sidebar_main.py
+++ b/askbot/conf/sidebar_main.py
@@ -32,6 +32,15 @@ settings.register(
settings.register(
values.BooleanValue(
SIDEBAR_MAIN,
+ 'SIDEBAR_MAIN_HEADER_ANON_ONLY',
+ description=_('Show above only to anonymous users'),
+ default=False
+ )
+)
+
+settings.register(
+ values.BooleanValue(
+ SIDEBAR_MAIN,
'SIDEBAR_MAIN_SHOW_AVATARS',
description = _('Show avatar block in sidebar'),
help_text = _(
@@ -94,3 +103,12 @@ settings.register(
)
)
+settings.register(
+ values.BooleanValue(
+ SIDEBAR_MAIN,
+ 'SIDEBAR_MAIN_FOOTER_ANON_ONLY',
+ default=False,
+ description=_('Show above only to anonymous users')
+ )
+)
+
diff --git a/askbot/conf/sidebar_profile.py b/askbot/conf/sidebar_profile.py
index 948daa4a..a216de4b 100644
--- a/askbot/conf/sidebar_profile.py
+++ b/askbot/conf/sidebar_profile.py
@@ -16,8 +16,8 @@ SIDEBAR_PROFILE = ConfigurationGroup(
settings.register(
values.LongStringValue(
SIDEBAR_PROFILE,
- 'SIDEBAR_PROFILE_HEADER',
- description = _('Custom sidebar header'),
+ 'SIDEBAR_PROFILE',
+ description = _('Custom sidebar'),
default = '',
help_text = _(
'Use this area to enter content at the TOP of the sidebar'
@@ -25,23 +25,16 @@ settings.register(
'(as well as the sidebar footer), please '
'use the HTML validation service to make sure that '
'your input is valid and works well in all browsers.'
- )
+ )
)
)
+
settings.register(
- values.LongStringValue(
+ values.BooleanValue(
SIDEBAR_PROFILE,
- 'SIDEBAR_PROFILE_FOOTER',
- description = _('Custom sidebar footer'),
- default = '',
- help_text = _(
- 'Use this area to enter content at the BOTTOM of the sidebar'
- 'in HTML format. When using this option '
- '(as well as the sidebar header), please '
- 'use the HTML validation service to make sure that '
- 'your input is valid and works well in all browsers.'
- )
+ 'SIDEBAR_PROFILE_ANON_ONLY',
+ description=_('Show above only to anonymous users'),
+ default=False
)
)
-
diff --git a/askbot/conf/sidebar_question.py b/askbot/conf/sidebar_question.py
index ffe2f783..8d38692a 100644
--- a/askbot/conf/sidebar_question.py
+++ b/askbot/conf/sidebar_question.py
@@ -27,6 +27,15 @@ settings.register(
)
settings.register(
+ values.BooleanValue(
+ SIDEBAR_QUESTION,
+ 'QUESTION_PAGE_TOP_BANNER_ANON_ONLY',
+ default=False,
+ description=_('Show above only to anonymous users'),
+ )
+)
+
+settings.register(
values.LongStringValue(
SIDEBAR_QUESTION,
'QUESTION_PAGE_ANSWER_BANNER',
@@ -42,6 +51,16 @@ settings.register(
)
settings.register(
+ values.BooleanValue(
+ SIDEBAR_QUESTION,
+ 'QUESTION_PAGE_ANSWER_BANNER_ANON_ONLY',
+ default=False,
+ description=_('Show above only to anonymous users'),
+ )
+)
+
+
+settings.register(
values.LongStringValue(
SIDEBAR_QUESTION,
'SIDEBAR_QUESTION_HEADER',
@@ -60,6 +79,15 @@ settings.register(
settings.register(
values.BooleanValue(
SIDEBAR_QUESTION,
+ 'SIDEBAR_QUESTION_HEADER_ANON_ONLY',
+ default=False,
+ description=_('Show above only to anonymous users')
+ )
+)
+
+settings.register(
+ values.BooleanValue(
+ SIDEBAR_QUESTION,
'SIDEBAR_QUESTION_SHOW_TAGS',
description = _('Show tag list in sidebar'),
help_text = _(
@@ -113,3 +141,11 @@ settings.register(
)
)
+settings.register(
+ values.BooleanValue(
+ SIDEBAR_QUESTION,
+ 'SIDEBAR_QUESTION_FOOTER_ANON_ONLY',
+ default=False,
+ description=_('Show above only to anonymous users')
+ )
+)
diff --git a/askbot/conf/site_modes.py b/askbot/conf/site_modes.py
index 7c81341e..feadd32b 100644
--- a/askbot/conf/site_modes.py
+++ b/askbot/conf/site_modes.py
@@ -27,7 +27,6 @@ LARGE_SITE_MODE_SETTINGS = {
'MIN_REP_TO_EDIT_OTHERS_POSTS': 2000,
'MIN_REP_TO_VIEW_OFFENSIVE_FLAGS': 2000,
'MIN_REP_TO_CLOSE_OTHERS_QUESTIONS': 2000,
- 'MIN_REP_TO_LOCK_POSTS': 4000,
'MIN_REP_TO_HAVE_STRONG_URL': 250,
#badge settings
'NOTABLE_QUESTION_BADGE_MIN_VIEWS': 250,
diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst
index cda70e77..48afb5ea 100644
--- a/askbot/doc/source/changelog.rst
+++ b/askbot/doc/source/changelog.rst
@@ -3,6 +3,9 @@ Changes in Askbot
Development version
-------------------
+* Added management command `apply_hinted_tags` to batch-apply tags from a list
+* Added hovercard on the user's karma display in the header
+* Added option to hide ad blocks from logged in users
* Applied Askbot templates to the settings control panel
* Added option to auto-follow questions by the question posters with default "on"
* Support for Django 1.5
diff --git a/askbot/doc/source/contributors.rst b/askbot/doc/source/contributors.rst
index 44cd8ccb..85d252bc 100644
--- a/askbot/doc/source/contributors.rst
+++ b/askbot/doc/source/contributors.rst
@@ -47,6 +47,7 @@ Programming, bug fixes and documentation
* `Jorge López Pérez <https://github.com/adobo>`_
* `Zafer Cakmak <https://github.com/xaph>`_
* `Kevin Porterfield <http://www.shotgunsoftware.com>_`
+* `Robert Martin <https://github.com/bobbydavid>_`
Translations
------------
diff --git a/askbot/doc/source/management-commands.rst b/askbot/doc/source/management-commands.rst
index cc5e952f..da93dcb5 100644
--- a/askbot/doc/source/management-commands.rst
+++ b/askbot/doc/source/management-commands.rst
@@ -25,6 +25,11 @@ The bulk of the management commands fall into this group and will probably be th
| `add_admin <user_id>` | Turn user into an administrator |
| | `<user_id>` is a numeric user id of the account |
+---------------------------------+-------------------------------------------------------------+
+| `apply_hinted_tags | Apply tags to all questions in batch given the list of tags |
+| --tag-names <file>` | provided with a file. The file must contain tags - |
+| | one per line. If many tags match - only the most frequent |
+| | will be selected. |
++---------------------------------+-------------------------------------------------------------+
| `remove_admin <user_id>` | Remove admin status from a user account - the opposite of |
| | the `add_admin` command |
+---------------------------------+-------------------------------------------------------------+
diff --git a/askbot/management/commands/apply_hinted_tags.py b/askbot/management/commands/apply_hinted_tags.py
new file mode 100644
index 00000000..94bf2383
--- /dev/null
+++ b/askbot/management/commands/apply_hinted_tags.py
@@ -0,0 +1,58 @@
+import datetime
+from django.core.management.base import BaseCommand
+from django.core.management.base import CommandError
+from optparse import make_option
+from askbot.utils.console import ProgressBar
+from askbot.models import Thread
+from askbot.models import User
+
+class Command(BaseCommand):
+ help = """Adds tags to questions. Tags should be given via a file
+ with one tag per line. The tags will be matched with the words
+ found in the question title. Then, most frequently used matching tags
+ will be applied. This command respects the maximum number of tags
+ allowed per question.
+ """
+ option_list = BaseCommand.option_list + (
+ make_option('--tags-file', '-t',
+ action = 'store',
+ type = 'str',
+ dest = 'tags_file',
+ default = None,
+ help = 'file containing tag names, one per line'
+ ),
+ )
+ def handle(self, *args, **kwargs):
+ """reads the tags file, parses it,
+ then applies tags to questions by matching them
+ with the question titles and content
+ """
+ if kwargs['tags_file'] is None:
+ raise CommandError('parameter --tags-file is required')
+ try:
+ tags_input = open(kwargs['tags_file']).read()
+ except IOError:
+ raise CommandError('file "%s" not found' % kwargs['tags_file'])
+
+ tags_list = map(lambda v: v.strip(), tags_input.split('\n'))
+
+ multiword_tags = list()
+ for tag in tags_list:
+ if ' ' in tag:
+ multiword_tags.append(tag)
+
+ if len(multiword_tags):
+ message = 'multiword tags tags not allowed, have: %s' % ', '.join(multiword_tags)
+ raise CommandError(message)
+
+ threads = Thread.objects.all()
+ count = threads.count()
+ message = 'Applying tags to questions'
+
+ user = User.objects.all().order_by('-id')[0]
+ now = datetime.datetime.now()
+
+ for thread in ProgressBar(threads.iterator(), count, message):
+ thread.apply_hinted_tags(
+ tags_list, user=user, timestamp=now, silent=True
+ )
diff --git a/askbot/management/commands/send_email_alerts.py b/askbot/management/commands/send_email_alerts.py
index b7432296..06f40c65 100644
--- a/askbot/management/commands/send_email_alerts.py
+++ b/askbot/management/commands/send_email_alerts.py
@@ -29,7 +29,8 @@ def get_all_origin_posts(mentions):
def extend_question_list(
src, dst, cutoff_time = None,
limit=False, add_mention=False,
- add_comment = False
+ add_comment = False,
+ languages=None
):
"""src is a query set with questions
or None
@@ -48,6 +49,8 @@ def extend_question_list(
raise ValueError('cutoff_time is a mandatory parameter')
for q in src:
+ if languages and src.language_code not in languages:
+ continue
if q in dst:
meta_data = dst[q]
else:
@@ -162,6 +165,11 @@ class Command(NoArgsCommand):
Q_set_A = not_seen_qs
Q_set_B = seen_before_last_mod_qs
+ if django_settings.ASKBOT_MULTILINGUAL:
+ languages = user.languages.split()
+ else:
+ languages = None
+
for feed in user_feeds:
if feed.feed_type == 'm_and_c':
#alerts on mentions and comments are processed separately
@@ -216,8 +224,8 @@ class Command(NoArgsCommand):
q_list = SortedDict()
#todo: refactor q_list into a separate class?
- extend_question_list(q_sel_A, q_list)
- extend_question_list(q_sel_B, q_list)
+ extend_question_list(q_sel_A, q_list, languages=languages)
+ extend_question_list(q_sel_B, q_list, languages=languages)
#build list of comment and mention responses here
#it is separate because posts are not marked as changed
@@ -247,8 +255,9 @@ class Command(NoArgsCommand):
extend_question_list(
q_commented,
q_list,
- cutoff_time = cutoff_time,
- add_comment = True
+ cutoff_time=cutoff_time,
+ add_comment=True,
+ languages=languages
)
mentions = Activity.objects.get_mentions(
@@ -267,27 +276,37 @@ class Command(NoArgsCommand):
q_mentions_A = Q_set_A.filter(id__in = q_mentions_id)
q_mentions_A.cutoff_time = cutoff_time
- extend_question_list(q_mentions_A, q_list, add_mention=True)
+ extend_question_list(
+ q_mentions_A,
+ q_list,
+ add_mention=True,
+ languages=languages
+ )
q_mentions_B = Q_set_B.filter(id__in = q_mentions_id)
q_mentions_B.cutoff_time = cutoff_time
- extend_question_list(q_mentions_B, q_list, add_mention=True)
+ extend_question_list(
+ q_mentions_B,
+ q_list,
+ add_mention=True,
+ languages=languages
+ )
except EmailFeedSetting.DoesNotExist:
pass
if user.email_tag_filter_strategy == const.INCLUDE_INTERESTING:
- extend_question_list(q_all_A, q_list)
- extend_question_list(q_all_B, q_list)
+ extend_question_list(q_all_A, q_list, languages=languages)
+ extend_question_list(q_all_B, q_list, languages=languages)
- extend_question_list(q_ask_A, q_list, limit=True)
- extend_question_list(q_ask_B, q_list, limit=True)
+ extend_question_list(q_ask_A, q_list, limit=True, languages=languages)
+ extend_question_list(q_ask_B, q_list, limit=True, languages=languages)
- extend_question_list(q_ans_A, q_list, limit=True)
- extend_question_list(q_ans_B, q_list, limit=True)
+ extend_question_list(q_ans_A, q_list, limit=True, languages=languages)
+ extend_question_list(q_ans_B, q_list, limit=True, languages=languages)
if user.email_tag_filter_strategy == const.EXCLUDE_IGNORED:
- extend_question_list(q_all_A, q_list, limit=True)
- extend_question_list(q_all_B, q_list, limit=True)
+ extend_question_list(q_all_A, q_list, limit=True, languages=languages)
+ extend_question_list(q_all_B, q_list, limit=True, languages=languages)
ctype = ContentType.objects.get_for_model(Post)
EMAIL_UPDATE_ACTIVITY = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT
diff --git a/askbot/media/js/live_search.js b/askbot/media/js/live_search.js
index b812070c..2cb62b2b 100644
--- a/askbot/media/js/live_search.js
+++ b/askbot/media/js/live_search.js
@@ -14,6 +14,14 @@ SearchDropMenu.prototype.setAskHandler = function(handler) {
this._askHandler = handler;
};
+SearchDropMenu.prototype.setSearchWidget = function(widget) {
+ this._searchWidget = widget;
+};
+
+SearchDropMenu.prototype.getSearchWidget = function() {
+ return this._searchWidget;
+};
+
SearchDropMenu.prototype.setAskButtonEnabled = function(isEnabled) {
this._askButtonEnabled = isEnabled;
};
@@ -42,6 +50,11 @@ SearchDropMenu.prototype.render = function() {
}
};
+SearchDropMenu.prototype.clearSelectedItem = function() {
+ this._selectedItemIndex = 0;
+ this._resultsList.find('li').removeClass('selected');
+}
+
/**
* @param {number} idx position of item starting from 1 for the topmost
* Selects item inentified by position.
@@ -126,7 +139,17 @@ SearchDropMenu.prototype.makeKeyHandler = function() {
return false;
}
}
- me.selectItem(curItem);
+
+ var widget = me.getSearchWidget();
+ if (curItem === 0) {
+ //activate key handlers on input box
+ widget.setFullTextSearchEnabled(true);
+ me.clearSelectedItem();
+ } else {
+ //deactivate key handlers on input box
+ widget.setFullTextSearchEnabled(false);
+ me.selectItem(curItem);
+ }
return false
}
};
@@ -772,6 +795,14 @@ FullTextSearch.prototype.updateToolTip = function() {
}
};
+FullTextSearch.prototype.setFullTextSearchEnabled = function(enabled) {
+ this._fullTextSearchEnabled = enabled;
+};
+
+FullTextSearch.prototype.getFullTextSearchEnabled = function() {
+ return this._fullTextSearchEnabled;
+};
+
/**
* keydown handler operates on the tooltip and the X button
* also opens and closes drop menu according to the min search word threshold
@@ -793,8 +824,12 @@ FullTextSearch.prototype.makeKeyDownHandler = function() {
return false;
}
} else if (keyCode === 13) {
- formSubmitHandler(e);
- return false;
+ if (me.getFullTextSearchEnabled()) {
+ formSubmitHandler(e);
+ return false;
+ } else {
+ return true;
+ }
}
var query = me.getSearchQuery();
@@ -856,6 +891,7 @@ FullTextSearch.prototype.decorate = function(element) {
this._toolTip = toolTip;
var dropMenu = new SearchDropMenu();
+ dropMenu.setSearchWidget(this);
dropMenu.setAskHandler(this.makeAskHandler());
dropMenu.setAskButtonEnabled(this._askButtonEnabled);
this._dropMenu = dropMenu;
diff --git a/askbot/media/js/utils.js b/askbot/media/js/utils.js
index 0380e6fe..ec3af964 100644
--- a/askbot/media/js/utils.js
+++ b/askbot/media/js/utils.js
@@ -59,6 +59,11 @@ var setController = function(controller, name) {
askbot['controllers'][name] = controller;
};
+var sortChildNodes = function(node, cmpFunc) {
+ var items = node.children().sort(cmpFunc);
+ node.append(items);
+};
+
var getUniqueValues = function(values) {
var uniques = new Object();
var out = new Array();
@@ -2011,8 +2016,18 @@ SelectBox.prototype.createDom = function() {
var GroupDropdown = function(groups){
WrappedElement.call(this);
this._group_list = groups;
+};
+inherits(GroupDropdown, WrappedElement);
+
+GroupDropdown.prototype.createDom = function(){
+ this._element = this.makeElement('ul');
+ this._element.attr('class', 'dropdown-menu');
+ this._element.attr('id', 'groups-dropdown');
+ this._element.attr('role', 'menu');
+ this._element.attr('aria-labelledby', 'navGroups');
+
this._input_box = new TippedInput();
- this._input_box.setInstruction('group name');
+ this._input_box.setInstruction(gettext('group name'));
this._input_box.createDom();
this._input_box_element = this._input_box.getElement();
this._input_box_element.attr('class', 'group-name');
@@ -2021,115 +2036,128 @@ var GroupDropdown = function(groups){
this._add_link.attr('href', '#');
this._add_link.attr('class', 'group-name');
this._add_link.text(gettext('add new group'));
+
+ for (var i=0; i<this._group_list.length; i++){
+ var li = this.makeElement('li');
+ var a = this.makeElement('a');
+ a.text(this._group_list[i].name);
+ a.attr('href', this._group_list[i].link);
+ a.attr('class', 'group-name');
+ li.append(a);
+ this._element.append(li);
+ }
+ if (askbot['data']['userIsAdmin']) {
+ this.enableAddGroups();
+ }
};
-inherits(GroupDropdown, WrappedElement);
-GroupDropdown.prototype.createDom = function(){
- this._element = this.makeElement('ul');
- this._element.attr('class', 'dropdown-menu');
- this._element.attr('id', 'groups-dropdown');
- this._element.attr('role', 'menu');
- this._element.attr('aria-labelledby', 'navGroups');
-
- for (i=0; i<this._group_list.length; i++){
- li_element = this.makeElement('li');
- a_element = this.makeElement('a');
- a_element.text(this._group_list[i].name);
- a_element.attr('href', this._group_list[i].link);
- a_element.attr('class', 'group-name');
- li_element.append(a_element);
- this._element.append(li_element);
- }
+/**
+ * inserts a link to group with a given url to the group page
+ * and name
+ */
+GroupDropdown.prototype.insertGroup = function(group_name, url){
+
+ //1) take out first and last list elements:
+ // everyone and the "add group" item
+ var list = this._element.children();
+ var everyoneGroup = list.first().detach();
+ var groupAdder = list.last().detach();
+ var divider = this._element.find('.divider').detach();
+
+ //2) append group link into the list
+ var li = this.makeElement('li');
+ var a = this.makeElement('a');
+ a.attr('href', url);
+ a.attr('class', 'group-name');
+ a.text(group_name);
+ li.append(a);
+ li.hide();
+ this._element.append(li);
+
+ //3) sort rest of the list alphanumerically
+ sortChildNodes(
+ this._element,
+ function(a, b) {
+ var valA = $(a).find('a').text().toLowerCase();
+ var valB = $(b).find('a').text().toLowerCase();
+ return (valA < valB) ? -1: (valA > valB) ? 1: 0;
+ }
+ );
+
+ //a dramatic effect
+ li.fadeIn();
+
+ //4) reinsert the first and last elements of the list:
+ this._element.prepend(everyoneGroup);
+ this._element.append(divider);
+ this._element.append(groupAdder);
};
-GroupDropdown.prototype.decorate = function(element){
- this._element = element;
- this._element.attr('class', 'dropdown-menu');
- this._element.attr('id', 'groups-dropdown');
- this._element.attr('role', 'menu');
- this._element.attr('aria-labelledby', 'navGroups');
-
- for (i=0; i<this._group_list.length; i++){
- li_element = this.makeElement('li');
- a_element = this.makeElement('a');
- a_element.text(this._group_list[i].name);
- a_element.attr('href', this._group_list[i].link);
- a_element.attr('class', 'group-name');
- li_element.append(a_element);
- this._element.append(li_element);
- }
+GroupDropdown.prototype.setState = function(state) {
+ if (state === 'display') {
+ this._input_box_element.hide();
+ this._add_link.show();
+ }
};
-GroupDropdown.prototype.insertGroup = function(group_name, url){
- var new_group_li = this.makeElement('li');
- new_group_a = this.makeElement('a');
- new_group_a.attr('href', url);
- new_group_a.attr('class', 'group-name');
- new_group_a.text(group_name);
- new_group_li.append(new_group_a);
- links_array = this._element.find('a')
- for (i=1; i < links_array.length; i++){
- var listedName = links_array[i].text;
- var cleanedListedName = listedName.toLowerCase();
- var cleanedNewName = group_name.toLowerCase()
- if (listedName < newName) {
- if (i == links_array.length - 1){
- new_group_li.insertAfter(this._element.find('li')[i-1])
- break;
- } else {
- continue;
- }
- } else if (cleanedNewName === cleanedNewName) {
- var message = interpolate(gettext(
- 'Group %(name)s already exists. Group names are case-insensitive.'
- ), {'name': listedName}, true
- );
- notify.show(message);
- return;
- } else {
- new_group_li.insertAfter(this._element.find('li')[i-1])
- break;
+GroupDropdown.prototype.hasGroup = function(groupName) {
+ var items = this._element.find('li');
+ for (var i=1; i < items.length - 1; i++) {
+ var cGroupName = $(items[i]).find('a').text();
+ if (cGroupName.toLowerCase() === groupName.toLowerCase()) {
+ return true;
}
}
+ return false;
};
GroupDropdown.prototype._add_group_handler = function(group_name){
- var group_name = this._input_box_element.val();
- self = this;
- if (!group_name){
- return;
- }
+ var group_name = this._input_box_element.val();
+ var me = this;
+ if (!group_name){
+ return;
+ }
- $.ajax({
- type: 'POST',
- url: askbot['urls']['add_group'],
- data: {group: group_name},
- success: function(data){
- if (data.success){
- self.insertGroup(data.group_name, data.url);
- self._input_box_element.hide();
- self._add_link.show();
- return true;
- } else{
- return false;
- }
- },
- error: function(){console.log('error');}
- });
+ $.ajax({
+ type: 'POST',
+ url: askbot['urls']['add_group'],
+ data: {group: group_name},
+ success: function(data){
+ if (data['success']){
+ var groupName = data['group_name'];
+ if (me.hasGroup(groupName)) {
+ var message = interpolate(gettext(
+ 'Group %(name)s already exists. Group names are case-insensitive.'
+ ), {'name': groupName}, true
+ );
+ notify.show(message);
+ return false;
+ } else {
+ me.insertGroup(data['group_name'], data['url']);
+ me.setState('display');
+ return true;
+ }
+ } else{
+ notify.show(data['message']);
+ return false;
+ }
+ },
+ error: function(){console.log('error');}
+ });
};
GroupDropdown.prototype.enableAddGroups = function(){
var self = this;
this._add_link.click(function(){
- self._add_link.hide();
- self._input_box_element.show();
- self._input_box_element.focus();
+ self._add_link.hide();
+ self._input_box_element.show();
+ self._input_box_element.focus();
});
this._input_box_element.keydown(function(event){
- if (event.which == 13 || event.keyCode==13){
- self._add_group_handler();
- self._input_box_element.val('');
- }
+ if (event.which == 13 || event.keyCode==13){
+ self._add_group_handler();
+ self._input_box_element.val('');
+ }
});
var divider = this.makeElement('li');
@@ -2297,6 +2325,149 @@ Tag.prototype.createDom = function(){
}
};
+var PermsHoverCard = function() {
+ WrappedElement.call(this);
+ this._isLoaded = false;
+};
+inherits(PermsHoverCard, WrappedElement);
+
+PermsHoverCard.prototype.setContent = function(data) {
+ this._element.html(data['html']);
+};
+
+PermsHoverCard.prototype.setTrigger = function(trigger) {
+ this._trigger = trigger;
+};
+
+PermsHoverCard.prototype.setPosition = function() {
+ var trigger = this._trigger.getElement();
+ var coors = trigger.offset();
+ var height = trigger.outerHeight();
+ var triangle = this._element.find('.triangle')
+ var triangleHeight = triangle.outerHeight();
+ this._element.css({
+ 'top': coors.top + height + triangleHeight,
+ 'left': coors.left
+ });
+};
+
+PermsHoverCard.prototype.setUrl = function(url) {
+ this._url = url;
+};
+
+PermsHoverCard.prototype.startLoading = function(onLoad) {
+ var me = this;
+ $.ajax({
+ type: 'GET',
+ dataType: 'json',
+ cache: false,
+ url: this._url,
+ success: function(data) {
+ if (data['success']) {
+ me.setContent(data);
+ me.setPosition();
+ onLoad();
+ me.setIsLoaded();
+ } else {
+ notify.show(data['message']);
+ }
+ }
+ });
+};
+
+PermsHoverCard.prototype.isLoaded = function() {
+ return this._isLoaded;
+};
+
+PermsHoverCard.prototype.setIsLoaded = function() {
+ this._isLoaded = true;
+};
+
+PermsHoverCard.prototype.getOpenHandler = function() {
+ var me = this;
+ return function() {
+ me.clearCancelOpenTimeout();
+ if (me.isLoaded()) {
+ me.getElement().show();
+ } else {
+ var onload = function() {
+ me.getElement().show();
+ }
+ me.startLoading(onload);
+ }
+ };
+};
+
+PermsHoverCard.prototype.setCancelOpenTimoutId = function(timeoutId) {
+ this._cancelOpenTimeoutId = timeoutId;
+};
+
+PermsHoverCard.prototype.clearCancelOpenTimeout = function() {
+ var timeout = this._cancelOpenTimeoutId;
+ if (timeout) {
+ clearTimeout(timeout);
+ }
+};
+
+PermsHoverCard.prototype.getCloseHandler = function() {
+ var me = this;
+ return function() {
+ var element = me.getElement();
+ //start timeout to close
+ var timeout = setTimeout(function() {
+ element.hide();
+ //element.fadeOut('fast');
+ }, 200);
+ me.setCancelOpenTimoutId(timeout);
+ };
+};
+
+PermsHoverCard.prototype.getImmediateCloseHandler = function() {
+ var me = this;
+ return function() {
+ me.getElement().hide();
+ };
+};
+
+PermsHoverCard.prototype.getKeepHandler = function() {
+ var me = this;
+ return function() {
+ me.clearCancelOpenTimeout();
+ };
+};
+
+PermsHoverCard.prototype.createDom = function() {
+ var element = this.makeElement('div');
+ this._element = element;
+ element.addClass('hovercard');
+ element.hover(
+ this.getKeepHandler(),
+ this.getCloseHandler()
+ );
+ this._element.hide();
+};
+
+var ShowPermsTrigger = function() {
+ WrappedElement.call(this);
+};
+inherits(ShowPermsTrigger, WrappedElement);
+
+ShowPermsTrigger.prototype.decorate = function(element) {
+ this._element = element;
+ var hoverCard = new PermsHoverCard();
+ this._hoverCard = hoverCard;
+ $('body').append(hoverCard.getElement());
+
+ hoverCard.setTrigger(this);
+ hoverCard.setUrl(element.data('url'));
+
+ var onEnter = hoverCard.getOpenHandler();
+ var onExit = hoverCard.getCloseHandler();
+ element.hover(onEnter, onExit);
+ var onClose = hoverCard.getImmediateCloseHandler();
+ $('body').click(onClose);
+};
+
//Search Engine Keyword Highlight with Javascript
//http://scott.yang.id.au/code/se-hilite/
Hilite={elementid:"content",exact:true,max_nodes:1000,onload:true,style_name:"hilite",style_name_suffix:true,debug_referrer:""};Hilite.search_engines=[["local","q"],["cnprog\\.","q"],["google\\.","q"],["search\\.yahoo\\.","p"],["search\\.msn\\.","q"],["search\\.live\\.","query"],["search\\.aol\\.","userQuery"],["ask\\.com","q"],["altavista\\.","q"],["feedster\\.","q"],["search\\.lycos\\.","q"],["alltheweb\\.","q"],["technorati\\.com/search/([^\\?/]+)",1],["dogpile\\.com/info\\.dogpl/search/web/([^\\?/]+)",1,true]];Hilite.decodeReferrer=function(d){var g=null;var e=new RegExp("");for(var c=0;c<Hilite.search_engines.length;c++){var f=Hilite.search_engines[c];e.compile("^http://(www\\.)?"+f[0],"i");var b=d.match(e);if(b){var a;if(isNaN(f[1])){a=Hilite.decodeReferrerQS(d,f[1])}else{a=b[f[1]+1]}if(a){a=decodeURIComponent(a);if(f.length>2&&f[2]){a=decodeURIComponent(a)}a=a.replace(/\'|"/g,"");a=a.split(/[\s,\+\.]+/);return a}break}}return null};Hilite.decodeReferrerQS=function(f,d){var b=f.indexOf("?");var c;if(b>=0){var a=new String(f.substring(b+1));b=0;c=0;while((b>=0)&&((c=a.indexOf("=",b))>=0)){var e,g;e=a.substring(b,c);b=a.indexOf("&",c)+1;if(e==d){if(b<=0){return a.substring(c+1)}else{return a.substring(c+1,b-1)}}else{if(b<=0){return null}}}}return null};Hilite.hiliteElement=function(f,e){if(!e||f.childNodes.length==0){return}var c=new Array();for(var b=0;b<e.length;b++){e[b]=e[b].toLowerCase();if(Hilite.exact){c.push("\\b"+e[b]+"\\b")}else{c.push(e[b])}}c=new RegExp(c.join("|"),"i");var a={};for(var b=0;b<e.length;b++){if(Hilite.style_name_suffix){a[e[b]]=Hilite.style_name+(b+1)}else{a[e[b]]=Hilite.style_name}}var d=function(m){var j=c.exec(m.data);if(j){var n=j[0];var i="";var h=m.splitText(j.index);var g=h.splitText(n.length);var l=m.ownerDocument.createElement("SPAN");m.parentNode.replaceChild(l,h);l.className=a[n.toLowerCase()];l.appendChild(h);return l}else{return m}};Hilite.walkElements(f.childNodes[0],1,d)};Hilite.hilite=function(){var a=Hilite.debug_referrer?Hilite.debug_referrer:document.referrer;var b=null;a=Hilite.decodeReferrer(a);if(a&&((Hilite.elementid&&(b=document.getElementById(Hilite.elementid)))||(b=document.body))){Hilite.hiliteElement(b,a)}};Hilite.walkElements=function(d,f,e){var a=/^(script|style|textarea)/i;var c=0;while(d&&f>0){c++;if(c>=Hilite.max_nodes){var b=function(){Hilite.walkElements(d,f,e)};setTimeout(b,50);return}if(d.nodeType==1){if(!a.test(d.tagName)&&d.childNodes.length>0){d=d.childNodes[0];f++;continue}}else{if(d.nodeType==3){d=e(d)}}if(d.nextSibling){d=d.nextSibling}else{while(f>0){d=d.parentNode;f--;if(d.nextSibling){d=d.nextSibling;break}}}}};if(Hilite.onload){if(window.attachEvent){window.attachEvent("onload",Hilite.hilite)}else{if(window.addEventListener){window.addEventListener("load",Hilite.hilite,false)}else{var __onload=window.onload;window.onload=function(){Hilite.hilite();__onload()}}}};
diff --git a/askbot/media/style/style.css b/askbot/media/style/style.css
index 3aab9f21..fbbd206a 100644
--- a/askbot/media/style/style.css
+++ b/askbot/media/style/style.css
@@ -218,6 +218,43 @@ body.user-messages {
text-align: center;
margin: 5px 0 8px;
}
+.hovercard {
+ background: white;
+ border: 3px solid #ddd;
+ -webkit-box-shadow: 0 0 3px #929292;
+ -moz-box-shadow: 0 0 3px #929292;
+ box-shadow: 0 0 3px #929292;
+ font-size: 13px;
+ display: block;
+ max-width: 250px;
+ padding: 10px;
+ position: absolute;
+ border-radius: 5px;
+ -ms-border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -khtml-border-radius: 5px;
+ z-index: 1001;
+}
+.hovercard p:last-child {
+ margin-bottom: 0;
+}
+.hovercard ul {
+ margin-bottom: 0;
+}
+.hovercard ul li {
+ font-size: 13px;
+ line-height: 16px;
+ margin: 5px 0;
+}
+.hovercard .triangle {
+ border-left: 5px solid transparent;
+ border-right: 10px solid transparent;
+ border-bottom: 10px solid #ddd;
+ height: 0;
+ margin: -20px 0 10px 0;
+ width: 0;
+}
#closeNotify {
position: absolute;
right: 5px;
@@ -354,23 +391,17 @@ body.user-messages {
}
#metaNav a.group-name {
padding: 0px;
- float: center;
- margin: 5px 0px 5px 10px;
+ float: none;
+ margin: 5px 10px;
}
#metaNav input.group-name {
- border: none;
- height: 25px;
- font-size: 18px;
- font-weight: 100;
- text-decoration: none;
+ border: 1px solid #c9c9b5;
+ color: #464646;
display: block;
- margin: 0px 10px 0px 10px;
- width: 140px;
- font-family: 'Open Sans Condensed', Arial, sans-serif;
- font-weight: 100;
-}
-#metaNav input.group-name:focus {
- border: none;
+ font-size: 14px;
+ height: 25px;
+ margin: 0px 10px 5px 10px;
+ padding: 0 5px;
}
#metaNav a.group-name:hover {
background-color: transparent;
@@ -386,7 +417,7 @@ body.user-messages {
}
#metaNav .dropdown-menu {
border-top: none;
- left: 7%;
+ left: 33px;
z-index: 10100;
}
#metaNav .dropdown-menu a {
@@ -1742,7 +1773,7 @@ ul#related-tags li {
}
.groups-input,
.users-input {
- width: 152px;
+ width: 150px;
padding-left: 5px;
border: #c9c9b5 1px solid;
height: 25px;
@@ -1751,7 +1782,7 @@ ul#related-tags li {
.add-groups,
.add-users {
border: 0;
- margin-top: -2px;
+ margin: -2px 0 0 0 !important;
}
.share-input-col {
width: 160px;
@@ -1771,32 +1802,6 @@ ul#related-tags li {
width: 395px;
font-size: 14px;
}
-.groups-input,
-.users-input {
- width: 152px;
- padding-left: 5px;
- border: #c9c9b5 1px solid;
- height: 25px;
- font-size: 14px;
-}
-.add-groups,
-.add-users {
- border: 0;
- margin-top: -2px;
-}
-.add-everyone-group {
- text-align: center;
- margin: auto;
- display: block;
- padding: 0 10px;
-}
-#id_user,
-#id_user_author {
- height: 25px;
- padding-left: 5px;
- width: 395px;
- font-size: 14px;
-}
.title-desc {
color: #707070;
font-size: 13px;
@@ -1821,6 +1826,10 @@ ul#related-tags li {
margin-right: 7px;
}
.folded-editor {
+ box-shadow: inset 0 0 3px 1px #aaa;
+ -moz-box-shadow: inset 0 0 3px 1px #aaa;
+ -webkit-box-shadow: inset 0 0 3px 1px #aaa;
+ cursor: text;
height: 100px;
outline: none;
width: 100%;
@@ -1828,6 +1837,12 @@ ul#related-tags li {
.folded-editor .editor-proper {
display: none;
}
+.folded-editor.unfolded {
+ cursor: default;
+ box-shadow: 0 0 0 0;
+ -moz-box-shadow: 0 0 0 0;
+ -webkit-box-shadow: 0 0 0 0;
+}
.folded-editor p.prompt {
margin: 5px 8px;
display: block;
@@ -2280,7 +2295,9 @@ ul#related-tags li {
line-height: 18px;
margin-top: -2px;
margin-left: 4px;
- box-shadow: none;
+ -webkit-box-shadow: 0 0 0 #929292;
+ -moz-box-shadow: 0 0 0 #929292;
+ box-shadow: 0 0 0 #929292;
}
.question-page .post-controls .answer-convert input:hover,
.question-page .answer-controls .answer-convert input:hover {
diff --git a/askbot/media/style/style.less b/askbot/media/style/style.less
index efde976d..4a957dd6 100644
--- a/askbot/media/style/style.less
+++ b/askbot/media/style/style.less
@@ -232,6 +232,38 @@ body.user-messages {
margin: 5px 0 8px;
}
+.hovercard {
+ background: white;
+ border: 3px solid #ddd;
+ .box-shadow(0, 0, 3px);
+ font-size: 13px;
+ display: block;
+ max-width: 250px;
+ padding: 10px;
+ position: absolute;
+ .rounded-corners(5px);
+ z-index: 1001;
+ p:last-child {
+ margin-bottom: 0;
+ }
+ ul {
+ margin-bottom: 0;
+ li {
+ font-size: 13px;
+ line-height: 16px;
+ margin: 5px 0;
+ }
+ }
+ .triangle {
+ border-left: 5px solid transparent;
+ border-right: 10px solid transparent;
+ border-bottom: 10px solid #ddd;
+ height: 0;
+ margin: -20px 0 10px 0;
+ width: 0;
+ }
+}
+
#closeNotify {
position: absolute;
right: 5px;
@@ -381,25 +413,18 @@ body.user-messages {
a.group-name {
padding: 0px;
- float:center;
- margin:5px 0px 5px 10px;
+ float: none;
+ margin: 5px 10px;
}
- input.group-name{
- border:none;
- height: 25px;
- font-size: 18px;
- font-weight: 100;
- text-decoration: none;
+ input.group-name {
+ border: 1px solid #c9c9b5;
+ color: #464646;
display: block;
- margin: 0px 10px 0px 10px;
- width: 140px;
- font-family: @main-font;
- font-weight: 100;
- }
-
- input.group-name:focus{
- border:none;
+ font-size: 14px;
+ height: 25px;
+ margin: 0px 10px 5px 10px;
+ padding: 0 5px;
}
a.group-name:hover{
@@ -418,11 +443,11 @@ body.user-messages {
float:left;
}
- .dropdown-menu{
+ .dropdown-menu {
border-top: none;
- left: 7%;
+ left: 33px;
z-index: 10100;
- a{
+ a {
color: #666;
height: 25px;
}
@@ -1838,17 +1863,17 @@ ul#related-tags li {
.groups-input,
.users-input {
- width:152px;
- padding-left:5px;
- border:#c9c9b5 1px solid;
- height:25px;
+ width: 150px;
+ padding-left: 5px;
+ border: #c9c9b5 1px solid;
+ height: 25px;
font-size: 14px;
}
.add-groups,
.add-users {
- border:0;
- margin-top:-2px;
+ border: 0;
+ margin: -2px 0 0 0 !important;
}
.share-input-col {
@@ -1872,36 +1897,6 @@ ul#related-tags li {
font-size:14px;
}
-.groups-input,
-.users-input {
- width:152px;
- padding-left:5px;
- border:#c9c9b5 1px solid;
- height:25px;
- font-size: 14px;
-}
-
-.add-groups,
-.add-users {
- border:0;
- margin-top:-2px;
-}
-
-.add-everyone-group {
- text-align: center;
- margin: auto;
- display: block;
- padding: 0 10px;
-}
-
-#id_user,
-#id_user_author {
- height:25px;
- padding-left:5px;
- width:395px;
- font-size:14px;
-}
-
.title-desc {
color: @info-text;
font-size: 13px;
@@ -1928,6 +1923,10 @@ ul#related-tags li {
}
.folded-editor {
+ box-shadow: inset 0 0 3px 1px #aaa;
+ -moz-box-shadow: inset 0 0 3px 1px #aaa;
+ -webkit-box-shadow: inset 0 0 3px 1px #aaa;
+ cursor: text;
height: 100px;
outline: none;
width: 100%;
@@ -1935,6 +1934,13 @@ ul#related-tags li {
.editor-proper {
display: none;
}
+
+ &.unfolded {
+ cursor: default;
+ box-shadow: 0 0 0 0;
+ -moz-box-shadow: 0 0 0 0;
+ -webkit-box-shadow: 0 0 0 0;
+ }
p.prompt {
margin: 5px 8px;
display: block;
@@ -2401,7 +2407,7 @@ ul#related-tags li {
line-height:18px;
margin-top:-2px;
margin-left:4px;
- box-shadow: none;
+ .box-shadow(0, 0, 0);
}
.answer-convert input:hover{
diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py
index 8e3e3d01..797aa6a3 100644
--- a/askbot/models/__init__.py
+++ b/askbot/models/__init__.py
@@ -2532,12 +2532,21 @@ def toggle_favorite_question(
about processing the "cancel" option
another strange thing is that this function unlike others below
returns a value
+
+ todo: the on-screen follow and email subscription is not
+ fully merged yet - see use of FavoriteQuestion and follow/unfollow question
+ btw, names of the objects/methods is quite misleading ATM
"""
try:
+ #this attempts to remove the on-screen follow
fave = FavoriteQuestion.objects.get(thread=question.thread, user=self)
fave.delete()
result = False
question.thread.update_favorite_count()
+ #this removes email subscription
+ if question.thread.is_followed_by(self):
+ self.unfollow_question(question)
+
except FavoriteQuestion.DoesNotExist:
if timestamp is None:
timestamp = datetime.datetime.now()
@@ -2547,6 +2556,11 @@ def toggle_favorite_question(
added_at = timestamp,
)
fave.save()
+
+ #this removes email subscription
+ if question.thread.is_followed_by(self) is False:
+ self.follow_question(question)
+
result = True
question.thread.update_favorite_count()
award_badges_signal.send(None,
diff --git a/askbot/models/question.py b/askbot/models/question.py
index ecb7185a..d85a0b69 100644
--- a/askbot/models/question.py
+++ b/askbot/models/question.py
@@ -602,6 +602,64 @@ class Thread(models.Model):
self._question_cache = Post.objects.get(post_type='question', thread=self)
return self._question_cache
+ def apply_hinted_tags(self, hints=None, user=None, timestamp=None, silent=False):
+ """match words in title and body with hints
+ and apply some of the hints as tags,
+ so that total number of tags in no more
+ than the maximum allowed number of tags"""
+
+ #1) see how many tags we're missing,
+ #if we don't need more we return
+ existing_tags = self.get_tag_names()
+ tags_count = len(existing_tags)
+ if tags_count >= askbot_settings.MAX_TAGS_PER_POST:
+ return
+
+ #2) get set of words from title and body
+ post_text = self.title + ' ' + self._question_post().text
+ post_text = post_text.lower()#normalize
+ post_words = set(post_text.split())
+
+ #3) get intersection set
+ #normalize hints and tags and remember the originals
+ orig_hints = dict()
+ for hint in hints:
+ orig_hints[hint.lower()] = hint
+
+ norm_hints = orig_hints.keys()
+ norm_tags = map(lambda v: v.lower(), existing_tags)
+
+ common_words = (set(norm_hints) & post_words) - set(norm_tags)
+
+ #4) for each common word count occurances in corpus
+ counts = dict()
+ for word in common_words:
+ counts[word] = sum(map(lambda w: w.lower() == word.lower(), post_words))
+
+ #5) sort words by count
+ sorted_words = sorted(
+ common_words,
+ lambda a, b: cmp(counts[b], counts[a])
+ )
+
+ #6) extract correct number of most frequently used tags
+ need_tags = askbot_settings.MAX_TAGS_PER_POST - len(existing_tags)
+ add_tags = sorted_words[0:need_tags]
+ add_tags = map(lambda h: orig_hints[h], add_tags)
+
+ tagnames = ' '.join(existing_tags + add_tags)
+
+ if askbot_settings.FORCE_LOWERCASE_TAGS:
+ tagnames = tagnames.lower()
+
+ self.retag(
+ retagged_by=user,
+ retagged_at=timestamp or datetime.datetime.now(),
+ tagnames =' '.join(existing_tags + add_tags),
+ silent=silent
+ )
+
+
def get_absolute_url(self):
return self._question_post().get_absolute_url(thread = self)
#question_id = self._question_post().id
diff --git a/askbot/setup_templates/settings.py b/askbot/setup_templates/settings.py
index 258a5989..1427e506 100644
--- a/askbot/setup_templates/settings.py
+++ b/askbot/setup_templates/settings.py
@@ -307,5 +307,9 @@ if 'ASKBOT_CSS_DEVEL' in locals() and ASKBOT_CSS_DEVEL == True:
)
COMPRESS_JS_FILTERS = []
-COMPRESS_PARSER = 'compressor.parser.HtmlParser'
+COMPRESS_PARSER = 'compressor.parser.HtmlParser'
JINJA2_EXTENSIONS = ('compressor.contrib.jinja2ext.CompressorExtension',)
+
+# Use syncdb for tests instead of South migrations. Without this, some tests
+# fail spuriously in MySQL.
+SOUTH_TESTS_MIGRATE = False
diff --git a/askbot/setup_templates/settings.py.mustache b/askbot/setup_templates/settings.py.mustache
index f3c0a35b..f30297d7 100644
--- a/askbot/setup_templates/settings.py.mustache
+++ b/askbot/setup_templates/settings.py.mustache
@@ -27,6 +27,8 @@ DATABASES = {
'PASSWORD': '{{database_password}}', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
+ 'TEST_CHARSET': 'utf8', # Setting the character set and collation to utf-8
+ 'TEST_COLLATION': 'utf8_general_ci', # is necessary for MySQL tests to work properly.
}
}
@@ -46,7 +48,7 @@ EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
#go to the site's live settings and enable the feature
#"Email settings" -> "allow asking by email"
#
-# WARNING: command post_emailed_questions DELETES all
+# WARNING: command post_emailed_questions DELETES all
# emails from the mailbox each time
# do not use your personal mail box here!!!
#
@@ -125,7 +127,7 @@ ROOT_URLCONF = os.path.basename(os.path.dirname(__file__)) + '.urls'
#UPLOAD SETTINGS
FILE_UPLOAD_TEMP_DIR = os.path.join(
- os.path.dirname(__file__),
+ os.path.dirname(__file__),
'tmp'
).replace('\\','/')
@@ -258,7 +260,7 @@ HAYSTACK_SITECONF = 'askbot.search.haystack'
#http://django-haystack.readthedocs.org/en/v1.2.7/settings.html
HAYSTACK_SEARCH_ENGINE = 'simple'
-TINYMCE_COMPRESSOR = True
+TINYMCE_COMPRESSOR = True
TINYMCE_SPELLCHECKER = False
TINYMCE_JS_ROOT = os.path.join(STATIC_ROOT, 'default/media/js/tinymce/')
#TINYMCE_JS_URL = STATIC_URL + 'default/media/js/tinymce/tiny_mce.js'
@@ -287,7 +289,7 @@ TINYMCE_DEFAULT_CONFIG = {
}
#delayed notifications, time in seconds, 15 mins by default
-NOTIFICATION_DELAY_TIME = 60 * 15
+NOTIFICATION_DELAY_TIME = 60 * 15
GROUP_MESSAGING = {
'BASE_URL_GETTER_FUNCTION': 'askbot.models.user_get_profile_url',
@@ -303,5 +305,9 @@ if 'ASKBOT_CSS_DEVEL' in locals() and ASKBOT_CSS_DEVEL == True:
)
COMPRESS_JS_FILTERS = []
-COMPRESS_PARSER = 'compressor.parser.HtmlParser'
+COMPRESS_PARSER = 'compressor.parser.HtmlParser'
JINJA2_EXTENSIONS = ('compressor.contrib.jinja2ext.CompressorExtension',)
+
+# Use syncdb for tests instead of South migrations. Without this, some tests
+# fail spuriously in MySQL.
+SOUTH_TESTS_MIGRATE = False
diff --git a/askbot/templates/base.html b/askbot/templates/base.html
index 332fa093..93f1c170 100644
--- a/askbot/templates/base.html
+++ b/askbot/templates/base.html
@@ -12,6 +12,7 @@
{% if settings.GOOGLE_SITEMAP_CODE %}
<meta name="google-site-verification" content="{{settings.GOOGLE_SITEMAP_CODE}}" />
{% endif %}
+ <meta name="referrer" content="always" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
{% if settings.SITE_FAVICON %}
<link rel="shortcut icon" href="{{ settings.SITE_FAVICON|media }}" />
diff --git a/askbot/templates/main_page/sidebar.html b/askbot/templates/main_page/sidebar.html
index 7acbe091..610d2b60 100644
--- a/askbot/templates/main_page/sidebar.html
+++ b/askbot/templates/main_page/sidebar.html
@@ -1,6 +1,6 @@
{% import "macros.html" as macros %}
-{% if settings.SIDEBAR_MAIN_HEADER %}
+{% if 'SIDEBAR_MAIN_HEADER'|show_block_to(request.user) %}
<div class="box">
{{ settings.SIDEBAR_MAIN_HEADER }}
</div>
@@ -22,7 +22,7 @@
{% include "widgets/related_tags.html" %}
{% endif %}
-{% if settings.SIDEBARE_MAIN_FOOTER %}
+{% if 'SIDEBAR_MAIN_FOOTER'|show_block_to(request.user) %}
<div class="box">
{{ settings.SIDEBAR_MAIN_FOOTER }}
</div>
diff --git a/askbot/templates/meta/bottom_scripts.html b/askbot/templates/meta/bottom_scripts.html
index eec4256d..5c398358 100644
--- a/askbot/templates/meta/bottom_scripts.html
+++ b/askbot/templates/meta/bottom_scripts.html
@@ -97,9 +97,11 @@
askbot['urls']['add_group'] = "{% url add_group %}";
var group_dropdown = new GroupDropdown({{ group_list }});
$('.dropdown').append(group_dropdown.getElement());
- if (askbot['data']['userIsAdmin']) {
- group_dropdown.enableAddGroups();
- }
+ }
+ var userRep = $('#userToolsNav .reputation');
+ if (userRep.length) {
+ var showPermsTrigger = new ShowPermsTrigger();
+ showPermsTrigger.decorate(userRep);
}
});
if (askbot['data']['haveFlashNotifications']) {
diff --git a/askbot/templates/meta/html_head_javascript.html b/askbot/templates/meta/html_head_javascript.html
index 5d73d175..1a1531f7 100644
--- a/askbot/templates/meta/html_head_javascript.html
+++ b/askbot/templates/meta/html_head_javascript.html
@@ -7,7 +7,7 @@
{% if request.user.is_authenticated() %}
askbot['data']['userId'] = {{ request.user.id }};
askbot['data']['userName'] = '{{ request.user.username|escape }}';
- askbot['data']['userIsAdminOrMod'] = {{ request.user.is_administrator()|as_js_bool }};
+ askbot['data']['userIsAdminOrMod'] = {{ request.user.is_administrator_or_moderator()|as_js_bool }};
askbot['data']['userIsAdmin'] = {{ request.user.is_administrator()|as_js_bool }};
askbot['data']['userReputation'] = {{ request.user.reputation }};
{% else %}
diff --git a/askbot/templates/question.html b/askbot/templates/question.html
index 13593adc..ca2f4022 100644
--- a/askbot/templates/question.html
+++ b/askbot/templates/question.html
@@ -285,7 +285,7 @@
</script>
{% endblock %}
{% block content %}
- {% if settings.QUESTION_PAGE_TOP_BANNER %}
+ {% if 'QUESTION_PAGE_TOP_BANNER'|show_block_to(request.user) %}
<div class="banner">{{ settings.QUESTION_PAGE_TOP_BANNER|safe }}</div>
{% endif %}
{% if is_cacheable %}
diff --git a/askbot/templates/question/content.html b/askbot/templates/question/content.html
index 23286ce0..c8fef9a6 100644
--- a/askbot/templates/question/content.html
+++ b/askbot/templates/question/content.html
@@ -12,7 +12,7 @@
<div class="clean"></div>
{% for answer in answers %}
- {% if answers|length > 1 and loop.index == 2 %}
+ {% if loop.index == 2 and 'QUESTION_PAGE_ANSWER_BANNER'|show_block_to(request.user) %}
<div class="banner">{{ settings.QUESTION_PAGE_ANSWER_BANNER|safe }}</div>
{% endif %}
{% include "question/answer_card.html" %}
diff --git a/askbot/templates/question/sidebar.html b/askbot/templates/question/sidebar.html
index c11a4336..c4301b6c 100644
--- a/askbot/templates/question/sidebar.html
+++ b/askbot/templates/question/sidebar.html
@@ -1,5 +1,5 @@
{% import "macros.html" as macros %}
-{% if settings.SIDEBAR_QUESTION_HEADER %}
+{% if 'SIDEBAR_QUESTION_HEADER'|show_block_to(request.user) %}
<div class="box">
{{ settings.SIDEBAR_QUESTION_HEADER }}
</div>
@@ -26,19 +26,6 @@
{% endif %}
</div>
<div class="notify-sidebar">
- {%if request.user.is_authenticated() %}
- <input
- type="checkbox"
- id="question-subscribe-sidebar"
- {% if thread.is_followed_by(request.user) %}
- checked="checked"
- {% endif %}
- />
- <label for="question-subscribe-sidebar">{% trans %}email the updates{% endtrans %}</label>
- {%else%}
- <input type="checkbox" id="question-subscribe-sidebar"/>
- <label for="question-subscribe-sidebar">{% trans %}<strong>Here</strong> (once you log in) you will be able to sign up for the periodic email updates about this question.{% endtrans %}</label>
- {%endif%}
{% if settings.RSS_ENABLED %}
<p class="rss">
<a
@@ -173,7 +160,7 @@
{#% endcache %#}
{% endif %}
-{% if settings.SIDEBAR_QUESTION_FOOTER %}
+{% if 'SIDEBAR_QUESTION_FOOTER'|show_block_to(request.user) %}
<div class="box">
{{ settings.SIDEBAR_QUESTION_FOOTER }}
</div>
diff --git a/askbot/templates/user_profile/user.html b/askbot/templates/user_profile/user.html
index 3aee3cfa..c72dc857 100644
--- a/askbot/templates/user_profile/user.html
+++ b/askbot/templates/user_profile/user.html
@@ -36,11 +36,10 @@
{% endblock %}
{% endblock %}
{% block sidebar %}
-<div class="box">
- {{ settings.SIDEBAR_PROFILE_HEADER }}
-</div>
-<div class="box">
- {{ settings.SIDEBAR_PROFILE_FOOTER }}
-</div>
+ {% if 'SIDEBAR_PROFILE'|show_block_to(request.user) %}
+ <div class="box">
+ {{ settings.SIDEBAR_PROFILE }}
+ </div>
+ {% endif %}
{% endblock %}
<!-- end of user.html -->
diff --git a/askbot/templates/widgets/ask_form.html b/askbot/templates/widgets/ask_form.html
index 3ddb07dd..1d5029f1 100644
--- a/askbot/templates/widgets/ask_form.html
+++ b/askbot/templates/widgets/ask_form.html
@@ -13,6 +13,7 @@
</div>
</div>
{% set editor_is_folded = (
+ settings.QUESTION_BODY_EDITOR_MODE == 'folded' and
settings.MIN_QUESTION_BODY_LENGTH == 0 and
form.text.value()|is_empty_editor_value()
)
diff --git a/askbot/templates/widgets/user_long_score_and_badge_summary.html b/askbot/templates/widgets/user_long_score_and_badge_summary.html
index 35e4cb67..771a8f3f 100644
--- a/askbot/templates/widgets/user_long_score_and_badge_summary.html
+++ b/askbot/templates/widgets/user_long_score_and_badge_summary.html
@@ -1,7 +1,9 @@
{% set have_badges = user.gold or user.silver or user.bronze %}
{%- if karma_mode != 'hidden' -%}
-<a class="user-micro-info"
- href="{{user.get_absolute_url()}}?sort=reputation"
+<a
+ class="user-micro-info reputation"
+ href="{{user.get_absolute_url()}}?sort=reputation"
+ data-url="{% url 'get_perms_data' %}"
>{% trans %}karma:{% endtrans %} {{user.reputation}}</a>{% if badges_mode == 'public' and have_badges %},{% endif %}
{%- endif -%}
{% if badges_mode == 'public' and have_badges %}
diff --git a/askbot/templates/widgets/user_perms.html b/askbot/templates/widgets/user_perms.html
new file mode 100644
index 00000000..887a712f
--- /dev/null
+++ b/askbot/templates/widgets/user_perms.html
@@ -0,0 +1,28 @@
+<!--h2>{% trans karma=user.reputation %}Your karma is {{ karma }}{% endtrans %}</h2-->
+<div class="triangle"></div>
+<p>
+ {% trans %}Karma reflects the value of your contribution to this community.{% endtrans %}
+</p>
+<p>
+ {% if user.is_administrator_or_moderator() %}
+ {% if user.is_moderator() %}
+ {% set role=gettext('moderator') %}
+ {% else %}
+ {% set role=gettext('administrator') %}
+ {% endif %}
+ {% trans %}Since you are the site {{ role }}, you have access to all functions regardless of your karma.{% endtrans %}
+ {% else %}
+ {% trans %}The higher is your karma, the more rights you have on this site.{% endtrans %}
+ {% endif %}
+</p>
+{% if not user.is_administrator_or_moderator() %}
+<p> {% trans %}Currently, you can:{% endtrans %}</p>
+<ul>
+ <li>{% trans %}Post questions, answers and comments{% endtrans %}</li>
+ {% for perm in perms_data %}
+ {% if user.reputation >= perm[1] %}
+ <li>{{ perm[0] }}</li>
+ {% endif %}
+ {% endfor %}
+</ul>
+{% endif %}
diff --git a/askbot/templatetags/extra_filters_jinja.py b/askbot/templatetags/extra_filters_jinja.py
index dccd9a2a..93acea84 100644
--- a/askbot/templatetags/extra_filters_jinja.py
+++ b/askbot/templatetags/extra_filters_jinja.py
@@ -79,6 +79,15 @@ def safe_urlquote(text, quote_plus = False):
return urllib.quote(text.encode('utf8'))
@register.filter
+def show_block_to(block_name, user):
+ block = getattr(askbot_settings, block_name)
+ if block:
+ flag_name = block_name + '_ANON_ONLY'
+ require_anon = getattr(askbot_settings, flag_name, False)
+ return (require_anon is False) or user.is_anonymous()
+ return False
+
+@register.filter
def strip_path(url):
"""removes path part of the url"""
return url_utils.strip_path(url)
diff --git a/askbot/tests/cache_tests.py b/askbot/tests/cache_tests.py
index 5740cc2a..e0703d08 100644
--- a/askbot/tests/cache_tests.py
+++ b/askbot/tests/cache_tests.py
@@ -11,16 +11,19 @@ class CacheTests(AskbotTestCase):
self.post_answer(user=user, question=self.question)
settings.DEBUG = True # because it's forsed to False
+ def tearDown(self):
+ settings.DEBUG = False
+
def visit_question(self):
self.client.get(self.question.get_absolute_url(), follow=True)
-
+
def test_anonymous_question_cache(self):
self.visit_question()
- counter = len(connection.queries)
- print 'we have %d queries' % counter
+ before_count = len(connection.queries)
self.visit_question()
-
#second hit to the same question should give fewer queries
- self.assertTrue(counter > len(connection.queries))
- settings.DEBUG = False
+ after_count = len(connection.queries)
+ self.assertTrue(before_count > after_count,
+ ('Expected fewer queries after calling visit_question. ' +
+ 'Before visit: %d. After visit: %d.') % (before_count, after_count))
diff --git a/askbot/tests/db_api_tests.py b/askbot/tests/db_api_tests.py
index 8d775fd0..1a7ad9e4 100644
--- a/askbot/tests/db_api_tests.py
+++ b/askbot/tests/db_api_tests.py
@@ -514,9 +514,14 @@ class GroupTests(AskbotTestCase):
self.assertEqual(qa.groups.filter(name='private').exists(), True)
def test_global_group_name_setting_changes_group_name(self):
+ orig_group_name = askbot_settings.GLOBAL_GROUP_NAME;
askbot_settings.update('GLOBAL_GROUP_NAME', 'all-people')
group = models.Group.objects.get_global_group()
self.assertEqual(group.name, 'all-people')
+ # Revert the global group name, so we don't mess up other tests!
+ askbot_settings.update('GLOBAL_GROUP_NAME', orig_group_name);
+ group = models.Group.objects.get_global_group()
+ self.assertEqual(group.name, orig_group_name)
def test_ask_global_group_by_id_works(self):
group = models.Group.objects.get_global_group()
@@ -698,5 +703,3 @@ class LinkPostingTests(AskbotTestCase):
self.assert_no_link(question.html)
self.edit_question(user=admin, question=question, body_text=text + ' ok')
self.assert_has_link(question.html, 'http://wikipedia.org')
-
-
diff --git a/askbot/tests/email_alert_tests.py b/askbot/tests/email_alert_tests.py
index 199fd12d..ce107c9a 100644
--- a/askbot/tests/email_alert_tests.py
+++ b/askbot/tests/email_alert_tests.py
@@ -595,6 +595,19 @@ class BlankWeeklySelectedQuestionsEmailAlertTests(EmailAlertTests):
def setUp(self):
self.notification_schedule['q_sel'] = 'w'
self.setup_timestamp = datetime.datetime.now() - datetime.timedelta(14)
+ self.expected_results['q_ask'] = {'message_count': 1, }
+ self.expected_results['q_ask_delete_answer'] = {'message_count': 0, }
+ self.expected_results['question_comment'] = {'message_count': 0, }
+ self.expected_results['question_comment_delete'] = {'message_count': 0, }
+ self.expected_results['answer_comment'] = {'message_count': 0, }
+ self.expected_results['answer_delete_comment'] = {'message_count': 0, }
+ self.expected_results['mention_in_question'] = {'message_count': 0, }
+ self.expected_results['mention_in_answer'] = {'message_count': 0, }
+ self.expected_results['question_edit'] = {'message_count': 1, }
+ self.expected_results['answer_edit'] = {'message_count': 1, }
+ self.expected_results['question_and_answer_by_target'] = {'message_count': 0, }
+ self.expected_results['q_ans'] = {'message_count': 0, }
+ self.expected_results['q_ans_new_answer'] = {'message_count': 0, }
class BlankInstantSelectedQuestionsEmailAlertTests(EmailAlertTests):
"""blank means that this is testing for the absence of email
@@ -605,6 +618,19 @@ class BlankInstantSelectedQuestionsEmailAlertTests(EmailAlertTests):
def setUp(self):
self.notification_schedule['q_sel'] = 'i'
self.setup_timestamp = datetime.datetime.now() - datetime.timedelta(1)
+ self.expected_results['q_ask'] = {'message_count': 1, }
+ self.expected_results['q_ask_delete_answer'] = {'message_count': 1, }
+ self.expected_results['question_comment'] = {'message_count': 1, }
+ self.expected_results['question_comment_delete'] = {'message_count': 1, }
+ self.expected_results['answer_comment'] = {'message_count': 0, }
+ self.expected_results['answer_delete_comment'] = {'message_count': 0, }
+ self.expected_results['mention_in_question'] = {'message_count': 0, }
+ self.expected_results['mention_in_answer'] = {'message_count': 0, }
+ self.expected_results['question_edit'] = {'message_count': 1, }
+ self.expected_results['answer_edit'] = {'message_count': 1, }
+ self.expected_results['question_and_answer_by_target'] = {'message_count': 0, }
+ self.expected_results['q_ans'] = {'message_count': 0, }
+ self.expected_results['q_ans_new_answer'] = {'message_count': 0, }
class LiveWeeklySelectedQuestionsEmailAlertTests(EmailAlertTests):
"""live means that this is testing for the presence of email
diff --git a/askbot/tests/email_parsing_tests.py b/askbot/tests/email_parsing_tests.py
index 3ed0908a..9a5ff126 100644
--- a/askbot/tests/email_parsing_tests.py
+++ b/askbot/tests/email_parsing_tests.py
@@ -18,12 +18,7 @@ class EmailParsingTests(utils.AskbotTestCase):
def test_clean_email_body(self):
cleaned_body = mail.clean_html_email(self.rendered_template)
- print "EXPECTED BODY"
- print self.expected_output
- print '=================================================='
- print cleaned_body
- print "CLEANED BODY"
- self.assertEqual(cleaned_body, self.expected_output)
+ self.assertEqual(self.expected_output, cleaned_body)
def test_gmail_rich_text_response_stripped(self):
text = u'\n\nthis is my reply!\n\nOn Wed, Oct 31, 2012 at 1:45 AM, <kp@kp-dev.askbot.com> wrote:\n\n> **\n> '
diff --git a/askbot/tests/management_command_tests.py b/askbot/tests/management_command_tests.py
index db45b405..a44bb792 100644
--- a/askbot/tests/management_command_tests.py
+++ b/askbot/tests/management_command_tests.py
@@ -35,22 +35,21 @@ class ManagementCommandTests(AskbotTestCase):
question = self.post_question(user=user_one)
comment = self.post_comment(user=user_one, parent_post=question)
number_of_gold = 50
- user_one.gold = number_of_gold
+ user_one.gold = number_of_gold
reputation = 20
- user_one.reputation = reputation
+ user_one.reputation = reputation
user_one.save()
# Create a second user and transfer all objects from 'user_one' to 'user_two'
user_two = self.create_user(username='unique')
+ user_two_pk = user_two.pk
management.call_command('merge_users', user_one.id, user_two.id)
# Check that the first user was deleted
self.assertEqual(models.User.objects.filter(pk=user_one.id).count(), 0)
# Explicitly check that the values assigned to user_one are now user_two's
self.assertEqual(user_two.posts.get_questions().filter(pk=question.id).count(), 1)
self.assertEqual(user_two.posts.get_comments().filter(pk=comment.id).count(), 1)
- #todo: change groups to django groups
- #then replace to 3 back to 2 in the line below
- user_two = models.User.objects.get(pk=2)
- self.assertEqual(user_two.gold, number_of_gold)
+ user_two = models.User.objects.get(pk=user_two_pk)
+ self.assertEqual(user_two.gold, number_of_gold)
self.assertEqual(user_two.reputation, reputation)
def test_create_tag_synonym(self):
diff --git a/askbot/tests/post_model_tests.py b/askbot/tests/post_model_tests.py
index 703603c3..2e785802 100644
--- a/askbot/tests/post_model_tests.py
+++ b/askbot/tests/post_model_tests.py
@@ -546,7 +546,8 @@ class ThreadRenderCacheUpdateTests(AskbotTestCase):
})
self.assertEqual(2, Post.objects.count())
answer = Post.objects.get_answers()[0]
- self.assertRedirects(response=response, expected_url=answer.get_absolute_url())
+ expected_url=answer.get_absolute_url()
+ self.assertRedirects(response=response, expected_url=expected_url)
thread = answer.thread
self.assertEqual(1, thread.answer_count)
diff --git a/askbot/tests/question_views_tests.py b/askbot/tests/question_views_tests.py
index 9486b854..da3e081d 100644
--- a/askbot/tests/question_views_tests.py
+++ b/askbot/tests/question_views_tests.py
@@ -33,7 +33,7 @@ class PrivateQuestionViewsTests(AskbotTestCase):
dom = BeautifulSoup(response2.content)
title = dom.find('h1').text
self.assertTrue(unicode(const.POST_STATUS['private']) in title)
- question = models.Thread.objects.get(id=1)
+ question = models.Thread.objects.get()
self.assertEqual(question.title, self.qdata['title'])
self.assertFalse(models.Group.objects.get_global_group() in set(question.groups.all()))
@@ -114,7 +114,7 @@ class PrivateQuestionViewsTests(AskbotTestCase):
class PrivateAnswerViewsTests(AskbotTestCase):
-
+
def setUp(self):
self._backup = askbot_settings.GROUPS_ENABLED
askbot_settings.update('GROUPS_ENABLED', True)
@@ -147,7 +147,6 @@ class PrivateAnswerViewsTests(AskbotTestCase):
response = self.client.get(self.question.get_absolute_url())
self.assertFalse('some answer text' in response.content)
-
def test_private_checkbox_is_on_when_editing_private_answer(self):
answer = self.post_answer(
question=self.question, user=self.user, is_private=True
diff --git a/askbot/urls.py b/askbot/urls.py
index f71962f1..e82ad0df 100644
--- a/askbot/urls.py
+++ b/askbot/urls.py
@@ -534,7 +534,12 @@ urlpatterns = patterns('',
service_url(
r'^widgets/questions/(?P<widget_id>\d+)/$',
views.widgets.question_widget,
- name = 'question_widget'
+ name='question_widget'
+ ),
+ service_url(
+ r'^get-perms-data/$',
+ views.readers.get_perms_data,
+ name='get_perms_data'
),
service_url(
r'^start-sharing-twitter/$',
diff --git a/askbot/utils/slug.py b/askbot/utils/slug.py
index f9e30cbf..1c95e1d4 100644
--- a/askbot/utils/slug.py
+++ b/askbot/utils/slug.py
@@ -50,10 +50,13 @@ def slugify(input_text, max_length=150):
return input_text
allow_unicode_slugs = getattr(settings, 'ALLOW_UNICODE_SLUGS', False)
- if allow_unicode_slugs:
+ if isinstance(input_text, unicode) and not allow_unicode_slugs:
+ input_text = unidecode(input_text)
+
+ if isinstance(input_text, unicode):
slug = unicode_slugify(input_text)
else:
- slug = defaultfilters.slugify(unidecode(input_text))
+ slug = defaultfilters.slugify(input_text)
while len(slug) > max_length:
# try to shorten word by word until len(slug) <= max_length
temp = slug[:slug.rfind('-')]
diff --git a/askbot/views/readers.py b/askbot/views/readers.py
index f738da25..b2a27324 100644
--- a/askbot/views/readers.py
+++ b/askbot/views/readers.py
@@ -638,3 +638,65 @@ def get_comment(request):
comment = models.Post.objects.get(post_type='comment', id=id)
request.user.assert_can_edit_comment(comment)
return {'text': comment.text}
+
+
+@csrf.csrf_exempt
+@ajax_only
+@anonymous_forbidden
+@get_only
+def get_perms_data(request):
+ """returns details about permitted activities
+ according to the users reputation
+ """
+
+ items = (
+ 'MIN_REP_TO_VOTE_UP',
+ 'MIN_REP_TO_VOTE_DOWN',
+ )
+
+ if askbot_settings.MIN_DAYS_TO_ANSWER_OWN_QUESTION > 0:
+ items += ('MIN_REP_TO_ANSWER_OWN_QUESTION',)
+
+ if askbot_settings.ACCEPTING_ANSWERS_ENABLED:
+ items += (
+ 'MIN_REP_TO_ACCEPT_OWN_ANSWER',
+ 'MIN_REP_TO_ACCEPT_ANY_ANSWER',
+ )
+
+ items += (
+ 'MIN_REP_TO_FLAG_OFFENSIVE',
+ 'MIN_REP_TO_DELETE_OTHERS_COMMENTS',
+ 'MIN_REP_TO_DELETE_OTHERS_POSTS',
+ 'MIN_REP_TO_UPLOAD_FILES',
+ 'MIN_REP_TO_INSERT_LINK',
+ 'MIN_REP_TO_SUGGEST_LINK',
+ 'MIN_REP_TO_CLOSE_OWN_QUESTIONS',
+ 'MIN_REP_TO_REOPEN_OWN_QUESTIONS',
+ 'MIN_REP_TO_CLOSE_OTHERS_QUESTIONS',
+ 'MIN_REP_TO_RETAG_OTHERS_QUESTIONS',
+ 'MIN_REP_TO_EDIT_WIKI',
+ 'MIN_REP_TO_EDIT_OTHERS_POSTS',
+ 'MIN_REP_TO_VIEW_OFFENSIVE_FLAGS',
+ )
+
+ if askbot_settings.ALLOW_ASKING_BY_EMAIL or askbot_settings.REPLY_BY_EMAIL:
+ items += (
+ 'MIN_REP_TO_POST_BY_EMAIL',
+ 'MIN_REP_TO_TWEET_ON_OTHERS_ACCOUNTS',
+ )
+
+ data = list()
+ for item in items:
+ setting = (
+ askbot_settings.get_description(item),
+ getattr(askbot_settings, item)
+ )
+ data.append(setting)
+
+ template = get_template('widgets/user_perms.html')
+ html = template.render({
+ 'user': request.user,
+ 'perms_data': data
+ })
+
+ return {'html': html}
diff --git a/askbot/views/users.py b/askbot/views/users.py
index 179392d2..173ccb85 100644
--- a/askbot/views/users.py
+++ b/askbot/views/users.py
@@ -60,6 +60,7 @@ def owner_or_moderator_required(f):
return f(request, profile_owner, context)
return wrapped_func
+
def show_users(request, by_group=False, group_id=None, group_slug=None):
"""Users view, including listing of users by group"""
if askbot_settings.GROUPS_ENABLED and not by_group:
@@ -1111,7 +1112,7 @@ def user(request, id, slug=None, tab_name=None):
sort=None,
query=None,
tags=None,
- author=profile_owner.id,
+ author=None,
page=None,
user_logged_in=profile_owner.is_authenticated(),
)