From 460c64735ae3980dce0f094ca2a783e6bc8e0cef Mon Sep 17 00:00:00 2001 From: Adolfo Fitoria Date: Tue, 7 Aug 2012 19:24:12 -0600 Subject: Initial work for widget creation Widgets will work with iframes and javascript code to insert them. DONE: - View to ask a question - Form to ask a question - Initial work on templates. (no css yet) - Test for all the former TODO: - create widget builder view. - documentation, documentation, documentation! - Login view with special template and css. --- askbot/forms.py | 18 +++++ askbot/skins/default/templates/ask_by_widget.html | 16 ++++ .../default/templates/ask_widget_complete.html | 8 ++ askbot/skins/default/templates/widget_base.html | 18 +++++ askbot/tests/__init__.py | 1 + askbot/tests/form_tests.py | 33 ++++++-- askbot/tests/widget_tests.py | 52 +++++++++++++ askbot/urls.py | 89 ++++++++++++---------- askbot/views/__init__.py | 1 + askbot/views/widgets.py | 73 ++++++++++++++++++ 10 files changed, 264 insertions(+), 45 deletions(-) create mode 100644 askbot/skins/default/templates/ask_by_widget.html create mode 100644 askbot/skins/default/templates/ask_widget_complete.html create mode 100644 askbot/skins/default/templates/widget_base.html create mode 100644 askbot/tests/widget_tests.py create mode 100644 askbot/views/widgets.py diff --git a/askbot/forms.py b/askbot/forms.py index 978cdf0b..7906a5e0 100644 --- a/askbot/forms.py +++ b/askbot/forms.py @@ -888,6 +888,24 @@ ASK_BY_EMAIL_SUBJECT_HELP = _( '[tag1, tag2, tag3,...] question title' ) +class AskWidgetForm(forms.Form, FormWithHideableFields): + '''Simple form with just the title to ask a question''' + + title = TitleField() + ask_anonymously = forms.BooleanField( + label=_('ask anonymously'), + help_text=_( + 'Check if you do not want to reveal your name ' + 'when asking this question' + ), + required=False, + ) + + def __init__(self, *args, **kwargs): + super(AskWidgetForm, self).__init__(*args, **kwargs) + #hide ask_anonymously field + if askbot_settings.ALLOW_ASK_ANONYMOUSLY is False: + self.hide_field('ask_anonymously') class AskByEmailForm(forms.Form): """:class:`~askbot.forms.AskByEmailForm` diff --git a/askbot/skins/default/templates/ask_by_widget.html b/askbot/skins/default/templates/ask_by_widget.html new file mode 100644 index 00000000..f700f83a --- /dev/null +++ b/askbot/skins/default/templates/ask_by_widget.html @@ -0,0 +1,16 @@ +{% extends "widget_base.html" %} +{% block forestyle %} +{%endblock%} + +{%block body%} +Enter your question +
+ {% csrf_token %} + {{form.title}} + {% if form.ask_anonymously %} + {{form.ask_anonymously}} + {%endif%} + +
+{{form.errors}} +{%endblock%} diff --git a/askbot/skins/default/templates/ask_widget_complete.html b/askbot/skins/default/templates/ask_widget_complete.html new file mode 100644 index 00000000..82fe570c --- /dev/null +++ b/askbot/skins/default/templates/ask_widget_complete.html @@ -0,0 +1,8 @@ +{% extends "widget_base.html" %} +{% block forestyle %} +{%endblock%} + +{%block body%} +Question posted +{%endblock%} + diff --git a/askbot/skins/default/templates/widget_base.html b/askbot/skins/default/templates/widget_base.html new file mode 100644 index 00000000..8156095d --- /dev/null +++ b/askbot/skins/default/templates/widget_base.html @@ -0,0 +1,18 @@ + + + + {% spaceless %} + + {% block before_css %}{% endblock %} + {% block forestyle %}{% endblock %} + {% block forejs %}{% endblock %} + + {% endspaceless %} + + {% block body%} + {% endblock %} + {% block endjs %} + {% endblock %} + + + diff --git a/askbot/tests/__init__.py b/askbot/tests/__init__.py index c20b7f67..c1b80347 100644 --- a/askbot/tests/__init__.py +++ b/askbot/tests/__init__.py @@ -15,4 +15,5 @@ from askbot.tests.markup_test import * from askbot.tests.post_model_tests import * from askbot.tests.thread_model_tests import * from askbot.tests.reply_by_email_tests import * +from askbot.tests.widget_tests import * from askbot.tests.category_tree_tests import CategoryTreeTests diff --git a/askbot/tests/form_tests.py b/askbot/tests/form_tests.py index a37f380c..be88cf39 100644 --- a/askbot/tests/form_tests.py +++ b/askbot/tests/form_tests.py @@ -72,8 +72,8 @@ class AskByEmailFormTests(AskbotTestCase): askbot_settings.update('TAGS_ARE_REQUIRED', setting_backup) def test_email(self): - """loops through variants of the from field - in the emails and tests the email address + """loops through variants of the from field + in the emails and tests the email address extractor""" for test_case in EMAIL_CASES: self.data['sender'] = test_case[0] @@ -178,7 +178,7 @@ class EditQuestionAnonymouslyFormTests(AskbotTestCase): def setup_data(self, is_anon, can_be_anon, is_owner, box_checked): """sets up data in the same order as shown in the truth table above - + the four positional arguments are in the same order """ askbot_settings.update('ALLOW_ASK_ANONYMOUSLY', can_be_anon) @@ -264,7 +264,7 @@ class UserStatusFormTest(AskbotTestCase): self.moderator.set_status('m') self.subject = self.create_user('normal_user') self.subject.set_status('a') - self.form = forms.ChangeUserStatusForm(data, moderator = self.moderator, + self.form = forms.ChangeUserStatusForm(data, moderator = self.moderator, subject = self.subject) def test_moderator_can_suspend_user(self): self.setup_data('s') @@ -292,7 +292,7 @@ class UserNameFieldTest(AskbotTestCase): self.username_field.skip_clean = True self.assertEquals(self.username_field.clean('bar'), 'bar')#will pass anything - self.username_field.skip_clean = False + self.username_field.skip_clean = False #will not pass b/c instance is not User model self.username_field.user_instance = dict(foo=1) @@ -328,7 +328,7 @@ class AnswerEditorFieldTests(AskbotTestCase): self.field.clean, 'a' ) - + def test_pass_long_body(self): self.assertEquals( self.field.clean(10*'a'), @@ -361,3 +361,24 @@ class PostAsSomeoneFormTests(AskbotTestCase): def test_missing_username_fails(self): form = forms.PostAsSomeoneForm({'post_author_email': 'me@example.com'}) self.assertEqual(form.is_valid(), False) + +class AskWidgetFormTests(AskbotTestCase): + + form = forms.AskWidgetForm + + def setUp(self): + self.good_data = {'title': "What's the price of a house in london?"} + self.good_data_anon = {'title': "What's the price of a house in london?", + 'ask_anonymously': True} + + self.bad_data = {'title': ''} + + def test_valid_input(self): + form_object = self.form(self.good_data) + self.assertTrue(form_object.is_valid()) + form_object = self.form(self.good_data_anon) + self.assertTrue(form_object.is_valid()) + + def test_invalid_input(self): + form_object = self.form(self.bad_data) + self.assertFalse(form_object.is_valid()) diff --git a/askbot/tests/widget_tests.py b/askbot/tests/widget_tests.py new file mode 100644 index 00000000..e33f88b9 --- /dev/null +++ b/askbot/tests/widget_tests.py @@ -0,0 +1,52 @@ +from datetime import datetime + +from askbot import models +from askbot.tests.utils import AskbotTestCase + +from django.test.client import Client +from django.core.urlresolvers import reverse + + +class WidgetViewsTests(AskbotTestCase): + + def setUp(self): + self.client = Client() + self.user = self.create_user('user1') + self.user.set_password('sample') + self.user.save() + self.good_data = {'title': 'This is a title question', + 'ask_anonymously': False} + + def test_post_with_auth(self): + self.client.login(username='user1', password='sample') + response = self.client.post(reverse('ask_by_widget'), self.good_data) + self.assertEquals(response.status_code, 302) + self.client.logout() + + def test_post_without_auth(self): + response = self.client.post(reverse('ask_by_widget'), self.good_data) + self.assertEquals(response.status_code, 302) + self.assertTrue('widget_question' in self.client.session) + self.assertEquals(self.client.session['widget_question']['title'], + self.good_data['title']) + + def test_post_after_login(self): + widget_question_data = { 'title': 'testing post after login, does it?', + 'author': self.user, + 'added_at': datetime.now(), + 'wiki': False, + 'text': ' ', + 'tagnames': '', + 'is_anonymous': False + } + + self.client.login(username='user1', password='sample') + + session = self.client.session + session['widget_question'] = widget_question_data + session.save() + response = self.client.get(reverse('ask_by_widget'), + {'action': 'post-after-login'}) + self.assertFalse('widget_question' in self.client.session) + self.assertEquals(response.status_code, 302) + #verify posting question diff --git a/askbot/urls.py b/askbot/urls.py index f9bd74fb..703cdcbd 100644 --- a/askbot/urls.py +++ b/askbot/urls.py @@ -31,9 +31,9 @@ APP_PATH = os.path.dirname(__file__) urlpatterns = patterns('', url(r'^$', views.readers.index, name='index'), url( - r'^sitemap.xml$', - 'django.contrib.sitemaps.views.sitemap', - {'sitemaps': sitemaps}, + r'^sitemap.xml$', + 'django.contrib.sitemaps.views.sitemap', + {'sitemaps': sitemaps}, name='sitemap' ), #no translation for this url!! @@ -43,13 +43,13 @@ urlpatterns = patterns('', url(r'^%s$' % _('privacy/'), views.meta.privacy, name='privacy'), url(r'^%s$' % _('help/'), views.meta.help, name='help'), url( - r'^%s(?P\d+)/%s$' % (_('answers/'), _('edit/')), - views.writers.edit_answer, + r'^%s(?P\d+)/%s$' % (_('answers/'), _('edit/')), + views.writers.edit_answer, name='edit_answer' ), url( - r'^%s(?P\d+)/%s$' % (_('answers/'), _('revisions/')), - views.readers.revisions, + r'^%s(?P\d+)/%s$' % (_('answers/'), _('revisions/')), + views.readers.revisions, kwargs = {'post_type': 'answer'}, name='answer_revisions' ), @@ -67,12 +67,12 @@ urlpatterns = patterns('', r'(%s)?' % r'/page:(?P\d+)' + r'/$'), - views.readers.questions, + views.readers.questions, name='questions' ), # END main page urls - + url( r'^api/get_questions/', views.commands.api_get_questions, @@ -99,49 +99,49 @@ urlpatterns = patterns('', name='get_users_info' ), url( - r'^%s%s$' % (_('questions/'), _('ask/')), - views.writers.ask, + r'^%s%s$' % (_('questions/'), _('ask/')), + views.writers.ask, name='ask' ), url( - r'^%s(?P\d+)/%s$' % (_('questions/'), _('edit/')), - views.writers.edit_question, + r'^%s(?P\d+)/%s$' % (_('questions/'), _('edit/')), + views.writers.edit_question, name='edit_question' ), url(#this url is both regular and ajax - r'^%s(?P\d+)/%s$' % (_('questions/'), _('retag/')), - views.writers.retag_question, + r'^%s(?P\d+)/%s$' % (_('questions/'), _('retag/')), + views.writers.retag_question, name='retag_question' ), url( - r'^%s(?P\d+)/%s$' % (_('questions/'), _('close/')), - views.commands.close, + r'^%s(?P\d+)/%s$' % (_('questions/'), _('close/')), + views.commands.close, name='close' ), url( - r'^%s(?P\d+)/%s$' % (_('questions/'), _('reopen/')), - views.commands.reopen, + r'^%s(?P\d+)/%s$' % (_('questions/'), _('reopen/')), + views.commands.reopen, name='reopen' ), url( - r'^%s(?P\d+)/%s$' % (_('questions/'), _('answer/')), - views.writers.answer, + r'^%s(?P\d+)/%s$' % (_('questions/'), _('answer/')), + views.writers.answer, name='answer' ), url(#ajax only - r'^%s(?P\d+)/%s$' % (_('questions/'), _('vote/')), - views.commands.vote, + r'^%s(?P\d+)/%s$' % (_('questions/'), _('vote/')), + views.commands.vote, name='vote' ), url( - r'^%s(?P\d+)/%s$' % (_('questions/'), _('revisions/')), - views.readers.revisions, + r'^%s(?P\d+)/%s$' % (_('questions/'), _('revisions/')), + views.readers.revisions, kwargs = {'post_type': 'question'}, name='question_revisions' ), url( r'^%s%s$' % (_('widgets/'), _('questions/')), - views.readers.widget_questions, + views.readers.widget_questions, name='widget_questions' ), url(#ajax only @@ -156,7 +156,7 @@ urlpatterns = patterns('', ), url(#ajax only r'^post_comments/$', - views.writers.post_comments, + views.writers.post_comments, name='post_comments' ), url(#ajax only @@ -166,17 +166,17 @@ urlpatterns = patterns('', ), url(#ajax only r'^comment/delete/$', - views.writers.delete_comment, + views.writers.delete_comment, name='delete_comment' ), url(#ajax only r'^comment/get_text/$', - views.readers.get_comment, + views.readers.get_comment, name='get_comment' ), url( - r'^%s$' % _('tags/'), - views.readers.tags, + r'^%s$' % _('tags/'), + views.readers.tags, name='tags' ), url( @@ -291,12 +291,12 @@ urlpatterns = patterns('', ), url( r'^%s$' % _('users/'), - views.users.show_users, + views.users.show_users, name='users' ), url( r'^%s%s(?P\d+)/(?P.*)/$' % (_('users/'), _('by-group/')), - views.users.show_users, + views.users.show_users, kwargs = {'by_group': True}, name = 'users_by_group' ), @@ -375,8 +375,19 @@ urlpatterns = patterns('', views.commands.join_or_leave_group, name = 'join_or_leave_group' ), + #widgets url! + url( + r'^widgets/ask/$', + views.widgets.ask_widget, + name = 'ask_by_widget' + ), + url( + r'^widgets/ask/complete/$', + views.widgets.ask_widget_complete, + name = 'ask_by_widget_complete' + ), url( - r'^feeds/(?P.*)/$', + r'^feeds/(?P.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds}, name='feeds' @@ -386,7 +397,7 @@ urlpatterns = patterns('', url(r'^%s$' % _('feedback/'), views.meta.feedback, name='feedback'), #url(r'^feeds/rss/$', RssLastestQuestionsFeed, name="latest_questions_feed"), url( - r'^doc/(?P.*)$', + r'^doc/(?P.*)$', 'django.views.static.serve', {'document_root': os.path.join(APP_PATH,'doc','build','html').replace('\\','/')}, name='askbot_docs', @@ -421,14 +432,14 @@ urlpatterns = patterns('', #therefore the stackexchange urls feature won't work if getattr(settings, 'ASKBOT_USE_STACKEXCHANGE_URLS', False): urlpatterns += (url( - r'^%s(?P\d+)/' % _('questions/'), - views.readers.question, + r'^%s(?P\d+)/' % _('questions/'), + views.readers.question, name='question' ),) else: urlpatterns += (url( - r'^%s(?P\d+)/' % _('question/'), - views.readers.question, + r'^%s(?P\d+)/' % _('question/'), + views.readers.question, name='question' ),) diff --git a/askbot/views/__init__.py b/askbot/views/__init__.py index b9aaf8a9..a3c5e06d 100644 --- a/askbot/views/__init__.py +++ b/askbot/views/__init__.py @@ -6,6 +6,7 @@ from askbot.views import writers from askbot.views import commands from askbot.views import users from askbot.views import meta +from askbot.views import widgets from django.conf import settings if 'avatar' in settings.INSTALLED_APPS: from askbot.views import avatar_views diff --git a/askbot/views/widgets.py b/askbot/views/widgets.py new file mode 100644 index 00000000..ea093916 --- /dev/null +++ b/askbot/views/widgets.py @@ -0,0 +1,73 @@ +from datetime import datetime + +from django.views.decorators import csrf +from django.shortcuts import redirect +from django.utils import simplejson +from django.contrib.auth.models import User +from django.core import exceptions + +from django.contrib.auth.decorators import login_required + +from askbot.skins.loaders import render_into_skin +from askbot import models +from askbot import forms + +@csrf.csrf_protect +def ask_widget(request): + + def post_question(data, request): + thread = models.Thread.objects.create_new(**data_dict) + question = thread._question_post() + request.session['widget_question_url'] = question.get_absolute_url() + return question + + + if request.method == "POST": + form = forms.AskWidgetForm(request.POST) + if form.is_valid(): + ask_anonymously = form.cleaned_data['ask_anonymously'] + title = form.cleaned_data['title'] + data_dict = { + 'title': title, + 'added_at': datetime.now(), + 'wiki': False, + 'text': ' ', + 'tagnames': '', + 'is_anonymous': ask_anonymously + } + if request.user.is_authenticated(): + data_dict['author'] = request.user + question = post_question(data_dict, request) + return redirect('ask_by_widget_complete') + else: + request.session['widget_question'] = data_dict + #return redirect('widgets_login') + return redirect('user_signin') + else: + if 'widget_question' in request.session or \ + request.GET.get('action', 'post-after-login'): + if request.user.is_authenticated(): + data_dict = request.session['widget_question'] + data_dict['author'] = request.user + question = post_question(request.session['widget_question'], request) + del request.session['widget_question'] + return redirect('ask_by_widget_complete') + else: + #FIXME: this redirect is temporal need to create the correct view + #return redirect('widgets_login') + return redirect('user_signin') + + form = forms.AskWidgetForm() + data = {'form': form} + return render_into_skin('ask_by_widget.html', data, request) + +@login_required +def ask_widget_complete(request): + question_url = request.session.get('widget_question_url') + if question_url: + del request.session['widget_question_url'] + else: + question_url = '#' + + data = {'question_url': question_url} + return render_into_skin('ask_widget_complete.html', data, request) -- cgit v1.2.3-1-g7c22