diff options
author | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2012-09-06 11:37:33 -0400 |
---|---|---|
committer | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2012-09-06 11:37:33 -0400 |
commit | cc3ebc871f8da4329aad5db65e960b052e8f8834 (patch) | |
tree | 450ce91dcc2de37b9837de6e4db94965f77d07dc | |
parent | c46cbfb2e5bf1d28a5fbfbcf156e5d3509241316 (diff) | |
parent | 996507782f455c17afcf68667ad83c963a9179c7 (diff) | |
download | askbot-cc3ebc871f8da4329aad5db65e960b052e8f8834.tar.gz askbot-cc3ebc871f8da4329aad5db65e960b052e8f8834.tar.bz2 askbot-cc3ebc871f8da4329aad5db65e960b052e8f8834.zip |
merged with adolfos master branch
23 files changed, 230 insertions, 46 deletions
diff --git a/askbot/__init__.py b/askbot/__init__.py index c79d19f9..97b5ee92 100644 --- a/askbot/__init__.py +++ b/askbot/__init__.py @@ -5,6 +5,7 @@ Functions in the askbot module perform various basic actions on behalf of the forum application """ import os +import platform VERSION = (0, 7, 43) @@ -30,11 +31,14 @@ REQUIREMENTS = { 'recaptcha_works': 'django-recaptcha-works', 'openid': 'python-openid', 'pystache': 'pystache==0.3.1', - 'lamson': 'Lamson', 'pytz': 'pytz', 'tinymce': 'django-tinymce', + 'longerusername': 'longerusername', } +if platform.system() != 'Windows': + REQUIREMENTS['lamson'] = 'Lamson' + #necessary for interoperability of django and coffin try: from askbot import patches diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst index eb45eed2..f90fdc73 100644 --- a/askbot/doc/source/changelog.rst +++ b/askbot/doc/source/changelog.rst @@ -3,11 +3,19 @@ Changes in Askbot Development version ------------------- - adding "extra options" to the ldap session (Evgeny) +* Repost comment as answer (Adolfo) +* Question list widget (Adolfo) +* Ask a question widget (Adolfo) +* Embeddable widget generator (Adolfo) +* Groups are shown in the dropdown menu in the header (Adolfo) +* Added group moderation requests to the moderators inboxes (Evgeny) +* Group joining may be open/closed or moderated (Evgeny) +* Adding "extra options" to the ldap session (Evgeny) * Tag moderation (Evgeny) * Editable optional three level category selector for the tags (Evgeny) * Tag editor adding tags as they are typed (Evgeny) * Added optional support for unicode slugs (Evgeny) +* Allow user names longer than 30 characters (Evgeny) * Option to disable feedback form for the anonymos users (Evgeny) * Optional restriction to have confirmed email address to join forum (Evgeny) * Optional list of allowed email addresses and email domain name for the new users (Evgeny) diff --git a/askbot/doc/source/optional-modules.rst b/askbot/doc/source/optional-modules.rst index c8f2dba3..4ba7b925 100644 --- a/askbot/doc/source/optional-modules.rst +++ b/askbot/doc/source/optional-modules.rst @@ -276,6 +276,11 @@ Askbot supports posting replies by email. For this feature to work ``Lamson`` a pip install django-lamson +.. note:: + On Windows installation of the Lamson module may require + additional work. Askbot does not support this feature + on Windows automatically. + The lamson daemon needs a folder to store it's mail queue files and a folder to store log files, create the folders folder named ``run`` and ``logs`` within your project folder by executing the following commands: mkdir run diff --git a/askbot/management/commands/clean_session.py b/askbot/management/commands/clean_session.py index 6ba9352c..2e663b22 100644 --- a/askbot/management/commands/clean_session.py +++ b/askbot/management/commands/clean_session.py @@ -1,13 +1,18 @@ +"""deletes expired sessions from the session database table +works only when sessions are stored in the database +""" from django.core.management.base import NoArgsCommand from django.contrib.sessions.models import Session from django.db import transaction from optparse import make_option -from askbot.utils.console import print_progress +from askbot.utils.console import ProgressBar from datetime import datetime -DELETE_LIMIT = 1000 +ITEMS_PER_TRANSACTION = 1000 class Command(NoArgsCommand): + """Django management command class""" + option_list = NoArgsCommand.option_list + ( make_option('--quiet', action='store_true', @@ -19,32 +24,23 @@ class Command(NoArgsCommand): @transaction.commit_manually def handle_noargs(self, **options): - '''deletes old sessions''' + """deletes old sessions""" quiet = options.get('quiet', False) - expired_session_count = Session.objects.filter(expire_date__lt=datetime.now()).count() - expired_session_list= Session.objects.filter(expire_date__lt=datetime.now()).values_list('session_key', flat=True) - transaction.commit() - - if not quiet: - print "There are %d expired sessions" % expired_session_count - range_limit = len(expired_session_list) - 1 - higher_limit = lower_limit = 0 + expired_sessions = Session.objects.filter( + expire_date__lt=datetime.now() + ) + count = expired_sessions.count() + expired_sessions = expired_sessions.iterator() + if quiet is False: + message = 'There are %d expired sessions' % count + expired_sessions = ProgressBar(expired_sessions, count, message) + + deleted_count = 0 + for session in expired_sessions: + session.delete() + deleted_count += 1 + if deleted_count % ITEMS_PER_TRANSACTION == 0: + transaction.commit() - for i in range(DELETE_LIMIT, range_limit, DELETE_LIMIT): - lower_limit = i - higher_limit = lower_limit + DELETE_LIMIT - sublist = expired_session_list[lower_limit:higher_limit] - Session.objects.filter(session_key__in = sublist).delete() - transaction.commit() - if not quiet: - print_progress(higher_limit-1, expired_session_count) - - if higher_limit < expired_session_list: - sublist = expired_session_list[higher_limit:expired_session_count] - Session.objects.filter(session_key__in = sublist).delete() - print_progress(expired_session_count, expired_session_count) - transaction.commit() - - if not quiet: - print "sessions cleared" + transaction.commit() diff --git a/askbot/migrations/0001_initial.py b/askbot/migrations/0001_initial.py index 0fc434f8..d11c8f2f 100644 --- a/askbot/migrations/0001_initial.py +++ b/askbot/migrations/0001_initial.py @@ -12,17 +12,17 @@ class Migration(SchemaMigration): def forwards(self, orm): #1) patch the existing auth_user table - safe_add_column('auth_user', 'website', self.gf('django.db.models.fields.URLField')(max_length=200, blank=True), keep_default = False) - safe_add_column('auth_user', 'about', self.gf('django.db.models.fields.TextField')(blank=True), keep_default = False) + safe_add_column('auth_user', 'website', self.gf('django.db.models.fields.URLField')(max_length=200, blank=True, null=True), keep_default = False) + safe_add_column('auth_user', 'about', self.gf('django.db.models.fields.TextField')(blank=True, null=True), keep_default = False) safe_add_column('auth_user', 'hide_ignored_questions', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default = False) safe_add_column('auth_user', 'gold', self.gf('django.db.models.fields.SmallIntegerField')(default=0), keep_default = False) safe_add_column('auth_user', 'email_isvalid', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default = False) - safe_add_column('auth_user', 'real_name', self.gf('django.db.models.fields.CharField')(max_length=100, blank=True), keep_default = False) - safe_add_column('auth_user', 'location', self.gf('django.db.models.fields.CharField')(max_length=100, blank=True), keep_default = False) + safe_add_column('auth_user', 'real_name', self.gf('django.db.models.fields.CharField')(max_length=100, blank=True, null=True), keep_default = False) + safe_add_column('auth_user', 'location', self.gf('django.db.models.fields.CharField')(max_length=100, blank=True, null=True), keep_default = False) safe_add_column('auth_user', 'email_key', self.gf('django.db.models.fields.CharField')(max_length=32, null=True), keep_default = False) safe_add_column('auth_user', 'date_of_birth', self.gf('django.db.models.fields.DateField')(null=True, blank=True), keep_default = False) safe_add_column('auth_user', 'reputation', self.gf('django.db.models.fields.PositiveIntegerField')(default=1), keep_default = False) - safe_add_column('auth_user', 'gravatar', self.gf('django.db.models.fields.CharField')(max_length=32), keep_default = False) + safe_add_column('auth_user', 'gravatar', self.gf('django.db.models.fields.CharField')(max_length=32, null=True), keep_default = False) safe_add_column('auth_user', 'bronze', self.gf('django.db.models.fields.SmallIntegerField')(default=0), keep_default = False) safe_add_column('auth_user', 'tag_filter_setting', self.gf('django.db.models.fields.CharField')(default='ignored', max_length=16), keep_default = False) safe_add_column('auth_user', 'last_seen', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now), keep_default = False) diff --git a/askbot/setup_templates/settings.py b/askbot/setup_templates/settings.py index d0cb6e2d..0af52df1 100644 --- a/askbot/setup_templates/settings.py +++ b/askbot/setup_templates/settings.py @@ -150,6 +150,7 @@ TEMPLATE_CONTEXT_PROCESSORS = ( INSTALLED_APPS = ( + 'longerusername', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', diff --git a/askbot/setup_templates/settings.py.mustache b/askbot/setup_templates/settings.py.mustache index e9d9245e..82ff1d92 100644 --- a/askbot/setup_templates/settings.py.mustache +++ b/askbot/setup_templates/settings.py.mustache @@ -149,6 +149,7 @@ TEMPLATE_CONTEXT_PROCESSORS = ( INSTALLED_APPS = ( + 'longerusername', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', diff --git a/askbot/setup_templates/tinymce_sample_config.py b/askbot/setup_templates/tinymce_sample_config.py index d3ac1d12..c75170b0 100644 --- a/askbot/setup_templates/tinymce_sample_config.py +++ b/askbot/setup_templates/tinymce_sample_config.py @@ -21,5 +21,6 @@ TINYMCE_DEFAULT_CONFIG = { 'theme_advanced_resizing': True, 'theme_advanced_resize_horizontal': False, 'theme_advanced_statusbar_location': 'bottom', + 'width': '723', 'height': '250' } diff --git a/askbot/skins/common/media/js/post.js b/askbot/skins/common/media/js/post.js index 22b8cf9b..4cbb9f7e 100644 --- a/askbot/skins/common/media/js/post.js +++ b/askbot/skins/common/media/js/post.js @@ -1665,6 +1665,8 @@ var Comment = function(widget, data){ this._data = data || {}; this._blank = true;//set to false by setContent this._element = null; + this._is_convertible = askbot['data']['userIsAdminOrMod']; + this.convert_link = null; this._delete_prompt = gettext('delete this comment'); if (data && data['is_deletable']){ this._deletable = data['is_deletable']; @@ -1701,6 +1703,12 @@ Comment.prototype.decorate = function(element){ this._edit_link.decorate(edit_link); } + var convert_link = this._element.find('form.convert'); + if (this._is_convertible){ + this._convert_link = new ConvertLink(comment_id); + this._convert_link.decorate(convert_link); + } + var vote = new CommentVoteButton(this); vote.decorate(this._element.find('.comment-votes .upvote')); @@ -1784,6 +1792,11 @@ Comment.prototype.setContent = function(data){ this._edit_link.setHandler(this.getEditHandler()) this._comment_body.append(this._edit_link.getElement()); } + + if (this._is_convertible){ + this._convert_link = new ConvertLink(this._data['id']); + this._comment_body.append(this._convert_link.getElement()); + } this._element.append(this._comment_body); this._blank = false; @@ -1808,6 +1821,9 @@ Comment.prototype.dispose = function(){ if (this._edit_link){ this._edit_link.dispose(); } + if (this._convert_link){ + this._convert_link.dispose(); + } this._data = null; Comment.superClass_.dispose.call(this); }; diff --git a/askbot/skins/common/media/js/utils.js b/askbot/skins/common/media/js/utils.js index 837f4e69..0e23963e 100644 --- a/askbot/skins/common/media/js/utils.js +++ b/askbot/skins/common/media/js/utils.js @@ -655,6 +655,36 @@ EditLink.prototype.decorate = function(element){ this.setHandlerInternal(); }; +var ConvertLink = function(comment_id){ + WrappedElement.call(this) + this._comment_id = comment_id; +}; +inherits(ConvertLink, WrappedElement); + +ConvertLink.prototype.createDom = function(){ + var element = this.makeElement('form'); + element.addClass('convert'); + element.attr('method', 'POST'); + element.attr('action', askbot['urls']['convertComment']); + var hidden_input = this.makeElement('input'); + hidden_input.attr('type', 'hidden'); + hidden_input.attr('value', this._comment_id); + hidden_input.attr('name', 'comment_id'); + hidden_input.attr('id', 'id_comment_id'); + element.append(hidden_input); + + var submit = this.makeElement('input'); + submit.attr('type', 'submit'); + submit.attr('value', gettext('convert to answer')); + element.append(submit); + this.decorate(element); +}; + + +ConvertLink.prototype.decorate = function(element){ + this._element = element; +}; + var DeleteIcon = function(title){ SimpleControl.call(this); this._title = title; diff --git a/askbot/skins/common/media/js/wmd/wmd.js b/askbot/skins/common/media/js/wmd/wmd.js index b9f35c03..5aeacd98 100644 --- a/askbot/skins/common/media/js/wmd/wmd.js +++ b/askbot/skins/common/media/js/wmd/wmd.js @@ -21,6 +21,7 @@ Attacklab.wmdBase = function(){ // Used to work around some browser bugs where we can't use feature testing. + global.isChrome = /chrome/.test(nav.userAgent.toLowerCase()); global.isIE = /msie/.test(nav.userAgent.toLowerCase()); global.isIE_5or6 = /msie 6/.test(nav.userAgent.toLowerCase()) || /msie 5/.test(nav.userAgent.toLowerCase()); global.isIE_7plus = global.isIE && !global.isIE_5or6; @@ -1611,6 +1612,10 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){ var regexText; var replacementText; + + if (global.isChrome) {//Chrome bug workaround + 'X'.match(/()./); + } this.selection = this.selection.replace(/(^\n*)/, ""); this.startTag = this.startTag + re.$1; diff --git a/askbot/skins/default/media/style/style.css b/askbot/skins/default/media/style/style.css index bdba3c28..2e558988 100644 --- a/askbot/skins/default/media/style/style.css +++ b/askbot/skins/default/media/style/style.css @@ -204,7 +204,8 @@ body.user-messages { } .notify .notification { margin-top: 6px; - margin-bottom: 6px; + /*margin-bottom: 6px;*/ + font-size: 16px; color: #424242; } @@ -1319,7 +1320,6 @@ ul#related-tags li { .groups-page h1, .moderate-tags-page h1 { float: left; - padding-top: 7px; } .moderate-tags-page button { line-height: 18px; @@ -2306,6 +2306,26 @@ ul#related-tags li { .question-page .comments .comment-body .edit { padding-left: 6px; } +.question-page .comments .comment-body .convert { + display: inline; + white-space: nowrap; + padding-left: 0px; +} +.question-page .comments .comment-body .convert input { + background: none; + padding: 0px; + color: #1B79BD; + border: none; + width: auto; + font-family: Arial; + line-height: 14px; + margin-left: 6px; + font-size: 13px; +} +.question-page .comments .comment-body .convert input:hover { + text-decoration: underline; + cursor: pointer; +} .question-page .comments .comment-body p { font-size: 13px; line-height: 1.3; @@ -2773,6 +2793,9 @@ ul#related-tags li { /*.users-page .tabBar{ width:375px; }*/ +.users-page #group-openness-selector { + width: 200px; +} .user { padding: 5px 10px 5px 0; line-height: 140%; diff --git a/askbot/skins/default/media/style/style.less b/askbot/skins/default/media/style/style.less index e7f219b2..71570ee1 100644 --- a/askbot/skins/default/media/style/style.less +++ b/askbot/skins/default/media/style/style.less @@ -2158,6 +2158,29 @@ ul#related-tags li { .edit{ padding-left:6px; } + + .convert { + display: inline; + white-space: nowrap; + padding-left: 0px; + } + + .convert input{ + background: none; + padding: 0px; + color: #1B79BD; + border:none; + width:auto; + font-family: Arial; + line-height: 14px; + margin-left: 6px; + font-size: 13px; + } + + .convert input:hover{ + text-decoration:underline; + cursor:pointer; + } } .comment-body p{ diff --git a/askbot/skins/default/templates/macros.html b/askbot/skins/default/templates/macros.html index afdde6b6..e976241c 100644 --- a/askbot/skins/default/templates/macros.html +++ b/askbot/skins/default/templates/macros.html @@ -424,6 +424,11 @@ for the purposes of the AJAX comment editor #} <span class="age"> ({{ timeago(comment.added_at) }})</span> <a id="post-{{comment.id}}-edit" class="edit">{% trans %}edit{% endtrans %}</a> + <form action="{% url comment_to_answer %}" method="POST" accept-charset="utf-8" class='convert'> + {% csrf_token %} + <input type="hidden" value="{{comment.id}}" name="comment_id" id="id_comment_id"> + <input type="submit" value="{% trans %}convert to answer{% endtrans %}"> + </form> </div> </div> <script type="text/javascript"> diff --git a/askbot/skins/default/templates/meta/bottom_scripts.html b/askbot/skins/default/templates/meta/bottom_scripts.html index de829bb7..a36a63ec 100644 --- a/askbot/skins/default/templates/meta/bottom_scripts.html +++ b/askbot/skins/default/templates/meta/bottom_scripts.html @@ -6,6 +6,12 @@ <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, <a href="{{noscript_url}}">here is how</a>{% endtrans %} </noscript> + <script type="text/javascript"> + //IE fix to hide the red margin + var noscript = document.getElementsByTagName('noscript')[0]; + noscript.style.padding = '0px'; + noscript.style.backgroundColor = 'transparent'; + </script> </div> <script type="text/javascript"> var i18nLang = '{{settings.LANGUAGE_CODE}}'; diff --git a/askbot/skins/default/templates/meta/html_head_stylesheets.html b/askbot/skins/default/templates/meta/html_head_stylesheets.html index cadc69e0..85bb489c 100644 --- a/askbot/skins/default/templates/meta/html_head_stylesheets.html +++ b/askbot/skins/default/templates/meta/html_head_stylesheets.html @@ -12,7 +12,9 @@ {% if settings.USE_LOCAL_FONTS %} {% include "meta/fonts.html" %} {% else %} - <link href='http://fonts.googleapis.com/css?family=Open+Sans+Condensed:400,700&subset=latin,cyrillic-ext,latin-ext' rel='stylesheet' type='text/css' /> + {# note: IE8 fix - a combined font link wont work so we have two #} + <link href='http://fonts.googleapis.com/css?family=Open+Sans+Condensed:700&subset=latin-ext' rel='stylesheet' type='text/css'> + <link href='http://fonts.googleapis.com/css?family=Open+Sans+Condensed:700&subset=cyrillic-ext' rel='stylesheet' type='text/css'> {% endif %} {{ skin.get_extra_css_link() }} {% if settings.USE_CUSTOM_CSS %} diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html index 28de61e7..651392fc 100644 --- a/askbot/skins/default/templates/question.html +++ b/askbot/skins/default/templates/question.html @@ -156,11 +156,22 @@ ); } } + + function hide_convert_links(){ + if (!askbot['data']['userIsAdminOrMod']){ + var links = document.getElementsByClassName('convert'); + for (i=0; i<links.length; i++){ + links[i].setAttribute('style', 'display:none;'); + } + } + } + askbot['functions'] = askbot['functions'] || {}; askbot['functions']['renderPostVoteButtons'] = render_vote_buttons; askbot['functions']['renderPostControls'] = render_post_controls; askbot['functions']['renderAddCommentButton'] = render_add_comment_button; askbot['functions']['renderAddAnswerButton'] = render_add_answer_button; + askbot['functions']['hideConvertLinks'] = hide_convert_links; })(); /*]]>*/ </script> diff --git a/askbot/skins/default/templates/question/javascript.html b/askbot/skins/default/templates/question/javascript.html index bc640623..19a7269c 100644 --- a/askbot/skins/default/templates/question/javascript.html +++ b/askbot/skins/default/templates/question/javascript.html @@ -9,6 +9,7 @@ askbot['urls']['postComments'] = '{% url post_comments %}'; askbot['urls']['editComment'] = '{% url edit_comment %}'; askbot['urls']['deleteComment'] = '{% url delete_comment %}'; + askbot['urls']['convertComment'] = '{% url comment_to_answer %}'; askbot['urls']['getComment'] = '{% url get_comment %}'; askbot['urls']['saveDraftAnswer'] = '{% url save_draft_answer %}'; askbot['urls']['question_url_template'] = scriptUrl + '{{ 'question/'|transurl }}{{ "{{QuestionID}}/{{questionSlug}}" }}';{# yes it needs to be that whacky #} @@ -67,6 +68,7 @@ draftHandler.setThreadId({{ thread.id }}); draftHandler.decorate($(document)); } + askbot['functions']['hideConvertLinks'](); }); $(window).bind('hashchange', animate_hashes); diff --git a/askbot/startup_procedures.py b/askbot/startup_procedures.py index 33c33da4..a0c60800 100644 --- a/askbot/startup_procedures.py +++ b/askbot/startup_procedures.py @@ -573,6 +573,24 @@ def test_tinymce(): 'as template:\n\n' + get_tinymce_sample_config() print_errors(errors, header=header, footer=footer) +def test_longerusername(): + """tests proper installation of the "longerusername" app + """ + errors = list() + if 'longerusername' not in django_settings.INSTALLED_APPS: + errors.append( + "add 'longerusername', as the first item in the INSTALLED_APPS" + ) + else: + index = django_settings.INSTALLED_APPS.index('longerusername') + if index != 0: + message = "move 'longerusername', to the beginning of INSTALLED_APPS" + raise AskbotConfigError(message) + + if errors: + errors.append('run "python manage.py migrate longerusername"') + print_errors(errors) + def run_startup_tests(): """function that runs all startup tests, mainly checking settings config so far @@ -589,6 +607,7 @@ def run_startup_tests(): #test_csrf_cookie_domain() test_tinymce() test_staticfiles() + test_longerusername() test_avatar() settings_tester = SettingsTester({ 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY': { diff --git a/askbot/urls.py b/askbot/urls.py index d69db744..808bf84c 100644 --- a/askbot/urls.py +++ b/askbot/urls.py @@ -71,6 +71,7 @@ urlpatterns = patterns('', name='questions' ), # END main page urls + url( r'^api/get_questions/', views.commands.api_get_questions, @@ -187,6 +188,11 @@ urlpatterns = patterns('', views.readers.get_comment, name='get_comment' ), + url(#post only + r'^comment/convert/$', + views.writers.comment_to_answer, + name='comment_to_answer' + ), url( r'^%s$' % _('tags/'), views.readers.tags, diff --git a/askbot/utils/forms.py b/askbot/utils/forms.py index e8f9e622..381ea717 100644 --- a/askbot/utils/forms.py +++ b/askbot/utils/forms.py @@ -9,6 +9,7 @@ from askbot.conf import settings as askbot_settings from askbot.utils.slug import slugify from askbot.utils.functions import split_list from askbot import const +from longerusername import MAX_USERNAME_LENGTH import logging import urllib @@ -86,12 +87,14 @@ class UserNameField(StrippedNonEmptyCharField): else: widget_attrs = login_form_widget_attrs - super(UserNameField,self).__init__(max_length=30, - widget=forms.TextInput(attrs=widget_attrs), + max_length = MAX_USERNAME_LENGTH + super(UserNameField,self).__init__( + max_length=max_length, + widget=forms.TextInput(attrs=login_form_widget_attrs), label=label, error_messages=error_messages, **kw - ) + ) def clean(self,username): """ validate username """ diff --git a/askbot/views/writers.py b/askbot/views/writers.py index a9f1c4a0..9cde2c39 100644 --- a/askbot/views/writers.py +++ b/askbot/views/writers.py @@ -50,7 +50,7 @@ QUESTIONS_PAGE_SIZE = 10 ANSWERS_PAGE_SIZE = 10 @csrf.csrf_exempt -def upload(request):#ajax upload file to a question or answer +def upload(request):#ajax upload file to a question or answer """view that handles file upload via Ajax """ @@ -71,6 +71,7 @@ def upload(request):#ajax upload file to a question or answer if file_name_prefix not in ('', 'group_logo_'): raise exceptions.PermissionDenied('invalid upload file name prefix') + #todo: check file type f = request.FILES['file-upload']#take first file #todo: extension checking should be replaced with mimetype checking #and this must be part of the form validation @@ -121,14 +122,14 @@ def __import_se_data(dump_file): """non-view function that imports the SE data in the future may import other formats as well - In this function stdout is temporarily + In this function stdout is temporarily redirected, so that the underlying importer management command could stream the output to the browser todo: maybe need to add try/except clauses to restore the redirects in the exceptional situations """ - + fake_stdout = tempfile.NamedTemporaryFile() real_stdout = sys.stdout sys.stdout = fake_stdout @@ -226,7 +227,7 @@ def ask(request):#view used to ask a new question author=request.user ) drafts.delete() - + user = form.get_post_user(request.user) try: question = user.post_question( @@ -421,7 +422,7 @@ def edit_question(request, id): body_text = form.cleaned_data['text'], revision_comment = form.cleaned_data['summary'], tags = form.cleaned_data['tags'], - wiki = is_wiki, + wiki = is_wiki, edit_anonymously = is_anon_edit, is_private = post_privately ) @@ -720,3 +721,18 @@ def delete_comment(request): unicode(e), mimetype = 'application/json' ) + +@decorators.admins_only +@decorators.post_only +def comment_to_answer(request): + comment_id = request.POST.get('comment_id') + if comment_id: + comment_id = int(comment_id) + comment = get_object_or_404(models.Post, post_type = 'comment', id=comment_id) + comment.post_type = 'answer' + comment.save() + comment.thread.invalidate_cached_data() + + return HttpResponseRedirect(comment.get_absolute_url()) + else: + raise Http404 diff --git a/askbot_requirements.txt b/askbot_requirements.txt index 1e851490..8771a7e6 100644 --- a/askbot_requirements.txt +++ b/askbot_requirements.txt @@ -20,3 +20,4 @@ python-openid pystache==0.3.1 pytz django-tinymce +longerusername |