-
Notifications
You must be signed in to change notification settings - Fork 0
/
tasks.py
154 lines (135 loc) · 5.84 KB
/
tasks.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
"""Definitions of Celery tasks in Askbot
in this module there are two types of functions:
* those wrapped with a @task decorator and a ``_celery_task`` suffix - celery tasks
* those with the same base name, but without the decorator and the name suffix
the actual work units run by the task
Celery tasks are special functions in a way that they require all the parameters
be serializable - so instead of ORM objects we pass object id's and
instead of query sets - lists of ORM object id's.
That is the reason for having two types of methods here:
* the base methods (those without the decorator and the
``_celery_task`` in the end of the name
are work units that are called from the celery tasks.
* celery tasks - shells that reconstitute the necessary ORM
objects and call the base methods
"""
import sys
import traceback
from django.contrib.contenttypes.models import ContentType
from celery.decorators import task
from askbot.models import Activity
from askbot.models import User
from askbot.models import send_instant_notifications_about_activity_in_post
# TODO: Make exceptions raised inside record_post_update_celery_task() ...
# ... propagate upwards to test runner, if only CELERY_ALWAYS_EAGER = True
# (i.e. if Celery tasks are not deferred but executed straight away)
@task(ignore_results = True)
def record_post_update_celery_task(
post_id,
post_content_type_id,
newly_mentioned_user_id_list = None,
updated_by_id = None,
timestamp = None,
created = False,
diff = None,
):
#reconstitute objects from the database
updated_by = User.objects.get(id = updated_by_id)
post_content_type = ContentType.objects.get(id = post_content_type_id)
post = post_content_type.get_object_for_this_type(id = post_id)
newly_mentioned_users = User.objects.filter(
id__in = newly_mentioned_user_id_list
)
try:
record_post_update(
post = post,
updated_by = updated_by,
newly_mentioned_users = newly_mentioned_users,
timestamp = timestamp,
created = created,
diff = diff
)
except Exception:
if 'test' in sys.argv:
# HACK: exceptions from Celery job don;t propagate upwards to Django test runner
# so at least le't sprint tracebacks
print >>sys.stderr, traceback.format_exc()
raise
def record_post_update(
post = None,
updated_by = None,
newly_mentioned_users = None,
timestamp = None,
created = False,
diff = None
):
"""Called when a post is updated. Arguments:
* ``newly_mentioned_users`` - users who are mentioned in the
post for the first time
* ``created`` - a boolean. True when ``post`` has just been created
* remaining arguments are self - explanatory
The method does two things:
* records "red envelope" recipients of the post
* sends email alerts to all subscribers to the post
"""
#todo: take into account created == True case
(activity_type, update_object) = post.get_updated_activity_data(created)
if post.is_comment():
#it's just a comment!
summary = post.text
else:
#summary = post.get_latest_revision().summary
summary = diff
update_activity = Activity(
user = updated_by,
active_at = timestamp,
content_object = post,
activity_type = activity_type,
question = post.get_origin_post(),
summary = summary
)
update_activity.save()
#what users are included depends on the post type
#for example for question - all Q&A contributors
#are included, for comments only authors of comments and parent
#post are included
recipients = post.get_response_receivers(
exclude_list = [updated_by, ]
)
update_activity.add_recipients(recipients)
#create new mentions
for u in newly_mentioned_users:
#todo: a hack - some users will not have record of a mention
#may need to fix this in the future. Added this so that
#recipients of the response who are mentioned as well would
#not get two notifications in the inbox for the same post
if u in recipients:
continue
Activity.objects.create_new_mention(
mentioned_whom = u,
mentioned_in = post,
mentioned_by = updated_by,
mentioned_at = timestamp
)
assert(updated_by not in recipients)
for user in (set(recipients) | set(newly_mentioned_users)):
user.update_response_counts()
#todo: weird thing is that only comments need the recipients
#todo: debug these calls and then uncomment in the repo
#argument to this call
notification_subscribers = post.get_instant_notification_subscribers(
potential_subscribers = recipients,
mentioned_users = newly_mentioned_users,
exclude_list = [updated_by, ]
)
#todo: fix this temporary spam protection plug
if created:
if not (updated_by.is_administrator() or updated_by.is_moderator()):
if updated_by.reputation < 15:
notification_subscribers = \
[u for u in notification_subscribers if u.is_administrator()]
send_instant_notifications_about_activity_in_post(
update_activity = update_activity,
post = post,
recipients = notification_subscribers,
)