16 except ImportError: |
16 except ImportError: |
17 def gethostname(): # gae |
17 def gethostname(): # gae |
18 return 'XXX' |
18 return 'XXX' |
19 |
19 |
20 from logilab.common.textutils import normalize_text |
20 from logilab.common.textutils import normalize_text |
21 from logilab.common.deprecation import class_renamed |
21 |
22 |
22 from cubicweb.selectors import yes |
23 from cubicweb import RegistryException |
|
24 from cubicweb.selectors import implements, yes |
|
25 from cubicweb.view import EntityView, Component |
23 from cubicweb.view import EntityView, Component |
26 from cubicweb.common.mail import format_mail |
24 from cubicweb.common.mail import format_mail |
27 |
25 |
28 from cubicweb.server.pool import PreCommitOperation |
|
29 from cubicweb.server.hookhelper import SendMailOp |
26 from cubicweb.server.hookhelper import SendMailOp |
30 from cubicweb.server.hooksmanager import Hook |
|
31 |
27 |
32 |
28 |
33 class RecipientsFinder(Component): |
29 class RecipientsFinder(Component): |
34 """this component is responsible to find recipients of a notification |
30 """this component is responsible to find recipients of a notification |
35 |
31 |
53 lang = self.vreg.property_value('ui.language') |
49 lang = self.vreg.property_value('ui.language') |
54 dests = zip(self.req.vreg.config['default-dest-addrs'], repeat(lang)) |
50 dests = zip(self.req.vreg.config['default-dest-addrs'], repeat(lang)) |
55 else: # mode == 'none' |
51 else: # mode == 'none' |
56 dests = [] |
52 dests = [] |
57 return dests |
53 return dests |
58 |
|
59 |
|
60 # hooks ####################################################################### |
|
61 |
|
62 class RenderAndSendNotificationView(PreCommitOperation): |
|
63 """delay rendering of notification view until precommit""" |
|
64 def precommit_event(self): |
|
65 if self.view.rset and self.view.rset[0][0] in self.session.transaction_data.get('pendingeids', ()): |
|
66 return # entity added and deleted in the same transaction |
|
67 self.view.render_and_send(**getattr(self, 'viewargs', {})) |
|
68 |
|
69 class StatusChangeHook(Hook): |
|
70 """notify when a workflowable entity has its state modified""" |
|
71 events = ('after_add_entity',) |
|
72 accepts = ('TrInfo',) |
|
73 |
|
74 def call(self, session, entity): |
|
75 if not entity.from_state: # not a transition |
|
76 return |
|
77 rset = entity.related('wf_info_for') |
|
78 try: |
|
79 view = session.vreg['views'].select('notif_status_change', session, |
|
80 rset=rset, row=0) |
|
81 except RegistryException: |
|
82 return |
|
83 comment = entity.printable_value('comment', format='text/plain') |
|
84 if comment: |
|
85 comment = normalize_text(comment, 80, |
|
86 rest=entity.comment_format=='text/rest') |
|
87 RenderAndSendNotificationView(session, view=view, viewargs={ |
|
88 'comment': comment, 'previous_state': entity.previous_state.name, |
|
89 'current_state': entity.new_state.name}) |
|
90 |
|
91 |
|
92 class RelationChangeHook(Hook): |
|
93 events = ('before_add_relation', 'after_add_relation', |
|
94 'before_delete_relation', 'after_delete_relation') |
|
95 accepts = ('Any',) |
|
96 def call(self, session, fromeid, rtype, toeid): |
|
97 """if a notification view is defined for the event, send notification |
|
98 email defined by the view |
|
99 """ |
|
100 rset = session.eid_rset(fromeid) |
|
101 vid = 'notif_%s_%s' % (self.event, rtype) |
|
102 try: |
|
103 view = session.vreg['views'].select(vid, session, rset=rset, row=0) |
|
104 except RegistryException: |
|
105 return |
|
106 RenderAndSendNotificationView(session, view=view) |
|
107 |
|
108 |
|
109 class EntityChangeHook(Hook): |
|
110 events = ('after_add_entity', |
|
111 'after_update_entity') |
|
112 accepts = ('Any',) |
|
113 def call(self, session, entity): |
|
114 """if a notification view is defined for the event, send notification |
|
115 email defined by the view |
|
116 """ |
|
117 rset = entity.as_rset() |
|
118 vid = 'notif_%s' % self.event |
|
119 try: |
|
120 view = session.vreg['views'].select(vid, session, rset=rset, row=0) |
|
121 except RegistryException: |
|
122 return |
|
123 RenderAndSendNotificationView(session, view=view) |
|
124 |
54 |
125 |
55 |
126 # abstract or deactivated notification views and mixin ######################## |
56 # abstract or deactivated notification views and mixin ######################## |
127 |
57 |
128 class NotificationView(EntityView): |
58 class NotificationView(EntityView): |
294 def subject(self): |
224 def subject(self): |
295 entity = self.rset.get_entity(self.row or 0, self.col or 0) |
225 entity = self.rset.get_entity(self.row or 0, self.col or 0) |
296 return u'%s #%s (%s)' % (self.req.__('New %s' % entity.e_schema), |
226 return u'%s #%s (%s)' % (self.req.__('New %s' % entity.e_schema), |
297 entity.eid, self.user_login()) |
227 entity.eid, self.user_login()) |
298 |
228 |
|
229 from logilab.common.deprecation import class_renamed, class_moved |
299 NormalizedTextView = class_renamed('NormalizedTextView', ContentAddedView) |
230 NormalizedTextView = class_renamed('NormalizedTextView', ContentAddedView) |
|
231 from cubicweb.hooks.notification import RenderAndSendNotificationView |
|
232 RenderAndSendNotificationView = class_moved(RenderAndSendNotificationView) |