]> git.openstreetmap.org Git - osqa.git/commitdiff
General cleanup. Moved many hardcoded stuff still left in the code to an admin option...
authorhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Mon, 10 May 2010 03:34:09 +0000 (03:34 +0000)
committerhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Mon, 10 May 2010 03:34:09 +0000 (03:34 +0000)
Moved akismet to it's own module.

git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@187 0cfe37f9-358a-4d5e-be75-b63607b5c754

44 files changed:
forum/actions/meta.py
forum/authentication/__init__.py
forum/context.py
forum/feed.py
forum/forms.py
forum/management/commands/send_email_alerts.py
forum/middleware/anon_user.py
forum/models/base.py
forum/models/meta.py
forum/models/node.py
forum/modules/__init__.py
forum/modules/decorators.py
forum/settings/__init__.py
forum/settings/base.py
forum/settings/basic.py
forum/settings/extkeys.py
forum/settings/form.py
forum/settings/forms.py
forum/settings/users.py [new file with mode: 0644]
forum/skins/default/templates/revisions.html
forum/startup.py
forum/subscriptions.py
forum/templatetags/extra_tags.py
forum/urls.py
forum/utils/forms.py
forum/utils/mail.py
forum/views/__init__.py
forum/views/admin.py
forum/views/auth.py
forum/views/commands.py
forum/views/decorators.py
forum/views/meta.py
forum/views/readers.py
forum/views/users.py
forum/views/writers.py
forum_modules/akismet/__init__.py [new file with mode: 0644]
forum_modules/akismet/lib/__init__.py [new file with mode: 0644]
forum_modules/akismet/lib/akismet.py [moved from forum/akismet.py with 100% similarity]
forum_modules/akismet/settings.py [new file with mode: 0644]
forum_modules/akismet/startup.py [new file with mode: 0644]
forum_modules/akismet/templates/foundspam.html [new file with mode: 0644]
forum_modules/openidauth/authentication.py
forum_modules/openidauth/consumer.py
settings_local.py.dist

index 50637460c239d84a7d4241e9678ae7aa77b1e9d6..c92d8992501abbde75bb58ce95fdf336e99987db 100644 (file)
@@ -15,7 +15,7 @@ class VoteAction(ActionProxy):
         vote.save()\r
 \r
     def cancel_action(self):\r
-        vote = self.vote.all()[0]\r
+        vote = self.vote\r
         self.update_node_score(-vote.value)\r
         vote.delete()\r
 \r
@@ -98,7 +98,7 @@ class FlagAction(ActionProxy):
                 DeleteAction(node=self.node, user=self.user, extra="BYFLAGGED").save()\r
 \r
     def cancel_action(self):\r
-        self.flag.all()[0].delete()\r
+        self.flag.delete()\r
         self.node.reset_flag_count_cache()\r
 \r
     @classmethod\r
index 08ea03fd0575aa799464ade7274b8625223b6b6b..8dbf825a525c2ab49c17a38834961ac6135706ce 100644 (file)
@@ -31,27 +31,3 @@ AUTH_PROVIDERS = dict([
             if name in contexts
         ])
 
-
-#todo: probably this don't belong here, also this post_stored routine needs a lot of work
-user_logged_in = django.dispatch.Signal(providing_args=["user", "old_session"])
-
-#def post_stored_anonymous_content(user,old_session,**kwargs):
-#    from forum.models import AnonymousQuestion, AnonymousAnswer
-#    aq_list = AnonymousQuestion.objects.filter(session_key = old_session)
-#    aa_list = AnonymousAnswer.objects.filter(session_key = old_session)
-#    import settings
-#    if settings.EMAIL_VALIDATION == 'on':#add user to the record
-#        for aq in aq_list:
-#            aq.author = user
-#            aq.save()
-#        for aa in aa_list:
-#            aa.author = user
-#            aa.save()
-#        #maybe add pending posts message?
-#    else: #just publish the questions
-#        for aq in aq_list:
-#            aq.publish(user)
-#        for aa in aa_list:
-#            aa.publish(user)
-#
-#user_logged_in.connect(post_stored_anonymous_content)
\ No newline at end of file
index 3814bb6065d46d91a48969a4ac599bc3cff4deb0..f7139ac404769e056e8bba04b539439d3d2fb075 100644 (file)
@@ -1,4 +1,5 @@
-from django.conf import settings
+from forum import settings
+from django.conf import settings as djsettings
 def application_settings(context):
     my_settings = {
         'APP_TITLE' : settings.APP_TITLE,
@@ -8,15 +9,14 @@ def application_settings(context):
         'APP_DESCRIPTION' : settings.APP_DESCRIPTION,
         'APP_INTRO' : settings.APP_INTRO,
         'APP_LOGO' : settings.APP_LOGO,
-        'EMAIL_VALIDATION': settings.EMAIL_VALIDATION,
+        'EMAIL_VALIDATION': 'off',
         'FEEDBACK_SITE_URL': settings.FEEDBACK_SITE_URL,
-        'FORUM_SCRIPT_ALIAS': settings.FORUM_SCRIPT_ALIAS,
-        'LANGUAGE_CODE': settings.LANGUAGE_CODE,
+        'FORUM_SCRIPT_ALIAS': djsettings.FORUM_SCRIPT_ALIAS,
+        'LANGUAGE_CODE': djsettings.LANGUAGE_CODE,
         'GOOGLE_SITEMAP_CODE':settings.GOOGLE_SITEMAP_CODE,
         'GOOGLE_ANALYTICS_KEY':settings.GOOGLE_ANALYTICS_KEY,
         'WIKI_ON':settings.WIKI_ON,
-        'RESOURCE_REVISION':settings.RESOURCE_REVISION,
-        'OSQA_SKIN':settings.OSQA_DEFAULT_SKIN,
+        'OSQA_SKIN':djsettings.OSQA_DEFAULT_SKIN,
         'APP_FAVICON':settings.APP_FAVICON,
         }
     return {'settings':my_settings}
