Browse files

Accepting incoming merge of the jambazov feature branch. Mostly inclu…

…des new bug fixes.

git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@718 0cfe37f9-358a-4d5e-be75-b63607b5c754
  • Loading branch information...
1 parent 8c29337 commit 2444d6ffd7995be782615589fb1d5aef2c8277ce claycarpenter committed Jan 31, 2011
View
2 forum/feed.py
@@ -15,7 +15,7 @@
@decorate(add_domain, needs_origin=False)
def add_domain(domain, url, *args, **kwargs):
- return "%s%s" % (settings.APP_URL, url)
+ return "%s%s" % (settings.APP_BASE_URL, url)
class BaseNodeFeed(Feed):
if old_version:
View
7 forum/forms/admin.py
@@ -58,9 +58,8 @@ def render(self, name, value, attrs=None):
return """
<input class="url_field" type="text" name="%(name)s" value="%(value)s" />
- <a class="url_field_anchor" target="_blank" href="%(app_url)s%(script_alias)s"></a>
- """ % {'name': name, 'value': value, 'app_url': settings.APP_URL,
- 'script_alias': settings.FORUM_SCRIPT_ALIAS}
+ <a class="url_field_anchor" target="_blank" href="%(app_url)s"></a>
+ """ % {'name': name, 'value': value, 'app_url': settings.APP_URL}
class PageForm(forms.Form):
@@ -105,4 +104,4 @@ def __init__(self, *args, **kwargs):
self.fields['email'].label = _('email address')
-
+
View
16 forum/forms/general.py
@@ -5,10 +5,10 @@
from forum import settings
from django.http import str_to_unicode
from forum.models import User
-from forum_modules.recaptcha.formfield import ReCaptchaField
+from forum.modules import call_all_handlers
import urllib
-DEFAULT_NEXT = '/' + getattr(settings, 'FORUM_SCRIPT_ALIAS')
+DEFAULT_NEXT = getattr(settings, 'APP_BASE_URL')
def clean_next(next):
if next is None:
return DEFAULT_NEXT
@@ -156,4 +156,14 @@ def clean_password2(self):
return self.cleaned_data['password2']
class SimpleCaptchaForm(forms.Form):
- captcha = ReCaptchaField()
+ def __init__(self, *args, **kwargs):
+ spam_fields = call_all_handlers('create_anti_spam_field')
+ if spam_fields:
+ spam_fields = dict(spam_fields)
+ for name, field in spam_fields.items():
+ self.fields[name] = field
+
+ self._anti_spam_fields = spam_fields.keys()
+ else:
+ self._anti_spam_fields = []
+
View
55 forum/forms/qanda.py
@@ -8,6 +8,9 @@
from django.utils.safestring import mark_safe
from general import NextUrlField, UserNameField, SetPasswordForm
from forum import settings
+
+from forum.modules import call_all_handlers
+
import logging
class TitleField(forms.CharField):
@@ -154,6 +157,17 @@ def __init__(self, data=None, user=None, *args, **kwargs):
super(AskForm, self).__init__(data, *args, **kwargs)
self.fields['tags'] = TagNamesField(user)
+
+ if int(user.reputation) < settings.CAPTCHA_IF_REP_LESS_THAN and not (user.is_superuser or user.is_staff):
+ spam_fields = call_all_handlers('create_anti_spam_field')
+ if spam_fields:
+ spam_fields = dict(spam_fields)
+ for name, field in spam_fields.items():
+ self.fields[name] = field
+
+ self._anti_spam_fields = spam_fields.keys()
+ else:
+ self._anti_spam_fields = []
if settings.WIKI_ON:
self.fields['wiki'] = WikiField()
@@ -162,16 +176,23 @@ class AnswerForm(forms.Form):
text = AnswerEditorField()
wiki = WikiField()
- def __init__(self, question, *args, **kwargs):
- super(AnswerForm, self).__init__(*args, **kwargs)
+ def __init__(self, data=None, user=None, *args, **kwargs):
+ super(AnswerForm, self).__init__(data, *args, **kwargs)
+
+ if int(user.reputation) < settings.CAPTCHA_IF_REP_LESS_THAN and not (user.is_superuser or user.is_staff):
+ spam_fields = call_all_handlers('create_anti_spam_field')
+ if spam_fields:
+ spam_fields = dict(spam_fields)
+ for name, field in spam_fields.items():
+ self.fields[name] = field
+
+ self._anti_spam_fields = spam_fields.keys()
+ else:
+ self._anti_spam_fields = []
if settings.WIKI_ON:
self.fields['wiki'] = WikiField()
- #if question.nis.wiki:
- # self.fields['wiki'].initial = True
-
-
class RetagQuestionForm(forms.Form):
tags = TagNamesField()
# initialize the default values
@@ -214,6 +235,17 @@ def __init__(self, question, user, revision=None, *args, **kwargs):
self.fields['tags'] = TagNamesField(user)
self.fields['tags'].initial = revision.tagnames
+ if int(user.reputation) < settings.CAPTCHA_IF_REP_LESS_THAN and not (user.is_superuser or user.is_staff):
+ spam_fields = call_all_handlers('create_anti_spam_field')
+ if spam_fields:
+ spam_fields = dict(spam_fields)
+ for name, field in spam_fields.items():
+ self.fields[name] = field
+
+ self._anti_spam_fields = spam_fields.keys()
+ else:
+ self._anti_spam_fields = []
+
if settings.WIKI_ON:
self.fields['wiki'] = WikiField(disabled=(question.nis.wiki and not user.can_cancel_wiki(question)), initial=question.nis.wiki)
@@ -229,6 +261,17 @@ def __init__(self, answer, user, revision=None, *args, **kwargs):
self.fields['text'].initial = revision.body
+ if int(user.reputation) < settings.CAPTCHA_IF_REP_LESS_THAN and not (user.is_superuser or user.is_staff):
+ spam_fields = call_all_handlers('create_anti_spam_field')
+ if spam_fields:
+ spam_fields = dict(spam_fields)
+ for name, field in spam_fields.items():
+ self.fields[name] = field
+
+ self._anti_spam_fields = spam_fields.keys()
+ else:
+ self._anti_spam_fields = []
+
if settings.WIKI_ON:
self.fields['wiki'] = WikiField(disabled=(answer.nis.wiki and not user.can_cancel_wiki(answer)), initial=answer.nis.wiki)
View
1 forum/management/commands/checkinstall.py
@@ -80,5 +80,6 @@ def handle_noargs(self, **options):
print " Your APP_URL does not seem to be a valid url. Please fill this setting with the URL of your OSQA installation"
else:
print " APP_URL - %s" % settings.APP_URL
+ print " APP_BASE_URL - %s" % settings.APP_BASE_URL
View
7 forum/models/node.py
@@ -419,8 +419,6 @@ def delete(self, *args, **kwargs):
super(Node, self).delete(*args, **kwargs)
def save(self, *args, **kwargs):
- tags_changed = self._process_changes_in_tags()
-
if not self.id:
self.node_type = self.get_type()
super(BaseModel, self).save(*args, **kwargs)
@@ -431,8 +429,11 @@ def save(self, *args, **kwargs):
if self.parent_id and not self.abs_parent_id:
self.abs_parent = self.parent.absolute_parent
-
+
+ tags_changed = self._process_changes_in_tags()
+
super(Node, self).save(*args, **kwargs)
+
if tags_changed: self.tags = list(Tag.objects.filter(name__in=self.tagname_list()))
class Meta:
View
2 forum/models/user.py
@@ -22,6 +22,8 @@
)
class AnonymousUser(DjangoAnonymousUser):
+ reputation = 0
+
def get_visible_answers(self, question):
return question.answers.filter_state(deleted=False)
View
3 forum/settings/__init__.py
@@ -16,7 +16,8 @@
NODE_MAN_FILTERS = Setting('NODE_MAN_FILTERS', [])
APP_URL = djsettings.APP_URL
-FORUM_SCRIPT_ALIAS = djsettings.FORUM_SCRIPT_ALIAS
+APP_BASE_URL = djsettings.APP_BASE_URL
+FORCE_SCRIPT_NAME = djsettings.FORCE_SCRIPT_NAME
OSQA_SKIN = djsettings.OSQA_DEFAULT_SKIN
LANGUAGE_CODE = djsettings.LANGUAGE_CODE
ADMIN_MEDIA_PREFIX = djsettings.ADMIN_MEDIA_PREFIX
View
12 forum/settings/email.py
@@ -40,16 +40,16 @@
EMAIL_USE_TLS = Setting('EMAIL_USE_TLS', False, EMAIL_SET, dict(
label = _("Use TLS"),
-help_text = _("Does your SMTP server usFes TLS for authentication."),
+help_text = _("Whether to use TLS for authentication with your SMTP server."),
required=False))
DEFAULT_FROM_EMAIL = Setting('DEFAULT_FROM_EMAIL', '', EMAIL_SET, dict(
-label = _("Site 'from' email address"),
+label = _("Site 'from' Email Address"),
help_text = _("The address that will show up on the 'from' field on emails sent by your website."),
required=False))
EMAIL_SUBJECT_PREFIX = Setting('EMAIL_SUBJECT_PREFIX', '', EMAIL_SET, dict(
-label = _("Email subject prefix"),
+label = _("Email Subject Prefix"),
help_text = _("Every email sent through your website will have the subject prefixed by this string. It's usually a good idea to have such a prefix so your users can easily set up a filter on theyr email clients."),
required=False))
@@ -59,17 +59,17 @@
required=False))
EMAIL_BORDER_COLOR = Setting('EMAIL_BORDER_COLOR', '#e5ebf8', EMAIL_SET, dict(
-label = _("Email Border color"),
+label = _("Email Border Color"),
help_text = _("The outter border color of the email base template"),
required=False))
EMAIL_PARAGRAPH_STYLE = Setting('EMAIL_PARAGRAPH_STYLE', "color:#333333;font-family:'helvetica neue', arial, Helvetica, sans-serif;line-height:18px;font-size:14px;margin-top:10px;", EMAIL_SET, dict(
-label = _("Email Paragraph style"),
+label = _("Email Paragraph Style"),
help_text = _("A valid css string to be used to style email paragraphs (the P tag)."),
required=False))
EMAIL_ANCHOR_STYLE = Setting('EMAIL_ANCHOR_STYLE', "text-decoration:none;color:#3060a8;font-weight:bold;", EMAIL_SET, dict(
-label = _("Email link style"),
+label = _("Email Link Style"),
help_text = _("A valid css string to be used to style email links (the A tag)."),
required=False))
View
4 forum/settings/minrep.py
@@ -3,6 +3,10 @@
MIN_REP_SET = SettingSet('minrep', _('Minimum reputation config'), _("Configure the minimum reputation required to perform certain actions on your site."), 300)
+CAPTCHA_IF_REP_LESS_THAN = Setting('CAPTCHA_IF_REP_LESS_THAN', 0, MIN_REP_SET, dict(
+label = _("Show captcha if user with less reputation than"),
+help_text = _("If the user has less reputation, captcha is used to when adding new content.")))
+
REP_TO_VOTE_UP = Setting('REP_TO_VOTE_UP', 15, MIN_REP_SET, dict(
label = _("Minimum reputation to vote up"),
help_text = _("The minimum reputation an user must have to be allowed to vote up.")))
View
8 forum/skins/default/templates/answer_edit.html
@@ -90,6 +90,14 @@
<div class="title-desc">
{{ form.summary.help_text }}
</div>
+
+ {% if form.recaptcha %}
+ <div class="question-captcha">
+ {{ form.recaptcha.errors }}
+ {{ form.recaptcha }}
+ </div>
+ {% endif %}
+
<input type="button" value="{% trans "Save edit" %}" class="submit" onclick="submitClicked(event, this.form)" />
<input type="button" value="{% trans "Cancel" %}" class="submit" onclick="submitClicked(event, this.form);history.back(-1);" />
</form>
View
9 forum/skins/default/templates/ask.html
@@ -148,6 +148,15 @@
<p class="title-desc">
{{ form.tags.help_text }}
</p>
+
+ {% if form.recaptcha %}
+ <div class="question-captcha" style="float: left">
+ {{ form.recaptcha.errors }}
+ {{ form.recaptcha }}
+ </div>
+ <div class="clear"></div>
+ {% endif %}
+
{% if not request.user.is_authenticated %}
<input name="ask" type="button" value="{% trans "Login/signup to post your question" %}" class="submit" onclick="submitClicked(event, this.form)"/>
{% else %}
View
2 forum/skins/default/templates/base_content.html
@@ -22,7 +22,7 @@
<script type="text/javascript">
/* <![CDATA[ */
var i18nLang = '{{settings.LANGUAGE_CODE}}';
- var scriptUrl = '/{{settings.FORUM_SCRIPT_ALIAS}}'
+ var scriptUrl = '{{settings.FORCE_SCRIPT_NAME}}/'
var osqaSkin = '{{settings.OSQA_SKIN}}';
var messages = {
View
13 forum/skins/default/templates/question.html
@@ -11,7 +11,7 @@
{% block metadescription %}{{ question.meta_description }}{% endblock %}
{% block metakeywords %}{{question.tagname_meta_generator}}{% endblock %}
{% block meta %}
- <link rel="canonical" href="{{settings.APP_URL}}{{question.get_absolute_url}}" />
+ <link rel="canonical" href="{{settings.APP_BASE_URL}}{{question.get_absolute_url}}" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="{{ question.get_absolute_url }}?type=rss">
{% endblock %}
{% block title %}{% spaceless %}{{ question.headline }}{% endspaceless %}{% endblock %}
@@ -239,8 +239,17 @@
</table>
</div>
{{ answer.text.errors }}
- <div id="previewer" class="wmd-preview"></div>
+ <div id="previewer" class="wmd-preview"></div>
</div>
+
+ {% if answer.recaptcha %}
+ <div class="question-captcha" style="float: left;">
+ {{ answer.recaptcha.errors }}
+ {{ answer.recaptcha }}
+ </div>
+ <div class="clear"></div>
+ {% endif %}
+
<p><span class="form-error"></span></p>
<input type="button"
{% if user.is_anonymous %}
View
9 forum/skins/default/templates/question_edit.html
@@ -140,6 +140,15 @@
<div class="title-desc">
{{ form.summary.help_text }}
</div>
+
+ {% if form.recaptcha %}
+ <div class="question-captcha" style="float: left">
+ {{ form.recaptcha.errors }}
+ {{ form.recaptcha }}
+ </div>
+ <div class="clear"></div>
+ {% endif %}
+
<div class="error" ></div>
<input type="button" value="{% trans "Save edit" %}" class="submit" onclick="submitClicked(event, this.form)" />
<input type="button" value="{% trans "Cancel" %}" class="submit" onclick="submitClicked(event, null); history.back(-1);" />
View
6 forum/subscriptions.py
@@ -1,6 +1,7 @@
import os
import re
import datetime
+import logging
from forum.models import User, Question, Comment, QuestionSubscription, SubscriptionSettings, Answer
from forum.utils.mail import send_template_email
from django.utils.translation import ugettext as _
@@ -110,10 +111,9 @@ def answer_accepted(action, new):
subscribers = question.subscribers.filter(
subscription_settings__enable_notifications=True,
- subscription_settings__notify_accepted=True,
subscription_settings__subscribed_questions='i'
).exclude(id=action.node.nstate.accepted.by.id).distinct()
-
+
subscribers = filter_subscribers(subscribers)
send_template_email(subscribers, "notifications/answeraccepted.html", {'answer': action.node})
@@ -176,4 +176,4 @@ def question_viewed(action, new):
#
# q_author.message_set.create(message=msg)
#
-#post_save.connect(record_answer_event, sender=Answer)
+#post_save.connect(record_answer_event, sender=Answer)
View
2 forum/templatetags/email_tags.py
@@ -98,7 +98,7 @@ def __init__(self, default_node):
self.default_node = default_node
def render(self, context):
- domain = settings.APP_URL
+ domain = settings.APP_BASE_URL
path = self.default_node.render(context)
return "%s%s" % (domain, path)
View
21 forum/templatetags/extra_tags.py
@@ -100,9 +100,9 @@ def diff_date(date, limen=2):
if days > 2:
if date.year == now.year:
- return date.strftime(_("%b %d at %H:%M"))
+ return date.strftime(_("%b %d at %H:%M").encode())
else:
- return date.strftime(_("%b %d '%y at %H:%M"))
+ return date.strftime(_("%b %d '%y at %H:%M").encode())
elif days == 2:
return _('2 days ago')
elif days == 1:
@@ -118,8 +118,15 @@ def diff_date(date, limen=2):
def media(url):
url = skins.find_media_source(url)
if url:
- url = '///' + settings.FORUM_SCRIPT_ALIAS + '/m/' + url
- return posixpath.normpath(url)
+ # Create the URL prefix.
+ url_prefix = settings.FORCE_SCRIPT_NAME + '/m/'
+
+ # Make sure any duplicate forward slashes are replaced with a single
+ # forward slash.
+ url_prefix = re.sub("/+", "/", url_prefix)
+
+ url = url_prefix + url
+ return url
class ItemSeparatorNode(template.Node):
def __init__(self, separator):
@@ -138,7 +145,7 @@ def __init__(self, nodelist):
self.items = nodelist
def render(self, context):
- prefix = '///' + settings.FORUM_SCRIPT_ALIAS + 'm/'
+ prefix = settings.APP_URL + 'm/'
url = ''
if self.items:
url += '/'
@@ -147,7 +154,7 @@ def render(self, context):
url = skins.find_media_source(url)
url = prefix + url
- out = posixpath.normpath(url)
+ out = url
return out.replace(' ', '')
@register.tag(name='blockmedia')
@@ -167,7 +174,7 @@ def blockmedia(parser, token):
@register.simple_tag
def fullmedia(url):
- domain = settings.APP_URL
+ domain = settings.APP_BASE_URL
#protocol = getattr(settings, "PROTOCOL", "http")
path = media(url)
return "%s%s" % (domain, path)
View
2 forum/utils/html.py
@@ -68,7 +68,7 @@ def hyperlink(url, title, **attrs):
return mark_safe('<a href="%s" %s>%s</a>' % (url, " ".join('%s="%s"' % i for i in attrs.items()), title))
def objlink(obj, **attrs):
- return hyperlink(settings.APP_URL + obj.get_absolute_url(), unicode(obj), **attrs)
+ return hyperlink(settings.APP_BASE_URL + obj.get_absolute_url(), unicode(obj), **attrs)
View
13 forum/views/auth.py
@@ -31,6 +31,9 @@
def signin_page(request):
request.session['on_signin_url'] = request.META.get('HTTP_REFERER', '/')
+
+ if reverse('auth_signin') == request.session['on_signin_url'].replace(settings.APP_URL, ''):
+ request.session['on_signin_url'] = reverse('index')
all_providers = [provider.context for provider in AUTH_PROVIDERS.values()]
@@ -258,6 +261,11 @@ def temp_signin(request, user, code):
user = get_object_or_404(User, id=user)
if (ValidationHash.objects.validate(code, user, 'templogin', [user.id])):
+
+ # If the user requests temp_signin he must have forgotten his password. So we mark it as unusable.
+ user.set_unusable_password()
+ user.save()
+
return login_and_forward(request, user, reverse('user_authsettings', kwargs={'id': user.id}),
_(
"You are logged in with a temporary access key, please take the time to fix your issue with authentication."
@@ -272,6 +280,11 @@ def send_validation_email(request):
try:
hash = ValidationHash.objects.get(user=request.user, type='email')
hash.delete()
+
+ # If we were able to get a previous validation hash we should raise an
+ # Exception immediately. Otherwise new validation hash will not be created
+ # and users will not receive the desired e-mail vaidation link.
+ raise Exception("Validation has already been sent")
except:
hash = ValidationHash.objects.create_new(request.user, 'email', [request.user.email])
View
4 forum/views/readers.py
@@ -314,9 +314,9 @@ def question(request, id, slug='', answer=None):
return HttpResponsePermanentRedirect(question.get_absolute_url())
if request.POST:
- answer_form = AnswerForm(question, request.POST)
+ answer_form = AnswerForm(request.POST, user=request.user)
else:
- answer_form = AnswerForm(question)
+ answer_form = AnswerForm(user=request.user)
answers = request.user.get_visible_answers(question)
View
2 forum/views/writers.py
@@ -218,7 +218,7 @@ def answer(request, id):
question = get_object_or_404(Question, id=id)
if request.POST:
- form = AnswerForm(question, request.POST)
+ form = AnswerForm(request.POST, request.user)
if request.session.pop('reviewing_pending_data', False) or not form.is_valid():
request.session['redirect_POST_data'] = request.POST
View
7 forum_modules/akismet/templates/foundspam.html
@@ -19,7 +19,10 @@
{% for post_item in post_data.items %}
<input type="hidden" name="{{ post_item.0 }}" value="{{ post_item.1 }}" />
{% endfor %}
- {{ captcha_form.captcha }}</td>
+
+ {{ captcha_form.recaptcha }}
+
+ </td>
</tr>
<tr>
<td><input type="submit" value"{% trans "Submit" %} /></td>
@@ -28,4 +31,4 @@
</form>
</div>
-{% endblock %}
+{% endblock %}
View
3 forum_modules/localauth/authentication.py
@@ -15,4 +15,5 @@ class LocalAuthContext(ConsumerTemplateContext):
weight = 1000
human_name = 'Local authentication'
stack_item_template = 'modules/localauth/loginform.html'
- show_to_logged_in_user = False
+ show_to_logged_in_user = False
+
View
BIN locale/bg/LC_MESSAGES/django.mo
Binary file not shown.
View
9,070 locale/bg/LC_MESSAGES/django.po
9,070 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
20 settings.py
@@ -59,6 +59,26 @@
# User settings
from settings_local import *
+try:
+ if len(FORUM_SCRIPT_ALIAS) > 0:
+ APP_URL = '%s/%s' % (APP_URL, FORUM_SCRIPT_ALIAS[:-1])
+except NameError:
+ pass
+
+app_url_split = APP_URL.split("://")
+
+APP_PROTOCOL = app_url_split[0]
+APP_DOMAIN = app_url_split[1].split('/')[0]
+APP_BASE_URL = '%s://%s' % (APP_PROTOCOL, APP_DOMAIN)
+
+FORCE_SCRIPT_NAME = ''
+
+for path in app_url_split[1].split('/')[1:]:
+ FORCE_SCRIPT_NAME = FORCE_SCRIPT_NAME + '/' + path
+
+if FORCE_SCRIPT_NAME.endswith('/'):
+ FORCE_SCRIPT_NAME = FORCE_SCRIPT_NAME[:-1]
+
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.contenttypes',
View
14 settings_local.py.dist
@@ -35,20 +35,14 @@ CACHE_BACKEND = 'file://%s' % os.path.join(os.path.dirname(__file__),'cache').re
#CACHE_BACKEND = 'dummy://'
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
-APP_URL = 'http://' #used by email notif system and RSS
+# This should be equal to your domain name, plus the web application context.
+# This shouldn't be followed by a trailing slash.
+# I.e., http://www.yoursite.com or http://www.hostedsite.com/yourhostapp
+APP_URL = 'http://'
#LOCALIZATIONS
TIME_ZONE = 'America/New_York'
-###########################
-#
-# this will allow running your forum with url like http://site.com/forum
-#
-# FORUM_SCRIPT_ALIAS = 'forum/'
-#
-FORUM_SCRIPT_ALIAS = '' #no leading slash, default = '' empty string
-
-
#OTHER SETTINGS
USE_I18N = True
View
2 urls.py
@@ -3,7 +3,7 @@
from django.conf import settings
urlpatterns = patterns('',
- (r'^%s' % settings.FORUM_SCRIPT_ALIAS, include('forum.urls')),
+ (r'', include('forum.urls')),
)
if 'rosetta' in settings.INSTALLED_APPS:

0 comments on commit 2444d6f

Please sign in to comment.