From 07fe485fb0a119fb87f8ec948185b5acdd65300e Mon Sep 17 00:00:00 2001 From: hernani Date: Mon, 10 May 2010 03:34:09 +0000 Subject: [PATCH] General cleanup. Moved many hardcoded stuff still left in the code to an admin option, and removed a bunch of unused stuff. Moved akismet to it's own module. git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@187 0cfe37f9-358a-4d5e-be75-b63607b5c754 --- forum/actions/meta.py | 4 +- forum/authentication/__init__.py | 24 --------- forum/context.py | 12 ++--- forum/feed.py | 2 +- forum/forms.py | 2 +- .../management/commands/send_email_alerts.py | 2 +- forum/middleware/anon_user.py | 2 +- forum/models/base.py | 2 +- forum/models/meta.py | 6 +-- forum/models/node.py | 12 ++--- forum/modules/__init__.py | 7 ++- forum/modules/decorators.py | 8 ++- forum/settings/__init__.py | 7 ++- forum/settings/base.py | 10 ++-- forum/settings/basic.py | 6 ++- forum/settings/extkeys.py | 4 -- forum/settings/form.py | 4 ++ forum/settings/forms.py | 12 ++++- forum/settings/users.py | 26 +++++++++ forum/skins/default/templates/revisions.html | 2 +- forum/startup.py | 2 + forum/subscriptions.py | 2 +- forum/templatetags/extra_tags.py | 6 +-- forum/urls.py | 7 +-- forum/utils/forms.py | 9 ++-- forum/utils/mail.py | 6 +-- forum/views/__init__.py | 10 ++++ forum/views/admin.py | 2 + forum/views/auth.py | 7 ++- forum/views/commands.py | 21 ++------ forum/views/decorators.py | 4 +- forum/views/meta.py | 2 +- forum/views/readers.py | 2 +- forum/views/users.py | 3 +- forum/views/writers.py | 27 ++-------- forum_modules/akismet/__init__.py | 0 forum_modules/akismet/lib/__init__.py | 0 .../akismet/lib}/akismet.py | 0 forum_modules/akismet/settings.py | 8 +++ forum_modules/akismet/startup.py | 51 ++++++++++++++++++ .../akismet/templates/foundspam.html | 15 ++++++ forum_modules/openidauth/authentication.py | 7 +++ forum_modules/openidauth/consumer.py | 53 ++++++++++++++++--- settings_local.py.dist | 19 +------ 44 files changed, 263 insertions(+), 154 deletions(-) create mode 100644 forum/settings/users.py create mode 100644 forum_modules/akismet/__init__.py create mode 100644 forum_modules/akismet/lib/__init__.py rename {forum => forum_modules/akismet/lib}/akismet.py (100%) create mode 100644 forum_modules/akismet/settings.py create mode 100644 forum_modules/akismet/startup.py create mode 100644 forum_modules/akismet/templates/foundspam.html diff --git a/forum/actions/meta.py b/forum/actions/meta.py index 5063746..c92d899 100644 --- a/forum/actions/meta.py +++ b/forum/actions/meta.py @@ -15,7 +15,7 @@ class VoteAction(ActionProxy): vote.save() def cancel_action(self): - vote = self.vote.all()[0] + vote = self.vote self.update_node_score(-vote.value) vote.delete() @@ -98,7 +98,7 @@ class FlagAction(ActionProxy): DeleteAction(node=self.node, user=self.user, extra="BYFLAGGED").save() def cancel_action(self): - self.flag.all()[0].delete() + self.flag.delete() self.node.reset_flag_count_cache() @classmethod diff --git a/forum/authentication/__init__.py b/forum/authentication/__init__.py index 08ea03f..8dbf825 100644 --- a/forum/authentication/__init__.py +++ b/forum/authentication/__init__.py @@ -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 diff --git a/forum/context.py b/forum/context.py index 3814bb6..f7139ac 100644 --- a/forum/context.py +++ b/forum/context.py @@ -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} diff --git a/forum/feed.py b/forum/feed.py index 02a7d3c..0f8deae 100644 --- a/forum/feed.py +++ b/forum/feed.py @@ -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/') diff --git a/forum/forms.py b/forum/forms.py index 2196981..978ef17 100644 --- a/forum/forms.py +++ b/forum/forms.py @@ -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): diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py index 4b6a05f..0931ab1 100644 --- a/forum/management/commands/send_email_alerts.py +++ b/forum/management/commands/send_email_alerts.py @@ -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 diff --git a/forum/middleware/anon_user.py b/forum/middleware/anon_user.py index 866734d..a517f66 100644 --- a/forum/middleware/anon_user.py +++ b/forum/middleware/anon_user.py @@ -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 diff --git a/forum/models/base.py b/forum/models/base.py index 676f1c7..1f15bde 100644 --- a/forum/models/base.py +++ b/forum/models/base.py @@ -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 diff --git a/forum/models/meta.py b/forum/models/meta.py index 53d4c49..3fd0680 100644 --- a/forum/models/meta.py +++ b/forum/models/meta.py @@ -5,7 +5,7 @@ class Vote(models.Model): user = models.ForeignKey(User, related_name="votes") node = models.ForeignKey(Node, related_name="votes") value = models.SmallIntegerField() - action = models.ForeignKey(Action, unique=True, related_name="vote") + action = models.OneToOneField(Action, related_name="vote") voted_at = models.DateTimeField(default=datetime.datetime.now) class Meta: @@ -17,7 +17,7 @@ class Flag(models.Model): user = models.ForeignKey(User, related_name="flags") node = models.ForeignKey(Node, related_name="flags") reason = models.CharField(max_length=300) - action = models.ForeignKey(Action, unique=True, related_name="flag") + action = models.OneToOneField(Action, related_name="flag") flagged_at = models.DateTimeField(default=datetime.datetime.now) class Meta: @@ -86,7 +86,7 @@ class Award(models.Model): awarded_at = models.DateTimeField(default=datetime.datetime.now) trigger = models.ForeignKey(Action, related_name="awards", null=True) - action = models.ForeignKey(Action, related_name="award", unique=True) + action = models.OneToOneField(Action, related_name="award") class Meta: diff --git a/forum/models/node.py b/forum/models/node.py index 19973e9..d2b70b6 100644 --- a/forum/models/node.py +++ b/forum/models/node.py @@ -1,4 +1,3 @@ -from forum.akismet import * from base import * from tag import Tag @@ -257,11 +256,12 @@ class Node(BaseModel, NodeContent): @staticmethod def isSpam(comment, data): - if not settings.WORDPRESS_API_KEY: - return False - - api = Akismet(settings.WORDPRESS_API_KEY, settings.APP_URL) - return api.comment_check(comment, data) + return False + #if not settings.WORDPRESS_API_KEY: + # return False + # + #api = Akismet(settings.WORDPRESS_API_KEY, settings.APP_URL) + #return api.comment_check(comment, data) class Meta: app_label = 'forum' diff --git a/forum/modules/__init__.py b/forum/modules/__init__.py index 023b464..f17d003 100644 --- a/forum/modules/__init__.py +++ b/forum/modules/__init__.py @@ -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 diff --git a/forum/modules/decorators.py b/forum/modules/decorators.py index 17d248b..a4c1fad 100644 --- a/forum/modules/decorators.py +++ b/forum/modules/decorators.py @@ -37,7 +37,7 @@ def decorate(origin, needs_origin=True): return origin return decorator - raise Exception('Not an decoratable function: %s' % origin.name) + raise TypeError('Not a decoratable function: %s' % origin.__name__) def decorator(fn): origin.decorate(fn, needs_origin) @@ -46,6 +46,12 @@ def decorate(origin, needs_origin=True): return decorator +def decorate_all(module): + [setattr(module, n, decoratable(f)) for n, f in + [(n, getattr(module, n)) for n in dir(module)] + if (callable(f)) and (not inspect.isclass(f)) and (f.__module__ == module.__name__)] + + diff --git a/forum/settings/__init__.py b/forum/settings/__init__.py index a8530ee..9ab0c6b 100644 --- a/forum/settings/__init__.py +++ b/forum/settings/__init__.py @@ -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) diff --git a/forum/settings/base.py b/forum/settings/base.py index f640a7c..e160970 100644 --- a/forum/settings/base.py +++ b/forum/settings/base.py @@ -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): diff --git a/forum/settings/basic.py b/forum/settings/basic.py index 2952bd7..fa62281 100644 --- a/forum/settings/basic.py +++ b/forum/settings/basic.py @@ -42,4 +42,8 @@ widget=Textarea)) APP_COPYRIGHT = Setting('APP_COPYRIGHT', u'Copyright OSQA, 2010. Some rights reserved under creative commons license.', BASIC_SET, dict( label = _("Copyright notice"), -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."))) + +FEEDBACK_SITE_URL = Setting('FEEDBACK_SITE_URL', '', BASIC_SET, dict( +label = _("Feedback site url"), +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 diff --git a/forum/settings/extkeys.py b/forum/settings/extkeys.py index 16afd7c..9d439df 100644 --- a/forum/settings/extkeys.py +++ b/forum/settings/extkeys.py @@ -13,7 +13,3 @@ label = _("Google analytics key"), help_text = _("Your Google analytics key. You can get one at the Google analytics official website"), required=False)) -WORDPRESS_API_KEY = Setting('WORDPRESS_API_KEY', '', EXT_KEYS_SET, dict( -label = _("Wordpress API key"), -help_text = _("Your Wordpress API key. You can get one at http://wordpress.com/"), -required=False)) diff --git a/forum/settings/form.py b/forum/settings/form.py index ba1b5b5..45df66f 100644 --- a/forum/settings/form.py +++ b/forum/settings/form.py @@ -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 """ diff --git a/forum/settings/forms.py b/forum/settings/forms.py index aa5a352..81e5446 100644 --- a/forum/settings/forms.py +++ b/forum/settings/forms.py @@ -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 index 0000000..01377d7 --- /dev/null +++ b/forum/settings/users.py @@ -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."))) + diff --git a/forum/skins/default/templates/revisions.html b/forum/skins/default/templates/revisions.html index 4c57e61..eb24116 100644 --- a/forum/skins/default/templates/revisions.html +++ b/forum/skins/default/templates/revisions.html @@ -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"); } diff --git a/forum/startup.py b/forum/startup.py index 3a64253..d1388fa 100644 --- a/forum/startup.py +++ b/forum/startup.py @@ -1,3 +1,5 @@ +import forum.views + import forum.badges import forum.subscriptions diff --git a/forum/subscriptions.py b/forum/subscriptions.py index 4dc8f34..3fa4c69 100644 --- a/forum/subscriptions.py +++ b/forum/subscriptions.py @@ -5,7 +5,7 @@ from forum.models import User, Question, Comment, QuestionSubscription, Subscrip from forum.utils.mail import send_email from django.utils.translation import ugettext as _ from forum.actions import AskAction, AnswerAction, CommentAction, AcceptAnswerAction, UserJoinsAction, QuestionViewAction -from django.conf import settings +from forum import settings from django.db.models import Q, F def create_subscription_if_not_exists(question, user): diff --git a/forum/templatetags/extra_tags.py b/forum/templatetags/extra_tags.py index e519504..9f595c8 100644 --- a/forum/templatetags/extra_tags.py +++ b/forum/templatetags/extra_tags.py @@ -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') diff --git a/forum/urls.py b/forum/urls.py index 28555e5..0155406 100644 --- a/forum/urls.py +++ b/forum/urls.py @@ -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 diff --git a/forum/utils/forms.py b/forum/utils/forms.py index aef2f19..d91e59f 100644 --- a/forum/utils/forms.py +++ b/forum/utils/forms.py @@ -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( diff --git a/forum/utils/mail.py b/forum/utils/mail.py index 1dc2209..4d11f85 100644 --- a/forum/utils/mail.py +++ b/forum/utils/mail.py @@ -9,7 +9,7 @@ from email.MIMEImage import MIMEImage from django.core.mail import DNS_NAME from smtplib import SMTP import email.Charset -from django.conf import settings +from forum import settings from django.template import loader, Context, Template from forum.utils.html import sanitize_html from forum.context import application_settings @@ -64,7 +64,7 @@ def create_msg(subject, sender, recipient, html, text, images): msgRoot['Subject'] = subject msgRoot['From'] = named(sender) msgRoot['To'] = named(recipient) - msgRoot.preamble = 'This is a multi-part message from %s.' % str(settings.APP_SHORT_NAME) + msgRoot.preamble = 'This is a multi-part message from %s.' % unicode(settings.APP_SHORT_NAME).encode('utf8') msgAlternative = MIMEMultipart('alternative') msgRoot.attach(msgAlternative) @@ -86,7 +86,7 @@ def create_msg(subject, sender, recipient, html, text, images): def send_email(subject, recipients, template, context={}, sender=None, images=[], threaded=True): if sender is None: - sender = (str(settings.APP_SHORT_NAME), str(settings.DEFAULT_FROM_EMAIL)) + sender = (unicode(settings.APP_SHORT_NAME), unicode(settings.DEFAULT_FROM_EMAIL)) if not len(images): images = [(os.path.join(str(settings.UPFILES_FOLDER), os.path.basename(str(settings.APP_LOGO))), 'logo')] diff --git a/forum/views/__init__.py b/forum/views/__init__.py index bfd0be8..f169b50 100644 --- a/forum/views/__init__.py +++ b/forum/views/__init__.py @@ -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) diff --git a/forum/views/admin.py b/forum/views/admin.py index ca0f813..126a348 100644 --- a/forum/views/admin.py +++ b/forum/views/admin.py @@ -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) diff --git a/forum/views/auth.py b/forum/views/auth.py index 3d8403f..f9d299d 100644 --- a/forum/views/auth.py +++ b/forum/views/auth.py @@ -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 diff --git a/forum/views/commands.py b/forum/views/commands.py index 452d57d..d8c4231 100644 --- a/forum/views/commands.py +++ b/forum/views/commands.py @@ -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']) diff --git a/forum/views/decorators.py b/forum/views/decorators.py index 44ec8ba..141887a 100644 --- a/forum/views/decorators.py +++ b/forum/views/decorators.py @@ -71,8 +71,8 @@ def command(func): response['success'] = True except Exception, e: - import sys, traceback - traceback.print_exc(file=sys.stdout) + #import sys, traceback + #traceback.print_exc(file=sys.stdout) if isinstance(e, CommandException): response = { diff --git a/forum/views/meta.py b/forum/views/meta.py index 885b8b6..c143d13 100644 --- a/forum/views/meta.py +++ b/forum/views/meta.py @@ -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 _ diff --git a/forum/views/readers.py b/forum/views/readers.py index 11e7160..7f201aa 100644 --- a/forum/views/readers.py +++ b/forum/views/readers.py @@ -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 diff --git a/forum/views/users.py b/forum/views/users.py index c12c391..8acd5d6 100644 --- a/forum/views/users.py +++ b/forum/views/users.py @@ -91,7 +91,8 @@ def edit_user(request, id): set_new_email(user, new_email) - #user.username = sanitize_html(form.cleaned_data['username']) + if settings.EDITABLE_SCREEN_NAME: + user.username = sanitize_html(form.cleaned_data['username']) user.real_name = sanitize_html(form.cleaned_data['realname']) user.website = sanitize_html(form.cleaned_data['website']) user.location = sanitize_html(form.cleaned_data['city']) diff --git a/forum/views/writers.py b/forum/views/writers.py index 980357e..638f070 100644 --- a/forum/views/writers.py +++ b/forum/views/writers.py @@ -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 index 0000000..e69de29 diff --git a/forum_modules/akismet/lib/__init__.py b/forum_modules/akismet/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/forum/akismet.py b/forum_modules/akismet/lib/akismet.py similarity index 100% rename from forum/akismet.py rename to forum_modules/akismet/lib/akismet.py diff --git a/forum_modules/akismet/settings.py b/forum_modules/akismet/settings.py new file mode 100644 index 0000000..8dae543 --- /dev/null +++ b/forum_modules/akismet/settings.py @@ -0,0 +1,8 @@ +from forum.settings.base import Setting +from forum.settings.extkeys import EXT_KEYS_SET +from django.utils.translation import ugettext_lazy as _ + +WORDPRESS_API_KEY = Setting('WORDPRESS_API_KEY', '', EXT_KEYS_SET, dict( +label = _("Wordpress API key"), +help_text = _("Your Wordpress API key. You can get one at http://wordpress.com/"), +required=False)) diff --git a/forum_modules/akismet/startup.py b/forum_modules/akismet/startup.py new file mode 100644 index 0000000..2035ea0 --- /dev/null +++ b/forum_modules/akismet/startup.py @@ -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 index 0000000..8c39a89 --- /dev/null +++ b/forum_modules/akismet/templates/foundspam.html @@ -0,0 +1,15 @@ +{% extends "base_content.html" %} +{% load i18n %} +{% block title %}{% trans "Akismet message" %}{% endblock %} + +{% block content %} +
+{% blocktrans %}Akismet believes your {{ action_name }} is spam.{% endblocktrans %} +
+
+{% blocktrans %} +We're sorry, but Akismet believes your {{ action_name }} is spam.
+If you believe this is an error, please contact the forum administrator. +{% endblocktrans %} +
+{% endblock %} \ No newline at end of file diff --git a/forum_modules/openidauth/authentication.py b/forum_modules/openidauth/authentication.py index c82b99e..6802cb0 100644 --- a/forum_modules/openidauth/authentication.py +++ b/forum_modules/openidauth/authentication.py @@ -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 diff --git a/forum_modules/openidauth/consumer.py b/forum_modules/openidauth/consumer.py index 6803596..e9cf211 100644 --- a/forum_modules/openidauth/consumer.py +++ b/forum_modules/openidauth/consumer.py @@ -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: diff --git a/settings_local.py.dist b/settings_local.py.dist index aab362a..3b1cd45 100644 --- a/settings_local.py.dist +++ b/settings_local.py.dist @@ -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 -- 2.39.5