forked from MapStory/mapstory-meta
-
Notifications
You must be signed in to change notification settings - Fork 0
/
social_signals.py
233 lines (199 loc) · 9 KB
/
social_signals.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
from django.db.models.signals import post_save
from django.db.models.signals import m2m_changed
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.template import loader
from django.core.files import File
from django.core.files.temp import NamedTemporaryFile
from geonode.maps.models import Layer
from geonode.maps.models import Map
from geonode.maps.models import map_changed_signal
from mapstory.models import PublishingStatus
from mapstory.models import ContactDetail
from mapstory.models import UserActivity
from mapstory.templatetags import mapstory_tags
from flag.signals import content_flagged
from dialogos.models import Comment
from agon_ratings.models import Rating
from mapstory.util import user
from mailer import send_html_mail
from social_auth.backends.facebook import FacebookBackend
from social_auth.backends.twitter import TwitterBackend
from social_auth.backends import google
import datetime
import urllib2
import re
from urlparse import urlparse
import logging
_logger = logging.getLogger('mapstory.social_signals')
def activity_summary(actions, plain_text=False):
sep = "\n" if plain_text else "<br/>"
return sep.join([mapstory_tags.activity_item(a, plain_text) for a in actions])
def batch_notification(days=1):
for u in User.objects.filter(useractivity__notification_preference='S'):
day_ago = datetime.datetime.now() - datetime.timedelta(days=days)
actions = u.useractivity.other_actor_actions.filter(timestamp__gte=day_ago)
if not actions: continue
_logger.info('sending %d notifications to %s', len(actions), u)
send_html_mail("[MapStory] Daily Summary Notification",
message=activity_summary(actions, plain_text=True),
message_html=activity_summary(actions),
from_email="do-not-reply@mapstory.org",
recipient_list=[u.email])
def notify_handler(sender, instance, action, model, pk_set, **kwargs):
if action != 'post_add': return
if instance.notification_preference != 'E':
return
assert len(pk_set) == 1
real_action = getattr(model,'objects').get(id=iter(pk_set).next())
send_html_mail("[MapStory] Notification",
message=mapstory_tags.activity_item(real_action, plain_text=True),
message_html=mapstory_tags.activity_item(real_action),
from_email="do-not-reply@mapstory.org",
recipient_list=[instance.user.email])
def action(actor, verb, action_object=None, target=None, public=True):
'''using the signal api doesn't give us a ref to the new action...'''
# this'll cause some circular dep problems...
from actstream.models import Action
newaction = Action(
actor_content_type=ContentType.objects.get_for_model(actor),
actor_object_id=actor.pk,
verb=unicode(verb),
public=public,
timestamp=datetime.datetime.now())
if action_object:
newaction.action_object = action_object
newaction.action_object_content_type = ContentType.objects.get_for_model(action_object)
if target:
newaction.target = target
newaction.target_content_type = ContentType.objects.get_for_model(target)
newaction.save()
return newaction
def _is_annotations_layer(obj):
if isinstance(obj, Layer):
from django.conf import settings # circular deps
for exc in settings.LAYER_EXCLUSIONS:
if re.search(exc, obj.name):
return True
return False
def action_handler(create_verb='created', update_verb='updated', provide_user=True):
def handler(sender, instance, created, **kwargs):
if created and not create_verb:
return
try:
publish = getattr(instance, 'publish', None)
except PublishingStatus.DoesNotExist:
publish = None
if publish and publish.status != 'Public':
return
active_verb = create_verb if created else update_verb
actor = instance
action_object = None
if provide_user:
actor = user()
if not actor or actor.is_anonymous():
# a non request caused this
return
action_object = instance
if _is_annotations_layer(action_object):
# for now, could create an action for the map
return
action(actor, verb=active_verb, action_object=action_object)
return handler
def register_save_handler(model, **kwargs):
handler = action_handler(**kwargs)
post_save.connect(handler, sender=model, weak=False)
def rating_handler(sender, instance, created, **kwargs):
actor = instance.user
target = instance.content_object
act = action(actor, verb='rated', action_object=instance, target=target)
if actor != target.owner:
target.owner.useractivity.other_actor_actions.add(act)
def comment_handler(sender, instance, created, **kwargs):
actor = instance.author
if not actor: return
target = instance.content_object # object being commented on (map/layer)
parent = instance.parent # possible parent comment
if created:
verb = 'commented'
if parent:
verb = 'replied'
act = action(actor, verb=verb, action_object=instance, target=parent)
else:
act = action(actor, verb='edited', action_object=instance, target=target)
# track this activity - too expensive to query this out after the fact
# only track if the comment is
# a) on someone elses layer/map or
if actor != target.owner:
target.owner.useractivity.other_actor_actions.add(act)
# b) in reply to someone elses comment
elif parent and actor != parent.author:
parent.author.useractivity.other_actor_actions.add(act)
def publishing_handler(sender, instance, created, **kw):
if instance.status == 'Public':
what = instance.map or instance.layer
if _is_annotations_layer(what):
return
action(what.owner, 'published', action_object=what)
layers = getattr(what, 'local_layers', [])
for l in layers:
if l.owner != what.owner:
# make this hidden so it doesn't show up
act = action(what.owner, verb='published', action_object=l,
target=what, public=False)
# except here
l.owner.useractivity.other_actor_actions.add(act)
def map_handler(sender, what_changed, old, new, **kw):
if what_changed == 'layers' and sender.publish.status == 'Public':
added = old ^ new
layers = Layer.objects.filter(typename__in=added)
for l in layers:
act = action(sender.owner, verb='added', action_object=l,
target=sender)
# if the layer owner is not the map owner, tell the layer owner
if l.owner != sender.owner:
l.owner.useractivity.other_actor_actions.add(act)
def flag_handler(flagged_instance, flagged_content, **kw):
target = flagged_content.content_object
get_absolute_url = getattr(target, 'get_absolute_url', None)
recps = User.objects.filter(is_staff=True).exclude(email='').exclude(email__isnull=True)
link = get_absolute_url() if get_absolute_url else ''
message = loader.render_to_string("flag/email.txt", {
'flag' : flagged_instance,
'url' : link,
'display' : '%s[%s]' % (target._meta.object_name, target.id)
})
for u in recps:
u.email_user('mapstory flagged content', message)
def get_user_avatar(backend, details, response, social_user, uid,\
user, *args, **kwargs):
url = None
if backend.__class__ == FacebookBackend:
url = "http://graph.facebook.com/%s/picture?type=large" % response['id']
elif backend.__class__ == TwitterBackend:
url = response.get('profile_image_url', '').replace('_normal', '')
elif backend.__class__ == google.GoogleOAuth2Backend and "picture" in response:
url = response["picture"]
if url:
name = urlparse(url).path.split('/')[-1]
img_temp = NamedTemporaryFile(delete=True)
img_temp.write(urllib2.urlopen(url).read())
img_temp.flush()
try:
a = user.avatar_set.get()
except:
a = user.avatar_set.model(user=user)
a.avatar.save(name, File(img_temp))
user.avatar_set.add(a)
def audit_user(backend, details, response, social_user, uid,\
user, *args, **kwargs):
user.get_profile().update_audit()
register_save_handler(ContactDetail, create_verb='joined MapStory', provide_user=False)
register_save_handler(Layer, create_verb='uploaded')
register_save_handler(Map)
map_changed_signal.connect(map_handler)
post_save.connect(publishing_handler, sender=PublishingStatus)
post_save.connect(rating_handler, sender=Rating)
post_save.connect(comment_handler, sender=Comment)
m2m_changed.connect(notify_handler, sender=UserActivity.other_actor_actions.through)
content_flagged.connect(flag_handler)