diff options
author | Adolfo Fitoria <adolfo.fitoria@gmail.com> | 2012-08-02 13:47:30 -0600 |
---|---|---|
committer | Adolfo Fitoria <adolfo.fitoria@gmail.com> | 2012-08-02 13:47:30 -0600 |
commit | cfbe88a098e01297f6fd3a66364146e531d3a1c8 (patch) | |
tree | 22a46002cf4a6b15d123bf9d8630ab7ed4875163 | |
parent | 4f6a78f465de5b439ece14ffea79351572dbb75d (diff) | |
parent | 9f70b5c627ba0943542127cc0b4d30b1c4f515ef (diff) | |
download | askbot-cfbe88a098e01297f6fd3a66364146e531d3a1c8.tar.gz askbot-cfbe88a098e01297f6fd3a66364146e531d3a1c8.tar.bz2 askbot-cfbe88a098e01297f6fd3a66364146e531d3a1c8.zip |
Merge branch 'master' into django1.4
25 files changed, 389 insertions, 65 deletions
diff --git a/askbot/conf/moderation.py b/askbot/conf/moderation.py index 9f8e24c7..8e77385f 100644 --- a/askbot/conf/moderation.py +++ b/askbot/conf/moderation.py @@ -4,8 +4,16 @@ from askbot.conf.settings_wrapper import settings from askbot.conf.super_groups import DATA_AND_FORMATTING from askbot.deps.livesettings import ConfigurationGroup from askbot.deps.livesettings import BooleanValue +from django.core.cache import cache from django.utils.translation import ugettext as _ +def empty_cache_callback(old_value, new_value): + """used to clear cache on change of certain values""" + if old_value != new_value: + #todo: change this to warmup cache + cache.clear() + return new_value + MODERATION = ConfigurationGroup( 'MODERATION', _('Content moderation'), @@ -18,5 +26,6 @@ settings.register( 'ENABLE_CONTENT_MODERATION', default = False, description = _('Enable content moderation'), + update_callback = empty_cache_callback ) ) diff --git a/askbot/conf/user_settings.py b/askbot/conf/user_settings.py index 9077a720..e7dea7c8 100644 --- a/askbot/conf/user_settings.py +++ b/askbot/conf/user_settings.py @@ -16,6 +16,15 @@ USER_SETTINGS = livesettings.ConfigurationGroup( ) settings.register( + livesettings.StringValue( + USER_SETTINGS, + 'NEW_USER_GREETING', + default = '', + description = _('On-screen greeting shown to the new users') + ) +) + +settings.register( livesettings.BooleanValue( USER_SETTINGS, 'EDITABLE_SCREEN_NAME', diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst index c0540be9..48725c07 100644 --- a/askbot/doc/source/changelog.rst +++ b/askbot/doc/source/changelog.rst @@ -6,6 +6,7 @@ Development version * Added optional support for unicode slugs (Evgeny) * Optionally allow limiting one answer per question per person (Evgeny) * Added management command `build_livesettings_cache` (Adolfo) +* Administrators can post under fictional user accounts without logging out (jtrain, Evgeny) * Welcome email for the case when replying by email is enabled (Evgeny) * Detection of email signature based on the response to the welcome email (Evgeny) * Hide "website" and "about" section of the blocked user profiles diff --git a/askbot/doc/source/contributors.rst b/askbot/doc/source/contributors.rst index 69348b84..ce8656ea 100644 --- a/askbot/doc/source/contributors.rst +++ b/askbot/doc/source/contributors.rst @@ -41,6 +41,7 @@ Programming and documentation * Silvio Heuberger * `Alexandros <https://github.com/alexandros-z>`_ * `Paul Backhouse <https://github.com/powlo>`_ +* `jtrain <https://github.com/jtrain>`_ Translations ------------ diff --git a/askbot/forms.py b/askbot/forms.py index 1188ed59..ecf86717 100644 --- a/askbot/forms.py +++ b/askbot/forms.py @@ -3,6 +3,7 @@ used in AskBot""" import re from django import forms from askbot import const +from django.forms.util import ErrorList from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext_lazy, string_concat from django.utils.text import get_text_list @@ -733,7 +734,80 @@ class FormWithHideableFields(object): self.fields[name] = self.__hidden_fields.pop(name) -class AskForm(forms.Form, FormWithHideableFields): +class PostAsSomeoneForm(forms.Form): + post_author_username = forms.CharField( + initial=_('User name:'), + help_text=_( + 'Enter name to post on behalf of someone else. ' + 'Can create new accounts.' + ), + required=False, + widget=forms.TextInput(attrs={'class': 'tipped-input'}) + ) + post_author_email = forms.CharField( + initial=_('Email address:'), + required=False, + widget=forms.TextInput(attrs={'class': 'tipped-input'}) + ) + + def get_post_user(self, user): + """returns user on whose behalf the post or a revision + is being made + """ + username = self.cleaned_data['post_author_username'] + email= self.cleaned_data['post_author_email'] + if user.is_administrator() and username and email: + post_user = user.get_or_create_fake_user(username, email) + else: + post_user = user + return post_user + + def clean_post_author_username(self): + """if value is the same as initial, it is reset to + empty string + todo: maybe better to have field where initial value is invalid, + then we would not have to have two almost identical clean functions? + """ + username = self.cleaned_data.get('post_author_username', '') + initial_username = unicode(self.fields['post_author_username'].initial) + if username == initial_username: + self.cleaned_data['post_author_username'] = '' + return self.cleaned_data['post_author_username'] + + def clean_post_author_email(self): + """if value is the same as initial, it is reset to + empty string""" + email = self.cleaned_data.get('post_author_email', '') + initial_email = unicode(self.fields['post_author_email'].initial) + if email == initial_email: + email = '' + if email != '': + email = forms.EmailField().clean(email) + self.cleaned_data['post_author_email'] = email + return email + + def clean(self): + """requires email address if user name is given""" + username = self.cleaned_data.get('post_author_username', '') + email = self.cleaned_data.get('post_author_email', '') + if username == '' and email: + username_errors = self._errors.get( + 'post_author_username', + ErrorList() + ) + username_errors.append(_('User name is required with the email')) + self._errors['post_author_username'] = username_errors + raise forms.ValidationError('missing user name') + elif email == '' and username: + email_errors = self._errors.get('post_author_email', ErrorList()) + email_errors.append(_('Email is required if user name is added')) + self._errors['post_author_email'] = email_errors + raise forms.ValidationError('missing email') + + return self.cleaned_data + + +class AskForm(PostAsSomeoneForm, FormWithHideableFields): """the form used to askbot questions field ask_anonymously is shown to the user if the if ALLOW_ASK_ANONYMOUSLY live setting is True @@ -757,14 +831,6 @@ class AskForm(forms.Form, FormWithHideableFields): required=False, max_length=255, widget=forms.TextInput(attrs={'size': 40, 'class': 'openid-input'}) ) - user = forms.CharField( - required=False, max_length=255, - widget=forms.TextInput(attrs={'size': 35}) - ) - email = forms.CharField( - required=False, max_length=255, - widget=forms.TextInput(attrs={'size': 35}) - ) def __init__(self, *args, **kwargs): super(AskForm, self).__init__(*args, **kwargs) @@ -867,21 +933,13 @@ class AskByEmailForm(forms.Form): return self.cleaned_data['subject'] -class AnswerForm(forms.Form): +class AnswerForm(PostAsSomeoneForm): text = AnswerEditorField() wiki = WikiField() openid = forms.CharField( required=False, max_length=255, widget=forms.TextInput(attrs={'size': 40, 'class': 'openid-input'}) ) - user = forms.CharField( - required=False, max_length=255, - widget=forms.TextInput(attrs={'size': 35}) - ) - email = forms.CharField( - required=False, max_length=255, - widget=forms.TextInput(attrs={'size': 35}) - ) email_notify = EmailNotifyField(initial=False) def __init__(self, *args, **kwargs): @@ -952,7 +1010,7 @@ class RevisionForm(forms.Form): self.fields['revision'].initial = latest_revision.revision -class EditQuestionForm(forms.Form, FormWithHideableFields): +class EditQuestionForm(PostAsSomeoneForm, FormWithHideableFields): title = TitleField() text = QuestionEditorField() tags = TagNamesField() @@ -1053,6 +1111,7 @@ class EditQuestionForm(forms.Form, FormWithHideableFields): field edit_anonymously. It relies on correct cleaning if the "reveal_identity" field """ + super(EditQuestionForm, self).clean() reveal_identity = self.cleaned_data.get('reveal_identity', False) stay_anonymous = False if reveal_identity is False and self.can_stay_anonymous(): @@ -1061,7 +1120,7 @@ class EditQuestionForm(forms.Form, FormWithHideableFields): return self.cleaned_data -class EditAnswerForm(forms.Form): +class EditAnswerForm(PostAsSomeoneForm): text = AnswerEditorField() summary = SummaryField() wiki = WikiField() diff --git a/askbot/migrations/0126_add_field__auth_user__is_fake.py b/askbot/migrations/0126_add_field__auth_user__is_fake.py new file mode 100644 index 00000000..e0928ed7 --- /dev/null +++ b/askbot/migrations/0126_add_field__auth_user__is_fake.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from south.db import db +from south.v2 import SchemaMigration + +class Migration(SchemaMigration): + + def forwards(self, orm): + try: + # Adding field 'User.is_fake' + db.add_column( + u'auth_user', 'is_fake', + self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False) + except: + pass + + def backwards(self, orm): + db.delete_column('auth_user', 'is_fake') + + complete_apps = ['askbot'] diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py index 1c884ed6..c1beb594 100644 --- a/askbot/models/__init__.py +++ b/askbot/models/__init__.py @@ -83,6 +83,7 @@ User.add_to_class( choices = const.USER_STATUS_CHOICES ) ) +User.add_to_class('is_fake', models.BooleanField(default=False)) User.add_to_class('email_isvalid', models.BooleanField(default=False)) #@UndefinedVariable User.add_to_class('email_key', models.CharField(max_length=32, null=True)) @@ -343,6 +344,24 @@ def user_can_post_by_email(self): return askbot_settings.REPLY_BY_EMAIL and \ self.reputation > askbot_settings.MIN_REP_TO_POST_BY_EMAIL +def user_get_or_create_fake_user(self, username, email): + """ + Get's or creates a user, most likely with the purpose + of posting under that account. + """ + assert(self.is_administrator()) + + try: + user = User.objects.get(username=username) + except User.DoesNotExist: + user = User() + user.username = username + user.email = email + user.is_fake = True + user.set_unusable_password() + user.save() + return user + def _assert_user_can( user = None, post = None, #related post (may be parent) @@ -2172,14 +2191,14 @@ def user_get_badge_summary(self): bit = ungettext( 'one silver badge', '%(count)d silver badges', - self.gold + self.silver ) % {'count': self.silver} badge_bits.append(bit) - if self.silver: + if self.bronze: bit = ungettext( 'one bronze badge', '%(count)d bronze badges', - self.gold + self.bronze ) % {'count': self.bronze} badge_bits.append(bit) @@ -2537,6 +2556,7 @@ User.add_to_class('get_absolute_url', user_get_absolute_url) User.add_to_class('get_avatar_url', user_get_avatar_url) User.add_to_class('get_default_avatar_url', user_get_default_avatar_url) User.add_to_class('get_gravatar_url', user_get_gravatar_url) +User.add_to_class('get_or_create_fake_user', user_get_or_create_fake_user) User.add_to_class('get_marked_tags', user_get_marked_tags) User.add_to_class('get_marked_tag_names', user_get_marked_tag_names) User.add_to_class('strip_email_signature', user_strip_email_signature) @@ -2844,7 +2864,7 @@ def send_instant_notifications_about_activity_in_post( newly mentioned users are carried through to reduce database hits """ - if askbot_settings.ENABLE_CONTENT_MODERATION and post.approved == False: + if post.is_approved() is False: return if recipients is None: @@ -3215,22 +3235,29 @@ def send_respondable_email_validation_message( ) -def send_welcome_email(user, **kwargs): +def greet_new_user(user, **kwargs): """sends welcome email to the newly created user todo: second branch should send email with a simple clickable link. """ + if askbot_settings.NEW_USER_GREETING: + user.message_set.create(message = askbot_settings.NEW_USER_GREETING) + if askbot_settings.REPLY_BY_EMAIL:#with this on we also collect signature - data = { - 'site_name': askbot_settings.APP_SHORT_NAME - } - send_respondable_email_validation_message( - user = user, - subject_line = _('Welcome to %(site_name)s') % data, - data = data, - template_name = 'email/welcome_lamson_on.html' - ) + template_name = 'email/welcome_lamson_on.html' + else: + template_name = 'email/welcome_lamson_off.html' + + data = { + 'site_name': askbot_settings.APP_SHORT_NAME + } + send_respondable_email_validation_message( + user = user, + subject_line = _('Welcome to %(site_name)s') % data, + data = data, + template_name = template_name + ) def complete_pending_tag_subscriptions(sender, request, *args, **kwargs): @@ -3317,7 +3344,7 @@ signals.delete_question_or_answer.connect(record_delete_question, sender=Post) signals.flag_offensive.connect(record_flag_offensive, sender=Post) signals.remove_flag_offensive.connect(remove_flag_offensive, sender=Post) signals.tags_updated.connect(record_update_tags) -signals.user_registered.connect(send_welcome_email) +signals.user_registered.connect(greet_new_user) signals.user_updated.connect(record_user_full_updated, sender=User) signals.user_logged_in.connect(complete_pending_tag_subscriptions)#todo: add this to fake onlogin middleware signals.user_logged_in.connect(post_anonymous_askbot_content) diff --git a/askbot/models/base.py b/askbot/models/base.py index b3a12fbf..74b8c2dd 100644 --- a/askbot/models/base.py +++ b/askbot/models/base.py @@ -41,7 +41,7 @@ class BaseQuerySetManager(models.Manager): return getattr(self.get_query_set(), attr, *args) -class AnonymousContent(models.Model): +class DraftContent(models.Model): """Base class for AnonymousQuestion and AnonymousAnswer""" session_key = models.CharField(max_length=40) #session id for anonymous questions wiki = models.BooleanField(default=False) diff --git a/askbot/models/post.py b/askbot/models/post.py index d61c1ae2..25b3f47a 100644 --- a/askbot/models/post.py +++ b/askbot/models/post.py @@ -29,7 +29,7 @@ from askbot.conf import settings as askbot_settings from askbot import exceptions from askbot.utils import markup from askbot.utils.html import sanitize_html -from askbot.models.base import BaseQuerySetManager, AnonymousContent +from askbot.models.base import BaseQuerySetManager, DraftContent #todo: maybe merge askbot.utils.markup and forum.utils.html from askbot.utils.diff import textDiff as htmldiff @@ -513,8 +513,18 @@ class Post(models.Model): def is_reject_reason(self): return self.post_type == 'reject_reason' + def is_approved(self): + """``False`` only when moderation is ``True`` and post + ``self.approved is False`` + """ + if askbot_settings.ENABLE_CONTENT_MODERATION: + if self.approved == False: + return False + return True + def needs_moderation(self): - return self.approved == False + #todo: do we need this, can't we just use is_approved()? + return self.approved is False def get_absolute_url(self, no_slug = False, question_post=None, thread=None): from askbot.utils.slug import slugify @@ -1207,9 +1217,8 @@ class Post(models.Model): def _question__assert_is_visible_to(self, user): """raises QuestionHidden""" - if askbot_settings.ENABLE_CONTENT_MODERATION: - if self.approved == False: - raise exceptions.QuestionHidden() + if self.is_approved() is False: + raise exceptions.QuestionHidden() if self.deleted: message = _( 'Sorry, this question has been ' @@ -1897,7 +1906,7 @@ class PostFlagReason(models.Model): app_label = 'askbot' -class AnonymousAnswer(AnonymousContent): +class AnonymousAnswer(DraftContent): question = models.ForeignKey(Post, related_name='anonymous_answers') def publish(self, user): diff --git a/askbot/models/question.py b/askbot/models/question.py index 3e8d2267..2bb9e80a 100644 --- a/askbot/models/question.py +++ b/askbot/models/question.py @@ -14,7 +14,7 @@ from django.utils.translation import ungettext import askbot import askbot.conf from askbot.models.tag import Tag -from askbot.models.base import AnonymousContent +from askbot.models.base import DraftContent from askbot.models.post import Post, PostRevision from askbot.models import signals from askbot import const @@ -580,7 +580,7 @@ class Thread(models.Model): #pass through only deleted question posts if post.deleted and post.post_type != 'question': continue - if post.approved == False:#hide posts on the moderation queue + if post.is_approved() is False:#hide posts on the moderation queue continue post_to_author[post.id] = post.author_id @@ -641,6 +641,8 @@ class Thread(models.Model): """ def get_data(): + # todo: code in this function would be simpler if + # we had question post id denormalized on the thread tags_list = self.get_tag_names() similar_threads = Thread.objects.filter( tags__name__in=tags_list @@ -659,20 +661,28 @@ class Thread(models.Model): similar_threads = similar_threads[:10] # Denormalize questions to speed up template rendering + # todo: just denormalize question_post_id on the thread! thread_map = dict([(thread.id, thread) for thread in similar_threads]) questions = Post.objects.get_questions() questions = questions.select_related('thread').filter(thread__in=similar_threads) for q in questions: thread_map[q.thread_id].question_denorm = q - # Postprocess data - similar_threads = [ - { - 'url': thread.question_denorm.get_absolute_url(), - 'title': thread.get_title(thread.question_denorm) - } for thread in similar_threads - ] - return similar_threads + # Postprocess data for the final output + result = list() + for thread in similar_threads: + question_post = getattr(thread, 'question_denorm', None) + # unfortunately the if statement below is necessary due to + # a possible bug + # all this proves that it's wrong to reference threads by + # the question post id in the question page urls!!! + # this is a "legacy" problem inherited from the old models + if question_post: + url = question_post.get_absolute_url() + title = thread.get_title(question_post) + result.append({'url': url, 'title': title}) + + return result def get_cached_data(): """similar thread data will expire @@ -919,7 +929,7 @@ class FavoriteQuestion(models.Model): return '[%s] favorited at %s' %(self.user, self.added_at) -class AnonymousQuestion(AnonymousContent): +class AnonymousQuestion(DraftContent): """question that was asked before logging in maybe the name is a little misleading, the user still may or may not want to stay anonymous after the question diff --git a/askbot/skins/common/media/js/post.js b/askbot/skins/common/media/js/post.js index 58f2436d..32453212 100644 --- a/askbot/skins/common/media/js/post.js +++ b/askbot/skins/common/media/js/post.js @@ -2408,6 +2408,33 @@ $(document).ready(function() { }); questionRetagger.init(); socialSharing.init(); + + var proxyUserNameInput = $('#id_post_author_username'); + var proxyUserEmailInput = $('#id_post_author_email'); + if (proxyUserNameInput.length === 1) { + var tip = new TippedInput(); + tip.decorate(proxyUserNameInput); + + var userSelectHandler = function(data) { + proxyUserEmailInput.val(data['data'][0]); + }; + + var fakeUserAc = new AutoCompleter({ + url: '/get-users-info/',//askbot['urls']['get_users_info'], + preloadData: true, + minChars: 1, + useCache: true, + matchInside: true, + maxCacheLength: 100, + delay: 10, + onItemSelect: userSelectHandler + }); + fakeUserAc.decorate(proxyUserNameInput); + } + if (proxyUserEmailInput.length === 1) { + var tip = new TippedInput(); + tip.decorate(proxyUserEmailInput); + } }); diff --git a/askbot/skins/common/media/js/utils.js b/askbot/skins/common/media/js/utils.js index 81aff7c3..3f585435 100644 --- a/askbot/skins/common/media/js/utils.js +++ b/askbot/skins/common/media/js/utils.js @@ -313,6 +313,7 @@ TippedInput.prototype.decorate = function(element){ this._element = element; var instruction_text = this.getVal(); this._instruction = instruction_text; + this.reset(); var me = this; $(element).focus(function(){ if (me.isBlank()){ diff --git a/askbot/skins/common/templates/widgets/edit_post.html b/askbot/skins/common/templates/widgets/edit_post.html index 66f79237..f26e57f6 100644 --- a/askbot/skins/common/templates/widgets/edit_post.html +++ b/askbot/skins/common/templates/widgets/edit_post.html @@ -18,7 +18,7 @@ {% if post_type == 'question' %} <div class="form-item"> {% if tags_are_required %} - <label for=id_tags"> + <label for="id_tags"> {% if mandatory_tags %} <strong>{% trans %}tags{% endtrans %}</strong> {% trans %}, one of these is required{% endtrans %} @@ -54,6 +54,7 @@ <div class="form-error" >{{ post_form.summary.errors }}</div> </div> {% endif %} + <div class="preview-toggle"> <span id="pre-collapse" @@ -63,3 +64,41 @@ </span> </div> <div id="previewer" class="wmd-preview"></div> + +{% if user and user.is_authenticated() and user.is_administrator() %} + {# admin can post answers or questions on behalf of anyone. #} + <table class="proxy-user-info"> + <tbody> + <tr><td colspan="2"> + <label> + {% trans %}To post on behalf of someone else, enter user name <strong>and</strong> email below.{% endtrans %} + </label> + </td></tr> + <tr> + <td> + <div class="form-item"> + {{ post_form.post_author_username }} + <!--input + id="id_post_author_username" + name="post_author_username" + value="{% trans %}User name:{% endtrans %}" + /--> + </div> + <div class="form-item"> + {{ post_form.post_author_email }} + <!--input + id="id_post_author_email" + name="post_author_email" + value="{% trans %}Email address:{% endtrans %}" + /--> + </div> + </td> + </tr> + <tr> + <td colspan="2"> + <span class="form-error">{{ post_form.post_author_username.errors }}</span> + <span class="form-error">{{ post_form.post_author_email.errors }}</span> + </td> + </tbody> + </table> +{% endif %} diff --git a/askbot/skins/default/media/style/style.css b/askbot/skins/default/media/style/style.css index 7a695825..c8d92f60 100644 --- a/askbot/skins/default/media/style/style.css +++ b/askbot/skins/default/media/style/style.css @@ -1358,7 +1358,9 @@ ul#related-tags li { font-size: 13px; } .ask-page #id_tags, -.edit-question-page #id_tags { +.edit-question-page #id_tags, +#id_user, +#id_user_author { border: #cce6ec 3px solid; height: 25px; padding-left: 5px; diff --git a/askbot/skins/default/media/style/style.less b/askbot/skins/default/media/style/style.less index 4e272eca..db5d14f8 100644 --- a/askbot/skins/default/media/style/style.less +++ b/askbot/skins/default/media/style/style.less @@ -1345,13 +1345,46 @@ ul#related-tags li { font-size:13px; } - #id_tags{ + #id_tags { border:#cce6ec 3px solid; height:25px; padding-left:5px; + font-size:14px; width:395px; + } +} + +.ask-page, +.question-page, +.edit-question-page, +.edit-answer-page { + #id_post_author_username, + #id_post_author_email { + border:#cce6ec 3px solid; + height:25px; + padding-left:5px; font-size:14px; + width:186px; } + #id_post_author_email { + margin-left: 10px; + } + table.proxy-user-info { + border-spacing: 0px; + + .form-item { + float: left; + } + } +} + +#id_user, +#id_user_author { + border:#cce6ec 3px solid; + height:25px; + padding-left:5px; + width:395px; + font-size:14px; } .title-desc { diff --git a/askbot/skins/default/templates/answer_edit.html b/askbot/skins/default/templates/answer_edit.html index bbc00420..a1dbb4f9 100644 --- a/askbot/skins/default/templates/answer_edit.html +++ b/askbot/skins/default/templates/answer_edit.html @@ -16,7 +16,7 @@ <div style="vertical-align:middle"> {{ revision_form.revision }} <input type="submit" style="display:none" id="select_revision" name="select_revision" value="{% trans %}select revision{% endtrans %}"> </div> - {{ macros.edit_post(form) }} + {{ macros.edit_post(form, user = request.user) }} {% if settings.WIKI_ON and answer.wiki == False %} {{ macros.checkbox_in_div(form.wiki) }} {% endif %} diff --git a/askbot/skins/default/templates/email/welcome_lamson_off.html b/askbot/skins/default/templates/email/welcome_lamson_off.html new file mode 100644 index 00000000..d1b9854d --- /dev/null +++ b/askbot/skins/default/templates/email/welcome_lamson_off.html @@ -0,0 +1,11 @@ +{% import "email/macros.html" as macros %} +{# site_name - is short name of the site, email_code - address portion +of the reply email used for this message, we scan to the last appearance +of the email code to detect the response signature that will appear under #} +<p style="{{ macros.heading_style() }}"> + {% trans %}Welcome to {{ site_name }}!{% endtrans %} +</p> +<p> + {% trans %}We look forward to your Questions!{% endtrans %} +</p> +{% include "email/footer.html" %} diff --git a/askbot/skins/default/templates/macros.html b/askbot/skins/default/templates/macros.html index 261c860f..4cc4e081 100644 --- a/askbot/skins/default/templates/macros.html +++ b/askbot/skins/default/templates/macros.html @@ -479,7 +479,8 @@ for the purposes of the AJAX comment editor #} post_form, post_type = None, mandatory_tags = None, - edit_title = False + edit_title = False, + user = None ) -%} {%include "widgets/edit_post.html" %} diff --git a/askbot/skins/default/templates/question/new_answer_form.html b/askbot/skins/default/templates/question/new_answer_form.html index 68af8afb..9868d3ba 100644 --- a/askbot/skins/default/templates/question/new_answer_form.html +++ b/askbot/skins/default/templates/question/new_answer_form.html @@ -39,7 +39,7 @@ {% endif %} </p> {% endif %} - {{ macros.edit_post(answer) }} + {{ macros.edit_post(answer, user = request.user) }} <input id="add-answer-btn" type="submit" class="submit after-editor" style="float:left"/> <script type="text/javascript"> askbot['functions']['renderAddAnswerButton'](); diff --git a/askbot/skins/default/templates/question_edit.html b/askbot/skins/default/templates/question_edit.html index 47873e0e..adf2f35b 100644 --- a/askbot/skins/default/templates/question_edit.html +++ b/askbot/skins/default/templates/question_edit.html @@ -20,7 +20,8 @@ form, post_type='question', edit_title=True, - mandatory_tags = mandatory_tags + mandatory_tags = mandatory_tags, + user = request.user ) }} <div class="after-editor"> diff --git a/askbot/skins/default/templates/widgets/ask_form.html b/askbot/skins/default/templates/widgets/ask_form.html index b8a5ce2c..2ece84d5 100644 --- a/askbot/skins/default/templates/widgets/ask_form.html +++ b/askbot/skins/default/templates/widgets/ask_form.html @@ -26,7 +26,8 @@ form, post_type = 'question', edit_title = False, - mandatory_tags = mandatory_tags + mandatory_tags = mandatory_tags, + user = request.user ) }} <div class="question-options"> diff --git a/askbot/tests/form_tests.py b/askbot/tests/form_tests.py index 654272b3..a37f380c 100644 --- a/askbot/tests/form_tests.py +++ b/askbot/tests/form_tests.py @@ -334,3 +334,30 @@ class AnswerEditorFieldTests(AskbotTestCase): self.field.clean(10*'a'), 10*'a' ) + + +class PostAsSomeoneFormTests(AskbotTestCase): + + form = forms.PostAsSomeoneForm + + def setUp(self): + self.good_data = { + 'username': 'me', + 'email': 'me@example.com' + } + + def test_blank_form_validates(self): + form = forms.PostAsSomeoneForm({}) + self.assertEqual(form.is_valid(), True) + + def test_complete_form_validates(self): + form = forms.PostAsSomeoneForm(self.good_data) + self.assertEqual(form.is_valid(), True) + + def test_missing_email_fails(self): + form = forms.PostAsSomeoneForm({'post_author_username': 'me'}) + self.assertEqual(form.is_valid(), False) + + def test_missing_username_fails(self): + form = forms.PostAsSomeoneForm({'post_author_email': 'me@example.com'}) + self.assertEqual(form.is_valid(), False) diff --git a/askbot/urls.py b/askbot/urls.py index 869f7d69..f39371e5 100644 --- a/askbot/urls.py +++ b/askbot/urls.py @@ -79,6 +79,11 @@ urlpatterns = patterns('', name = 'api_get_questions' ), url( + r'^get-users-info/', + views.commands.get_users_info, + name='get_users_info' + ), + url( r'^%s%s$' % (_('questions/'), _('ask/')), views.writers.ask, name='ask' diff --git a/askbot/views/commands.py b/askbot/views/commands.py index e343c85e..12305f46 100644 --- a/askbot/views/commands.py +++ b/askbot/views/commands.py @@ -913,3 +913,26 @@ def save_post_reject_reason(request): } else: raise Exception(forms.format_form_errors(form)) + + +@decorators.get_only +@decorators.admins_only +def get_users_info(request): + """retuns list of user names and email addresses + of "fake" users - so that admins can post on their + behalf""" + user_info_list = models.User.objects.filter( + is_fake=True + ).values_list( + 'username', + 'email' + ) + + result_list = list() + for user_info in user_info_list: + username = user_info[0] + email = user_info[1] + result_list.append('%s|%s' % (username, email)) + + output = '\n'.join(result_list) + return HttpResponse(output, mimetype = 'text/plain') diff --git a/askbot/views/writers.py b/askbot/views/writers.py index 9a2de128..6bda3782 100644 --- a/askbot/views/writers.py +++ b/askbot/views/writers.py @@ -15,6 +15,7 @@ import time import urlparse from django.shortcuts import get_object_or_404 from django.contrib.auth.decorators import login_required +from django.contrib.auth.models import User from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404 from django.utils import simplejson from django.utils.html import strip_tags, escape @@ -218,8 +219,10 @@ def ask(request):#view used to ask a new question ask_anonymously = form.cleaned_data['ask_anonymously'] if request.user.is_authenticated(): + + user = form.get_post_user(request.user) try: - question = request.user.post_question( + question = user.post_question( title = title, body_text = text, tags = tagnames, @@ -376,7 +379,9 @@ def edit_question(request, id): is_anon_edit = form.cleaned_data['stay_anonymous'] is_wiki = form.cleaned_data.get('wiki', question.wiki) - request.user.edit_question( + user = form.get_post_user(request.user) + + user.edit_question( question = question, title = form.cleaned_data['title'], body_text = form.cleaned_data['text'], @@ -446,7 +451,8 @@ def edit_answer(request, id): if form.is_valid(): if form.has_changed(): - request.user.edit_answer( + user = form.get_post_user(request.user) + user.edit_answer( answer = answer, body_text = form.cleaned_data['text'], revision_comment = form.cleaned_data['summary'], @@ -492,7 +498,10 @@ def answer(request, id):#process a new answer if request.user.is_authenticated(): try: follow = form.cleaned_data['email_notify'] - answer = request.user.post_answer( + + user = form.get_post_user(request.user) + + answer = user.post_answer( question = question, body_text = text, follow = follow, |