index 02a7d3c432441278f19d67ba69636a9ab9b50281..0f8deaec3cfba590bb02d26a4130727498035c91 100644 (file)
@@ -13,7 +13,7 @@
 from django.contrib.syndication.feeds import Feed, FeedDoesNotExist
 from django.utils.translation import ugettext as _
 from models import Question
-from django.conf import settings
+from forum import settings
 class RssLastestQuestionsFeed(Feed):
     title = settings.APP_TITLE + _(' - ')+ _('latest questions')
     link = settings.APP_URL #+ '/' + _('question/')
index 2196981f6258c31e1c3ca373a7e45a66c0d4e2ce..978ef175eeed03a60e5d47c44c81f78e9e3efe43 100644 (file)
@@ -8,7 +8,7 @@ from forum.models import User
 
 from django.utils.safestring import mark_safe
 from forum.utils.forms import NextUrlField, UserNameField, SetPasswordForm
-from django.conf import settings
+from forum import settings
 import logging
 
 class TitleField(forms.CharField):
index 4b6a05f761be026c26d2dc8e98a76c127d130960..0931ab1cbc53487e7e2d99455f161c6be3f0d50a 100644 (file)
@@ -3,7 +3,7 @@ from django.core.management.base import NoArgsCommand
 from django.utils.translation import ugettext as _
 from django.template import loader, Context, Template
 from django.core.mail import EmailMultiAlternatives
-from django.conf import settings
+from forum import settings
 from forum.models import KeyValue, Activity, User, QuestionSubscription
 from forum.utils.mail import send_email
 
index 866734dae47127802c82396fb62bcf036842f730..a517f664b0e37c8c513cb5445e94a92bb3e8ed54 100644 (file)
@@ -2,7 +2,7 @@ from django.http import HttpResponseRedirect
 from forum.utils.forms import get_next_url
 from django.utils.translation import ugettext as _
 from forum.user_messages import create_message, get_and_delete_messages
-from django.conf import settings
+from forum import settings
 from django.core.urlresolvers import reverse
 import logging
 
index 676f1c7b6258a54b41c3c3e5739bf6208fcbf7b9..1f15bde0bdc1dd304bd6f518ace1209d70e94bc4 100644 (file)
@@ -14,7 +14,7 @@ from django.utils.translation import ugettext as _
 from django.utils.safestring import mark_safe
 from django.contrib.sitemaps import ping_google
 import django.dispatch
-from django.conf import settings
+from forum import settings
 import logging
 
 
index 53d4c493049697efd25192185b25ef8611f2a751..3fd068081e3ef1d7cc65b2744d22dc9f38a52b88 100644 (file)
@@ -5,7 +5,7 @@ class Vote(models.Model):
     user = models.ForeignKey(User, related_name="votes")\r
     node = models.ForeignKey(Node, related_name="votes")\r
     value = models.SmallIntegerField()\r
-    action = models.ForeignKey(Action, unique=True, related_name="vote")\r
+    action = models.OneToOneField(Action, related_name="vote")\r
     voted_at = models.DateTimeField(default=datetime.datetime.now)\r
 \r
     class Meta:\r
@@ -17,7 +17,7 @@ class Flag(models.Model):
     user = models.ForeignKey(User, related_name="flags")\r
     node = models.ForeignKey(Node, related_name="flags")\r
     reason = models.CharField(max_length=300)\r
-    action = models.ForeignKey(Action, unique=True, related_name="flag")\r
+    action = models.OneToOneField(Action, related_name="flag")\r
     flagged_at = models.DateTimeField(default=datetime.datetime.now)\r
 \r
     class Meta:\r
@@ -86,7 +86,7 @@ class Award(models.Model):
     awarded_at = models.DateTimeField(default=datetime.datetime.now)\r
 \r
     trigger = models.ForeignKey(Action, related_name="awards", null=True)\r
-    action = models.ForeignKey(Action, related_name="award", unique=True)\r
+    action = models.OneToOneField(Action, related_name="award")\r
 \r
 \r
     class Meta:\r
index 19973e9e3c4744c20e3ce490c72a1d753e8e44ba..d2b70b6eeb099e6f207f18ca1f016c15fd79d585 100644 (file)
@@ -1,4 +1,3 @@
-from forum.akismet import *\r
 from base import *\r
 from tag import Tag\r
 \r
@@ -257,11 +256,12 @@ class Node(BaseModel, NodeContent):
 \r
     @staticmethod\r
     def isSpam(comment, data):\r
-        if not settings.WORDPRESS_API_KEY:\r
-            return False\r
-            \r
-        api = Akismet(settings.WORDPRESS_API_KEY, settings.APP_URL)\r
-        return api.comment_check(comment, data)\r
+        return False\r
+        #if not settings.WORDPRESS_API_KEY:\r
+        #    return False\r
+        #\r
+        #api = Akismet(settings.WORDPRESS_API_KEY, settings.APP_URL)\r
+        #return api.comment_check(comment, data)\r
 \r
     class Meta:\r
         app_label = 'forum'\r
index 023b46406220894d72e9849e0e195fc2a5428610..f17d00367d702d5d0af80d630e3055f4dca9c3c5 100644 (file)
@@ -25,9 +25,12 @@ def get_modules_script(script_name):
     for m in MODULE_LIST:
         try:
             all.append(__import__('%s.%s' % (m.__name__, script_name), globals(), locals(), [m.__name__]))
