From: Attila-Mihaly Balazs
Date: Tue, 3 Dec 2013 13:53:08 +0000 (+0200)
Subject: Migrate to Django 1.6
X-Git-Tag: live~28^2~6
X-Git-Url: https://git.openstreetmap.org./osqa.git/commitdiff_plain/dcacc3b4c2ba2f550806a2d22b183f6fac4f63ff?ds=sidebyside
Migrate to Django 1.6
---
diff --git a/forum/actions/node.py b/forum/actions/node.py
index 5ba6e2b..f9f2206 100644
--- a/forum/actions/node.py
+++ b/forum/actions/node.py
@@ -4,6 +4,8 @@ from forum.models.action import ActionProxy
from forum.models import Comment, Question, Answer, NodeRevision
import logging
+from django.contrib import messages
+
class NodeEditAction(ActionProxy):
def create_revision_data(self, initial=False, **data):
revision_data = dict(summary=data.get('summary', (initial and _('Initial revision') or '')), body=data['text'])
@@ -28,7 +30,7 @@ class AskAction(NodeEditAction):
question.save()
self.node = question
- self.user.message_set.create(message=self.describe(self.user))
+ messages.info(request, self.describe(self.user))
def describe(self, viewer=None):
return _("%(user)s asked %(question)s") % {
@@ -47,7 +49,7 @@ class AnswerAction(NodeEditAction):
def process_action(self):
self.node.question.reset_answer_count_cache()
- self.user.message_set.create(message=self.describe(self.user))
+ messages.info(request, self.describe(self.user))
def describe(self, viewer=None):
diff --git a/forum/actions/user.py b/forum/actions/user.py
index 7d636be..3e1721b 100644
--- a/forum/actions/user.py
+++ b/forum/actions/user.py
@@ -7,6 +7,8 @@ from forum import settings
from forum.settings import APP_SHORT_NAME
from forum.utils.mail import send_template_email
+from django.contrib import messages
+
class UserJoinsAction(ActionProxy):
verb = _("joined")
@@ -76,8 +78,7 @@ class BonusRepAction(ActionProxy):
message=_("Congratulations, you have been awarded an extra %s reputation points.") % self._value +
' %s' % self.extra.get('message', _('Thank you')))
else:
- self._affected.message_set.create(
- message=_("You have been penalized in %s reputation points.") % self._value +
+ messages.info(request, _("You have penalized %s in %s reputation points.") % (self._affected, self._value) +
' %s' % self.extra.get('message', ''))
def describe(self, viewer=None):
@@ -110,7 +111,6 @@ class AwardPointsAction(ActionProxy):
self.repute(self._affected, self._value)
self.repute(self.user, -self._value)
-
self._affected.message_set.create(
message=_("Congratulations, you have been awarded an extra %(points)s reputation %(points_label)s on this answer.") % {
'points': self._value,
diff --git a/forum/context.py b/forum/context.py
index 641af38..957b5f9 100644
--- a/forum/context.py
+++ b/forum/context.py
@@ -6,18 +6,12 @@ def application_settings(context):
def auth_processor(request):
if hasattr(request, 'user'):
user = request.user
- if user.is_authenticated():
- messages = user.message_set.all()
- else:
- messages = None
else:
from django.contrib.auth.models import AnonymousUser
user = AnonymousUser()
- messages = None
from django.core.context_processors import PermWrapper
return {
'user': user,
- 'messages': messages,
'perms': PermWrapper(user),
}
diff --git a/forum/forms/general.py b/forum/forms/general.py
index 01c528b..06ee23c 100644
--- a/forum/forms/general.py
+++ b/forum/forms/general.py
@@ -3,7 +3,6 @@ import re
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
from forum import settings
-from django.http import str_to_unicode
from forum.models import User
from forum.modules import call_all_handlers
import urllib
@@ -13,7 +12,9 @@ DEFAULT_NEXT = getattr(settings, 'APP_BASE_URL')
def clean_next(next):
if next is None:
return DEFAULT_NEXT
- next = str_to_unicode(urllib.unquote(next), 'utf-8')
+ next = urllib.unquote(next)
+ if not isinstance(next, unicode):
+ next = unicode(next, 'utf-8')
next = next.strip()
if next.startswith('/'):
return next
diff --git a/forum/forms/qanda.py b/forum/forms/qanda.py
index d2cc837..ea75ddd 100644
--- a/forum/forms/qanda.py
+++ b/forum/forms/qanda.py
@@ -354,6 +354,7 @@ class SubscriptionSettingsForm(forms.ModelForm):
class Meta:
model = SubscriptionSettings
+ fields = ['enable_notifications', 'member_joins', 'new_question', 'new_question_watched_tags', 'subscribed_questions']
class UserPreferencesForm(forms.Form):
sticky_sorts = forms.BooleanField(required=False, initial=False)
diff --git a/forum/middleware/admin_messages.py b/forum/middleware/admin_messages.py
index 2d391de..71af55f 100644
--- a/forum/middleware/admin_messages.py
+++ b/forum/middleware/admin_messages.py
@@ -1,7 +1,7 @@
-from forum.user_messages import create_message
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
from django.core.exceptions import ObjectDoesNotExist
+from django.contrib import messages
from forum.settings import EMAIL_HOST, EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, \
APP_URL
@@ -29,14 +29,8 @@ class AdminMessagesMiddleware(object):
# We do not want to repeat ourselves. If the message already exists in the message list, we're not going to
# add it. That's why first of all we're going the check if it is there.
- try:
- # If the message doesn't exist in the RelatedManager ObjectsDoesNotExist is going to be raised.
- request.user.message_set.all().get(message=msg)
- except ObjectDoesNotExist:
- # Let's create the message.
- request.user.message_set.create(message=msg)
- except:
- pass
+ if msg not in [m.message for m in messages.api.get_messages(request)]:
+ messages.info(request, msg)
def check_app_url(self, request):
# We consider the APP_URL setting not configured if it contains only the protocol
@@ -50,11 +44,5 @@ class AdminMessagesMiddleware(object):
# We do not want to repeat ourselves. If the message already exists in the message list, we're not going to
# add it. That's why first of all we're going the check if it is there.
- try:
- # If the message doesn't exist in the RelatedManager ObjectsDoesNotExist is going to be raised.
- request.user.message_set.all().get(message=msg)
- except ObjectDoesNotExist:
- # Let's create the message.
- request.user.message_set.create(message=msg)
- except:
- pass
+ if msg not in [m.message for m in messages.api.get_messages(request)]:
+ messages.info(request, msg)
diff --git a/forum/middleware/anon_user.py b/forum/middleware/anon_user.py
index 25f192a..dafca3e 100644
--- a/forum/middleware/anon_user.py
+++ b/forum/middleware/anon_user.py
@@ -1,11 +1,12 @@
from django.http import HttpResponseRedirect, HttpResponse
from forum.forms import get_next_url
from django.utils.translation import ugettext as _
-from forum.user_messages import create_message, get_and_delete_messages
from forum import settings
from django.core.urlresolvers import reverse
import logging
+from django.contrib import messages
+
class AnonymousMessageManager(object):
def __init__(self,request):
self.request = request
@@ -25,8 +26,6 @@ class ConnectToSessionMessagesMiddleware(object):
def process_request(self, request):
if not request.user.is_authenticated():
request.user.__deepcopy__ = dummy_deepcopy #plug on deepcopy which may be called by django db "driver"
- request.user.message_set = AnonymousMessageManager(request) #here request is linked to anon user
- request.user.get_and_delete_messages = request.user.message_set.get_and_delete
#also set the first greeting one time per session only
if 'greeting_set' not in request.session:
@@ -37,7 +36,7 @@ class ConnectToSessionMessagesMiddleware(object):
# If the store greeting in cookie setting is activated make sure that the greeting_set cookies isn't set
if (settings.STORE_GREETING_IN_COOKIE and not request.COOKIES.has_key('greeting_set')) or \
not settings.STORE_GREETING_IN_COOKIE:
- request.user.message_set.create(message=msg)
+ messages.info(request, msg)
if settings.STORE_GREETING_IN_COOKIE:
request.COOKIES.set(key='greeting_set', value=True)
diff --git a/forum/middleware/cancel.py b/forum/middleware/cancel.py
index 2d78a17..9d8f870 100644
--- a/forum/middleware/cancel.py
+++ b/forum/middleware/cancel.py
@@ -1,6 +1,8 @@
from django.http import HttpResponseRedirect
from forum.forms import get_next_url
import logging
+from django.contrib import messages
+
class CancelActionMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
if 'cancel' in request.REQUEST:
@@ -9,7 +11,7 @@ class CancelActionMiddleware(object):
msg = getattr(view_func,'CANCEL_MESSAGE')
except AttributeError:
msg = 'action canceled'
- request.user.message_set.create(message=msg)
+ messages.info(request, msg)
return HttpResponseRedirect(get_next_url(request))
else:
return None
diff --git a/forum/models/action.py b/forum/models/action.py
index 7e88745..b3cfd26 100644
--- a/forum/models/action.py
+++ b/forum/models/action.py
@@ -28,7 +28,7 @@ class ActionQuerySet(CachedQuerySet):
class ActionManager(CachedManager):
use_for_related_fields = True
- def get_query_set(self):
+ def get_queryset(self):
qs = ActionQuerySet(self.model)
if self.model is not Action:
diff --git a/forum/models/base.py b/forum/models/base.py
index 912c21a..9c328c5 100644
--- a/forum/models/base.py
+++ b/forum/models/base.py
@@ -190,7 +190,7 @@ class CachedQuerySet(models.query.QuerySet):
class CachedManager(models.Manager):
use_for_related_fields = True
- def get_query_set(self):
+ def get_queryset(self):
return CachedQuerySet(self.model)
def get_or_create(self, *args, **kwargs):
@@ -226,7 +226,7 @@ class DenormalizedField(object):
cls.add_to_class("reset_%s_cache" % name, reset_cache)
-class BaseMetaClass(models.Model.__metaclass__):
+class BaseMetaClass(type(models.Model)):
to_denormalize = []
def __new__(cls, *args, **kwargs):
diff --git a/forum/models/node.py b/forum/models/node.py
index 5b6cdb5..20ede47 100644
--- a/forum/models/node.py
+++ b/forum/models/node.py
@@ -152,7 +152,7 @@ class NodeQuerySet(CachedQuerySet):
class NodeManager(CachedManager):
use_for_related_fields = True
- def get_query_set(self):
+ def get_queryset(self):
qs = NodeQuerySet(self.model)
# If the node is an answer, question or comment we filter the Node model by type
diff --git a/forum/models/tag.py b/forum/models/tag.py
index 73b1e30..eca23e4 100644
--- a/forum/models/tag.py
+++ b/forum/models/tag.py
@@ -11,8 +11,8 @@ from forum import modules
class ActiveTagManager(CachedManager):
use_for_related_fields = True
- def get_query_set(self):
- return super(ActiveTagManager, self).get_query_set().exclude(used_count__lt=1)
+ def get_queryset(self):
+ return super(ActiveTagManager, self).get_queryset().exclude(used_count__lt=1)
class Tag(BaseModel):
name = models.CharField(max_length=255, unique=True)
diff --git a/forum/models/user.py b/forum/models/user.py
index cf47c66..0437614 100644
--- a/forum/models/user.py
+++ b/forum/models/user.py
@@ -209,15 +209,6 @@ class User(BaseModel, DjangoUser):
sub_settings = SubscriptionSettings(user=self)
sub_settings.save()
- def get_messages(self):
- messages = []
- for m in self.message_set.all():
- messages.append(m.message)
- return messages
-
- def delete_messages(self):
- self.message_set.all().delete()
-
@models.permalink
def get_profile_url(self):
keyword_arguments = {
diff --git a/forum/models/utils.py b/forum/models/utils.py
index 1fbda58..5a1912c 100644
--- a/forum/models/utils.py
+++ b/forum/models/utils.py
@@ -81,7 +81,7 @@ class PickledObjectField(models.Field):
raise
return value
- def get_db_prep_value(self, value):
+ def get_db_prep_value(self, value, connection, prepared=False):
if value is not None and not isinstance(value, PickledObject):
if type(value).__name__ in self.markable_types and not (isinstance(value, basestring) and len(value
) > MAX_MARKABLE_STRING_LENGTH):
diff --git a/forum/modules/__init__.py b/forum/modules/__init__.py
index f1ad7d9..6942c91 100644
--- a/forum/modules/__init__.py
+++ b/forum/modules/__init__.py
@@ -16,15 +16,10 @@ def get_modules_script(script_name):
try:
all.append(__import__('%s.%s' % (m.__name__, script_name), globals(), locals(), [m.__name__]))
- except ImportError, e:
- #print repr(type(e)) + m.__name__ + ":" + str(e)
- pass
- except:
- import traceback
- msg = "Error importing %s from module %s: \n %s" % (
- script_name, m, traceback.format_exc()
- )
- logging.error(msg)
+ except Exception, e:
+ if isinstance(e, ImportError) and str(e).endswith(script_name):
+ continue
+ logging.exception("Error importing %s from module %s", script_name, m)
return all
diff --git a/forum/settings/__init__.py b/forum/settings/__init__.py
index 218f114..1458599 100644
--- a/forum/settings/__init__.py
+++ b/forum/settings/__init__.py
@@ -4,17 +4,17 @@ from base import Setting, SettingSet, BaseSetting
from django.forms.widgets import Textarea
from django.utils.translation import ugettext_lazy as _
from django.conf import settings as djsettings
-from django.utils.version import get_svn_revision
+from django.utils.version import get_git_changeset
from forum.modules import get_modules_script_implementations
OSQA_VERSION = "Development Build"
-SVN_REVISION = get_svn_revision(djsettings.SITE_SRC_ROOT)
+VCS_REVISION = get_git_changeset()
# We'll have to keep in mind this variable on every release.
-if SVN_REVISION == u'SVN-unknown':
- SVN_REVISION = u'SVN-1000'
+if VCS_REVISION == u'SVN-unknown':
+ VCS_REVISION = u'SVN-1000'
MAINTAINANCE_MODE = Setting('MAINTAINANCE_MODE', None)
diff --git a/forum/settings/basic.py b/forum/settings/basic.py
index a4efd6f..1f9ddc9 100644
--- a/forum/settings/basic.py
+++ b/forum/settings/basic.py
@@ -1,52 +1,52 @@
-import os.path
-
-from base import Setting, SettingSet
-from forms import ImageFormWidget
-
-from django.utils.translation import ugettext_lazy as _
-from django.forms.widgets import Textarea
-
-BASIC_SET = SettingSet('basic', _('Basic settings'), _("The basic settings for your application"), 1)
-
-APP_LOGO = Setting('APP_LOGO', '/upfiles/logo.png', BASIC_SET, dict(
-label = _("Application logo"),
-help_text = _("Your site main logo."),
-widget=ImageFormWidget))
-
-APP_FAVICON = Setting('APP_FAVICON', '/m/default/media/images/favicon.ico', BASIC_SET, dict(
-label = _("Favicon"),
-help_text = _("Your site favicon."),
-widget=ImageFormWidget))
-
-APP_TITLE = Setting('APP_TITLE', u'OSQA: Open Source Q&A Forum', BASIC_SET, dict(
-label = _("Application title"),
-help_text = _("The title of your application that will show in the browsers title bar")))
-
-APP_SHORT_NAME = Setting(u'APP_SHORT_NAME', 'OSQA', BASIC_SET, dict(
-label = _("Application short name"),
-help_text = "The short name for your application that will show up in many places."))
-
-APP_KEYWORDS = Setting('APP_KEYWORDS', u'OSQA,CNPROG,forum,community', BASIC_SET, dict(
-label = _("Application keywords"),
-help_text = _("The meta keywords that will be available through the HTML meta tags.")))
-
-APP_DESCRIPTION = Setting('APP_DESCRIPTION', u'Ask and answer questions.', BASIC_SET, dict(
-label = _("Application description"),
-help_text = _("The description of your application"),
-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.")))
-
-SUPPORT_URL = Setting('SUPPORT_URL', '', BASIC_SET, dict(
-label = _("Support URL"),
-help_text = _("The URL provided for users to get support. It can be http: or mailto: or whatever your preferred support scheme is."),
-required=False))
-
-CONTACT_URL = Setting('CONTACT_URL', '', BASIC_SET, dict(
-label = _("Contact URL"),
-help_text = _("The URL provided for users to contact you. It can be http: or mailto: or whatever your preferred contact scheme is."),
-required=False))
-
-
+import os.path
+
+from base import Setting, SettingSet
+from forms import ImageFormWidget
+
+from django.utils.translation import ugettext_lazy as _
+from django.forms.widgets import Textarea
+
+BASIC_SET = SettingSet('basic', _('Basic settings'), _("The basic settings for your application"), 1)
+
+APP_LOGO = Setting('APP_LOGO', '/upfiles/logo.png', BASIC_SET, dict(
+label = _("Application logo"),
+help_text = _("Your site main logo."),
+widget=ImageFormWidget))
+
+APP_FAVICON = Setting('APP_FAVICON', '/m/default/media/images/favicon.ico', BASIC_SET, dict(
+label = _("Favicon"),
+help_text = _("Your site favicon."),
+widget=ImageFormWidget))
+
+APP_TITLE = Setting('APP_TITLE', u'OSQA: Open Source Q&A Forum', BASIC_SET, dict(
+label = _("Application title"),
+help_text = _("The title of your application that will show in the browsers title bar")))
+
+APP_SHORT_NAME = Setting(u'APP_SHORT_NAME', 'OSQA', BASIC_SET, dict(
+label = _("Application short name"),
+help_text = "The short name for your application that will show up in many places."))
+
+APP_KEYWORDS = Setting('APP_KEYWORDS', u'OSQA,CNPROG,forum,community', BASIC_SET, dict(
+label = _("Application keywords"),
+help_text = _("The meta keywords that will be available through the HTML meta tags.")))
+
+APP_DESCRIPTION = Setting('APP_DESCRIPTION', u'Ask and answer questions.', BASIC_SET, dict(
+label = _("Application description"),
+help_text = _("The description of your application"),
+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.")))
+
+SUPPORT_URL = Setting('SUPPORT_URL', '', BASIC_SET, dict(
+label = _("Support URL"),
+help_text = _("The URL provided for users to get support. It can be http: or mailto: or whatever your preferred support scheme is."),
+required=False))
+
+CONTACT_URL = Setting('CONTACT_URL', '', BASIC_SET, dict(
+label = _("Contact URL"),
+help_text = _("The URL provided for users to contact you. It can be http: or mailto: or whatever your preferred contact scheme is."),
+required=False))
+
+
diff --git a/forum/settings/email.py b/forum/settings/email.py
index 71a7136..896efbd 100644
--- a/forum/settings/email.py
+++ b/forum/settings/email.py
@@ -1,86 +1,86 @@
-from base import Setting, SettingSet
-from django.utils.translation import ugettext_lazy as _
-from django.forms.widgets import PasswordInput
-from django.forms.widgets import RadioSelect
-from forms import TestEmailSettingsWidget
-
-EMAIL_SET = SettingSet('email', _('Email settings'), _("Email server and other email related settings."), 50)
-
-TEST_EMAIL_SETTINGS = Setting('TEST_EMAIL_SETTINGS', '', EMAIL_SET, dict(
-label = _("E-Mail settings test"),
-help_text = _("Test the current E-Mail configuration."),
-required=False,
-widget=TestEmailSettingsWidget))
-
-EMAIL_HOST = Setting('EMAIL_HOST', '', EMAIL_SET, dict(
-label = _("Email Server"),
-help_text = _("The SMTP server through which your application will be sending emails."),
-required=False))
-
-EMAIL_PORT = Setting('EMAIL_PORT', 25, EMAIL_SET, dict(
-label = _("Email Port"),
-help_text = _("The port on which your SMTP server is listening to. Usually this is 25, but can be something else."),
-required=False))
-
-EMAIL_HOST_USER = Setting('EMAIL_HOST_USER', '', EMAIL_SET, dict(
-label = _("Email User"),
-help_text = _("The username for your SMTP connection."),
-required=False))
-
-EMAIL_HOST_PASSWORD = Setting('EMAIL_HOST_PASSWORD', '', EMAIL_SET, dict(
-label = _("Email Password"),
-help_text = _("The password for your SMTP connection."),
-required=False,
-widget=PasswordInput(render_value=True)))
-
-EMAIL_USE_TLS = Setting('EMAIL_USE_TLS', False, EMAIL_SET, dict(
-label = _("Use TLS"),
-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"),
-help_text = _("The address that will show up on the 'from' field on emails sent by your website."),
-required=False))
-
-DEFAULT_REPLY_TO_EMAIL = Setting('DEFAULT_REPLY_TO_EMAIL', '', EMAIL_SET, dict(
-label = _("Site 'reply-to' Email Address"),
-help_text = _("The address that will show up on the 'reply-to' field on emails sent by your website."),
-required=False))
-
-EMAIL_SUBJECT_PREFIX = Setting('EMAIL_SUBJECT_PREFIX', '', EMAIL_SET, dict(
-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 their email clients."),
-required=False))
-
-EMAIL_FOOTER_TEXT = Setting(u'EMAIL_FOOTER_TEXT', '', EMAIL_SET, dict(
-label = _("Email Footer Text"),
-help_text = _("Email footer text, usually \"CAN SPAM\" compliance, or the physical address of the organization running the website. See this Wikipedia article for more info."),
-required=False))
-
-EMAIL_BORDER_COLOR = Setting('EMAIL_BORDER_COLOR', '#e5ebf8', EMAIL_SET, dict(
-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"),
-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"),
-help_text = _("A valid css string to be used to style email links (the A tag)."),
-required=False))
-
-SEND_DIGEST_ONLY_TO_ACTIVE_USERS = Setting('SEND_DIGEST_ONLY_TO_ACTIVE_USERS', True, EMAIL_SET, dict(
-label = _("Send digest only to active users"),
-help_text = _("If checked the daily digest won't be sent to users that have been suspended."),
-required=False))
-
-SEND_DIGEST_ONLY_TO_VALIDATED_USERS = Setting('SEND_DIGEST_ONLY_TO_VALIDATED_USERS', True, EMAIL_SET, dict(
-label = _("Send digest only to validated users"),
-help_text = _("If checked the daily digest won't be sent to users that haven't validated their emails."),
-required=False))
-
-EMAIL_DIGEST_FLAG = Setting('EMAIL_DIGEST_FLAG', None)
+from base import Setting, SettingSet
+from django.utils.translation import ugettext_lazy as _
+from django.forms.widgets import PasswordInput
+from django.forms.widgets import RadioSelect
+from forms import TestEmailSettingsWidget
+
+EMAIL_SET = SettingSet('email', _('Email settings'), _("Email server and other email related settings."), 50)
+
+TEST_EMAIL_SETTINGS = Setting('TEST_EMAIL_SETTINGS', '', EMAIL_SET, dict(
+label = _("E-Mail settings test"),
+help_text = _("Test the current E-Mail configuration."),
+required=False,
+widget=TestEmailSettingsWidget))
+
+EMAIL_HOST = Setting('EMAIL_HOST', '', EMAIL_SET, dict(
+label = _("Email Server"),
+help_text = _("The SMTP server through which your application will be sending emails."),
+required=False))
+
+EMAIL_PORT = Setting('EMAIL_PORT', 25, EMAIL_SET, dict(
+label = _("Email Port"),
+help_text = _("The port on which your SMTP server is listening to. Usually this is 25, but can be something else."),
+required=False))
+
+EMAIL_HOST_USER = Setting('EMAIL_HOST_USER', '', EMAIL_SET, dict(
+label = _("Email User"),
+help_text = _("The username for your SMTP connection."),
+required=False))
+
+EMAIL_HOST_PASSWORD = Setting('EMAIL_HOST_PASSWORD', '', EMAIL_SET, dict(
+label = _("Email Password"),
+help_text = _("The password for your SMTP connection."),
+required=False,
+widget=PasswordInput(render_value=True)))
+
+EMAIL_USE_TLS = Setting('EMAIL_USE_TLS', False, EMAIL_SET, dict(
+label = _("Use TLS"),
+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"),
+help_text = _("The address that will show up on the 'from' field on emails sent by your website."),
+required=False))
+
+DEFAULT_REPLY_TO_EMAIL = Setting('DEFAULT_REPLY_TO_EMAIL', '', EMAIL_SET, dict(
+label = _("Site 'reply-to' Email Address"),
+help_text = _("The address that will show up on the 'reply-to' field on emails sent by your website."),
+required=False))
+
+EMAIL_SUBJECT_PREFIX = Setting('EMAIL_SUBJECT_PREFIX', '', EMAIL_SET, dict(
+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 their email clients."),
+required=False))
+
+EMAIL_FOOTER_TEXT = Setting(u'EMAIL_FOOTER_TEXT', '', EMAIL_SET, dict(
+label = _("Email Footer Text"),
+help_text = _("Email footer text, usually \"CAN SPAM\" compliance, or the physical address of the organization running the website. See this Wikipedia article for more info."),
+required=False))
+
+EMAIL_BORDER_COLOR = Setting('EMAIL_BORDER_COLOR', '#e5ebf8', EMAIL_SET, dict(
+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"),
+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"),
+help_text = _("A valid css string to be used to style email links (the A tag)."),
+required=False))
+
+SEND_DIGEST_ONLY_TO_ACTIVE_USERS = Setting('SEND_DIGEST_ONLY_TO_ACTIVE_USERS', True, EMAIL_SET, dict(
+label = _("Send digest only to active users"),
+help_text = _("If checked the daily digest won't be sent to users that have been suspended."),
+required=False))
+
+SEND_DIGEST_ONLY_TO_VALIDATED_USERS = Setting('SEND_DIGEST_ONLY_TO_VALIDATED_USERS', True, EMAIL_SET, dict(
+label = _("Send digest only to validated users"),
+help_text = _("If checked the daily digest won't be sent to users that haven't validated their emails."),
+required=False))
+
+EMAIL_DIGEST_FLAG = Setting('EMAIL_DIGEST_FLAG', None)
diff --git a/forum/settings/extkeys.py b/forum/settings/extkeys.py
index 9d439df..11b43e3 100644
--- a/forum/settings/extkeys.py
+++ b/forum/settings/extkeys.py
@@ -1,15 +1,15 @@
-from base import Setting, SettingSet
-from django.utils.translation import ugettext_lazy as _
-
-EXT_KEYS_SET = SettingSet('extkeys', _('External Keys'), _("Keys for various external providers that your application may optionally use."), 100)
-
-GOOGLE_SITEMAP_CODE = Setting('GOOGLE_SITEMAP_CODE', '', EXT_KEYS_SET, dict(
-label = _("Google sitemap code"),
-help_text = _("This is the code you get when you register your site at Google webmaster central."),
-required=False))
-
-GOOGLE_ANALYTICS_KEY = Setting('GOOGLE_ANALYTICS_KEY', '', EXT_KEYS_SET, dict(
-label = _("Google analytics key"),
-help_text = _("Your Google analytics key. You can get one at the Google analytics official website"),
-required=False))
-
+from base import Setting, SettingSet
+from django.utils.translation import ugettext_lazy as _
+
+EXT_KEYS_SET = SettingSet('extkeys', _('External Keys'), _("Keys for various external providers that your application may optionally use."), 100)
+
+GOOGLE_SITEMAP_CODE = Setting('GOOGLE_SITEMAP_CODE', '', EXT_KEYS_SET, dict(
+label = _("Google sitemap code"),
+help_text = _("This is the code you get when you register your site at Google webmaster central."),
+required=False))
+
+GOOGLE_ANALYTICS_KEY = Setting('GOOGLE_ANALYTICS_KEY', '', EXT_KEYS_SET, dict(
+label = _("Google analytics key"),
+help_text = _("Your Google analytics key. You can get one at the Google analytics official website"),
+required=False))
+
diff --git a/forum/settings/minrep.py b/forum/settings/minrep.py
index 1c9e17d..a8dac0d 100644
--- a/forum/settings/minrep.py
+++ b/forum/settings/minrep.py
@@ -1,95 +1,95 @@
-from base import Setting, SettingSet
-from django.utils.translation import ugettext_lazy as _
-
-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.")))
-
-REP_TO_VOTE_DOWN = Setting('REP_TO_VOTE_DOWN', 100, MIN_REP_SET, dict(
-label = _("Minimum reputation to vote down"),
-help_text = _("The minimum reputation an user must have to be allowed to vote down.")))
-
-REP_TO_FLAG = Setting('REP_TO_FLAG', 15, MIN_REP_SET, dict(
-label = _("Minimum reputation to flag a post"),
-help_text = _("The minimum reputation an user must have to be allowed to flag a post.")))
-
-REP_TO_COMMENT = Setting('REP_TO_COMMENT', 50, MIN_REP_SET, dict(
-label = _("Minimum reputation to comment"),
-help_text = _("The minimum reputation an user must have to be allowed to comment a post.")))
-
-REP_TO_LIKE_COMMENT = Setting('REP_TO_LIKE_COMMENT', 15, MIN_REP_SET, dict(
-label = _("Minimum reputation to like a comment"),
-help_text = _("The minimum reputation an user must have to be allowed to \"like\" a comment.")))
-
-REP_TO_UPLOAD = Setting('REP_TO_UPLOAD', 60, MIN_REP_SET, dict(
-label = _("Minimum reputation to upload"),
-help_text = _("The minimum reputation an user must have to be allowed to upload a file.")))
-
-REP_TO_CREATE_TAGS = Setting('REP_TO_CREATE_TAGS', 250, MIN_REP_SET, dict(
-label = _("Minimum reputation to create tags"),
-help_text = _("The minimum reputation an user must have to be allowed to create new tags.")))
-
-REP_TO_CLOSE_OWN = Setting('REP_TO_CLOSE_OWN', 250, MIN_REP_SET, dict(
-label = _("Minimum reputation to close own question"),
-help_text = _("The minimum reputation an user must have to be allowed to close his own question.")))
-
-UNIFY_PERMISSIONS_TO_CLOSE_AND_REOPEN = Setting('UNIFY_PERMISSIONS_TO_CLOSE_AND_REOPEN', True, MIN_REP_SET, dict(
-label = _("Unify close and reopen permissions"),
-help_text = _("If checked the same permissions as the ones to close question will be required to reopen it."),
-required=False))
-
-REP_TO_REOPEN_OWN = Setting('REP_TO_REOPEN_OWN', 500, MIN_REP_SET, dict(
-label = _("Minimum reputation to reopen own question"),
-help_text = _("The minimum reputation an user must have to be allowed to reopen his own question.")))
-
-REP_TO_RETAG = Setting('REP_TO_RETAG', 500, MIN_REP_SET, dict(
-label = _("Minimum reputation to retag others questions"),
-help_text = _("The minimum reputation an user must have to be allowed to retag others questions.")))
-
-REP_TO_EDIT_WIKI = Setting('REP_TO_EDIT_WIKI', 750, MIN_REP_SET, dict(
-label = _("Minimum reputation to edit wiki posts"),
-help_text = _("The minimum reputation an user must have to be allowed to edit community wiki posts.")))
-
-REP_TO_WIKIFY = Setting('REP_TO_WIKIFY', 2000, MIN_REP_SET, dict(
-label = _("Minimum reputation to mark post as community wiki"),
-help_text = _("The minimum reputation an user must have to be allowed to mark a post as community wiki.")))
-
-REP_TO_EDIT_OTHERS = Setting('REP_TO_EDIT_OTHERS', 2000, MIN_REP_SET, dict(
-label = _("Minimum reputation to edit others posts"),
-help_text = _("The minimum reputation an user must have to be allowed to edit others posts.")))
-
-REP_TO_CLOSE_OTHERS = Setting('REP_TO_CLOSE_OTHERS', 3000, MIN_REP_SET, dict(
-label = _("Minimum reputation to close others posts"),
-help_text = _("The minimum reputation an user must have to be allowed to close others posts.")))
-
-REP_TO_DELETE_COMMENTS = Setting('REP_TO_DELETE_COMMENTS', 2000, MIN_REP_SET, dict(
-label = _("Minimum reputation to delete comments"),
-help_text = _("The minimum reputation an user must have to be allowed to delete comments.")))
-
-REP_TO_CONVERT_TO_COMMENT = Setting('REP_TO_CONVERT_TO_COMMENT', 2000, MIN_REP_SET, dict(
-label = _("Minimum reputation to convert answers to comment"),
-help_text = _("The minimum reputation an user must have to be allowed to convert an answer into a comment.")))
-
-REP_TO_CONVERT_COMMENTS_TO_ANSWERS = Setting('REP_TO_CONVERT_COMMENTS_TO_ANSWERS', 2000, MIN_REP_SET, dict(
-label = _("Minimum reputation to convert comments to answers"),
-help_text = _("The minimum reputation an user must have to be allowed to convert comments into an answer.")))
-
-REP_TO_CONVERT_TO_QUESTION = Setting('REP_TO_CONVERT_TO_QUESTION', 2000, MIN_REP_SET, dict(
-label = _("Minimum reputation to convert answers to questions"),
-help_text = _("The minimum reputation an user must have to be allowed to convert an answer into a question.")))
-
-REP_TO_VIEW_FLAGS = Setting('REP_TO_VIEW_FLAGS', 2000, MIN_REP_SET, dict(
-label = _("Minimum reputation to view offensive flags"),
-help_text = _("The minimum reputation an user must have to view offensive flags.")))
-
-#REP_TO_DISABLE_NOFOLLOW = Setting('REP_TO_DISABLE_NOFOLLOW', 2000, MIN_REP_SET, dict(
-#label = _("Minimum reputation to disable nofollow"),
-#help_text = _("""
-#The minimum reputation an user must have to be allowed to disable the nofollow attribute of a post link.
-#""")))
+from base import Setting, SettingSet
+from django.utils.translation import ugettext_lazy as _
+
+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.")))
+
+REP_TO_VOTE_DOWN = Setting('REP_TO_VOTE_DOWN', 100, MIN_REP_SET, dict(
+label = _("Minimum reputation to vote down"),
+help_text = _("The minimum reputation an user must have to be allowed to vote down.")))
+
+REP_TO_FLAG = Setting('REP_TO_FLAG', 15, MIN_REP_SET, dict(
+label = _("Minimum reputation to flag a post"),
+help_text = _("The minimum reputation an user must have to be allowed to flag a post.")))
+
+REP_TO_COMMENT = Setting('REP_TO_COMMENT', 50, MIN_REP_SET, dict(
+label = _("Minimum reputation to comment"),
+help_text = _("The minimum reputation an user must have to be allowed to comment a post.")))
+
+REP_TO_LIKE_COMMENT = Setting('REP_TO_LIKE_COMMENT', 15, MIN_REP_SET, dict(
+label = _("Minimum reputation to like a comment"),
+help_text = _("The minimum reputation an user must have to be allowed to \"like\" a comment.")))
+
+REP_TO_UPLOAD = Setting('REP_TO_UPLOAD', 60, MIN_REP_SET, dict(
+label = _("Minimum reputation to upload"),
+help_text = _("The minimum reputation an user must have to be allowed to upload a file.")))
+
+REP_TO_CREATE_TAGS = Setting('REP_TO_CREATE_TAGS', 250, MIN_REP_SET, dict(
+label = _("Minimum reputation to create tags"),
+help_text = _("The minimum reputation an user must have to be allowed to create new tags.")))
+
+REP_TO_CLOSE_OWN = Setting('REP_TO_CLOSE_OWN', 250, MIN_REP_SET, dict(
+label = _("Minimum reputation to close own question"),
+help_text = _("The minimum reputation an user must have to be allowed to close his own question.")))
+
+UNIFY_PERMISSIONS_TO_CLOSE_AND_REOPEN = Setting('UNIFY_PERMISSIONS_TO_CLOSE_AND_REOPEN', True, MIN_REP_SET, dict(
+label = _("Unify close and reopen permissions"),
+help_text = _("If checked the same permissions as the ones to close question will be required to reopen it."),
+required=False))
+
+REP_TO_REOPEN_OWN = Setting('REP_TO_REOPEN_OWN', 500, MIN_REP_SET, dict(
+label = _("Minimum reputation to reopen own question"),
+help_text = _("The minimum reputation an user must have to be allowed to reopen his own question.")))
+
+REP_TO_RETAG = Setting('REP_TO_RETAG', 500, MIN_REP_SET, dict(
+label = _("Minimum reputation to retag others questions"),
+help_text = _("The minimum reputation an user must have to be allowed to retag others questions.")))
+
+REP_TO_EDIT_WIKI = Setting('REP_TO_EDIT_WIKI', 750, MIN_REP_SET, dict(
+label = _("Minimum reputation to edit wiki posts"),
+help_text = _("The minimum reputation an user must have to be allowed to edit community wiki posts.")))
+
+REP_TO_WIKIFY = Setting('REP_TO_WIKIFY', 2000, MIN_REP_SET, dict(
+label = _("Minimum reputation to mark post as community wiki"),
+help_text = _("The minimum reputation an user must have to be allowed to mark a post as community wiki.")))
+
+REP_TO_EDIT_OTHERS = Setting('REP_TO_EDIT_OTHERS', 2000, MIN_REP_SET, dict(
+label = _("Minimum reputation to edit others posts"),
+help_text = _("The minimum reputation an user must have to be allowed to edit others posts.")))
+
+REP_TO_CLOSE_OTHERS = Setting('REP_TO_CLOSE_OTHERS', 3000, MIN_REP_SET, dict(
+label = _("Minimum reputation to close others posts"),
+help_text = _("The minimum reputation an user must have to be allowed to close others posts.")))
+
+REP_TO_DELETE_COMMENTS = Setting('REP_TO_DELETE_COMMENTS', 2000, MIN_REP_SET, dict(
+label = _("Minimum reputation to delete comments"),
+help_text = _("The minimum reputation an user must have to be allowed to delete comments.")))
+
+REP_TO_CONVERT_TO_COMMENT = Setting('REP_TO_CONVERT_TO_COMMENT', 2000, MIN_REP_SET, dict(
+label = _("Minimum reputation to convert answers to comment"),
+help_text = _("The minimum reputation an user must have to be allowed to convert an answer into a comment.")))
+
+REP_TO_CONVERT_COMMENTS_TO_ANSWERS = Setting('REP_TO_CONVERT_COMMENTS_TO_ANSWERS', 2000, MIN_REP_SET, dict(
+label = _("Minimum reputation to convert comments to answers"),
+help_text = _("The minimum reputation an user must have to be allowed to convert comments into an answer.")))
+
+REP_TO_CONVERT_TO_QUESTION = Setting('REP_TO_CONVERT_TO_QUESTION', 2000, MIN_REP_SET, dict(
+label = _("Minimum reputation to convert answers to questions"),
+help_text = _("The minimum reputation an user must have to be allowed to convert an answer into a question.")))
+
+REP_TO_VIEW_FLAGS = Setting('REP_TO_VIEW_FLAGS', 2000, MIN_REP_SET, dict(
+label = _("Minimum reputation to view offensive flags"),
+help_text = _("The minimum reputation an user must have to view offensive flags.")))
+
+#REP_TO_DISABLE_NOFOLLOW = Setting('REP_TO_DISABLE_NOFOLLOW', 2000, MIN_REP_SET, dict(
+#label = _("Minimum reputation to disable nofollow"),
+#help_text = _("""
+#The minimum reputation an user must have to be allowed to disable the nofollow attribute of a post link.
+#""")))
diff --git a/forum/settings/repgain.py b/forum/settings/repgain.py
index 6b283ec..8326757 100644
--- a/forum/settings/repgain.py
+++ b/forum/settings/repgain.py
@@ -1,49 +1,49 @@
-from base import Setting, SettingSet
-from django.utils.translation import ugettext_lazy as _
-
-REP_GAIN_SET = SettingSet('repgain', _('Reputation gains and losses config'), _("Configure the reputation points a user may gain or lose upon certain actions."), 200)
-
-INITIAL_REP = Setting('INITIAL_REP', 1, REP_GAIN_SET, dict(
-label = _("Initial reputation"),
-help_text = _("The initial reputation an user gets when he first signs in.")))
-
-MAX_REP_BY_UPVOTE_DAY = Setting('MAX_REP_BY_UPVOTE_DAY', 200, REP_GAIN_SET, dict(
-label = "Max rep by up votes / day",
-help_text = _("Maximum reputation a user can gain in one day for being upvoted.")))
-
-REP_GAIN_BY_EMAIL_VALIDATION = Setting('REP_GAIN_BY_EMAIL_VALIDATION', 10, REP_GAIN_SET, dict(
-label = _("Rep gain by e-mail validation"),
-help_text = _("Reputation a user gains for validating his e-mail.")))
-
-REP_GAIN_BY_UPVOTED = Setting('REP_GAIN_BY_UPVOTED', 10, REP_GAIN_SET, dict(
-label = _("Rep gain by upvoted"),
-help_text = _("Reputation a user gains for having one of his posts up voted.")))
-
-REP_LOST_BY_DOWNVOTED = Setting('REP_LOST_BY_DOWNVOTED', 2, REP_GAIN_SET, dict(
-label = _("Rep lost by downvoted"),
-help_text = _("Reputation a user loses for having one of his posts down voted.")))
-
-REP_LOST_BY_DOWNVOTING = Setting('REP_LOST_BY_DOWNVOTING', 1, REP_GAIN_SET, dict(
-label = _("Rep lost by downvoting"),
-help_text = _("Reputation a user loses for down voting a post.")))
-
-
-REP_GAIN_BY_ACCEPTED = Setting('REP_GAIN_BY_ACCEPTED', 15, REP_GAIN_SET, dict(
-label = _("Rep gain by accepted answer"),
-help_text = _("Reputation a user gains for having one of his answers accepted.")))
-
-REP_GAIN_BY_ACCEPTING = Setting('REP_GAIN_BY_ACCEPTING', 2, REP_GAIN_SET, dict(
-label = _("Rep gain by accepting answer"),
-help_text = _("Reputation a user gains for accepting an answer to one of his questions.")))
-
-REP_LOST_BY_FLAGGED = Setting('REP_LOST_BY_FLAGGED', 2, REP_GAIN_SET, dict(
-label = _("Rep lost by post flagged"),
-help_text = _("Reputation a user loses by having one of his posts flagged.")))
-
-REP_LOST_BY_FLAGGED_3_TIMES = Setting('REP_LOST_BY_FLAGGED_3_TIMES', 30, REP_GAIN_SET, dict(
-label = _("Rep lost by post flagged and hidden"),
-help_text = _("Reputation a user loses by having the last revision of one of his posts flagged the enough number of times to hide the post.")))
-
-REP_LOST_BY_FLAGGED_5_TIMES = Setting('REP_LOST_BY_FLAGGED_5_TIMES', 100, REP_GAIN_SET, dict(
-label = _("Rep lost by post flagged and deleted"),
+from base import Setting, SettingSet
+from django.utils.translation import ugettext_lazy as _
+
+REP_GAIN_SET = SettingSet('repgain', _('Reputation gains and losses config'), _("Configure the reputation points a user may gain or lose upon certain actions."), 200)
+
+INITIAL_REP = Setting('INITIAL_REP', 1, REP_GAIN_SET, dict(
+label = _("Initial reputation"),
+help_text = _("The initial reputation an user gets when he first signs in.")))
+
+MAX_REP_BY_UPVOTE_DAY = Setting('MAX_REP_BY_UPVOTE_DAY', 200, REP_GAIN_SET, dict(
+label = "Max rep by up votes / day",
+help_text = _("Maximum reputation a user can gain in one day for being upvoted.")))
+
+REP_GAIN_BY_EMAIL_VALIDATION = Setting('REP_GAIN_BY_EMAIL_VALIDATION', 10, REP_GAIN_SET, dict(
+label = _("Rep gain by e-mail validation"),
+help_text = _("Reputation a user gains for validating his e-mail.")))
+
+REP_GAIN_BY_UPVOTED = Setting('REP_GAIN_BY_UPVOTED', 10, REP_GAIN_SET, dict(
+label = _("Rep gain by upvoted"),
+help_text = _("Reputation a user gains for having one of his posts up voted.")))
+
+REP_LOST_BY_DOWNVOTED = Setting('REP_LOST_BY_DOWNVOTED', 2, REP_GAIN_SET, dict(
+label = _("Rep lost by downvoted"),
+help_text = _("Reputation a user loses for having one of his posts down voted.")))
+
+REP_LOST_BY_DOWNVOTING = Setting('REP_LOST_BY_DOWNVOTING', 1, REP_GAIN_SET, dict(
+label = _("Rep lost by downvoting"),
+help_text = _("Reputation a user loses for down voting a post.")))
+
+
+REP_GAIN_BY_ACCEPTED = Setting('REP_GAIN_BY_ACCEPTED', 15, REP_GAIN_SET, dict(
+label = _("Rep gain by accepted answer"),
+help_text = _("Reputation a user gains for having one of his answers accepted.")))
+
+REP_GAIN_BY_ACCEPTING = Setting('REP_GAIN_BY_ACCEPTING', 2, REP_GAIN_SET, dict(
+label = _("Rep gain by accepting answer"),
+help_text = _("Reputation a user gains for accepting an answer to one of his questions.")))
+
+REP_LOST_BY_FLAGGED = Setting('REP_LOST_BY_FLAGGED', 2, REP_GAIN_SET, dict(
+label = _("Rep lost by post flagged"),
+help_text = _("Reputation a user loses by having one of his posts flagged.")))
+
+REP_LOST_BY_FLAGGED_3_TIMES = Setting('REP_LOST_BY_FLAGGED_3_TIMES', 30, REP_GAIN_SET, dict(
+label = _("Rep lost by post flagged and hidden"),
+help_text = _("Reputation a user loses by having the last revision of one of his posts flagged the enough number of times to hide the post.")))
+
+REP_LOST_BY_FLAGGED_5_TIMES = Setting('REP_LOST_BY_FLAGGED_5_TIMES', 100, REP_GAIN_SET, dict(
+label = _("Rep lost by post flagged and deleted"),
help_text = _("Reputation a user loses by having the last revision of one of his posts flagged the enough number of times to delete the post.")))
\ No newline at end of file
diff --git a/forum/settings/upload.py b/forum/settings/upload.py
index 6e66e00..3c1fd24 100644
--- a/forum/settings/upload.py
+++ b/forum/settings/upload.py
@@ -1,17 +1,17 @@
-import os.path
-from base import Setting, SettingSet
-from django.utils.translation import ugettext_lazy as _
-
-UPLOAD_SET = SettingSet('paths', _('File upload settings'), _("File uploads related settings."), 600)
-
-UPFILES_FOLDER = Setting('UPFILES_FOLDER', os.path.join(os.path.dirname(os.path.dirname(__file__)),'upfiles'), UPLOAD_SET, dict(
-label = _("Uploaded files folder"),
-help_text = _("The filesystem path where uploaded files will be stored. Please note that this folder must exist.")))
-
-UPFILES_ALIAS = Setting('UPFILES_ALIAS', '/upfiles/', UPLOAD_SET, dict(
-label = _("Uploaded files alias"),
-help_text = _("The url alias for uploaded files. Notice that if you change this setting, you'll need to restart your site.")))
-
-ALLOW_MAX_FILE_SIZE = Setting('ALLOW_MAX_FILE_SIZE', 2.5, UPLOAD_SET, dict(
-label = _("Max file size"),
+import os.path
+from base import Setting, SettingSet
+from django.utils.translation import ugettext_lazy as _
+
+UPLOAD_SET = SettingSet('paths', _('File upload settings'), _("File uploads related settings."), 600)
+
+UPFILES_FOLDER = Setting('UPFILES_FOLDER', os.path.join(os.path.dirname(os.path.dirname(__file__)),'upfiles'), UPLOAD_SET, dict(
+label = _("Uploaded files folder"),
+help_text = _("The filesystem path where uploaded files will be stored. Please note that this folder must exist.")))
+
+UPFILES_ALIAS = Setting('UPFILES_ALIAS', '/upfiles/', UPLOAD_SET, dict(
+label = _("Uploaded files alias"),
+help_text = _("The url alias for uploaded files. Notice that if you change this setting, you'll need to restart your site.")))
+
+ALLOW_MAX_FILE_SIZE = Setting('ALLOW_MAX_FILE_SIZE', 2.5, UPLOAD_SET, dict(
+label = _("Max file size"),
help_text = _("The maximum allowed file size for uploads in mb.")))
\ No newline at end of file
diff --git a/forum/settings/voting.py b/forum/settings/voting.py
index aea9153..e4e81b6 100644
--- a/forum/settings/voting.py
+++ b/forum/settings/voting.py
@@ -1,32 +1,32 @@
-from base import Setting, SettingSet
-from django.utils.translation import ugettext_lazy as _
-
-VOTE_RULES_SET = SettingSet('voting', _('Voting rules'), _("Configure the voting rules on your site."), 400)
-
-USER_REPUTATION_TO_MAX_VOTES = Setting('USER_REPUTATION_TO_MAX_VOTES', True, VOTE_RULES_SET, dict(
-label = _("Add reputation to max votes per day"), required=False,
-help_text = _("The user reputation is added to the static MAX_VOTES_PER_DAY option. Users with higher reputation can vote more.")))
-
-MAX_VOTES_PER_DAY = Setting('MAX_VOTES_PER_DAY', 30, VOTE_RULES_SET, dict(
-label = _("Maximum votes per day"),
-help_text = _("The maximum number of votes an user can cast per day.")))
-
-START_WARN_VOTES_LEFT = Setting('START_WARN_VOTES_LEFT', 10, VOTE_RULES_SET, dict(
-label = _("Start warning about votes left"),
-help_text = _("From how many votes left should an user start to be warned about it.")))
-
-MAX_FLAGS_PER_DAY = Setting('MAX_FLAGS_PER_DAY', 5, VOTE_RULES_SET, dict(
-label = _("Maximum flags per day"),
-help_text = _("The maximum number of times an can flag a post per day.")))
-
-FLAG_COUNT_TO_HIDE_POST = Setting('FLAG_COUNT_TO_HIDE_POST', 3, VOTE_RULES_SET, dict(
-label = _("Flag count to hide post"),
-help_text = _("How many times a post needs to be flagged to be hidden from the main page.")))
-
-FLAG_COUNT_TO_DELETE_POST = Setting('FLAG_COUNT_TO_DELETE_POST', 5, VOTE_RULES_SET, dict(
-label = _("Flag count to delete post"),
-help_text = _("How many times a post needs to be flagged to be deleted.")))
-
-DENY_UNVOTE_DAYS = Setting('DENY_UNVOTE_DAYS', 1, VOTE_RULES_SET, dict(
-label = _("Days to cancel a vote"),
+from base import Setting, SettingSet
+from django.utils.translation import ugettext_lazy as _
+
+VOTE_RULES_SET = SettingSet('voting', _('Voting rules'), _("Configure the voting rules on your site."), 400)
+
+USER_REPUTATION_TO_MAX_VOTES = Setting('USER_REPUTATION_TO_MAX_VOTES', True, VOTE_RULES_SET, dict(
+label = _("Add reputation to max votes per day"), required=False,
+help_text = _("The user reputation is added to the static MAX_VOTES_PER_DAY option. Users with higher reputation can vote more.")))
+
+MAX_VOTES_PER_DAY = Setting('MAX_VOTES_PER_DAY', 30, VOTE_RULES_SET, dict(
+label = _("Maximum votes per day"),
+help_text = _("The maximum number of votes an user can cast per day.")))
+
+START_WARN_VOTES_LEFT = Setting('START_WARN_VOTES_LEFT', 10, VOTE_RULES_SET, dict(
+label = _("Start warning about votes left"),
+help_text = _("From how many votes left should an user start to be warned about it.")))
+
+MAX_FLAGS_PER_DAY = Setting('MAX_FLAGS_PER_DAY', 5, VOTE_RULES_SET, dict(
+label = _("Maximum flags per day"),
+help_text = _("The maximum number of times an can flag a post per day.")))
+
+FLAG_COUNT_TO_HIDE_POST = Setting('FLAG_COUNT_TO_HIDE_POST', 3, VOTE_RULES_SET, dict(
+label = _("Flag count to hide post"),
+help_text = _("How many times a post needs to be flagged to be hidden from the main page.")))
+
+FLAG_COUNT_TO_DELETE_POST = Setting('FLAG_COUNT_TO_DELETE_POST', 5, VOTE_RULES_SET, dict(
+label = _("Flag count to delete post"),
+help_text = _("How many times a post needs to be flagged to be deleted.")))
+
+DENY_UNVOTE_DAYS = Setting('DENY_UNVOTE_DAYS', 1, VOTE_RULES_SET, dict(
+label = _("Days to cancel a vote"),
help_text = _("How many days an user can cancel a vote after he originaly casted it.")))
\ No newline at end of file
diff --git a/forum/skins/default/media/iepngfix/iepngfix.htc b/forum/skins/default/media/iepngfix/iepngfix.htc
index 909f599..6423ad4 100755
--- a/forum/skins/default/media/iepngfix/iepngfix.htc
+++ b/forum/skins/default/media/iepngfix/iepngfix.htc
@@ -1,198 +1,198 @@
-
-
-
+
+
+
diff --git a/forum/skins/default/media/iepngfix/iepngfix_tilebg.js b/forum/skins/default/media/iepngfix/iepngfix_tilebg.js
index 6a1ff49..4252253 100755
--- a/forum/skins/default/media/iepngfix/iepngfix_tilebg.js
+++ b/forum/skins/default/media/iepngfix/iepngfix_tilebg.js
@@ -1,173 +1,173 @@
-// IE5.5+ PNG Alpha Fix v2.0 Alpha: Background Tiling Support
-// (c) 2008-2009 Angus Turnbull http://www.twinhelix.com
-
-// This is licensed under the GNU LGPL, version 2.1 or later.
-// For details, see: http://creativecommons.org/licenses/LGPL/2.1/
-
-var IEPNGFix = window.IEPNGFix || {};
-
-IEPNGFix.tileBG = function(elm, pngSrc, ready) {
- // Params: A reference to a DOM element, the PNG src file pathname, and a
- // hidden "ready-to-run" passed when called back after image preloading.
-
- var data = this.data[elm.uniqueID],
- elmW = Math.max(elm.clientWidth, elm.scrollWidth),
- elmH = Math.max(elm.clientHeight, elm.scrollHeight),
- bgX = elm.currentStyle.backgroundPositionX,
- bgY = elm.currentStyle.backgroundPositionY,
- bgR = elm.currentStyle.backgroundRepeat;
-
- // Cache of DIVs created per element, and image preloader/data.
- if (!data.tiles) {
- data.tiles = {
- elm: elm,
- src: '',
- cache: [],
- img: new Image(),
- old: {}
- };
- }
- var tiles = data.tiles,
- pngW = tiles.img.width,
- pngH = tiles.img.height;
-
- if (pngSrc) {
- if (!ready && pngSrc != tiles.src) {
- // New image? Preload it with a callback to detect dimensions.
- tiles.img.onload = function() {
- this.onload = null;
- IEPNGFix.tileBG(elm, pngSrc, 1);
- };
- return tiles.img.src = pngSrc;
- }
- } else {
- // No image?
- if (tiles.src) ready = 1;
- pngW = pngH = 0;
- }
- tiles.src = pngSrc;
-
- if (!ready && elmW == tiles.old.w && elmH == tiles.old.h &&
- bgX == tiles.old.x && bgY == tiles.old.y && bgR == tiles.old.r) {
- return;
- }
-
- // Convert English and percentage positions to pixels.
- var pos = {
- top: '0%',
- left: '0%',
- center: '50%',
- bottom: '100%',
- right: '100%'
- },
- x,
- y,
- pc;
- x = pos[bgX] || bgX;
- y = pos[bgY] || bgY;
- if (pc = x.match(/(\d+)%/)) {
- x = Math.round((elmW - pngW) * (parseInt(pc[1]) / 100));
- }
- if (pc = y.match(/(\d+)%/)) {
- y = Math.round((elmH - pngH) * (parseInt(pc[1]) / 100));
- }
- x = parseInt(x);
- y = parseInt(y);
-
- // Handle backgroundRepeat.
- var repeatX = { 'repeat': 1, 'repeat-x': 1 }[bgR],
- repeatY = { 'repeat': 1, 'repeat-y': 1 }[bgR];
- if (repeatX) {
- x %= pngW;
- if (x > 0) x -= pngW;
- }
- if (repeatY) {
- y %= pngH;
- if (y > 0) y -= pngH;
- }
-
- // Go!
- this.hook.enabled = 0;
- if (!({ relative: 1, absolute: 1 }[elm.currentStyle.position])) {
- elm.style.position = 'relative';
- }
- var count = 0,
- xPos,
- maxX = repeatX ? elmW : x + 0.1,
- yPos,
- maxY = repeatY ? elmH : y + 0.1,
- d,
- s,
- isNew;
- if (pngW && pngH) {
- for (xPos = x; xPos < maxX; xPos += pngW) {
- for (yPos = y; yPos < maxY; yPos += pngH) {
- isNew = 0;
- if (!tiles.cache[count]) {
- tiles.cache[count] = document.createElement('div');
- isNew = 1;
- }
- var clipR = Math.max(0, xPos + pngW > elmW ? elmW - xPos : pngW),
- clipB = Math.max(0, yPos + pngH > elmH ? elmH - yPos : pngH);
- d = tiles.cache[count];
- s = d.style;
- s.behavior = 'none';
- s.left = (xPos - parseInt(elm.currentStyle.paddingLeft)) + 'px';
- s.top = yPos + 'px';
- s.width = clipR + 'px';
- s.height = clipB + 'px';
- s.clip = 'rect(' +
- (yPos < 0 ? 0 - yPos : 0) + 'px,' +
- clipR + 'px,' +
- clipB + 'px,' +
- (xPos < 0 ? 0 - xPos : 0) + 'px)';
- s.display = 'block';
- if (isNew) {
- s.position = 'absolute';
- s.zIndex = -999;
- if (elm.firstChild) {
- elm.insertBefore(d, elm.firstChild);
- } else {
- elm.appendChild(d);
- }
- }
- this.fix(d, pngSrc, 0);
- count++;
- }
- }
- }
- while (count < tiles.cache.length) {
- this.fix(tiles.cache[count], '', 0);
- tiles.cache[count++].style.display = 'none';
- }
-
- this.hook.enabled = 1;
-
- // Cache so updates are infrequent.
- tiles.old = {
- w: elmW,
- h: elmH,
- x: bgX,
- y: bgY,
- r: bgR
- };
-};
-
-
-IEPNGFix.update = function() {
- // Update all PNG backgrounds.
- for (var i in IEPNGFix.data) {
- var t = IEPNGFix.data[i].tiles;
- if (t && t.elm && t.src) {
- IEPNGFix.tileBG(t.elm, t.src);
- }
- }
-};
-IEPNGFix.update.timer = 0;
-
-if (window.attachEvent && !window.opera) {
- window.attachEvent('onresize', function() {
- clearTimeout(IEPNGFix.update.timer);
- IEPNGFix.update.timer = setTimeout(IEPNGFix.update, 100);
- });
-}
+// IE5.5+ PNG Alpha Fix v2.0 Alpha: Background Tiling Support
+// (c) 2008-2009 Angus Turnbull http://www.twinhelix.com
+
+// This is licensed under the GNU LGPL, version 2.1 or later.
+// For details, see: http://creativecommons.org/licenses/LGPL/2.1/
+
+var IEPNGFix = window.IEPNGFix || {};
+
+IEPNGFix.tileBG = function(elm, pngSrc, ready) {
+ // Params: A reference to a DOM element, the PNG src file pathname, and a
+ // hidden "ready-to-run" passed when called back after image preloading.
+
+ var data = this.data[elm.uniqueID],
+ elmW = Math.max(elm.clientWidth, elm.scrollWidth),
+ elmH = Math.max(elm.clientHeight, elm.scrollHeight),
+ bgX = elm.currentStyle.backgroundPositionX,
+ bgY = elm.currentStyle.backgroundPositionY,
+ bgR = elm.currentStyle.backgroundRepeat;
+
+ // Cache of DIVs created per element, and image preloader/data.
+ if (!data.tiles) {
+ data.tiles = {
+ elm: elm,
+ src: '',
+ cache: [],
+ img: new Image(),
+ old: {}
+ };
+ }
+ var tiles = data.tiles,
+ pngW = tiles.img.width,
+ pngH = tiles.img.height;
+
+ if (pngSrc) {
+ if (!ready && pngSrc != tiles.src) {
+ // New image? Preload it with a callback to detect dimensions.
+ tiles.img.onload = function() {
+ this.onload = null;
+ IEPNGFix.tileBG(elm, pngSrc, 1);
+ };
+ return tiles.img.src = pngSrc;
+ }
+ } else {
+ // No image?
+ if (tiles.src) ready = 1;
+ pngW = pngH = 0;
+ }
+ tiles.src = pngSrc;
+
+ if (!ready && elmW == tiles.old.w && elmH == tiles.old.h &&
+ bgX == tiles.old.x && bgY == tiles.old.y && bgR == tiles.old.r) {
+ return;
+ }
+
+ // Convert English and percentage positions to pixels.
+ var pos = {
+ top: '0%',
+ left: '0%',
+ center: '50%',
+ bottom: '100%',
+ right: '100%'
+ },
+ x,
+ y,
+ pc;
+ x = pos[bgX] || bgX;
+ y = pos[bgY] || bgY;
+ if (pc = x.match(/(\d+)%/)) {
+ x = Math.round((elmW - pngW) * (parseInt(pc[1]) / 100));
+ }
+ if (pc = y.match(/(\d+)%/)) {
+ y = Math.round((elmH - pngH) * (parseInt(pc[1]) / 100));
+ }
+ x = parseInt(x);
+ y = parseInt(y);
+
+ // Handle backgroundRepeat.
+ var repeatX = { 'repeat': 1, 'repeat-x': 1 }[bgR],
+ repeatY = { 'repeat': 1, 'repeat-y': 1 }[bgR];
+ if (repeatX) {
+ x %= pngW;
+ if (x > 0) x -= pngW;
+ }
+ if (repeatY) {
+ y %= pngH;
+ if (y > 0) y -= pngH;
+ }
+
+ // Go!
+ this.hook.enabled = 0;
+ if (!({ relative: 1, absolute: 1 }[elm.currentStyle.position])) {
+ elm.style.position = 'relative';
+ }
+ var count = 0,
+ xPos,
+ maxX = repeatX ? elmW : x + 0.1,
+ yPos,
+ maxY = repeatY ? elmH : y + 0.1,
+ d,
+ s,
+ isNew;
+ if (pngW && pngH) {
+ for (xPos = x; xPos < maxX; xPos += pngW) {
+ for (yPos = y; yPos < maxY; yPos += pngH) {
+ isNew = 0;
+ if (!tiles.cache[count]) {
+ tiles.cache[count] = document.createElement('div');
+ isNew = 1;
+ }
+ var clipR = Math.max(0, xPos + pngW > elmW ? elmW - xPos : pngW),
+ clipB = Math.max(0, yPos + pngH > elmH ? elmH - yPos : pngH);
+ d = tiles.cache[count];
+ s = d.style;
+ s.behavior = 'none';
+ s.left = (xPos - parseInt(elm.currentStyle.paddingLeft)) + 'px';
+ s.top = yPos + 'px';
+ s.width = clipR + 'px';
+ s.height = clipB + 'px';
+ s.clip = 'rect(' +
+ (yPos < 0 ? 0 - yPos : 0) + 'px,' +
+ clipR + 'px,' +
+ clipB + 'px,' +
+ (xPos < 0 ? 0 - xPos : 0) + 'px)';
+ s.display = 'block';
+ if (isNew) {
+ s.position = 'absolute';
+ s.zIndex = -999;
+ if (elm.firstChild) {
+ elm.insertBefore(d, elm.firstChild);
+ } else {
+ elm.appendChild(d);
+ }
+ }
+ this.fix(d, pngSrc, 0);
+ count++;
+ }
+ }
+ }
+ while (count < tiles.cache.length) {
+ this.fix(tiles.cache[count], '', 0);
+ tiles.cache[count++].style.display = 'none';
+ }
+
+ this.hook.enabled = 1;
+
+ // Cache so updates are infrequent.
+ tiles.old = {
+ w: elmW,
+ h: elmH,
+ x: bgX,
+ y: bgY,
+ r: bgR
+ };
+};
+
+
+IEPNGFix.update = function() {
+ // Update all PNG backgrounds.
+ for (var i in IEPNGFix.data) {
+ var t = IEPNGFix.data[i].tiles;
+ if (t && t.elm && t.src) {
+ IEPNGFix.tileBG(t.elm, t.src);
+ }
+ }
+};
+IEPNGFix.update.timer = 0;
+
+if (window.attachEvent && !window.opera) {
+ window.attachEvent('onresize', function() {
+ clearTimeout(IEPNGFix.update.timer);
+ IEPNGFix.update.timer = setTimeout(IEPNGFix.update, 100);
+ });
+}
diff --git a/forum/skins/default/media/js/jquery.caret.js b/forum/skins/default/media/js/jquery.caret.js
index d22d511..7a00ee5 100644
--- a/forum/skins/default/media/js/jquery.caret.js
+++ b/forum/skins/default/media/js/jquery.caret.js
@@ -1,10 +1,10 @@
-/*
- *
- * Copyright (c) 2010 C. F., Wong (Cloudgen Examplet Store)
- * Licensed under the MIT License:
- * http://www.opensource.org/licenses/mit-license.php
- *
- */
-(function(k,e,i,j){k.fn.caret=function(b,l){var a,c,f=this[0],d=k.browser.msie;if(typeof b==="object"&&typeof b.start==="number"&&typeof b.end==="number"){a=b.start;c=b.end}else if(typeof b==="number"&&typeof l==="number"){a=b;c=l}else if(typeof b==="string")if((a=f.value.indexOf(b))>-1)c=a+b[e];else a=null;else if(Object.prototype.toString.call(b)==="[object RegExp]"){b=b.exec(f.value);if(b!=null){a=b.index;c=a+b[0][e]}}if(typeof a!="undefined"){if(d){d=this[0].createTextRange();d.collapse(true);
-d.moveStart("character",a);d.moveEnd("character",c-a);d.select()}else{this[0].selectionStart=a;this[0].selectionEnd=c}this[0].focus();return this}else{if(d){c=document.selection;if(this[0].tagName.toLowerCase()!="textarea"){d=this.val();a=c[i]()[j]();a.moveEnd("character",d[e]);var g=a.text==""?d[e]:d.lastIndexOf(a.text);a=c[i]()[j]();a.moveStart("character",-d[e]);var h=a.text[e]}else{a=c[i]();c=a[j]();c.moveToElementText(this[0]);c.setEndPoint("EndToEnd",a);g=c.text[e]-a.text[e];h=g+a.text[e]}}else{g=
+/*
+ *
+ * Copyright (c) 2010 C. F., Wong (Cloudgen Examplet Store)
+ * Licensed under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ */
+(function(k,e,i,j){k.fn.caret=function(b,l){var a,c,f=this[0],d=k.browser.msie;if(typeof b==="object"&&typeof b.start==="number"&&typeof b.end==="number"){a=b.start;c=b.end}else if(typeof b==="number"&&typeof l==="number"){a=b;c=l}else if(typeof b==="string")if((a=f.value.indexOf(b))>-1)c=a+b[e];else a=null;else if(Object.prototype.toString.call(b)==="[object RegExp]"){b=b.exec(f.value);if(b!=null){a=b.index;c=a+b[0][e]}}if(typeof a!="undefined"){if(d){d=this[0].createTextRange();d.collapse(true);
+d.moveStart("character",a);d.moveEnd("character",c-a);d.select()}else{this[0].selectionStart=a;this[0].selectionEnd=c}this[0].focus();return this}else{if(d){c=document.selection;if(this[0].tagName.toLowerCase()!="textarea"){d=this.val();a=c[i]()[j]();a.moveEnd("character",d[e]);var g=a.text==""?d[e]:d.lastIndexOf(a.text);a=c[i]()[j]();a.moveStart("character",-d[e]);var h=a.text[e]}else{a=c[i]();c=a[j]();c.moveToElementText(this[0]);c.setEndPoint("EndToEnd",a);g=c.text[e]-a.text[e];h=g+a.text[e]}}else{g=
f.selectionStart;h=f.selectionEnd}a=f.value.substring(g,h);return{start:g,end:h,text:a,replace:function(m){return f.value.substring(0,g)+m+f.value.substring(h,f.value[e])}}}}})(jQuery,"length","createRange","duplicate");
\ No newline at end of file
diff --git a/forum/skins/default/media/js/osqa.admin.js b/forum/skins/default/media/js/osqa.admin.js
index ccd7103..cdeeddc 100644
--- a/forum/skins/default/media/js/osqa.admin.js
+++ b/forum/skins/default/media/js/osqa.admin.js
@@ -1,83 +1,83 @@
-$(function() {
- $('.string_list_widget_button').live('click', function() {
- $but = $(this);
-
- if ($but.is('.add')) {
- $new = $("
"',
- 'upload image':'?????????'
-};
-
-var i18nEn = {
- 'need >15 points to report spam':'need >15 points to report spam ',
- '>15 points requried to upvote':'>15 points required to upvote ',
- 'tags cannot be empty':'please enter at least one tag',
- 'anonymous users cannot vote':'sorry, anonymous users cannot vote ',
- 'anonymous users cannot select favorite questions':'sorry, anonymous users cannot select favorite questions ',
- 'to comment, need': '(to comment other people\'s posts, karma ',
- 'please see':'please see ',
- 'community karma points':' or more is necessary) - ',
- 'upload image':'Upload image:',
- 'enter image url':'enter URL of the image, e.g. http://www.example.com/image.jpg \"image title\"',
- 'enter url':'enter Web address, e.g. http://www.example.com \"page title\"',
- 'daily vote cap exhausted':'sorry, you\'ve used up todays vote cap',
- 'cannot pick own answer as best':'sorry, you cannot accept your own answer',
- 'cannot revoke old vote':'sorry, older votes cannot be revoked',
- 'please confirm offensive':'are you sure this post is offensive, contains spam, advertising, malicious remarks, etc.?',
- 'flag offensive cap exhausted':'sorry, you\'ve used up todays cap of flagging offensive messages ',
- 'confirm delete':'are you sure you want to delete this?',
- 'anonymous users cannot delete/undelete':'sorry, anonymous users cannot delete or undelete posts',
- 'post recovered':'your post is now restored!',
- 'post deleted':'your post has been deleted',
- 'confirm delete comment':'do you really want to delete this comment?',
- 'can write':'have ',
- 'tablimits info':'up to 5 tags, no more than 20 characters each',
- 'content minchars': 'please enter more than {0} characters',
- 'title minchars':"please enter at least {0} characters",
- 'characters':'characters left',
- 'cannot vote for own posts':'sorry, you cannot vote for your own posts',
- 'cannot flag message as offensive twice':'cannot flag message as offensive twice ',
- '>100 points required to downvote':'>100 points required to downvote '
-};
-
-var i18nEs = {
- 'insufficient privilege':'privilegio insuficiente',
- 'cannot pick own answer as best':'no puede escoger su propia respuesta como la mejor',
- 'anonymous users cannot select favorite questions':'usuarios anonimos no pueden seleccionar',
- 'please login':'por favor inicie sesión',
- 'anonymous users cannot vote':'usuarios anónimos no pueden votar',
- '>15 points requried to upvote': '>15 puntos requeridos para votar positivamente',
- '>100 points required to downvote':'>100 puntos requeridos para votar negativamente',
- 'please see': 'por favor vea',
- 'cannot vote for own posts':'no se puede votar por sus propias publicaciones',
- 'daily vote cap exhausted':'cuota de votos diarios excedida',
- 'cannot revoke old vote':'no puede revocar un voto viejo',
- 'please confirm offensive':"por favor confirme ofensiva",
- 'anonymous users cannot flag offensive posts':'usuarios anónimos no pueden marcar publicaciones como ofensivas',
- 'cannot flag message as offensive twice':'no puede marcar mensaje como ofensivo dos veces',
- 'flag offensive cap exhausted':'cuota para marcar ofensivas ha sido excedida',
- 'need >15 points to report spam':"necesita >15 puntos para reportar spam",
- 'confirm delete':"¿Está seguro que desea borrar esto?",
- 'anonymous users cannot delete/undelete':"usuarios anónimos no pueden borrar o recuperar publicaciones",
- 'post recovered':"publicación recuperada",
- 'post deleted':"publicación borrada?",
- 'add comment':'agregar comentario',
- 'community karma points':'reputación comunitaria',
- 'to comment, need':'para comentar, necesita reputación',
- 'delete this comment':'borrar este comentario',
- 'hide comments':"ocultar comentarios",
- 'add a comment':"agregar comentarios",
- 'comments':"comentarios",
- 'confirm delete comment':"¿Realmente desea borrar este comentario?",
- 'characters':'caracteres faltantes',
- 'can write':'tiene ',
- 'click to close':'haga click para cerrar',
- 'loading...':'cargando...',
- 'tags cannot be empty':'las etiquetas no pueden estar vacÃas',
- 'tablimits info':"hasta 5 etiquetas de no mas de 20 caracteres cada una",
- 'content cannot be empty':'el contenido no puede estar vacÃo',
- 'content minchars': 'por favor introduzca mas de {0} caracteres',
- 'please enter title':'por favor ingrese un tÃtulo',
- 'title minchars':"por favor introduzca al menos {0} caracteres",
- 'delete':'borrar',
- 'undelete': 'recuperar',
- 'bold': 'negrita',
- 'italic':'cursiva',
- 'link':'enlace',
- 'quote':'citar',
- 'preformatted text':'texto preformateado',
- 'image':'imagen',
- 'numbered list':'lista numerada',
- 'bulleted list':'lista no numerada',
- 'heading':'??',
- 'horizontal bar':'barra horizontal',
- 'undo':'deshacer',
- 'redo':'rehacer',
- 'enter image url':'introduzca la URL de la imagen, por ejemplo? http://www.example.com/image.jpg \"titulo de imagen\"',
- 'enter url':'introduzca direcciones web, ejemplo? http://www.cnprog.com/ \"titulo del enlace\""',
- 'upload image':'cargar imagen?',
- 'questions/' : 'preguntas/',
- 'vote/' : 'votar/'
-};
-
-var i18n = {
- 'en':i18nEn,
- 'zh_CN':i18nZh,
- 'es':i18nEs
-};
-
-var i18n_dict = i18n[i18nLang];
-
-/*
- jQuery TextAreaResizer plugin
- Created on 17th January 2008 by Ryan O'Dell
- Version 1.0.4
-*/(function($){var textarea,staticOffset;var iLastMousePos=0;var iMin=32;var grip;$.fn.TextAreaResizer=function(){return this.each(function(){textarea=$(this).addClass('processed'),staticOffset=null;$(this).wrap('
"',
+ 'upload image':'?????????'
+};
+
+var i18nEn = {
+ 'need >15 points to report spam':'need >15 points to report spam ',
+ '>15 points requried to upvote':'>15 points required to upvote ',
+ 'tags cannot be empty':'please enter at least one tag',
+ 'anonymous users cannot vote':'sorry, anonymous users cannot vote ',
+ 'anonymous users cannot select favorite questions':'sorry, anonymous users cannot select favorite questions ',
+ 'to comment, need': '(to comment other people\'s posts, karma ',
+ 'please see':'please see ',
+ 'community karma points':' or more is necessary) - ',
+ 'upload image':'Upload image:',
+ 'enter image url':'enter URL of the image, e.g. http://www.example.com/image.jpg \"image title\"',
+ 'enter url':'enter Web address, e.g. http://www.example.com \"page title\"',
+ 'daily vote cap exhausted':'sorry, you\'ve used up todays vote cap',
+ 'cannot pick own answer as best':'sorry, you cannot accept your own answer',
+ 'cannot revoke old vote':'sorry, older votes cannot be revoked',
+ 'please confirm offensive':'are you sure this post is offensive, contains spam, advertising, malicious remarks, etc.?',
+ 'flag offensive cap exhausted':'sorry, you\'ve used up todays cap of flagging offensive messages ',
+ 'confirm delete':'are you sure you want to delete this?',
+ 'anonymous users cannot delete/undelete':'sorry, anonymous users cannot delete or undelete posts',
+ 'post recovered':'your post is now restored!',
+ 'post deleted':'your post has been deleted',
+ 'confirm delete comment':'do you really want to delete this comment?',
+ 'can write':'have ',
+ 'tablimits info':'up to 5 tags, no more than 20 characters each',
+ 'content minchars': 'please enter more than {0} characters',
+ 'title minchars':"please enter at least {0} characters",
+ 'characters':'characters left',
+ 'cannot vote for own posts':'sorry, you cannot vote for your own posts',
+ 'cannot flag message as offensive twice':'cannot flag message as offensive twice ',
+ '>100 points required to downvote':'>100 points required to downvote '
+};
+
+var i18nEs = {
+ 'insufficient privilege':'privilegio insuficiente',
+ 'cannot pick own answer as best':'no puede escoger su propia respuesta como la mejor',
+ 'anonymous users cannot select favorite questions':'usuarios anonimos no pueden seleccionar',
+ 'please login':'por favor inicie sesión',
+ 'anonymous users cannot vote':'usuarios anónimos no pueden votar',
+ '>15 points requried to upvote': '>15 puntos requeridos para votar positivamente',
+ '>100 points required to downvote':'>100 puntos requeridos para votar negativamente',
+ 'please see': 'por favor vea',
+ 'cannot vote for own posts':'no se puede votar por sus propias publicaciones',
+ 'daily vote cap exhausted':'cuota de votos diarios excedida',
+ 'cannot revoke old vote':'no puede revocar un voto viejo',
+ 'please confirm offensive':"por favor confirme ofensiva",
+ 'anonymous users cannot flag offensive posts':'usuarios anónimos no pueden marcar publicaciones como ofensivas',
+ 'cannot flag message as offensive twice':'no puede marcar mensaje como ofensivo dos veces',
+ 'flag offensive cap exhausted':'cuota para marcar ofensivas ha sido excedida',
+ 'need >15 points to report spam':"necesita >15 puntos para reportar spam",
+ 'confirm delete':"¿Está seguro que desea borrar esto?",
+ 'anonymous users cannot delete/undelete':"usuarios anónimos no pueden borrar o recuperar publicaciones",
+ 'post recovered':"publicación recuperada",
+ 'post deleted':"publicación borrada?",
+ 'add comment':'agregar comentario',
+ 'community karma points':'reputación comunitaria',
+ 'to comment, need':'para comentar, necesita reputación',
+ 'delete this comment':'borrar este comentario',
+ 'hide comments':"ocultar comentarios",
+ 'add a comment':"agregar comentarios",
+ 'comments':"comentarios",
+ 'confirm delete comment':"¿Realmente desea borrar este comentario?",
+ 'characters':'caracteres faltantes',
+ 'can write':'tiene ',
+ 'click to close':'haga click para cerrar',
+ 'loading...':'cargando...',
+ 'tags cannot be empty':'las etiquetas no pueden estar vacÃas',
+ 'tablimits info':"hasta 5 etiquetas de no mas de 20 caracteres cada una",
+ 'content cannot be empty':'el contenido no puede estar vacÃo',
+ 'content minchars': 'por favor introduzca mas de {0} caracteres',
+ 'please enter title':'por favor ingrese un tÃtulo',
+ 'title minchars':"por favor introduzca al menos {0} caracteres",
+ 'delete':'borrar',
+ 'undelete': 'recuperar',
+ 'bold': 'negrita',
+ 'italic':'cursiva',
+ 'link':'enlace',
+ 'quote':'citar',
+ 'preformatted text':'texto preformateado',
+ 'image':'imagen',
+ 'numbered list':'lista numerada',
+ 'bulleted list':'lista no numerada',
+ 'heading':'??',
+ 'horizontal bar':'barra horizontal',
+ 'undo':'deshacer',
+ 'redo':'rehacer',
+ 'enter image url':'introduzca la URL de la imagen, por ejemplo? http://www.example.com/image.jpg \"titulo de imagen\"',
+ 'enter url':'introduzca direcciones web, ejemplo? http://www.cnprog.com/ \"titulo del enlace\""',
+ 'upload image':'cargar imagen?',
+ 'questions/' : 'preguntas/',
+ 'vote/' : 'votar/'
+};
+
+var i18n = {
+ 'en':i18nEn,
+ 'zh_CN':i18nZh,
+ 'es':i18nEs
+};
+
+var i18n_dict = i18n[i18nLang];
+
+/*
+ jQuery TextAreaResizer plugin
+ Created on 17th January 2008 by Ryan O'Dell
+ Version 1.0.4
+*/(function($){var textarea,staticOffset;var iLastMousePos=0;var iMin=32;var grip;$.fn.TextAreaResizer=function(){return this.each(function(){textarea=$(this).addClass('processed'),staticOffset=null;$(this).wrap('
- {% blocktrans with question.nstate.closed.extra as close_reason %}The question has been closed for the following reason "{{ close_reason }}" by{% endblocktrans %}
- {{ question.nstate.closed.by.username }}
- {% diff_date question.nstate.closed.at %}
-
+ {% blocktrans with question.nstate.closed.extra as close_reason %}The question has been closed for the following reason "{{ close_reason }}" by{% endblocktrans %}
+ {{ question.nstate.closed.by.username }}
+ {% diff_date question.nstate.closed.at %}
+