summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-07-19 22:39:24 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-07-19 22:39:24 -0400
commitbc1a00485fe64a4aec77c271945543169d4f57fb (patch)
tree9df1b3ffe7c9b40e168fdc0238679d02740d82f4
parentd051346759d2248620a7329290188ea69814b5c4 (diff)
downloadaskbot-bc1a00485fe64a4aec77c271945543169d4f57fb.tar.gz
askbot-bc1a00485fe64a4aec77c271945543169d4f57fb.tar.bz2
askbot-bc1a00485fe64a4aec77c271945543169d4f57fb.zip
suspended and blocked users now cannot vote
-rw-r--r--askbot/locale/de/LC_MESSAGES/django.mobin80778 -> 81314 bytes
-rw-r--r--askbot/locale/de/LC_MESSAGES/django.po17
-rw-r--r--askbot/locale/en/LC_MESSAGES/django.mobin23891 -> 24349 bytes
-rw-r--r--askbot/locale/en/LC_MESSAGES/django.po17
-rw-r--r--askbot/locale/es/LC_MESSAGES/django.mobin43243 -> 43703 bytes
-rw-r--r--askbot/locale/es/LC_MESSAGES/django.po17
-rw-r--r--askbot/locale/fi/LC_MESSAGES/django.mobin73972 -> 74438 bytes
-rw-r--r--askbot/locale/fi/LC_MESSAGES/django.po17
-rw-r--r--askbot/locale/ru/LC_MESSAGES/django.mobin93578 -> 94248 bytes
-rw-r--r--askbot/locale/ru/LC_MESSAGES/django.po17
-rw-r--r--askbot/locale/tr/LC_MESSAGES/django.mobin52874 -> 53425 bytes
-rw-r--r--askbot/locale/tr/LC_MESSAGES/django.po17
-rw-r--r--askbot/locale/zh-cn/LC_MESSAGES/django.mobin24271 -> 24695 bytes
-rw-r--r--askbot/locale/zh-cn/LC_MESSAGES/django.po17
-rw-r--r--askbot/models/__init__.py107
-rw-r--r--askbot/models/meta.py21
-rw-r--r--askbot/skins/default/media/js/com.cnprog.i18n.js41
-rwxr-xr-xaskbot/skins/default/media/js/com.cnprog.post.js52
-rw-r--r--askbot/utils/decorators.py1
-rw-r--r--askbot/views/commands.py193
20 files changed, 400 insertions, 134 deletions
diff --git a/askbot/locale/de/LC_MESSAGES/django.mo b/askbot/locale/de/LC_MESSAGES/django.mo
index fd451a6d..8ee39e01 100644
--- a/askbot/locale/de/LC_MESSAGES/django.mo
+++ b/askbot/locale/de/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/locale/de/LC_MESSAGES/django.po b/askbot/locale/de/LC_MESSAGES/django.po
index b5de1030..1ded3e79 100644
--- a/askbot/locale/de/LC_MESSAGES/django.po
+++ b/askbot/locale/de/LC_MESSAGES/django.po
@@ -28,6 +28,23 @@ msgstr "Ein Zugang dieses Namens existiert bereits!"
msgid "can't have two logins to the same account yet, sorry."
msgstr "Zwei Logins für den selben Zugang sind leider noch nicht möglich."
+msgid "anonymous users cannot vote"
+msgstr "Gastbenutzer können nicht abstimmen"
+
+#, python-format
+msgid ">%(points)s points required to upvote"
+msgstr "Positiv bewerten benötigt mindestens %(points)s Punkte "
+
+#, python-format
+msgid ">%(points)s points required to downvote"
+msgstr "Negativ bewerten benötigt mindestens %(points)s Punkte"
+
+msgid "cannot vote for own posts"
+msgstr "Über selbst verfaßte Beiträge kann nicht abgestimmt werden"
+
+msgid "cannot revoke old vote"
+msgstr "Bewertung kann nicht mehr zurückgenommen werden"
+
#: django_authopenid/forms.py:157
msgid "Please enter valid username and password (both are case-sensitive)."
msgstr ""
diff --git a/askbot/locale/en/LC_MESSAGES/django.mo b/askbot/locale/en/LC_MESSAGES/django.mo
index 5b3e4ad5..e80b4343 100644
--- a/askbot/locale/en/LC_MESSAGES/django.mo
+++ b/askbot/locale/en/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/locale/en/LC_MESSAGES/django.po b/askbot/locale/en/LC_MESSAGES/django.po
index a3dfdafb..d259f4fc 100644
--- a/askbot/locale/en/LC_MESSAGES/django.po
+++ b/askbot/locale/en/LC_MESSAGES/django.po
@@ -24,6 +24,23 @@ msgstr ""
msgid "Account with this name already exists on the forum"
msgstr ""
+msgid "anonymous users cannot vote"
+msgstr "sorry, anonymous users cannot vote "
+
+#, python-format
+msgid ">%(points)s points required to upvote"
+msgstr ">%(points)s points required to upvote "
+
+#, python-format
+msgid ">%(points)s points required to downvote"
+msgstr ">%(points)s points required to downvote "
+
+msgid "cannot vote for own posts"
+msgstr "sorry, you cannot vote for your own posts"
+
+msgid "cannot revoke old vote"
+msgstr "sorry, but older votes cannot be revoked"
+
#: django_authopenid/forms.py:136
msgid "can't have two logins to the same account yet, sorry."
msgstr ""
diff --git a/askbot/locale/es/LC_MESSAGES/django.mo b/askbot/locale/es/LC_MESSAGES/django.mo
index 27fb5837..3e6d4406 100644
--- a/askbot/locale/es/LC_MESSAGES/django.mo
+++ b/askbot/locale/es/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/locale/es/LC_MESSAGES/django.po b/askbot/locale/es/LC_MESSAGES/django.po
index 5d5019d5..857c175e 100644
--- a/askbot/locale/es/LC_MESSAGES/django.po
+++ b/askbot/locale/es/LC_MESSAGES/django.po
@@ -31,10 +31,27 @@ msgstr ""
msgid "can't have two logins to the same account yet, sorry."
msgstr ""
+msgid "anonymous users cannot vote"
+msgstr "usuarios anónimos no pueden votar"
+
+#, python-format
+msgid ">%(points)s points required to upvote"
+msgstr ">%(points)s puntos requeridos para votar positivamente "
+
+#, python-format
+msgid ">%(points)s points required to downvote"
+msgstr ">%(points)s puntos requeridos para votar negativamente"
+
#: django_authopenid/forms.py:157
msgid "Please enter valid username and password (both are case-sensitive)."
msgstr "Ingrese su nombre de usuario y contraseña (sensible a las mayusculas)"
+msgid "cannot vote for own posts"
+msgstr "no se puede votar por sus propias publicaciones"
+
+msgid "cannot revoke old vote"
+msgstr "no puede revocar un voto viejo"
+
#: django_authopenid/forms.py:160 django_authopenid/forms.py:210
msgid "This account is inactive."
msgstr "Esta cuenta está inactiva."
diff --git a/askbot/locale/fi/LC_MESSAGES/django.mo b/askbot/locale/fi/LC_MESSAGES/django.mo
index 4d5d13da..6277ccb6 100644
--- a/askbot/locale/fi/LC_MESSAGES/django.mo
+++ b/askbot/locale/fi/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/locale/fi/LC_MESSAGES/django.po b/askbot/locale/fi/LC_MESSAGES/django.po
index 16669b1a..58e73cbd 100644
--- a/askbot/locale/fi/LC_MESSAGES/django.po
+++ b/askbot/locale/fi/LC_MESSAGES/django.po
@@ -34,6 +34,23 @@ msgstr "Kysymys ja kaikki sen vastaukset on poistettu"
msgid "The question has been deleted"
msgstr "Kysymys on poistettu"
+msgid "anonymous users cannot vote"
+msgstr "kirjaudu sisään, jotta voit käyttää tätä ominaisuutta"
+
+#, python-format
+msgid ">%(points)s points required to upvote"
+msgstr "tarvitset >%(points)s points äänestämiseen "
+
+#, python-format
+msgid ">%(points)s points required to downvote"
+msgstr ">%(points)s mainetta tarvitaan"
+
+msgid "cannot vote for own posts"
+msgstr "et voi äänestää omia postauksia"
+
+msgid "cannot revoke old vote"
+msgstr "vanhoja ääniä ei voi muuttaa"
+
#: feed.py:22
msgid " - "
msgstr " - "
diff --git a/askbot/locale/ru/LC_MESSAGES/django.mo b/askbot/locale/ru/LC_MESSAGES/django.mo
index 8afb2eaf..feb9d081 100644
--- a/askbot/locale/ru/LC_MESSAGES/django.mo
+++ b/askbot/locale/ru/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/locale/ru/LC_MESSAGES/django.po b/askbot/locale/ru/LC_MESSAGES/django.po
index 886316fa..e189e983 100644
--- a/askbot/locale/ru/LC_MESSAGES/django.po
+++ b/askbot/locale/ru/LC_MESSAGES/django.po
@@ -29,6 +29,23 @@ msgstr "аккаунт с таким именем уже существует н
msgid "can't have two logins to the same account yet, sorry."
msgstr "извините, но пока нельзя входить в аккаунт больше чем одним методом"
+msgid "anonymous users cannot vote"
+msgstr "неавторизированные пользователи не могут голосовать "
+
+#, python-format
+msgid ">%(points)s points required to upvote"
+msgstr "для повышения рейтинга требуется минимум %(points)s баллов "
+
+#, python-format
+msgid ">%(points)s points required to downvote"
+msgstr "для понижения рейтинга требуется минимум %(points)s баллов"
+
+msgid "cannot vote for own posts"
+msgstr "нельзя голосовать за собственные сообщения"
+
+msgid "cannot revoke old vote"
+msgstr "голос не может быть отозван"
+
#: django_authopenid/forms.py:158
msgid "Please enter valid username and password (both are case-sensitive)."
msgstr "Пожалуйста введите имя пользователя и пароль (с учетом регистра букв)"
diff --git a/askbot/locale/tr/LC_MESSAGES/django.mo b/askbot/locale/tr/LC_MESSAGES/django.mo
index 0bc6227d..64cd2338 100644
--- a/askbot/locale/tr/LC_MESSAGES/django.mo
+++ b/askbot/locale/tr/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/locale/tr/LC_MESSAGES/django.po b/askbot/locale/tr/LC_MESSAGES/django.po
index 0bc2ee80..8cfe11d6 100644
--- a/askbot/locale/tr/LC_MESSAGES/django.po
+++ b/askbot/locale/tr/LC_MESSAGES/django.po
@@ -28,6 +28,23 @@ msgstr "Hesap bu adla zaten forum var"
msgid "can't have two logins to the same account yet, sorry."
msgstr "Üzgünüm.. Bir hesaba aynı anda iki giriş mümkün değil."
+msgid "anonymous users cannot vote"
+msgstr "üye girişi yapmadan oy kullanamazsınız"
+
+#, python-format
+msgid ">%(points)s points required to upvote"
+msgstr "beğeninizi göstermek için en az %(points)s puan toplamalısınız "
+
+#, python-format
+msgid ">%(points)s points required to downvote"
+msgstr "beğenmediğinizi göstermek için en az %(points)s puan toplamalısınız"
+
+msgid "cannot vote for own posts"
+msgstr "kendi yazılarınıza oy veremezsiniz"
+
+msgid "cannot revoke old vote"
+msgstr "verilen bir oyu iptal edemezsiniz"
+
#: django_authopenid/forms.py:157
msgid "Please enter valid username and password (both are case-sensitive)."
msgstr "Lütfen) geçerli kullanıcı adı ve şifre (hem harf duyarlıdır girin."
diff --git a/askbot/locale/zh-cn/LC_MESSAGES/django.mo b/askbot/locale/zh-cn/LC_MESSAGES/django.mo
index a73a9675..be6432a8 100644
--- a/askbot/locale/zh-cn/LC_MESSAGES/django.mo
+++ b/askbot/locale/zh-cn/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/locale/zh-cn/LC_MESSAGES/django.po b/askbot/locale/zh-cn/LC_MESSAGES/django.po
index e08a05d2..b23f6ea6 100644
--- a/askbot/locale/zh-cn/LC_MESSAGES/django.po
+++ b/askbot/locale/zh-cn/LC_MESSAGES/django.po
@@ -19,10 +19,27 @@ msgstr ""
msgid "i-names are not supported"
msgstr "基本的HTML标签也是支持的"
+#, python-format
+msgid ">%(points)s points requried to upvote"
+msgstr "需要+%(points)s积分才能投支持票。"
+
#: django_authopenid/forms.py:134
msgid "Account with this name already exists on the forum"
msgstr ""
+msgid "anonymous users cannot vote"
+msgstr "匿名用户不能投票"
+
+#, python-format
+msgid ">%(points)s points required to downvote"
+msgstr "需要+%(points)s积分才能投反对票。"
+
+msgid "cannot vote for own posts"
+msgstr "不能给自己的帖子投票"
+
+msgid "cannot revoke old vote"
+msgstr "这个投票已经过时,不能撤销。"
+
#: django_authopenid/forms.py:135
msgid "can't have two logins to the same account yet, sorry."
msgstr ""
diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py
index c4d13b5d..8738ce41 100644
--- a/askbot/models/__init__.py
+++ b/askbot/models/__init__.py
@@ -29,6 +29,9 @@ from askbot.models.repute import Badge, Award, Repute
from askbot import auth
from askbot.utils.decorators import auto_now_timestamp
+class PermissionError(Exception):
+ pass
+
User.add_to_class(
'status',
models.CharField(
@@ -68,6 +71,95 @@ User.add_to_class('tag_filter_setting',
)
User.add_to_class('response_count', models.IntegerField(default=0))
+
+def user_assert_can_vote_for_post(
+ self,
+ post = None,
+ direction = None,
+ ):
+ """raises PermissionError exception
+ if user can't in fact upvote
+
+ :param:direction can be 'up' or 'down'
+ :param:post can be instance of question or answer
+ """
+ if self.is_blocked():
+ raise PermissionError(
+ _(
+ 'Sorry your account appears to be blocked ' +
+ 'and you cannot vote - please contact the ' +
+ 'site administrator to resolve the issue'
+ )
+ )
+ if self.is_suspended():
+ raise PermissionError(
+ _(
+ 'Sorry your account appears to be suspended ' +
+ 'and you cannot vote - please contact the ' +
+ 'site administrator to resolve the issue'
+ )
+ )
+ if self.is_moderator() or self.is_administrator():
+ return
+
+ if direction == 'up':
+ if self.reputation < askbot_settings.MIN_REP_TO_VOTE_UP:
+ msg = _(">%(points)s points required to upvote, bitch") % \
+ {'points': askbot_settings.MIN_REP_TO_VOTE_UP}
+ raise PermissionError(msg)
+ else:
+ if self.reputation < askbot_settings.MIN_REP_TO_VOTE_DOWN:
+ msg = _(">%(points)s points required to downvote") % \
+ {'points': askbot_settings.MIN_REP_TO_VOTE_DOWN}
+ raise PermissionError(msg)
+
+ if self == post.author:
+ raise PermissionError('cannot vote for own posts')
+
+
+def user_get_old_vote_for_post(self, post):
+ """returns previous vote for this post
+ by the user or None, if does not exist
+
+ raises assertion_error is number of old votes is > 1
+ which is illegal
+ """
+ post_content_type = ContentType.objects.get_for_model(post)
+ old_votes = Vote.objects.filter(
+ user = self,
+ content_type = post_content_type,
+ object_id = post.id
+ )
+ if len(old_votes) == 0:
+ return None
+ else:
+ assert(len(old_votes) == 1)
+
+ return old_votes[0]
+
+def user_assert_can_revoke_old_vote(self, vote):
+ """raises PermissionError if old vote
+ cannot be revoked due to age of the vote
+ """
+ if (datetime.datetime.now().day - vote.voted_at.day) \
+ >= askbot_settings.MAX_DAYS_TO_CANCEL_VOTE:
+ raise PermissionError(_('cannot revoke old vote'))
+
+def user_get_unused_votes_today(self):
+ """returns number of votes that are
+ still available to the user today
+ """
+ today = datetime.date.today()
+ one_day_interval = (today, today + datetime.timedelta(1))
+
+ used_votes = Vote.objects.filter(
+ user = self,
+ voted_at__range = one_day_interval
+ ).count()
+
+ available_votes = askbot_settings.MAX_VOTES_PER_USER_PER_DAY - used_votes
+ return max(0, available_votes)
+
def user_post_comment(
self,
parent_post = None,
@@ -417,6 +509,7 @@ def toggle_favorite_question(self, question, timestamp=None, cancel=False):
Question.objects.update_favorite_count(question)
return result
+@auto_now_timestamp
def _process_vote(user, post, timestamp=None, cancel=False, vote_type=None):
""""private" wrapper function that applies post upvotes/downvotes
and cancelations
@@ -460,13 +553,17 @@ def _process_vote(user, post, timestamp=None, cancel=False, vote_type=None):
if vote_type == Vote.VOTE_UP:
if cancel:
auth.onUpVotedCanceled(vote, post, user, timestamp)
+ return None
else:
auth.onUpVoted(vote, post, user, timestamp)
+ return vote
elif vote_type == Vote.VOTE_DOWN:
if cancel:
auth.onDownVotedCanceled(vote, post, user, timestamp)
+ return None
else:
auth.onDownVoted(vote, post, user, timestamp)
+ return vote
def user_unfollow_question(self, question = None):
if self in question.followed_by.all():
@@ -477,7 +574,7 @@ def user_follow_question(self, question = None):
question.followed_by.add(self)
def upvote(self, post, timestamp=None, cancel=False):
- _process_vote(
+ return _process_vote(
self,post,
timestamp=timestamp,
cancel=cancel,
@@ -485,7 +582,7 @@ def upvote(self, post, timestamp=None, cancel=False):
)
def downvote(self, post, timestamp=None, cancel=False):
- _process_vote(
+ return _process_vote(
self,post,
timestamp=timestamp,
cancel=cancel,
@@ -564,6 +661,10 @@ User.add_to_class('can_moderate_user', user_can_moderate_user)
User.add_to_class('moderate_user_reputation', user_moderate_user_reputation)
User.add_to_class('set_status', user_set_status)
User.add_to_class('get_status_display', user_get_status_display)
+User.add_to_class('assert_can_vote_for_post', user_assert_can_vote_for_post)
+User.add_to_class('get_old_vote_for_post', user_get_old_vote_for_post)
+User.add_to_class('assert_can_revoke_old_vote', user_assert_can_revoke_old_vote)
+User.add_to_class('get_unused_votes_today', user_get_unused_votes_today)
#todo: move this to askbot/utils ??
def format_instant_notification_body(
@@ -997,6 +1098,8 @@ EmailFeedSetting = EmailFeedSetting
__all__ = [
'signals',
+ 'PermissionError',
+
'Question',
'QuestionRevision',
'QuestionView',
diff --git a/askbot/models/meta.py b/askbot/models/meta.py
index 13ddd803..c10bb8fe 100644
--- a/askbot/models/meta.py
+++ b/askbot/models/meta.py
@@ -56,6 +56,27 @@ class Vote(base.MetaContent, base.UserContent):
assert(vote_type in (self.VOTE_UP, self.VOTE_DOWN))
return self.vote != vote_type
+ def cancel(self):
+ """cancel the vote
+ while taking into account whether vote was up
+ or down
+
+ return change in score on the post
+ """
+ #importing locally because of circular dependency
+ from askbot import auth
+ score_before = self.content_object.score
+ if self.vote > 0:
+ # cancel upvote
+ auth.onUpVotedCanceled(self, self.content_object, self.user)
+
+ else:
+ # cancel downvote
+ auth.onDownVotedCanceled(self, self.content_object, self.user)
+ score_after = self.content_object.score
+
+ return score_after - score_before
+
class FlaggedItemManager(models.Manager):
def get_flagged_items_count_today(self, user):
diff --git a/askbot/skins/default/media/js/com.cnprog.i18n.js b/askbot/skins/default/media/js/com.cnprog.i18n.js
index a52ab52f..926b42ff 100644
--- a/askbot/skins/default/media/js/com.cnprog.i18n.js
+++ b/askbot/skins/default/media/js/com.cnprog.i18n.js
@@ -4,13 +4,8 @@ var i18nZh = {
'cannot pick own answer as best':'不能设置自己的回答为最佳答案',
'anonymous users cannot select favorite questions':'匿名用户不能收藏问题,请先',
'please login':'注册或者登录',
- 'anonymous users cannot vote':'匿名用户不能投票',
- '>15 points requried to upvote':'需要+15积分才能投支持票。',
- '>100 points required to downvote':'需要+100积分才能投反对票。',
'please see': '查看',
- 'cannot vote for own posts':'不能给自己的帖子投票',
'daily vote cap exhausted':'对不起,您已用完今日所有的投票。',
- 'cannot revoke old vote':'这个投票已经过时,不能撤销。',
'please confirm offensive':"确定要归类该帖为广告、人身攻击、恶意言论吗?",
'anonymous users cannot flag offensive posts':'匿名用户不能操作,请先',
'cannot flag message as offensive twice':'不能重复操作。',
@@ -58,10 +53,9 @@ var i18nZh = {
};
var i18nEn = {
+ "anonymous users cannot vote": "sorry, anonymous users cannot vote ",
'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 ',
@@ -71,7 +65,6 @@ var i18nEn = {
'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?',
@@ -84,16 +77,13 @@ var i18nEn = {
'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 i18nFi = {
+ "anonymous users cannot vote": "kirjaudu sisään, jotta voit käyttää tätä ominaisuutta ",
'need >15 points to report spam':'tarvitset >15 pistettä raportoidaksesi roskapostista',
- '>15 points requried to upvote':'tarvitset >15 points äänestämiseen ',
'tags cannot be empty':'anna vähintään yksi tagi',
- 'anonymous users cannot vote':'kirjaudu sisään, jotta voit käyttää tätä ominaisuutta',
'anonymous users cannot select favorite questions':'kirjaudu sisään, jotta voit käyttää tätä ominaisuutta',
'to comment, need': '(kommentoidaksesi muita ',
'please see':'katso ',
@@ -103,7 +93,6 @@ var i18nFi = {
'enter url':'Anna URL-osoite, esim. http://www.example.com \"sivun otsikko\"',
'daily vote cap exhausted':'olet käyttänyt tämän päivän osalta äänesi',
'cannot pick own answer as best':'et voi hyväksyä omaa vastaustasi parhaaksi',
- 'cannot revoke old vote':'vanhoja ääniä ei voi muuttaa',
'please confirm offensive':'oletko varma, että tämä on roskaposti, loukkaava tai muuta hyväksymätöntä?',
'flag offensive cap exhausted':'olet käyttänyt tämän päivän merkkausmäärät ',
'confirm delete':'oletko varma, että haluat poistaa tämän?',
@@ -116,9 +105,7 @@ var i18nFi = {
'content minchars': 'syötä vähintään {0} merkkiä',
'title minchars':"syötä vähintään {0} merkkiä",
'characters':'merkkiä jäljellä',
- 'cannot vote for own posts':'et voi äänestää omia postauksia',
'cannot flag message as offensive twice':'ei voi merkata kahta kertaa ',
- '>100 points required to downvote':'>100 mainetta tarvitaan',
'questions/' : 'kysymykset/',
'answers/' : 'vastukset/',
'comments/' : 'kommentit/',
@@ -133,17 +120,13 @@ var i18nFi = {
};
var i18nTr = {
+ "anonymous users cannot vote":"üye girişi yapmadan oy kullanamazsınız",
'insufficient privilege':'buna yetkiniz yoktur',
'cannot pick own answer as best':'en cevap olarak kendi cevabınızı seçemezsiniz',
'anonymous users cannot select favorite questions':'üye girişi yapmadan favori seçemezsiniz',
'please login':'lütfen üye girişi yapınız',
- 'anonymous users cannot vote':'üye girişi yapmadan oy kullanamazsınız',
- '>15 points requried to upvote': 'beğeninizi göstermek için en az 15 puan toplamalısınız',
- '>100 points required to downvote':'beğenmediğinizi göstermek için en az 100 puan toplamalısınız',
'please see': 'lütfen bakın',
- 'cannot vote for own posts':'kendi yazılarınıza oy veremezsiniz',
'daily vote cap exhausted':'bugünlük oy verme kotanız doldu',
- 'cannot revoke old vote':'verilen bir oyu iptal edemezsiniz',
'please confirm offensive':"şikayetinizi onaylayın",
'anonymous users cannot flag offensive posts':'üye girişi yapmadan şikayet gönderemezsiniz',
'cannot flag message as offensive twice':'şikayet mesajı olarak iki kez işaretlemelisiniz',
@@ -202,17 +185,13 @@ var i18nTr = {
};
var i18nEs = {
+ "anonymous users cannot vote":"usuarios anónimos no pueden votar",
'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',
@@ -271,21 +250,17 @@ var i18nEs = {
};
var i18nDe = {
- '>100 points required to downvote': 'Negativ bewerten benötigt mindestens 100 Punkte',
- '>15 points requried to upvote': 'Positiv bewerten benötigt mindestens 15 Punkte',
+ "anonymous users cannot vote":"Gastbenutzer können nicht abstimmen ",
'add a comment': 'Kommentar hinzufügen',
'add comment': 'OK',
'anonymous users cannot delete/undelete': 'Gastbenutzer können Beiträge nicht löschen oder wiederherstellen',
'anonymous users cannot flag offensive posts': 'Gastbenutzer können Beiträge nicht melden',
'anonymous users cannot select favorite questions': 'Gastbenutzer können keine Fragen als Favoriten markieren',
- 'anonymous users cannot vote': 'Gastbenutzer können nicht abstimmen',
'bold': 'Fett',
'bulleted list': 'Liste',
'can write': 'Noch ',
'cannot flag message as offensive twice': 'Beiträge können nicht doppelt gemeldet werden',
'cannot pick own answer as best': 'Eigene Antworten können nicht als die korrekte akzeptiert werden',
- 'cannot revoke old vote': 'Bewertung kann nicht mehr zurückgenommen werden',
- 'cannot vote for own posts': 'Über selbst verfaßte Beiträge kann nicht abgestimmt werden',
'characters': 'Zeichen',
'click to close': 'Schließen mit Klick',
'comments': 'Kommentare',
@@ -341,22 +316,18 @@ var i18nDe = {
var i18nRu = {
- '>100 points required to downvote': 'для понижения рейтинга требуется минимум 100 баллов',
- '>15 points requried to upvote': 'для повышения рейтинга требуется минимум 15 баллов',
+ "anonymous users cannot vote": "неавторизированные пользователи не могут голосовать ",
'add a comment': 'добавить комментарий',
'add comment': 'добавить комментарий',
'anonymous users cannot delete/undelete': 'неавторизированные пользователи не могут восстанавливать и удалять сообщения',
'anonymous users cannot flag offensive posts': 'неавторизированные пользователи не могут пожаловаться на сообщение',
'anonymous users cannot select favorite questions': 'неавторизированные пользователи не могут добавлять вопросы в закладки',
- 'anonymous users cannot vote': 'неавторизированные пользователи не могут голосовать',
'answers/': 'ответы/',
'bold': 'жирный',
'bulleted list': 'список',
'can write': 'пишите',
'cannot flag message as offensive twice': 'нельзя отметить сообщение как спам два раза',
'cannot pick own answer as best': 'нельзя выбрать собственный ответ в качестве лучшего',
- 'cannot revoke old vote': 'голос не может быть отозван',
- 'cannot vote for own posts': 'нельзя голосовать за собственные сообщения',
'characters': 'символы',
'click to close': 'нажмите, что бы закрыть',
'comments': 'комментарии',
diff --git a/askbot/skins/default/media/js/com.cnprog.post.js b/askbot/skins/default/media/js/com.cnprog.post.js
index 7cc14e67..90956d9e 100755
--- a/askbot/skins/default/media/js/com.cnprog.post.js
+++ b/askbot/skins/default/media/js/com.cnprog.post.js
@@ -57,16 +57,13 @@ var Vote = function(){
var pleaseLogin = "<a href='" + scriptUrl + $.i18n._("account/") + $.i18n._("signin/")
+ "?next=" + scriptUrl + $.i18n._("question/") + "{{QuestionID}}/{{questionSlug}}'>"
- + $.i18n._('please login') + "</a>";
+ + $.i18n._('please login') + "</a>";
var pleaseSeeFAQ = $.i18n._('please see') + "<a href='" + scriptUrl + $.i18n._("faq/") + "'>faq</a>";
var favoriteAnonymousMessage = $.i18n._('anonymous users cannot select favorite questions');
var voteAnonymousMessage = $.i18n._('anonymous users cannot vote') + pleaseLogin;
- var upVoteRequiredScoreMessage = $.i18n._('>15 points requried to upvote') + pleaseSeeFAQ;
- var downVoteRequiredScoreMessage = $.i18n._('>100 points required to downvote') + pleaseSeeFAQ;
- var voteOwnDeniedMessage = $.i18n._('cannot vote for own posts');
- var voteRequiredMoreVotes = $.i18n._('daily vote cap exhausted') + pleaseSeeFAQ;
+ //there were a couple of more messages...
var voteDenyCancelMessage = $.i18n._('cannot revoke old vote') + pleaseSeeFAQ;
var offensiveConfirmation = $.i18n._('please confirm offensive');
var offensiveAnonymousMessage = $.i18n._('anonymous users cannot flag offensive posts') + pleaseLogin;
@@ -235,6 +232,7 @@ var Vote = function(){
};
var submit = function(object, voteType, callback) {
+ //this function submits votes
$.ajax({
type: "POST",
cache: false,
@@ -305,27 +303,25 @@ var Vote = function(){
};
var callback_vote = function(object, voteType, data){
- if(data.allowed == "0" && data.success == "0"){
- showMessage(object, voteAnonymousMessage.replace("{{QuestionID}}", questionId));
- }
- else if (data.allowed == "-3"){
- showMessage(object, voteRequiredMoreVotes);
+ if (data.success == '0'){
+ showMessage(object, data.message);
+ return;
}
- else if (data.allowed == "-2"){
- if (voteType == VoteType.questionUpVote || voteType == VoteType.answerUpVote){
- showMessage(object, upVoteRequiredScoreMessage);
+ else {
+ if (data.status == '1'){
+ setVoteImage(voteType, true, object);
}
- else if (voteType == VoteType.questionDownVote || voteType == VoteType.answerDownVote){
- showMessage(object, downVoteRequiredScoreMessage);
+ else {
+ setVoteImage(voteType, false, object);
}
+ setVoteNumber(object, data.count);
+ if (data.message.length > 0){
+ showMessage(object, data.message);
+ }
+ return;
}
- else if (data.allowed == "-1"){
- showMessage(object, voteOwnDeniedMessage);
- }
- else if (data.status == "2"){
- showMessage(object, voteDenyCancelMessage);
- }
- else if (data.status == "1"){
+ //may need to take a look at this again
+ if (data.status == "1"){
setVoteImage(voteType, true, object);
setVoteNumber(object, data.count);
}
@@ -389,12 +385,12 @@ var Vote = function(){
bindEvents();
},
- // Accept answer public function
+ //accept answer
accept: function(object){
postId = object.attr("id").substring(imgIdPrefixAccept.length);
submit(object, VoteType.acceptAnswer, callback_accept);
},
-
+ //mark question as favorite
favorite: function(object){
if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
showMessage(object, favoriteAnonymousMessage.replace("{{QuestionID}}", questionId));
@@ -405,9 +401,9 @@ var Vote = function(){
vote: function(object, voteType){
if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
- showMessage(object, voteAnonymousMessage.replace("{{QuestionID}}", questionId).replace("{{questionSlug}}", questionSlug));
- return false;
+ showMessage($(object), voteAnonymousMessage);
}
+ // up and downvote processor
if (voteType == VoteType.answerUpVote){
postId = object.attr("id").substring(imgIdPrefixAnswerVoteup.length);
}
@@ -417,7 +413,7 @@ var Vote = function(){
submit(object, voteType, callback_vote);
},
-
+ //flag offensive
offensive: function(object, voteType){
if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
showMessage($(object), offensiveAnonymousMessage.replace("{{QuestionID}}", questionId));
@@ -428,7 +424,7 @@ var Vote = function(){
submit(object, voteType, callback_offensive);
}
},
-
+ //delete question or answer (comments are deleted separately)
remove: function(object, voteType){
if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
showMessage($(object), removeAnonymousMessage.replace("{{QuestionID}}", questionId));
diff --git a/askbot/utils/decorators.py b/askbot/utils/decorators.py
index 3813d358..8c88e426 100644
--- a/askbot/utils/decorators.py
+++ b/askbot/utils/decorators.py
@@ -1,6 +1,7 @@
import hotshot
import time
import os
+import datetime
import functools
from django.conf import settings
from django.http import HttpResponse, HttpResponseForbidden, Http404
diff --git a/askbot/views/commands.py b/askbot/views/commands.py
index 1d9f9173..0ddfc36e 100644
--- a/askbot/views/commands.py
+++ b/askbot/views/commands.py
@@ -23,6 +23,61 @@ from django.contrib.auth.decorators import login_required
from askbot.utils.decorators import ajax_method, ajax_login_required
import logging
+def process_vote(user = None, vote_direction = None, post = None):
+ """function (non-view) that actually processes user votes
+ - i.e. up- or down- votes
+
+ in the future this needs to be converted into a real view function
+ for that url and javascript will need to be adjusted
+
+ also in the future make keys in response data be more meaningful
+ right now they are kind of cryptic - "status", "count"
+ """
+
+ if user.is_anonymous():
+ raise PermissionError(_('anonymous users cannot vote'))
+
+ user.assert_can_vote_for_post(
+ post = post,
+ direction = vote_direction
+ )
+
+ vote = user.get_old_vote_for_post(post)
+ response_data = {}
+ if vote != None:
+ user.assert_can_revoke_old_vote(vote)
+ score_delta = vote.cancel()
+ response_data['count'] = post.score + score_delta
+ response_data['status'] = 1 #this means "cancel"
+
+ else:
+ #this is a new vote
+ votes_left = user.get_unused_votes_today()
+ if votes_left <= 0:
+ raise PermissionError(
+ _('Sorry you ran out of votes for today')
+ )
+
+ votes_left -= 1
+ if votes_left <= \
+ askbot_settings.VOTES_LEFT_WARNING_THRESHOLD:
+ msg = _('You have %(votes_left)s votes left for today') \
+ % {'votes_left': votes_left }
+ response_data['message'] = msg
+
+ if vote_direction == 'up':
+ vote = user.upvote(post = post)
+ else:
+ vote = user.downvote(post = post)
+
+ response_data['count'] = post.score
+ response_data['status'] = 0 #this means "not cancel", normal operation
+
+ response_data['success'] = 1
+
+ return response_data
+
+
def vote(request, id):
"""
todo: this subroutine needs serious refactoring it's too long and is hard to understand
@@ -44,7 +99,7 @@ def vote(request, id):
accept answer code:
response_data['allowed'] = -1, Accept his own answer 0, no allowed - Anonymous 1, Allowed - by default
response_data['success'] = 0, failed 1, Success - by default
- response_data['status'] = 0, By default 1, Answer has been accepted already(Cancel)
+ response_data['status'] = 0, By default 1, Answer has been accepted already(Cancel)
vote code:
allowed = -3, Don't have enough votes left
@@ -72,23 +127,81 @@ def vote(request, id):
"message" : ''
}
- def __can_vote(vote_score, user):#refactor - belongs to auth.py
- if vote_score == 1:#refactor magic number
- return auth.can_vote_up(request.user)
+ try:
+ if request.is_ajax() and request.method == 'POST':
+ vote_type = request.POST.get('type')
else:
- return auth.can_vote_down(request.user)
+ raise Exception(_('Sorry, something is not right here...'))
- try:
- if not request.user.is_authenticated():
- response_data['allowed'] = 0
- response_data['success'] = 0
+ if vote_type == '0':
+ if request.user.is_authenticated():
+ answer_id = request.POST.get('postId')
+ answer = get_object_or_404(Answer, id=answer_id)
+ question = answer.question
+ # make sure question author is current user
+ if question.author == request.user:
+ # answer user who is also question author is not allow to accept answer
+ if answer.author == question.author:
+ response_data['success'] = 0
+ response_data['allowed'] = -1
+ # check if answer has been accepted already
+ elif answer.accepted:
+ auth.onAnswerAcceptCanceled(answer, request.user)
+ response_data['status'] = 1
+ else:
+ # set other answers in this question not accepted first
+ for answer_of_question in Answer.objects.get_answers_from_question(question, request.user):
+ if answer_of_question != answer and answer_of_question.accepted:
+ auth.onAnswerAcceptCanceled(answer_of_question, request.user)
+
+ #make sure retrieve data again after above author changes, they may have related data
+ answer = get_object_or_404(Answer, id=answer_id)
+ auth.onAnswerAccept(answer, request.user)
+ else:
+ raise Exception(
+ 'Sorry, only question owner can accept the answer'
+ )
+ else:
+ raise Exception(
+ _('Sorry, but anonymous users cannot accept answers')
+ )
+
+ elif vote_type in ('1', '2', '5', '6'):#Q&A up/down votes
+
+ ###############################
+ # all this can be avoided with
+ # better query parameters
+ vote_direction = 'up'
+ if vote_type in ('2','6'):
+ vote_direction = 'down'
+
+ if vote_type in ('5', '6'):
+ #todo: fix this weirdness - why postId here
+ #and not with question?
+ id = request.POST.get('postId')
+ post = get_object_or_404(Answer, id=id)
+ else:
+ post = get_object_or_404(Question, id=id)
+ #
+ ######################
+
+ response_data = process_vote(
+ user = request.user,
+ vote_direction = vote_direction,
+ post = post
+ )
elif request.is_ajax() and request.method == 'POST':
+
+ if not request.user.is_authenticated():
+ response_data['allowed'] = 0
+ response_data['success'] = 0
+
question = get_object_or_404(Question, id=id)
vote_type = request.POST.get('type')
#accept answer
- if vote_type == '0':
+ if vote_type == '00':
answer_id = request.POST.get('postId')
answer = get_object_or_404(Answer, id=answer_id)
# make sure question author is current user
@@ -122,65 +235,6 @@ def vote(request, id):
).count()
if fave == False:
response_data['status'] = 1
-
- elif vote_type in ['1', '2', '5', '6']:
- post_id = id
- post = question
- vote_score = 1
- if vote_type in ['5', '6']:
- answer_id = request.POST.get('postId')
- answer = get_object_or_404(Answer, id=answer_id)
- post_id = answer_id
- post = answer
- if vote_type in ['2', '6']:
- vote_score = -1
-
- if post.author == request.user:
- response_data['allowed'] = -1
- elif not __can_vote(vote_score, request.user):
- response_data['allowed'] = -2
- elif post.votes.filter(user=request.user).count() > 0:
- #todo: I think we have a bug here
- #we need to instead select vote on that particular post
- #not just the latest vote, although it is a good shortcut.
- #The problem is that this vote is deleted in one of
- #the on...Canceled() functions
- vote = post.votes.filter(user=request.user)[0]
- # get latest vote by the current user
- # unvote should be less than certain time
- if (datetime.datetime.now().day - vote.voted_at.day) \
- >= askbot_settings.MAX_DAYS_TO_CANCEL_VOTE:
- response_data['status'] = 2
- else:
- voted = vote.vote
- if voted > 0:
- # cancel upvote
- auth.onUpVotedCanceled(vote, post, request.user)
-
- else:
- # cancel downvote
- auth.onDownVotedCanceled(vote, post, request.user)
-
- response_data['status'] = 1
- response_data['count'] = post.score
- elif Vote.objects.get_votes_count_today_from_user(request.user)\
- >= askbot_settings.MAX_VOTES_PER_USER_PER_DAY:
- response_data['allowed'] = -3
- else:
- vote = Vote(user=request.user, content_object=post, vote=vote_score, voted_at=datetime.datetime.now())
- if vote_score > 0:
- # upvote
- auth.onUpVoted(vote, post, request.user)
- else:
- # downvote
- auth.onDownVoted(vote, post, request.user)
-
- votes_left = askbot_settings.MAX_VOTES_PER_USER_PER_DAY \
- - Vote.objects.get_votes_count_today_from_user(request.user)
- if votes_left <= \
- askbot_settings.VOTES_LEFT_WARNING_THRESHOLD:
- response_data['message'] = u'%s votes left' % votes_left
- response_data['count'] = post.score
elif vote_type in ['7', '8']:
post = question
post_id = id
@@ -249,6 +303,7 @@ def vote(request, id):
except Exception, e:
response_data['message'] = str(e)
+ response_data['success'] = 0
data = simplejson.dumps(response_data)
return HttpResponse(data, mimetype="application/json")