-        except Exception, e:
-            #print m.__name__ + ":" + str(e)
+        except ImportError, e:
+            #repr(type(e)) + m.__name__ + ":" + str(e)
             pass
+        except:
+            import sys, traceback
+            traceback.print_exc(file=sys.stdout)
 
     return all
 
index 17d248b1559b378f950da64f53e87404afe2f1a8..a4c1fadd7dfacac0deb7250c85133732f453187d 100644 (file)
@@ -37,7 +37,7 @@ def decorate(origin, needs_origin=True):
                 return origin\r
             return decorator\r
 \r
-        raise Exception('Not an decoratable function: %s' % origin.name)\r
+        raise TypeError('Not a decoratable function: %s' % origin.__name__)\r
 \r
     def decorator(fn):\r
         origin.decorate(fn, needs_origin)\r
@@ -46,6 +46,12 @@ def decorate(origin, needs_origin=True):
     return decorator\r
 \r
 \r
+def decorate_all(module):\r
+    [setattr(module, n, decoratable(f)) for n, f in\r
+        [(n, getattr(module, n)) for n in dir(module)]\r
+        if (callable(f)) and (not inspect.isclass(f)) and (f.__module__ == module.__name__)]\r
+\r
+\r
 \r
 \r
 \r
index a8530ee633aa5d99b6deb245173519f7bc6fa259..9ab0c6bf44554aeaedc3ec53ec8bc0f058148e48 100644 (file)
@@ -4,9 +4,13 @@ from forms import ImageFormWidget
 
 from django.forms.widgets import Textarea
 from django.utils.translation import ugettext_lazy as _
+from django.conf import settings as djsettings
 
-INTERNAL_VERSION = Setting('INTERNAL_VERSION', "59")
+OSQA_VERSION = Setting('OSQA_VERSION', "Development Version")
 SETTINGS_PACK = Setting('SETTINGS_PACK', "default")
+APP_URL = djsettings.APP_URL
+FORUM_SCRIPT_ALIAS = djsettings.FORUM_SCRIPT_ALIAS
+
 
 from basic import *
 from email import *
@@ -19,6 +23,7 @@ from about import *
 from faq import *
 from form import *
 from moderation import *
+from users import *
 
 BADGES_SET = SettingSet('badges', _('Badges config'), _("Configure badges on your OSQA site."), 500)
 
index f640a7c1f850356895d8be9f1b1ec03cd0b50189..e16097027102d0cb6f19b443aab9cf705897a2e8 100644 (file)
@@ -66,10 +66,12 @@ class BaseSetting(object):
         self.set_value(self.default)
 
     def _parse(self, value):
-        try:
-            return self.base_type(value)
-        except:
-            return value
+        if not isinstance(value, self.base_type):
+            try:
+                return self.base_type(value)
+            except:
+                pass
+        return value        
 
 
 class Setting(object):
index 2952bd79d34676cd7ef1ba864241c1dd6681a99f..fa622818ea22d62d40affe922516e98eef746605 100644 (file)
@@ -42,4 +42,8 @@ widget=Textarea))
 \r
 APP_COPYRIGHT = Setting('APP_COPYRIGHT', u'Copyright OSQA, 2010. Some rights reserved under creative commons license.', BASIC_SET, dict(\r
 label = _("Copyright notice"),\r
-help_text = _("The copyright notice visible at the footer of your page.")))
\ No newline at end of file
+help_text = _("The copyright notice visible at the footer of your page.")))\r
+\r
+FEEDBACK_SITE_URL = Setting('FEEDBACK_SITE_URL', '', BASIC_SET, dict(\r
+label = _("Feedback site url"),\r
+help_text = _("If you have a specific place to get feedback from your users, use this field and the fedback link on the footer will point there.")))
\ No newline at end of file
index 16afd7c4074384c9ad2299b76f13233d0b87c5cf..9d439df0b7ba5939d391a0da7cccea6cfa6a6e54 100644 (file)
@@ -13,7 +13,3 @@ label = _("Google analytics key"),
 help_text = _("Your Google analytics key. You can get one at the <a href='http://www.google.com/analytics/'>Google analytics official website</a>"),\r
 required=False))\r
 \r
-WORDPRESS_API_KEY = Setting('WORDPRESS_API_KEY', '', EXT_KEYS_SET, dict(\r
-label = _("Wordpress API key"),\r
-help_text = _("Your Wordpress API key. You can get one at <a href='http://wordpress.com/'>http://wordpress.com/</a>"),\r
-required=False))\r
index ba1b5b595eb38df271bbfc8d77a5bf4311a4f01c..45df66f7eb7c8b24860bee38f60adee582353198 100644 (file)
@@ -4,6 +4,10 @@ from django.utils.translation import ugettext_lazy as _
 
 FORUM_SET = SettingSet('form', _('Form settings'), _("General settings for the OSQA forms."), 10)
 
+WIKI_ON = Setting('WIKI_ON', True, FORUM_SET, dict(
+label = _("Enable community wiki"),
+help_text = _("Can questions or answers be marked as community wiki."),
+required=False))
 
 
 """ settings for questions """
index aa5a35285f6c03294bba0999ee52bd4d49d1cd61..81e5446583ff8cd66d0a8f15ddae5e5afa4c3bb3 100644 (file)
@@ -1,4 +1,5 @@
 import os
+from string import strip
 from django import forms
 from base import Setting
 from django.utils.translation import ugettext as _
@@ -20,7 +21,7 @@ class SettingsSetForm(forms.Form):
         super(SettingsSetForm, self).__init__(data, *args, **kwargs)
 
         for setting in set:
