Page Menu
Home
Search
Configure Global Search
Log In
Files
F13101230
activities.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
7 KB
Subscribers
None
activities.py
View Options
import
logging
from
flask
import
g
,
request
,
current_app
from
pillar.api.utils
import
gravatar
log
=
logging
.
getLogger
(
__name__
)
def
notification_parse
(
notification
):
activities_collection
=
current_app
.
data
.
driver
.
db
[
'activities'
]
activities_subscriptions_collection
=
\
current_app
.
data
.
driver
.
db
[
'activities-subscriptions'
]
users_collection
=
current_app
.
data
.
driver
.
db
[
'users'
]
nodes_collection
=
current_app
.
data
.
driver
.
db
[
'nodes'
]
activity
=
activities_collection
.
find_one
({
'_id'
:
notification
[
'activity'
]})
if
activity
is
None
or
activity
[
'object_type'
]
!=
'node'
:
return
node
=
nodes_collection
.
find_one
({
'_id'
:
activity
[
'object'
]})
if
not
node
:
# This can happen when a notification is generated and then the
# node is deleted.
return
# Initial support only for node_type comments
if
node
[
'node_type'
]
!=
'comment'
:
return
node
[
'parent'
]
=
nodes_collection
.
find_one
({
'_id'
:
node
[
'parent'
]})
object_type
=
'comment'
object_name
=
''
object_id
=
activity
[
'object'
]
if
node
[
'parent'
][
'user'
]
==
g
.
current_user
[
'user_id'
]:
owner
=
"your {0}"
.
format
(
node
[
'parent'
][
'node_type'
])
else
:
parent_comment_user
=
users_collection
.
find_one
(
{
'_id'
:
node
[
'parent'
][
'user'
]})
if
parent_comment_user
[
'_id'
]
==
node
[
'user'
]:
user_name
=
'their'
else
:
user_name
=
"{0}'s"
.
format
(
parent_comment_user
[
'username'
])
owner
=
"{0} {1}"
.
format
(
user_name
,
node
[
'parent'
][
'node_type'
])
context_object_type
=
node
[
'parent'
][
'node_type'
]
context_object_name
=
owner
context_object_id
=
activity
[
'context_object'
]
if
activity
[
'verb'
]
==
'replied'
:
action
=
'replied to'
elif
activity
[
'verb'
]
==
'commented'
:
action
=
'left a comment on'
else
:
action
=
activity
[
'verb'
]
lookup
=
{
'user'
:
g
.
current_user
[
'user_id'
],
'context_object_type'
:
'node'
,
'context_object'
:
context_object_id
,
}
subscription
=
activities_subscriptions_collection
.
find_one
(
lookup
)
if
subscription
and
subscription
[
'notifications'
][
'web'
]
==
True
:
is_subscribed
=
True
else
:
is_subscribed
=
False
# Parse user_actor
actor
=
users_collection
.
find_one
({
'_id'
:
activity
[
'actor_user'
]})
if
actor
:
parsed_actor
=
{
'username'
:
actor
[
'username'
],
'avatar'
:
gravatar
(
actor
[
'email'
])}
else
:
parsed_actor
=
None
updates
=
dict
(
_id
=
notification
[
'_id'
],
actor
=
parsed_actor
,
action
=
action
,
object_type
=
object_type
,
object_name
=
object_name
,
object_id
=
str
(
object_id
),
context_object_type
=
context_object_type
,
context_object_name
=
context_object_name
,
context_object_id
=
str
(
context_object_id
),
date
=
activity
[
'_created'
],
is_read
=
(
'is_read'
in
notification
and
notification
[
'is_read'
]),
is_subscribed
=
is_subscribed
,
subscription
=
subscription
[
'_id'
]
)
notification
.
update
(
updates
)
def
notification_get_subscriptions
(
context_object_type
,
context_object_id
,
actor_user_id
):
subscriptions_collection
=
current_app
.
data
.
driver
.
db
[
'activities-subscriptions'
]
lookup
=
{
'user'
:
{
"$ne"
:
actor_user_id
},
'context_object_type'
:
context_object_type
,
'context_object'
:
context_object_id
,
'is_subscribed'
:
True
,
}
return
subscriptions_collection
.
find
(
lookup
)
def
activity_subscribe
(
user_id
,
context_object_type
,
context_object_id
):
"""Subscribe a user to changes for a specific context. We create a subscription
if none is found.
:param user_id: id of the user we are going to subscribe
:param context_object_type: hardcoded index, check the notifications/model.py
:param context_object_id: object id, to be traced with context_object_type_id
"""
subscriptions_collection
=
current_app
.
data
.
driver
.
db
[
'activities-subscriptions'
]
lookup
=
{
'user'
:
user_id
,
'context_object_type'
:
context_object_type
,
'context_object'
:
context_object_id
}
subscription
=
subscriptions_collection
.
find_one
(
lookup
)
# If no subscription exists, we create one
if
not
subscription
:
current_app
.
post_internal
(
'activities-subscriptions'
,
lookup
)
def
activity_object_add
(
actor_user_id
,
verb
,
object_type
,
object_id
,
context_object_type
,
context_object_id
):
"""Add a notification object and creates a notification for each user that
- is not the original author of the post
- is actively subscribed to the object
This works using the following pattern:
ACTOR -> VERB -> OBJECT -> CONTEXT
:param actor_user_id: id of the user who is changing the object
:param verb: the action on the object ('commented', 'replied')
:param object_type: hardcoded name
:param object_id: object id, to be traced with object_type_id
"""
subscriptions
=
notification_get_subscriptions
(
context_object_type
,
context_object_id
,
actor_user_id
)
if
subscriptions
.
count
()
==
0
:
return
info
,
status
=
register_activity
(
actor_user_id
,
verb
,
object_type
,
object_id
,
context_object_type
,
context_object_id
)
if
status
!=
201
:
# If creation failed for any reason, do not create a any notifcation
return
for
subscription
in
subscriptions
:
notification
=
dict
(
user
=
subscription
[
'user'
],
activity
=
info
[
'_id'
])
current_app
.
post_internal
(
'notifications'
,
notification
)
def
register_activity
(
actor_user_id
,
verb
,
object_type
,
object_id
,
context_object_type
,
context_object_id
,
project_id
=
None
,
node_type
=
None
):
"""Registers an activity.
This works using the following pattern:
ACTOR -> VERB -> OBJECT -> CONTEXT
:param actor_user_id: id of the user who is changing the object
:param verb: the action on the object ('commented', 'replied')
:param object_type: hardcoded name, see database schema
:param object_id: object id, to be traced with object_type
:param context_object_type: the type of the context object, like 'project' or 'node',
see database schema
:param context_object_id:
:param project_id: optional project ID to make the activity easily queryable
per project.
:param node_type: optional, node type of the node receiving the activity.
:returns: tuple (info, status_code), where a successful operation should have
status_code=201. If it is not 201, a warning is logged.
"""
activity
=
{
'actor_user'
:
actor_user_id
,
'verb'
:
verb
,
'object_type'
:
object_type
,
'object'
:
object_id
,
'context_object_type'
:
context_object_type
,
'context_object'
:
context_object_id
}
if
project_id
:
activity
[
'project'
]
=
project_id
if
node_type
:
activity
[
'node_type'
]
=
node_type
info
,
_
,
_
,
status_code
=
current_app
.
post_internal
(
'activities'
,
activity
)
if
status_code
!=
201
:
log
.
error
(
'register_activity: code
%i
creating activity
%s
:
%s
'
,
status_code
,
activity
,
info
)
else
:
log
.
info
(
'register_activity: user
%s
"
%s
" on
%s
%s
, context
%s
%s
'
,
actor_user_id
,
verb
,
object_type
,
object_id
,
context_object_type
,
context_object_id
)
return
info
,
status_code
def
before_returning_item_notifications
(
response
):
if
request
.
args
.
get
(
'parse'
):
notification_parse
(
response
)
def
before_returning_resource_notifications
(
response
):
for
item
in
response
[
'_items'
]:
if
request
.
args
.
get
(
'parse'
):
notification_parse
(
item
)
def
setup_app
(
app
):
app
.
on_fetched_item_notifications
+=
before_returning_item_notifications
app
.
on_fetched_resource_notifications
+=
before_returning_resource_notifications
File Metadata
Details
Attached
Mime Type
text/x-python
Expires
Wed, May 25, 8:43 PM (2 d)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
11/b5/b73522c28be2ae5c139f44c92f44
Attached To
rPS Pillar
Event Timeline
Log In to Comment