|
a/Allura/allura/model/notification.py |
|
b/Allura/allura/model/notification.py |
|
... |
|
... |
18 |
|
18 |
|
19 |
import logging
|
19 |
import logging
|
20 |
from bson import ObjectId
|
20 |
from bson import ObjectId
|
21 |
from datetime import datetime, timedelta
|
21 |
from datetime import datetime, timedelta
|
22 |
from collections import defaultdict
|
22 |
from collections import defaultdict
|
23 |
from webhelpers import feedgenerator as FG
|
|
|
24 |
|
23 |
|
25 |
from pylons import c, g
|
24 |
from pylons import c, g
|
26 |
from tg import config
|
25 |
from tg import config
|
27 |
import pymongo
|
26 |
import pymongo
|
28 |
import jinja2
|
27 |
import jinja2
|
29 |
import markdown
|
|
|
30 |
|
28 |
|
31 |
from ming import schema as S
|
29 |
from ming import schema as S
|
32 |
from ming.orm import FieldProperty, ForeignIdProperty, RelationProperty, session
|
30 |
from ming.orm import FieldProperty, ForeignIdProperty, RelationProperty, session
|
33 |
from ming.orm.declarative import MappedClass
|
31 |
from ming.orm.declarative import MappedClass
|
34 |
|
32 |
|
35 |
from allura.lib.markdown_extensions import ForgeExtension
|
|
|
36 |
from allura.lib import helpers as h
|
33 |
from allura.lib import helpers as h
|
37 |
from allura.lib import security
|
34 |
from allura.lib import security
|
38 |
import allura.tasks.mail_tasks
|
35 |
import allura.tasks.mail_tasks
|
39 |
|
36 |
|
40 |
from .session import main_orm_session, project_orm_session
|
37 |
from .session import main_orm_session, project_orm_session
|
|
... |
|
... |
44 |
log = logging.getLogger(__name__)
|
41 |
log = logging.getLogger(__name__)
|
45 |
|
42 |
|
46 |
MAILBOX_QUIESCENT=None # Re-enable with [#1384]: timedelta(minutes=10)
|
43 |
MAILBOX_QUIESCENT=None # Re-enable with [#1384]: timedelta(minutes=10)
|
47 |
|
44 |
|
48 |
class Notification(MappedClass):
|
45 |
class Notification(MappedClass):
|
|
|
46 |
'''
|
|
|
47 |
Temporarily store notifications that will be emailed or displayed as a web flash.
|
|
|
48 |
'''
|
|
|
49 |
|
49 |
class __mongometa__:
|
50 |
class __mongometa__:
|
50 |
session = main_orm_session
|
51 |
session = main_orm_session
|
51 |
name = 'notification'
|
52 |
name = 'notification'
|
52 |
indexes = [ ('neighborhood_id', 'tool_name', 'pubdate'),
|
|
|
53 |
('author_id',), # used in ext/user_profile/user_main.py for user feeds
|
|
|
54 |
]
|
|
|
55 |
|
53 |
|
56 |
_id = FieldProperty(str, if_missing=h.gen_message_id)
|
54 |
_id = FieldProperty(str, if_missing=h.gen_message_id)
|
57 |
|
55 |
|
58 |
# Classify notifications
|
56 |
# Classify notifications
|
59 |
neighborhood_id = ForeignIdProperty('Neighborhood', if_missing=lambda:c.project.neighborhood._id)
|
57 |
neighborhood_id = ForeignIdProperty('Neighborhood', if_missing=lambda:c.project.neighborhood._id)
|
60 |
project_id = ForeignIdProperty('Project', if_missing=lambda:c.project._id)
|
58 |
project_id = ForeignIdProperty('Project', if_missing=lambda:c.project._id)
|
61 |
app_config_id = ForeignIdProperty('AppConfig', if_missing=lambda:c.app.config._id)
|
59 |
app_config_id = ForeignIdProperty('AppConfig', if_missing=lambda:c.app.config._id)
|
62 |
tool_name = FieldProperty(str, if_missing=lambda:c.app.config.tool_name)
|
60 |
tool_name = FieldProperty(str, if_missing=lambda:c.app.config.tool_name)
|
63 |
ref_id = ForeignIdProperty('ArtifactReference')
|
61 |
ref_id = ForeignIdProperty('ArtifactReference')
|
64 |
topic = FieldProperty(str)
|
62 |
topic = FieldProperty(str)
|
65 |
unique_id = FieldProperty(str, if_missing=lambda:h.nonce(40))
|
|
|
66 |
|
63 |
|
67 |
# Notification Content
|
64 |
# Notification Content
|
68 |
in_reply_to=FieldProperty(str)
|
65 |
in_reply_to=FieldProperty(str)
|
69 |
from_address=FieldProperty(str)
|
66 |
from_address=FieldProperty(str)
|
70 |
reply_to_address=FieldProperty(str)
|
67 |
reply_to_address=FieldProperty(str)
|
|
... |
|
... |
78 |
|
75 |
|
79 |
ref = RelationProperty('ArtifactReference')
|
76 |
ref = RelationProperty('ArtifactReference')
|
80 |
|
77 |
|
81 |
view = jinja2.Environment(
|
78 |
view = jinja2.Environment(
|
82 |
loader=jinja2.PackageLoader('allura', 'templates'))
|
79 |
loader=jinja2.PackageLoader('allura', 'templates'))
|
83 |
|
|
|
84 |
def author(self):
|
|
|
85 |
return User.query.get(_id=self.author_id) or User.anonymous()
|
|
|
86 |
|
80 |
|
87 |
@classmethod
|
81 |
@classmethod
|
88 |
def post(cls, artifact, topic, **kw):
|
82 |
def post(cls, artifact, topic, **kw):
|
89 |
'''Create a notification and send the notify message'''
|
83 |
'''Create a notification and send the notify message'''
|
90 |
import allura.tasks.notification_tasks
|
84 |
import allura.tasks.notification_tasks
|
|
... |
|
... |
185 |
n = cls(ref_id=artifact.index_id(),
|
179 |
n = cls(ref_id=artifact.index_id(),
|
186 |
topic=topic,
|
180 |
topic=topic,
|
187 |
link=kwargs.pop('link', artifact.url()),
|
181 |
link=kwargs.pop('link', artifact.url()),
|
188 |
**d)
|
182 |
**d)
|
189 |
return n
|
183 |
return n
|
190 |
|
|
|
191 |
@classmethod
|
|
|
192 |
def feed(cls, q, feed_type, title, link, description,
|
|
|
193 |
since=None, until=None, offset=None, limit=None):
|
|
|
194 |
"""Produces webhelper.feedgenerator Feed"""
|
|
|
195 |
d = dict(title=title, link=h.absurl(link), description=description, language=u'en')
|
|
|
196 |
if feed_type == 'atom':
|
|
|
197 |
feed = FG.Atom1Feed(**d)
|
|
|
198 |
elif feed_type == 'rss':
|
|
|
199 |
feed = FG.Rss201rev2Feed(**d)
|
|
|
200 |
query = defaultdict(dict)
|
|
|
201 |
query.update(q)
|
|
|
202 |
if since is not None:
|
|
|
203 |
query['pubdate']['$gte'] = since
|
|
|
204 |
if until is not None:
|
|
|
205 |
query['pubdate']['$lte'] = until
|
|
|
206 |
cur = cls.query.find(query)
|
|
|
207 |
cur = cur.sort('pubdate', pymongo.DESCENDING)
|
|
|
208 |
if limit is None: limit = 10
|
|
|
209 |
query = cur.limit(limit)
|
|
|
210 |
if offset is not None: query = cur.offset(offset)
|
|
|
211 |
for r in cur:
|
|
|
212 |
feed.add_item(title=r.subject,
|
|
|
213 |
link=h.absurl(r.link.encode('utf-8')),
|
|
|
214 |
pubdate=r.pubdate,
|
|
|
215 |
description=r.text,
|
|
|
216 |
unique_id=r.unique_id,
|
|
|
217 |
author_name=r.author().display_name,
|
|
|
218 |
author_link=h.absurl(r.author().url()))
|
|
|
219 |
return feed
|
|
|
220 |
|
184 |
|
221 |
def footer(self):
|
185 |
def footer(self):
|
222 |
template = self.view.get_template('mail/footer.txt')
|
186 |
template = self.view.get_template('mail/footer.txt')
|
223 |
return template.render(dict(
|
187 |
return template.render(dict(
|
224 |
notification=self,
|
188 |
notification=self,
|
|
... |
|
... |
515 |
notifications)
|
479 |
notifications)
|
516 |
elif self.type == 'summary':
|
480 |
elif self.type == 'summary':
|
517 |
Notification.send_summary(
|
481 |
Notification.send_summary(
|
518 |
self.user_id, u'noreply@in.sf.net', 'Digest Email',
|
482 |
self.user_id, u'noreply@in.sf.net', 'Digest Email',
|
519 |
notifications)
|
483 |
notifications)
|
|
|
484 |
# remove Notifications since they are no longer needed
|
|
|
485 |
Notification.query.remove({'_id': {'$in': [n._id for n in notifications]}})
|