-            if isinstance(setting, Setting.emulators.get(str, DummySetting)):
+            if isinstance(setting, (Setting.emulators.get(str, DummySetting), Setting.emulators.get(unicode, DummySetting))):
                 field = forms.CharField(**setting.field_context)
             elif isinstance(setting, Setting.emulators.get(float, DummySetting)):
                 field = forms.FloatField(**setting.field_context)
@@ -92,4 +93,13 @@ class StringListWidget(forms.Widget):
         else:
             return data[name]
 
+class CommaStringListWidget(forms.Textarea):
+    def value_from_datadict(self, data, files, name):
+        if 'submit' in data:
+            return map(strip, data[name].split(','))
+        else:
+            return ', '.join(data[name])    
+
+
+
 
diff --git a/forum/settings/users.py b/forum/settings/users.py
new file mode 100644 (file)
index 0000000..01377d7
--- /dev/null
@@ -0,0 +1,26 @@
+from forms import CommaStringListWidget
+from base import Setting, SettingSet
+from django.utils.translation import ugettext as _
+
+USERS_SET = SettingSet('users', _('Users settings'), _("General settings for the OSQA users."), 20)
+
+EDITABLE_SCREEN_NAME = Setting('EDITABLE_SCREEN_NAME', False, USERS_SET, dict(
+label = _("Editable screen name"),
+help_text = _("Allow users to alter their screen name."),
+required=False))
+
+MIN_USERNAME_LENGTH = Setting('MIN_USERNAME_LENGTH', 3, USERS_SET, dict(
+label = _("Minimum username length"),
+help_text = _("The minimum length (in character) of a username.")))
+
+RESERVED_USERNAMES = Setting('RESERVED_USERNAMES',
+[_('fuck'), _('shit'), _('ass'), _('sex'), _('add'), _('edit'), _('save'), _('delete'), _('manage'), _('update'), _('remove'), _('new')]
+, USERS_SET, dict(
+label = _("Disabled usernames"),
+help_text = _("A comma separated list of disabled usernames (usernames not allowed during a new user registration)."),
+widget=CommaStringListWidget))
+
+EMAIL_UNIQUE = Setting('EMAIL_UNIQUE', True, USERS_SET, dict(
+label = _("Force unique email"),
+help_text = _("Should each user have an unique email.")))
+
index 4c57e61b609c99bd9b43a931bbd09c3014a288b7..eb24116039752d8dcea663980a01617743acd88b 100644 (file)
@@ -23,7 +23,7 @@
             var visible = arrow.attr("src").indexOf("hide") > -1;
 
             var path = $.i18n._('/') + "media/images/expander-arrow-" + 
-                        (visible ? "show" : "hide") + ".gif" + "?v={{settings.RESOURCE_REVISION}}";
+                        (visible ? "show" : "hide") + ".gif";
             arrow.attr("src", path);
             $("#rev-body-" + id).slideToggle("fast");
         }
index 3a6425376a68cbd832b6b792e3420dbb28ad7796..d1388fa8524b038786f1a1596085a15984cc3042 100644 (file)
@@ -1,3 +1,5 @@
+import forum.views
+
 import forum.badges
 import forum.subscriptions
 
index 4dc8f34dcf88df57dc54dfc748b473525fbf8442..3fa4c69ffda8e592c65a9e6912a6f25a27f00844 100644 (file)
@@ -5,7 +5,7 @@ from forum.models import User, Question, Comment, QuestionSubscription, Subscrip
 from forum.utils.mail import send_email\r
 from django.utils.translation import ugettext as _\r
 from forum.actions import AskAction, AnswerAction, CommentAction, AcceptAnswerAction, UserJoinsAction, QuestionViewAction\r
-from django.conf import settings\r
+from forum import settings\r
 from django.db.models import Q, F\r
 \r
 def create_subscription_if_not_exists(question, user):\r
index e51950411cc65f9369c4b774fb0d768eea4ce91f..9f595c8418bf182c776fd1b88b0fae8be6092d48 100644 (file)
@@ -12,7 +12,7 @@ from forum.models import Question, Answer, QuestionRevision, AnswerRevision, Nod
 from django.utils.translation import ugettext as _
 from django.utils.translation import ungettext
 from django.utils import simplejson
-from django.conf import settings
+from forum import settings
 from django.template.defaulttags import url as default_url
 from forum import skins
 
@@ -262,7 +262,7 @@ def media(url):
     url = skins.find_media_source(url)
     if url:
         url = '///' + settings.FORUM_SCRIPT_ALIAS + '/m/' + url
-        return posixpath.normpath(url) + '?v=%d' % settings.RESOURCE_REVISION
+        return posixpath.normpath(url)
 
 class ItemSeparatorNode(template.Node):
     def __init__(self,separator):
@@ -320,7 +320,7 @@ class BlockMediaUrlNode(template.Node):
 
         url = skins.find_media_source(url)
         url = prefix + url
-        out = posixpath.normpath(url) + '?v=%d' % settings.RESOURCE_REVISION
+        out = posixpath.normpath(url)
         return out.replace(' ','')
 
 @register.tag(name='blockmedia')
index 28555e56e0417d37ea59b8c1b8c8e4f28a22b326..0155406b78ae71a802f87515b44fb0e72c443f59 100644 (file)
@@ -1,7 +1,7 @@
 import startup
 
 import os.path
-from django.conf import settings
+from forum import settings
 from django.conf.urls.defaults import *
 from django.contrib import admin
 from forum import views as app
@@ -134,8 +134,3 @@ urlpatterns += patterns('',
 
     url(r'^feeds/rss/$', RssLastestQuestionsFeed, name="latest_questions_feed"),
 )
