]> git.openstreetmap.org Git - osqa.git/blob - forum/actions/meta.py
fix breach in award points that allows user to award infinite points
[osqa.git] / forum / actions / meta.py
1 from django.utils.translation import ugettext as _
2 from django.db.models import F
3 from forum.models.action import ActionProxy, DummyActionProxy
4 from forum.models import Vote, Flag
5 from forum import settings
6
7 class VoteAction(ActionProxy):
8     def update_node_score(self, inc):
9         self.node.score = F('score') + inc
10         self.node.save()
11
12     def process_vote_action(self, value):
13         self.update_node_score(value)
14         vote = Vote(node=self.node, user=self.user, action=self, value=value)
15         vote.save()
16
17     def cancel_action(self):
18         vote = self.vote
19         self.update_node_score(-vote.value)
20         vote.delete()
21
22     @classmethod
23     def get_for(cls, user, node):
24         try:
25             vote = Vote.objects.get(user=user, node=node)
26             return vote.value
27         except:
28             return None
29
30     @classmethod
31     def get_action_for(cls, user, node):
32         try:
33             vote = Vote.objects.get(user=user, node=node)
34             return vote.action
35         except:
36             return None
37
38     def describe_vote(self, vote_desc, viewer=None):
39         return _("%(user)s %(vote_desc)s %(post_desc)s") % {
40             'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
41             'vote_desc': vote_desc, 'post_desc': self.describe_node(viewer, self.node)
42         }
43
44
45 class VoteUpAction(VoteAction):
46     def repute_users(self):
47         self.repute(self.node.author, int(settings.REP_GAIN_BY_UPVOTED))
48
49     def process_action(self):
50         self.process_vote_action(1)
51         self.user.reset_vote_up_count_cache()
52
53     def cancel_action(self):
54         super(VoteUpAction, self).cancel_action()
55         self.user.reset_vote_up_count_cache()
56
57     def describe(self, viewer=None):
58         return self.describe_vote(_("voted up"), viewer)
59
60 class VoteDownAction(VoteAction):
61     def repute_users(self):
62         self.repute(self.node.author, -int(settings.REP_LOST_BY_DOWNVOTED))
63         self.repute(self.user, -int(settings.REP_LOST_BY_DOWNVOTING))
64
65     def process_action(self):
66         self.process_vote_action(-1)
67         self.user.reset_vote_down_count_cache()
68
69     def cancel_action(self):
70         super(VoteDownAction, self).cancel_action()
71         self.user.reset_vote_down_count_cache()
72
73     def describe(self, viewer=None):
74         return self.describe_vote(_("voted down"), viewer)
75
76
77 class VoteUpCommentAction(VoteUpAction):
78     def repute_users(self):
79         pass
80
81     def process_action(self):
82         self.process_vote_action(1)
83
84     def cancel_action(self):
85         super(VoteUpAction, self).cancel_action()
86
87     def describe(self, viewer=None):
88         return self.describe_vote(_("liked"), viewer)
89
90
91 class FlagAction(ActionProxy):
92     def repute_users(self):
93         self.repute(self.node.author, -int(settings.REP_LOST_BY_FLAGGED))
94
95     def process_action(self):
96         flag = Flag(user=self.user, node=self.node, action=self, reason=self.extra)
97         flag.save()
98         self.node.reset_flag_count_cache()
99
100         if self.node.flag_count >= int(settings.FLAG_COUNT_TO_HIDE_POST):
101             self.repute(self.node.author, -int(settings.REP_LOST_BY_FLAGGED_3_TIMES))
102
103         if self.node.flag_count >= int(settings.FLAG_COUNT_TO_DELETE_POST):
104             self.repute(self.node.author, -int(settings.REP_LOST_BY_FLAGGED_5_TIMES))
105             if not self.node.nis.deleted:
106                 DeleteAction(node=self.node, user=self.user, extra="BYFLAGGED").save()
107
108     def cancel_action(self):
109         self.flag.delete()
110         self.node.reset_flag_count_cache()
111
112     @classmethod
113     def get_for(cls, user, node):
114         try:
115             flag = Flag.objects.get(user=user, node=node)
116             return flag.reason or _("No reason given")
117         except:
118             return None
119
120     def describe(self, viewer=None):
121         return _("%(user)s flagged %(post_desc)s: %(reason)s") % {
122             'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
123             'post_desc': self.describe_node(viewer, self.node), 'reason': self.extra
124         }
125
126
127 class AcceptAnswerAction(ActionProxy):
128     def repute_users(self):
129         if (self.user == self.node.parent.author) and (not self.user == self.node.author):
130             self.repute(self.user, int(settings.REP_GAIN_BY_ACCEPTING))
131
132         if self.user != self.node.author:
133             self.repute(self.node.author, int(settings.REP_GAIN_BY_ACCEPTED))
134
135     def process_action(self):
136         self.node.marked = True
137         self.node.nstate.accepted = self
138         self.node.save()
139         self.node.question.reset_accepted_count_cache()
140
141     def cancel_action(self):
142         self.node.marked = False
143         self.node.nstate.accepted = None
144         self.node.save()
145         self.node.question.reset_accepted_count_cache()
146
147     def describe(self, viewer=None):
148         answer = self.node
149         question = answer.parent
150
151         if self.user == question.author:
152             asker = (self.user == viewer) and _("your") or _("his")
153         else:
154             asker = self.hyperlink(question.author.get_profile_url(), question.author.username)
155
156         return _("%(user)s accepted %(answerer)s answer on %(asker)s question %(question)s") % {
157             'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
158             'answerer': self.hyperlink(answer.author.get_profile_url(), self.friendly_ownername(viewer, answer.author)),
159             'asker': asker,
160             'question': self.hyperlink(question.get_absolute_url(), question.title)
161         }
162
163
164 class FavoriteAction(ActionProxy):
165     def process_action(self):
166         self.node.reset_favorite_count_cache()
167
168     def cancel_action(self):
169         self.process_action()
170
171     def describe(self, viewer=None):
172         return _("%(user)s marked %(post_desc)s as favorite") % {
173             'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
174             'post_desc': self.describe_node(viewer, self.node),
175         }
176
177
178 class DeleteAction(ActionProxy):
179     def process_action(self):
180         self.node.mark_deleted(self)
181         
182         if self.node.node_type == "answer":
183             self.node.question.reset_answer_count_cache()
184
185     def cancel_action(self):
186         self.node.mark_deleted(None)
187
188         if self.node.node_type == "answer":
189             self.node.question.reset_answer_count_cache()
190
191     def describe(self, viewer=None):
192         return _("%(user)s deleted %(post_desc)s") % {
193             'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
194             'post_desc': self.describe_node(viewer, self.node)
195         }
196
197     def reason(self):
198         if self.extra != "BYFLAGGED":
199             return self.extra
200         else:
201             return _("flagged by multiple users: ") + "; ".join([f.extra for f in FlagAction.objects.filter(node=self.node)])
202
203 class UnknownAction(ActionProxy):
204     pass
205
206
207 class QuestionViewAction(DummyActionProxy):
208     def __init__(self, node, user, ip=None):
209         self.viewuser = user
210         self.node = node
211         super(QuestionViewAction, self).__init__(ip)
212
213     def process_action(self):
214         self.node.extra_count = F('extra_count') + 1
215         self.node.save()