diff options
-rw-r--r-- | askbot/conf/sidebar_question.py | 20 | ||||
-rw-r--r-- | askbot/doc/source/changelog.rst | 1 | ||||
-rw-r--r-- | askbot/management/commands/fix_answer_counts.py | 5 | ||||
-rw-r--r-- | askbot/management/commands/fix_question_tags.py | 30 | ||||
-rw-r--r-- | askbot/management/commands/fix_revisionless_posts.py | 7 | ||||
-rw-r--r-- | askbot/models/question.py | 2 | ||||
-rw-r--r-- | askbot/models/tag.py | 4 | ||||
-rw-r--r-- | askbot/skins/common/media/js/post.js | 5 | ||||
-rw-r--r-- | askbot/skins/common/media/js/utils.js | 4 | ||||
-rw-r--r-- | askbot/skins/default/media/style/style.less | 5 | ||||
-rw-r--r-- | askbot/skins/default/templates/macros.html | 16 | ||||
-rw-r--r-- | askbot/skins/default/templates/question.html | 3 | ||||
-rw-r--r-- | askbot/skins/default/templates/tags.html | 1 | ||||
-rw-r--r-- | askbot/skins/default/templates/user_profile/user_stats.html | 1 | ||||
-rw-r--r-- | askbot/tests/db_api_tests.py | 17 | ||||
-rw-r--r-- | askbot/tests/page_load_tests.py | 19 | ||||
-rw-r--r-- | askbot/tests/utils.py | 12 | ||||
-rw-r--r-- | askbot/views/commands.py | 3 |
18 files changed, 120 insertions, 35 deletions
diff --git a/askbot/conf/sidebar_question.py b/askbot/conf/sidebar_question.py index 4416823d..bb71be7e 100644 --- a/askbot/conf/sidebar_question.py +++ b/askbot/conf/sidebar_question.py @@ -6,21 +6,35 @@ from askbot.deps.livesettings import ConfigurationGroup from askbot.deps.livesettings import values from django.utils.translation import ugettext as _ from askbot.conf.super_groups import CONTENT_AND_UI -SIDEBAR_QUESTION = ConfigurationGroup( +SIDEBAR_QUESTION = ConfigurationGroup(#shitty name - why sidebar? 'SIDEBAR_QUESTION', - _('Question page sidebar'), + _('Question page banners and sidebar'), super_group = CONTENT_AND_UI ) settings.register( values.LongStringValue( SIDEBAR_QUESTION, + 'QUESTION_PAGE_TOP_BANNER', + description = _('Top banner'), + default = '', + help_text = _( + 'When using this option, please ' + 'use the HTML validation service to make sure that ' + 'your input is valid and works well in all browsers.' + ) + ) +) + +settings.register( + values.LongStringValue( + SIDEBAR_QUESTION, 'SIDEBAR_QUESTION_HEADER', description = _('Custom sidebar header'), default = '', help_text = _( 'Use this area to enter content at the TOP of the sidebar' - 'in HTML format. When using this option ' + 'in HTML format. When using this option ' '(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.' diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst index a15ad406..f975b83c 100644 --- a/askbot/doc/source/changelog.rst +++ b/askbot/doc/source/changelog.rst @@ -9,6 +9,7 @@ Development version to help prevent user profile spam (Evgeny) * Added a function to create a custom user profile tab, the feature requires access to the server (Evgeny) +* Added optional top banner to the question page (Evgeny) 0.7.43 (May 14, 2012) --------------------- diff --git a/askbot/management/commands/fix_answer_counts.py b/askbot/management/commands/fix_answer_counts.py index 959e37b6..9f22422e 100644 --- a/askbot/management/commands/fix_answer_counts.py +++ b/askbot/management/commands/fix_answer_counts.py @@ -23,6 +23,5 @@ class Command(NoArgsCommand): """function that handles the command job """ self.remove_save_signals() - questions = models.Question.objects.all() - for question in questions: - question.thread.update_answer_count() + for thread in models.Thread.objects.all(): + thread.update_answer_count() diff --git a/askbot/management/commands/fix_question_tags.py b/askbot/management/commands/fix_question_tags.py index 9858e397..d575e651 100644 --- a/askbot/management/commands/fix_question_tags.py +++ b/askbot/management/commands/fix_question_tags.py @@ -39,33 +39,33 @@ class Command(NoArgsCommand): transaction.commit() #go through questions and fix tag records on each - questions = models.Question.objects.all() + threads = models.Thread.objects.all() checked_count = 0 found_count = 0 - total_count = questions.count() + total_count = threads.count() print "Searching for questions with inconsistent tag records:", - for question in questions: - tags = question.thread.tags.all() - denorm_tag_set = set(question.get_tag_names()) - norm_tag_set = set(question.thread.tags.values_list('name', flat=True)) + for thread in threads: + tags = thread.tags.all() + denorm_tag_set = set(thread.get_tag_names()) + norm_tag_set = set(thread.tags.values_list('name', flat=True)) if norm_tag_set != denorm_tag_set: - if question.last_edited_by: - user = question.last_edited_by - timestamp = question.last_edited_at + if thread.last_edited_by: + user = thread.last_edited_by + timestamp = thread.last_edited_at else: - user = question.author - timestamp = question.added_at + user = thread.author + timestamp = thread.added_at - tagnames = forms.TagNamesField().clean(question.tagnames) + tagnames = forms.TagNamesField().clean(thread.tagnames) - question.thread.update_tags( + thread.update_tags( tagnames = tagnames, user = user, timestamp = timestamp ) - question.thread.tagnames = tagnames - question.thread.save() + thread.tagnames = tagnames + thread.save() found_count += 1 transaction.commit() diff --git a/askbot/management/commands/fix_revisionless_posts.py b/askbot/management/commands/fix_revisionless_posts.py index 92c03425..9535bef3 100644 --- a/askbot/management/commands/fix_revisionless_posts.py +++ b/askbot/management/commands/fix_revisionless_posts.py @@ -7,11 +7,11 @@ from django.db.models import signals, Count from askbot import models from askbot import const -def fix_revisionless_posts(post_class, post_name): +def fix_revisionless_posts(post_class): posts = post_class.objects.annotate( rev_count = Count('revisions') ).filter(rev_count = 0) - print 'have %d corrupted %ss' % (len(posts), post_name) + print 'have %d corrupted posts' % len(posts) for post in posts: post.add_revision( author = post.author, @@ -39,5 +39,4 @@ class Command(NoArgsCommand): """function that handles the command job """ self.remove_save_signals() - fix_revisionless_posts(models.Question, 'question') - fix_revisionless_posts(models.Answer, 'answer') + fix_revisionless_posts(models.Post) diff --git a/askbot/models/question.py b/askbot/models/question.py index b3d755f5..1729b531 100644 --- a/askbot/models/question.py +++ b/askbot/models/question.py @@ -74,6 +74,7 @@ class ThreadManager(models.Manager): by_email = False, email_address = None ): + """creates new thread""" # TODO: Some of this code will go to Post.objects.create_new thread = super( @@ -786,6 +787,7 @@ class Thread(models.Model): return False def retag(self, retagged_by=None, retagged_at=None, tagnames=None, silent=False): + """changes thread tags""" if None in (retagged_by, retagged_at, tagnames): raise Exception('arguments retagged_at, retagged_by and tagnames are required') diff --git a/askbot/models/tag.py b/askbot/models/tag.py index 5a83c67c..858db2e6 100644 --- a/askbot/models/tag.py +++ b/askbot/models/tag.py @@ -118,7 +118,9 @@ class GroupTagManager(BaseQuerySetManager): #replace spaces with dashes group_name = clean_group_name(group_name) try: - tag = self.get(name = group_name) + #iexact is important!!! b/c we don't want case variants + #of tags + tag = self.get(name__iexact = group_name) except self.model.DoesNotExist: tag = self.model(name = group_name, created_by = user) tag.save() diff --git a/askbot/skins/common/media/js/post.js b/askbot/skins/common/media/js/post.js index f5ef7c9d..58f2436d 100644 --- a/askbot/skins/common/media/js/post.js +++ b/askbot/skins/common/media/js/post.js @@ -1062,10 +1062,11 @@ var questionRetagger = function(){ var tags_str = ''; links.each(function(index, element){ if (index === 0){ - tags_str = $(element).html(); + //this is pretty bad - we should use Tag.getName() + tags_str = $(element).attr('data-tag-name'); } else { - tags_str += ' ' + $(element).html(); + tags_str += ' ' + $(element).attr('data-tag-name'); } }); return tags_str; diff --git a/askbot/skins/common/media/js/utils.js b/askbot/skins/common/media/js/utils.js index d5ce1c2d..d04a3cdb 100644 --- a/askbot/skins/common/media/js/utils.js +++ b/askbot/skins/common/media/js/utils.js @@ -987,7 +987,9 @@ Tag.prototype.decorate = function(element){ this._delete_icon.decorate(del); } this._inner_element = this._element.find('.tag'); - this._name = this.decodeTagName($.trim(this._inner_element.html())); + this._name = this.decodeTagName( + $.trim(this._inner_element.attr('data-tag-name')) + ); if (this._title !== null){ this._inner_element.attr('title', this._title); } diff --git a/askbot/skins/default/media/style/style.less b/askbot/skins/default/media/style/style.less index 87f1f4c8..343204fe 100644 --- a/askbot/skins/default/media/style/style.less +++ b/askbot/skins/default/media/style/style.less @@ -3167,6 +3167,11 @@ ul.post-tags li { ul.post-retag { margin-bottom:0px; margin-left:5px; + input { + width: 400px; + height: 1.5em; + margin: 3px 0 0 -3px; + } } #question-controls .tags { diff --git a/askbot/skins/default/templates/macros.html b/askbot/skins/default/templates/macros.html index e8d8246b..485713aa 100644 --- a/askbot/skins/default/templates/macros.html +++ b/askbot/skins/default/templates/macros.html @@ -200,7 +200,8 @@ poor design of the data or methods on data objects #} search_state = None, css_class = None, tag_css_class = None, - tag_html_tag = 'li' + tag_html_tag = 'li', + truncate_long_tags = False ) -%} <ul {% if id %}id="{{ id }}"{% endif %} @@ -214,7 +215,8 @@ poor design of the data or methods on data objects #} deletable = deletable, is_link = make_links, search_state = search_state, - html_tag = tag_html_tag + html_tag = tag_html_tag, + truncate_long_tag = False )}} {% endfor %} {% endif %} @@ -276,7 +278,8 @@ poor design of the data or methods on data objects #} css_class = None, search_state = None, html_tag = 'div', - extra_content = '' + extra_content = '', + truncate_long_tag = False ) -%} {% if not search_state %} {# get empty SearchState() if there's none; CAUTION: for some reason this doesn't work inside `spaceless` tag below! #} @@ -291,7 +294,12 @@ poor design of the data or methods on data objects #} title="{% trans %}see questions tagged '{{ tag }}'{% endtrans %}" {% endif %} rel="tag" - >{{ tag|replace('*', '✽')|truncate(20,True)}}</{% if not is_link or tag[-1] == '*' %}span{% else %}a{% endif %}> + data-tag-name="{{ tag|replace('*', '✽')|escape }}" + >{% if truncate_long_tag -%} + {{ tag|replace('*', '✽')|truncate(17, True) }} + {%- else -%} + {{ tag|replace('*', '✽') }} + {%- endif %}</{% if not is_link or tag[-1] == '*' %}span{% else %}a{% endif %}> {% if deletable %} <div class="delete-icon" {% if delete_link_title %} diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html index bd48bd54..bb74db33 100644 --- a/askbot/skins/default/templates/question.html +++ b/askbot/skins/default/templates/question.html @@ -157,6 +157,9 @@ </script> {% endblock %} {% block content %} + <div> + {{ settings.QUESTION_PAGE_TOP_BANNER }} + </div> {% if is_cacheable %} {% cache long_time "thread-content-html" thread.id %} {% include "question/content.html" %} diff --git a/askbot/skins/default/templates/tags.html b/askbot/skins/default/templates/tags.html index 6b89bdba..007388af 100644 --- a/askbot/skins/default/templates/tags.html +++ b/askbot/skins/default/templates/tags.html @@ -40,6 +40,7 @@ {{ macros.tag_widget( tag = tag.name, html_tag = 'div', + truncate_long_tag = True, extra_content = '<span class="tag-number">× ' ~ tag.used_count|intcomma ~ '</span>' ) diff --git a/askbot/skins/default/templates/user_profile/user_stats.html b/askbot/skins/default/templates/user_profile/user_stats.html index b125589c..177df214 100644 --- a/askbot/skins/default/templates/user_profile/user_stats.html +++ b/askbot/skins/default/templates/user_profile/user_stats.html @@ -90,6 +90,7 @@ tag.name, html_tag = 'div', search_state = search_state, + truncate_long_tag = True, extra_content = '<span class="tag-number">× ' ~ tag.user_tag_usage_count|intcomma ~ diff --git a/askbot/tests/db_api_tests.py b/askbot/tests/db_api_tests.py index 1f3d3b9b..3a0c9582 100644 --- a/askbot/tests/db_api_tests.py +++ b/askbot/tests/db_api_tests.py @@ -15,6 +15,9 @@ from askbot.conf import settings as askbot_settings import datetime class DBApiTests(AskbotTestCase): + """tests methods on User object, + that were added for askbot + """ def setUp(self): self.create_user() @@ -161,7 +164,8 @@ class DBApiTests(AskbotTestCase): matches = models.Post.objects.get_questions().get_by_text_query("database'") self.assertTrue(len(matches) == 1) -class UserLikeTests(AskbotTestCase): +class UserLikeTagTests(AskbotTestCase): + """tests for user liking and disliking tags""" def setUp(self): self.create_user() self.question = self.post_question(tags = 'one two three') @@ -387,3 +391,14 @@ class CommentTests(AskbotTestCase): self.other_user.upvote(comment, cancel = True) comment = models.Post.objects.get_comments().get(id = self.comment.id) self.assertEquals(comment.score, 0) + +class TagAndGroupTests(AskbotTestCase): + def setUp(self): + self.u1 = self.create_user('u1') + + def test_group_cannot_create_case_variant_tag(self): + self.post_question(user = self.u1, tags = 'one two three') + models.Tag.group_tags.get_or_create(user = self.u1, group_name = 'One') + tag_one = models.Tag.objects.filter(name__iexact = 'one') + self.assertEqual(tag_one.count(), 1) + self.assertEqual(tag_one[0].name, 'one') diff --git a/askbot/tests/page_load_tests.py b/askbot/tests/page_load_tests.py index ebfba0c3..e3e699a7 100644 --- a/askbot/tests/page_load_tests.py +++ b/askbot/tests/page_load_tests.py @@ -67,7 +67,9 @@ class PageLoadTestCase(AskbotTestCase): def setUp(self): self.old_cache = cache.cache - cache.cache = DummyCache('', {}) # Disable caching (to not interfere with production cache, not sure if that's possible but let's not risk it) + #Disable caching (to not interfere with production cache, + #not sure if that's possible but let's not risk it) + cache.cache = DummyCache('', {}) def tearDown(self): cache.cache = self.old_cache # Restore caching @@ -610,3 +612,18 @@ class QuestionPageRedirectTests(AskbotTestCase): #point to a non-existing comment resp = self.client.get(url, data={'comment': 100301}) self.assertRedirects(resp, expected_url = self.q.get_absolute_url()) + +class CommandViewTests(AskbotTestCase): + def test_get_tag_wiki_text_succeeds(self): + tag1 = self.create_tag('tag1') + response = self.client.get( + reverse('load_tag_wiki_text'), + data = {'tag_id': tag1.id} + ) + self.assertEqual(response.status_code, 200) + + def test_get_tag_wiki_text_fails(self): + tag1 = self.create_tag('tag1') + response = self.client.get(reverse('load_tag_wiki_text')) + self.assertEqual(response.status_code, 400)#bad request + diff --git a/askbot/tests/utils.py b/askbot/tests/utils.py index 8395b1ca..4bc69ac4 100644 --- a/askbot/tests/utils.py +++ b/askbot/tests/utils.py @@ -174,6 +174,18 @@ class AskbotTestCase(TestCase): timestamp = timestamp ) + def create_tag(self, tag_name, user = None): + """creates a user, b/c it is necessary""" + if user is None: + try: + user = models.User.objects.get(username = 'tag_creator') + except models.User.DoesNotExist: + user = self.create_user('tag_creator') + + tag = models.Tag(created_by = user, name = tag_name) + tag.save() + return tag + def post_comment( self, user = None, diff --git a/askbot/views/commands.py b/askbot/views/commands.py index ec535aef..83f62b34 100644 --- a/askbot/views/commands.py +++ b/askbot/views/commands.py @@ -485,6 +485,9 @@ def get_tag_list(request): @decorators.get_only def load_tag_wiki_text(request): """returns text of the tag wiki in markdown format""" + if 'tag_id' not in request.GET: + return HttpResponse('', status = 400)#bad request + tag = get_object_or_404(models.Tag, id = request.GET['tag_id']) tag_wiki_text = getattr(tag.tag_wiki, 'text', '').strip() return HttpResponse(tag_wiki_text, mimetype = 'text/plain') |