-
-if 'rosetta' in settings.INSTALLED_APPS:
-    urlpatterns += patterns('',
-        url(r'^rosetta/', include('rosetta.urls')),
-    )
\ No newline at end of file
index aef2f1904b71db586a9c01bc4d0722e676242a33..d91e59f6fe18771019e38c5ebd5907701233c866 100644 (file)
@@ -2,7 +2,7 @@ from django import forms
 import re
 from django.utils.translation import ugettext as _
 from django.utils.safestring import mark_safe
-from django.conf import settings
+from forum import settings
 from django.http import str_to_unicode
 from forum.models import User
 import urllib
@@ -37,8 +37,6 @@ login_form_widget_attrs = { 'class': 'required login' }
 username_re = re.compile(r'^[\w ]+$')
 
 class UserNameField(StrippedNonEmptyCharField):
-    RESERVED_NAMES = (u'fuck', u'shit', u'ass', u'sex', u'add',
-                       u'edit', u'save', u'delete', u'manage', u'update', 'remove', 'new')
     def __init__(self,db_model=User, db_field='username', must_exist=False,skip_clean=False,label=_('choose a username'),**kw):
         self.must_exist = must_exist
         self.skip_clean = skip_clean
@@ -50,6 +48,7 @@ class UserNameField(StrippedNonEmptyCharField):
                         'missing':_('sorry, there is no user with this name'),
                         'multiple-taken':_('sorry, we have a serious error - user name is taken by several users'),
                         'invalid':_('user name can only consist of letters, empty space and underscore'),
+                        'toshort':_('user name is to short, please use at least %d characters') % settings.MIN_USERNAME_LENGTH
                     }
         if 'error_messages' in kw:
             error_messages.update(kw['error_messages'])
@@ -72,9 +71,11 @@ class UserNameField(StrippedNonEmptyCharField):
             username = super(UserNameField, self).clean(username)
         except forms.ValidationError:
             raise forms.ValidationError(self.error_messages['required'])
+        if len(username) < settings.MIN_USERNAME_LENGTH:
+            raise forms.ValidationError(self.error_messages['toshort'])
         if self.required and not username_re.search(username):
             raise forms.ValidationError(self.error_messages['invalid'])
