Switch to unified view

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]}})