summaryrefslogtreecommitdiffstats
path: root/askbot/tasks.py
blob: 465465ef4fedd8ebcd446031cf6bb40e379ac0b7 (plain)
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
"""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
"""
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

@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
                            )

    record_post_update(
        post = post,
        updated_by = updated_by,
        newly_mentioned_users = newly_mentioned_users,
        timestamp = timestamp,
        created = created,
        diff = diff
    )

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.post_type != 'comment':
        #summary = post.get_latest_revision().summary
        summary = diff
    else:
        #it's just a comment!
        summary = post.comment

    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,
                        )