-        if username in self.RESERVED_NAMES:
+        if username in settings.RESERVED_USERNAMES:
             raise forms.ValidationError(self.error_messages['forbidden'])
         try:
             user = self.db_model.objects.get(
index 1dc2209f81b21e87dc8ea095ca4ca9dcea9ef470..4d11f854d710a625f9b5a5f690b51fe4faf87136 100644 (file)
@@ -9,7 +9,7 @@ from email.MIMEImage import MIMEImage
 from django.core.mail import DNS_NAME\r
 from smtplib import SMTP\r
 import email.Charset\r
-from django.conf import settings\r
+from forum import settings\r
 from django.template import loader, Context, Template\r
 from forum.utils.html import sanitize_html\r
 from forum.context import application_settings\r
@@ -64,7 +64,7 @@ def create_msg(subject, sender, recipient, html, text, images):
     msgRoot['Subject'] = subject\r
     msgRoot['From'] = named(sender)\r
     msgRoot['To'] =  named(recipient)\r
-    msgRoot.preamble = 'This is a multi-part message from %s.' % str(settings.APP_SHORT_NAME)\r
+    msgRoot.preamble = 'This is a multi-part message from %s.' % unicode(settings.APP_SHORT_NAME).encode('utf8')\r
 \r
     msgAlternative = MIMEMultipart('alternative')\r
     msgRoot.attach(msgAlternative)\r
@@ -86,7 +86,7 @@ def create_msg(subject, sender, recipient, html, text, images):
 \r
 def send_email(subject, recipients, template, context={}, sender=None, images=[], threaded=True):\r
     if sender is None:\r
-        sender = (str(settings.APP_SHORT_NAME), str(settings.DEFAULT_FROM_EMAIL))\r
+        sender = (unicode(settings.APP_SHORT_NAME), unicode(settings.DEFAULT_FROM_EMAIL))\r
 \r
     if not len(images):\r
         images = [(os.path.join(str(settings.UPFILES_FOLDER), os.path.basename(str(settings.APP_LOGO))), 'logo')]\r
index bfd0be8c3ecacd67d33872066ce5fc993e2f742e..f169b50b6c1bcf2c0ce8edbf0edc10bdf9e9ef11 100644 (file)
@@ -5,3 +5,13 @@ import users
 import meta
 import auth
 import admin
+
+#from forum.modules.decorators import decorate_all
+
+#decorate_all(readers)
+#decorate_all(writers)
+#decorate_all(commands)
+#decorate_all(users)
+#decorate_all(meta)
+#decorate_all(auth)
+#decorate_all(admin)
index ca0f81357359dfa31154091eafe0b7a4f4a9e7f7..126a348c735fada04184b24ee04921d37e1ea39c 100644 (file)
@@ -47,6 +47,8 @@ def settings_set(request, set_name):
 
             if set_name in ('minrep', 'badges', 'repgain'):
                 settings.SETTINGS_PACK.set_value("custom")
+
+        return HttpResponseRedirect(reverse('admin_set', args=[set_name]))
     else:
         form = SettingsSetForm(set)
 
index 3d8403f947bf0005324c074eae786ed09125f84b..f9d299d29da230eda99184d9a8f04f0b263806f4 100644 (file)
@@ -177,12 +177,12 @@ def external_register(request):
         provider_class = AUTH_PROVIDERS[request.session['auth_provider']].consumer
         user_data = provider_class.get_user_data(request.session['assoc_key'])
 
+        if not user_data:
+            user_data = request.session.get('auth_consumer_data', {})
+
         username = user_data.get('username', '')
         email = user_data.get('email', '')
 
-        if not email:
-            email = request.session.get('auth_email_request', '')
-
         if email:
             request.session['auth_validated_email'] = email
 
@@ -338,7 +338,6 @@ def login_and_forward(request,  user, forward=None, message=None):
     user.backend = "django.contrib.auth.backends.ModelBackend"
     login(request,  user)
 
-    #user_logged_in.send(user=user,old_session=old_session,sender=None)
     temp_data = request.session.pop('temp_node_data', None)
     if temp_data:
         request.POST = temp_data
index 452d57d0f0f0022c02667c195030ca4bc19f3f4d..d8c4231b46764847af62b981c71c7d1d2003054d 100644 (file)
@@ -1,5 +1,5 @@
 import datetime
-from django.conf import settings
+from forum import settings
 from django.core.exceptions import ObjectDoesNotExist
 from django.utils import simplejson
 from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden
@@ -11,6 +11,7 @@ from forum.actions import *
 from django.core.urlresolvers import reverse
 from django.contrib.auth.decorators import login_required
 from forum.utils.decorators import ajax_method, ajax_login_required
+from forum.modules.decorators import decoratable
 from decorators import command, CommandException
 from forum import settings
 import logging
@@ -42,12 +43,6 @@ class AnonymousNotAllowedException(CommandException):
             """ % {'action': action, 'signin_url': reverse('auth_signin')})
         )
 
-class SpamNotAllowedException(CommandException):
-    def __init__(self, action = "comment"):
-        super(SpamNotAllowedException, self).__init__(
-            _("""Your %s has been marked as spam.""" % action)
-        )
-
 class NotEnoughLeftException(CommandException):
     def __init__(self, action, limit):
         super(NotEnoughLeftException, self).__init__(
@@ -231,6 +226,7 @@ def mark_favorite(request, id):
         }
     }
 
+@decoratable
 @command
 def comment(request, id):
     post = get_object_or_404(Node, id=id)
@@ -253,17 +249,6 @@ def comment(request, id):
     if len(comment_text) > settings.FORM_MAX_COMMENT_BODY:
         raise CommandException(_("No more than %d characters on comment body.") % settings.FORM_MAX_COMMENT_BODY)
 
-    data = {
-        "user_ip":request.META["REMOTE_ADDR"],
-        "user_agent":request.environ['HTTP_USER_AGENT'],
-        "comment_author":request.user.username,
-        "comment_author_email":request.user.email,
-        "comment_author_url":request.user.website,
-        "comment":comment_text
-    }
-    if Node.isSpam(comment_text, data):
-        raise SpamNotAllowedException()
-
     if 'id' in request.POST:
         comment = get_object_or_404(Comment, id=request.POST['id'])
 
index 44ec8bad9142d44ed8beb1930a20309f7a478a23..141887a3e0f7cfdc8a4402c04205ec1ca35ed276 100644 (file)
@@ -71,8 +71,8 @@ def command(func):
 \r
             response['success'] = True\r
         except Exception, e:\r
-            import sys, traceback\r
-            traceback.print_exc(file=sys.stdout)\r
+            #import sys, traceback\r
+            #traceback.print_exc(file=sys.stdout)\r
 \r
             if isinstance(e, CommandException):\r
                 response = {\r
index 885b8b614740114bf164fa05342499f4e59039de..c143d133e5039dc0543e350ea155d12a4cc4b3d4 100644 (file)
@@ -3,7 +3,7 @@ from django.shortcuts import render_to_response, get_object_or_404
 from django.core.urlresolvers import reverse
 from django.template import RequestContext
 from django.http import HttpResponseRedirect, HttpResponse
-from django.conf import settings
+from forum import settings
 from forum.forms import FeedbackForm
 from django.core.urlresolvers import reverse
 from django.utils.translation import ugettext as _
index 11e7160f19727b436d693172ad31b88305ce5202..7f201aa551357d362c8bb88b2e22a65f1e4e6f4f 100644 (file)
@@ -2,7 +2,7 @@
 import datetime
 import logging
 from urllib import unquote
-from django.conf import settings as django_settings
+from forum import settings as django_settings
 from django.shortcuts import render_to_response, get_object_or_404
 from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404, HttpResponsePermanentRedirect
 from django.core.paginator import Paginator, EmptyPage, InvalidPage
index c12c391a678ceeebf4ff9a46c03abcdfacbae409..8acd5d687aedba4c3fe9dbc4fd11cbb3f81a2b80 100644 (file)
@@ -91,7 +91,8 @@ def edit_user(request, id):
 \r
             set_new_email(user, new_email)\r
 \r
-            #user.username = sanitize_html(form.cleaned_data['username'])\r
+            if settings.EDITABLE_SCREEN_NAME:\r
+                user.username = sanitize_html(form.cleaned_data['username'])\r
             user.real_name = sanitize_html(form.cleaned_data['realname'])\r
             user.website = sanitize_html(form.cleaned_data['website'])\r
             user.location = sanitize_html(form.cleaned_data['city'])\r
index 980357e3531442f93d0012bb7687a81adcfdb9a1..638f070945ea42ffc169ccdf78b2c6eb4b0419af 100644 (file)
@@ -14,10 +14,10 @@ from django.core.urlresolvers import reverse
 from django.core.exceptions import PermissionDenied
 
 from forum.actions import AskAction, AnswerAction, ReviseAction, RollbackAction, RetagAction
+from forum.modules.decorators import decoratable
 from forum.forms import *
 from forum.models import *
 from forum.utils.forms import get_next_url
-from forum.views.commands import SpamNotAllowedException
 
 
 def upload(request):#ajax upload file to a question or answer
@@ -64,23 +64,12 @@ def upload(request):#ajax upload file to a question or answer
 
     return HttpResponse(result, mimetype="application/xml")
 
-
+@decoratable
 def ask(request):
     if request.POST and "text" in request.POST:
         form = AskForm(request.POST)
         if form.is_valid():
             if request.user.is_authenticated():
-                data = {
-                    "user_ip":request.META["REMOTE_ADDR"],
-                    "user_agent":request.environ['HTTP_USER_AGENT'],
-                    "comment_author":request.user.username,
-                    "comment_author_email":request.user.email,
-                    "comment_author_url":request.user.website,
-                    "comment":request.POST['text']
-                }
-                if Node.isSpam(request.POST['text'], data):
-                    raise SpamNotAllowedException("question")
-
                 question = AskAction(user=request.user).save(data=form.cleaned_data).node
                 return HttpResponseRedirect(question.get_absolute_url())
             else:
@@ -193,23 +182,13 @@ def edit_answer(request, id):
                               'form': form,
                               }, context_instance=RequestContext(request))
 
+@decoratable
 def answer(request, id):
     question = get_object_or_404(Question, id=id)
     if request.POST:
         form = AnswerForm(question, request.POST)
         if form.is_valid():
             if request.user.is_authenticated():
-                data = {
-                    "user_ip":request.META["REMOTE_ADDR"],
-                    "user_agent":request.environ['HTTP_USER_AGENT'],
-                    "comment_author":request.user.username,
-                    "comment_author_email":request.user.email,
-                    "comment_author_url":request.user.website,
-                    "comment":request.POST['text']
-                }
-                if Node.isSpam(request.POST['text'], data):
-                    raise SpamNotAllowedException("answer")
-
                 answer = AnswerAction(user=request.user).save(dict(question=question, **form.cleaned_data)).node
                 return HttpResponseRedirect(answer.get_absolute_url())
             else:
diff --git a/forum_modules/akismet/__init__.py b/forum_modules/akismet/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/forum_modules/akismet/lib/__init__.py b/forum_modules/akismet/lib/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/forum_modules/akismet/settings.py b/forum_modules/akismet/settings.py
new file mode 100644 (file)
index 0000000..8dae543
--- /dev/null
@@ -0,0 +1,8 @@
+from forum.settings.base import Setting\r
+from forum.settings.extkeys import EXT_KEYS_SET\r
+from django.utils.translation import ugettext_lazy as _\r
+\r
+WORDPRESS_API_KEY = Setting('WORDPRESS_API_KEY', '', EXT_KEYS_SET, dict(\r
+label = _("Wordpress API key"),\r
+help_text = _("Your Wordpress API key. You can get one at <a href='http://wordpress.com/'>http://wordpress.com/</a>"),\r
+required=False))\r
diff --git a/forum_modules/akismet/startup.py b/forum_modules/akismet/startup.py
new file mode 100644 (file)
index 0000000..2035ea0
--- /dev/null
@@ -0,0 +1,51 @@
+from django.utils.translation import ugettext as _
+from django.http import HttpResponse, HttpResponseRedirect
+from django.utils import simplejson
+from django.shortcuts import render_to_response
+from forum.modules.decorators import decorate
+from forum import views
+from lib.akismet import Akismet
+from forum.settings import APP_URL, OSQA_VERSION
+import settings
+
+
+def check_spam(param, comment_type):
+    def wrapper(origin, request, *args, **kwargs):
+        if request.POST and request.POST.get(param, None) and settings.WORDPRESS_API_KEY:
+            comment = request.POST[param]
+            data = {
+                "user_ip":request.META["REMOTE_ADDR"],
+                "user_agent":request.environ['HTTP_USER_AGENT'],
+                "comment_type": comment_type,
+                "comment":comment
+            }
+
+            if request.user.is_authenticated():
+                data.update({
+                    "comment_author":request.user.username,
+                    "comment_author_email":request.user.email,
+                    "comment_author_url":request.user.website,    
+                })
+
+            api = Akismet(settings.WORDPRESS_API_KEY, APP_URL, "OSQA/%s" % OSQA_VERSION)
+            if api.comment_check(comment, data):
+                if request.is_ajax():
+                    response = {
+                        'success': False,
+                        'error_message': _("Sorry, but akismet thinks your %s is spam.") % comment_type
+                    }
+                    return HttpResponse(simplejson.dumps(response), mimetype="application/json")
+                else:
+                    return render_to_response('modules/akismet/foundspam.html', {
+                        'action_name': comment_type
+                    })
+                    
+        return origin(request, *args, **kwargs)
+    return wrapper
+            
+
+decorate(views.writers.ask)(check_spam('text', _('question')))
+decorate(views.writers.answer)(check_spam('text', _('answer')))
+decorate(views.commands.comment)(check_spam('comment', _('comment')))
+
+
diff --git a/forum_modules/akismet/templates/foundspam.html b/forum_modules/akismet/templates/foundspam.html
new file mode 100644 (file)
index 0000000..8c39a89
--- /dev/null
@@ -0,0 +1,15 @@
+{% extends "base_content.html" %}
+{% load i18n %}
+{% block title %}{% trans "Akismet message" %}{% endblock %}
+
+{% block content %}
+<div class="headNormal">
+{% blocktrans %}Akismet believes your {{ action_name }} is spam.{% endblocktrans %}
+</div>
+<div class="content">
+{% blocktrans %}
+We're sorry, but Akismet believes your {{ action_name }} is spam.<br />
+If you believe this is an error, please contact the forum administrator.
+{% endblocktrans %}
+</div>
+{% endblock %}
\ No newline at end of file
index c82b99eda3d7971d16e8d65823f0a6c6c0474714..6802cb049815b0460ad5b6804df8d43fb63819da 100644 (file)
@@ -44,6 +44,13 @@ class AolAuthContext(ConsumerTemplateContext):
 
 
 class MyOpenIdAuthConsumer(OpenIdAbstractAuthConsumer):
+    dataype2ax_schema = {
+        'username': ('http://schema.openid.net/namePerson/friendly', 'friendly'),
+        'email': 'http://schema.openid.net/contact/email',
+        'web': 'http://schema.openid.net/contact/web/default',
+        'birthdate': ('http://schema.openid.net/birthDate', 'birthDate'),
+    }
+
     def get_user_url(self, request):
         blog_name = request.POST['input_field']
         return "http://%s.myopenid.com/" % blog_name
index 680359681394a83d7bfe5060f4965abc87646028..e9cf21164930287e7bc9e98272f177d8029137a7 100644 (file)
@@ -1,3 +1,5 @@
+import re
+
 from django.utils.html import escape
 from django.http import get_host
 
@@ -15,6 +17,15 @@ from store import OsqaOpenIDStore
 
 class OpenIdAbstractAuthConsumer(AuthenticationConsumer):
 
+    dataype2ax_schema = {
+        'username': 'http://axschema.org/namePerson/friendly',
+        'email': 'http://axschema.org/contact/email',
+        'web': 'http://axschema.org/contact/web/default',
+        'firstname': 'http://axschema.org/namePerson/first',
+        'lastname': 'http://axschema.org/namePerson/last',
+        'birthdate': 'http://axschema.org/birthDate',
+    }
+
     def get_user_url(self, request):
         try:
             return request.POST['openid_identifier']
@@ -55,14 +66,18 @@ class OpenIdAbstractAuthConsumer(AuthenticationConsumer):
 
         if request.session.get('force_email_request', True):
             axr = AXFetchRequest()
-            axr.add(AttrInfo("http://axschema.org/contact/email", 1, True, "email"))
+            for data_type, schema in self.dataype2ax_schema.items():
+                if isinstance(schema, tuple):
+                    axr.add(AttrInfo(schema[0], 1, True, schema[1]))
+                else:
+                    axr.add(AttrInfo(schema, 1, True, data_type))
+
             auth_request.addExtension(axr)
 
         trust_root = getattr(
             settings, 'OPENID_TRUST_ROOT', get_url_host(request) + '/'
         )
 
-
         return auth_request.redirectURL(trust_root, redirect_to)
 
     def process_authentication_request(self, request):
@@ -72,8 +87,8 @@ class OpenIdAbstractAuthConsumer(AuthenticationConsumer):
             (k.encode('utf8'), v.encode('utf8')) for k, v in request.GET.items()
         ])
 
-        #for i in query_dict.items():
-        #    print "%s : %s" % i
+        for i in query_dict.items():
+            print "%s : %s" % i
 
         url = get_url_host(request) + request.path
         openid_response = consumer.complete(query_dict, url)
@@ -82,10 +97,34 @@ class OpenIdAbstractAuthConsumer(AuthenticationConsumer):
             if request.session.get('force_email_request', True):
                 try:
                     ax = AXFetchResponse.fromSuccessResponse(openid_response)
-                    email = ax.getExtensionArgs()['value.ext0.1']
-                    request.session['auth_email_request'] = email
+
+                    axargs = ax.getExtensionArgs()
+
+                    ax_schema2data_type = dict([(s, t) for t, s in self.dataype2ax_schema.items()])
+
+                    available_types = dict([
+                        (ax_schema2data_type[s], re.sub('^type\.', '', n))
+                        for n, s in axargs.items() if s in ax_schema2data_type
+                    ])
+
+                    available_data = dict([
+                        (t, axargs["value.%s.1" % s]) for t, s in available_types.items()
+                    ])
+
+                    print available_data
+                    
+
+                    #email = ax.getExtensionArgs()['value.ext0.1']
+                    #username = ax.getExtensionArgs()['value.ext0.2']
+                    
+                    request.session['auth_consumer_data'] = {
+                        'email': '',
+                        'username': ''
+                    }
+
                 except Exception, e:
-                    pass
+                    import sys, traceback
+                    traceback.print_exc(file=sys.stdout)
 
             return request.GET['openid.identity']
         elif openid_response.status == CANCEL:
index aab362a696d4513022fb40a9eb9d5dcdab1265b8..3b1cd458a2c1a85dd96baf2040de95c29a056b5f 100644 (file)
@@ -1,13 +1,5 @@
 # encoding:utf-8
 import os.path
-from django.utils.translation import ugettext as _
-
-def check_local_setting(name, value):
-    local_vars = locals()
-    if name in local_vars and local_vars[name] == value:
-        return True
-    else:
-        return False
 
 SITE_SRC_ROOT = os.path.dirname(__file__)
 LOG_FILENAME = 'django.osqa.log'
@@ -60,19 +52,10 @@ FORUM_SCRIPT_ALIAS = '' #no leading slash, default = '' empty string
 
 USE_I18N = True
 LANGUAGE_CODE = 'en'
-EMAIL_VALIDATION = 'off' #string - on|off
-MIN_USERNAME_LENGTH = 1
-EMAIL_UNIQUE = False
 
-WIKI_ON = True
-FEEDBACK_SITE_URL = None #None or url
-EDITABLE_SCREEN_NAME = False #True or False - can user change screen name?
+EMAIL_VALIDATION = 'off' #string - on|off
 
 DJANGO_VERSION = 1.1
-RESOURCE_REVISION=4
-
 OSQA_DEFAULT_SKIN = 'default'
 
 DISABLED_MODULES = ['books', 'recaptcha', 'project_badges']
-
-from forum.settings import *
\ No newline at end of file