def _members(self, type, event): settings = self._settings() # My Posts result = settings['my_posts'].get_user_setting(event.blog_post.author) if result[1]: yield ( 'email', event.blog_post.author, result[1], None, _('My Post') ) if event.category == 'post created': for result in settings['new_posts'].get_subscriptions(): yield result + (_('New Post'),) # Watched Author Posts def match(dist, value): for name in [i.strip() for i in value.split(',')]: if name == event.blog_post.author: return True return False for result in settings['author_posts'].get_subscriptions(match): yield result + (_('Author Post'),) # All for result in settings['all'].get_subscriptions(): yield result + (_('All Blog Events'),)
def post_process_request(self, req, template, data, content_type): if 'BLOG_VIEW' not in req.perm: return (template, data, content_type) if '_blog_watch_message_' in req.session: add_notice(req, req.session['_blog_watch_message_']) del req.session['_blog_watch_message_'] if req.authname == "anonymous": return (template, data, content_type) # FullBlogPlugin sets the blog_path arg in pre_process_request name = req.args.get('blog_path') if not name: return (template, data, content_type) klass = self.__class__.__name__ attrs = SubscriptionAttribute.find_by_sid_class_and_target( self.env, req.session.sid, req.session.authenticated, klass, name) if attrs: add_ctxtnav(req, tag.a(_('Unwatch This'), href=req.href.blog_watch(name))) else: add_ctxtnav(req, tag.a(_('Watch This'), href=req.href.blog_watch(name))) return (template, data, content_type)
def toggle_watched(self, sid, authenticated, realm, target, req=None): if self.is_watching(sid, authenticated, realm, target): self.set_unwatch(sid, authenticated, realm, target) self._schedule_notice(req, _("You are no longer receiving " "change notifications about this resource.")) else: self.set_watch(sid, authenticated, realm, target) self._schedule_notice(req, _("You are now receiving " "change notifications about this resource."))
def post_process_request(self, req, template, data, content_type): if 'BLOG_VIEW' not in req.perm: return (template, data, content_type) if '_blog_watch_message_' in req.session: add_notice(req, req.session['_blog_watch_message_']) del req.session['_blog_watch_message_'] if req.authname == "anonymous": return (template, data, content_type) # FullBlogPlugin sets the blog_path arg in pre_process_request name = req.args.get('blog_path') if not name: return (template, data, content_type) klass = self.__class__.__name__ attrs = SubscriptionAttribute.find_by_sid_class_and_target( self.env, req.session.sid, req.session.authenticated, klass, name) if attrs: add_ctxtnav( req, tag.a(_('Unwatch This'), href=req.href.blog_watch(name))) else: add_ctxtnav(req, tag.a(_('Watch This'), href=req.href.blog_watch(name))) return (template, data, content_type)
def toggle_watched(self, sid, authenticated, realm, target, req=None): if self.is_watching(sid, authenticated, realm, target): self.set_unwatch(sid, authenticated, realm, target) self._schedule_notice(req, _('You are no longer receiving ' \ 'change notifications about this resource.')) else: self.set_watch(sid, authenticated, realm, target) self._schedule_notice(req, _('You are now receiving ' \ 'change notifications about this resource.'))
def toggle_watched(self, sid, authenticated, resource, req=None): realm, resource = resource.split('/', 1) if self.is_watching(sid, authenticated, realm, resource): self.set_unwatch(sid, authenticated, realm, resource) self._schedule_notice(req, _('You are no longer receiving ' \ 'change notifications about this resource.')) else: self.set_watch(sid, authenticated, realm, resource) self._schedule_notice(req, _('You are now receiving ' \ 'change notifications about this resource.'))
def render_watcher(self, req): if not self.ctxtnav_names: return realm, target = self.path_info_to_realm_target(req.path_info) sess = req.session if self.is_watching(sess.sid, sess.authenticated, realm, target): action_name = len(self.ctxtnav_names) >= 2 and \ self.ctxtnav_names[1] or _("Unwatch This") else: action_name = self.ctxtnav_names and \ self.ctxtnav_names[0] or _("Watch This") add_ctxtnav(req, html.a(_(action_name), href=req.href.watch(realm, target)))
def do_update(db): attrs = SubscriptionAttribute.find_by_sid_class_and_target( self.env, req.session.sid, req.session.authenticated, klass, name) if attrs: SubscriptionAttribute.delete_by_sid_class_and_target( self.env, req.session.sid, req.session.authenticated, klass, name) req.session['_blog_watch_message_'] = \ _('You are no longer watching this blog post.') else: SubscriptionAttribute.add(self.env, req.session.sid, req.session.authenticated, klass, 'blog', (name, )) req.session['_blog_watch_message_'] = \ _('You are now watching this blog post.')
def do_update(db): attrs = SubscriptionAttribute.find_by_sid_class_and_target( self.env, req.session.sid, req.session.authenticated, klass, name) if attrs: SubscriptionAttribute.delete_by_sid_class_and_target( self.env, req.session.sid, req.session.authenticated, klass, name) req.session['_blog_watch_message_'] = \ _('You are no longer watching this blog post.') else: SubscriptionAttribute.add( self.env, req.session.sid, req.session.authenticated, klass, 'blog', (name,)) req.session['_blog_watch_message_'] = \ _('You are now watching this blog post.')
def send(self, from_addr, recipients, message): # use defaults to make sure connect() is called in the constructor smtpclass = smtplib.SMTP if self.use_ssl: smtpclass = smtplib.SMTP_SSL args = {'host': self.server, 'port': self.port} # timeout isn't supported until python 2.6 vparts = sys.version_info[0:2] if vparts[0] >= 2 and vparts[1] >= 6: args['timeout'] = self.timeout smtp = smtpclass(**args) smtp.set_debuglevel(self.debuglevel) if self.use_tls: smtp.ehlo() if not smtp.esmtp_features.has_key('starttls'): raise TracError(_("TLS enabled but server does not support " \ "TLS")) smtp.starttls() smtp.ehlo() if self.user: smtp.login(self.user.encode('utf-8'), self.password.encode('utf-8')) smtp.sendmail(from_addr, recipients, message) if self.use_tls or self.use_ssl: # avoid false failure detection when the server closes # the SMTP connection with TLS/SSL enabled import socket try: smtp.quit() except socket.sslerror: pass else: smtp.quit()
def _get_component_owner(self, event, ticket, setting): try: component = model.Component(self.env, ticket['component']) if component.owner: if setting.get_user_setting(component.owner)[1]: self._log_sub(component.owner, True, setting.name) return ('email', component.owner, True, None) except ResourceNotFound, message: self.log.warn(_("LegacyTicketSubscriber couldn't add " \ "component owner because component was not found, " \ "message: '%s'"%(message,)))
def _format_plaintext(self, event): page = event.target data = dict( action=event.category, attachment=event.attachment, page=page, author=event.author, comment=event.comment, category=event.category, page_link=self.env.abs_href('wiki', page.name), project_name=self.env.project_name, project_desc=self.env.project_description, project_link=self.env.project_url or self.env.abs_href(), ) old_page = WikiPage(self.env, page.name, page.version - 1) if page.version: data["changed"] = True data["diff_link"] = self.env.abs_href('wiki', page.name, action="diff", version=page.version) if self.wiki_email_diff: # DEVEL: Formatter needs req object to get preferred language. diff_header = _(""" Index: %(name)s ============================================================================== --- %(name)s (version: %(oldversion)s) +++ %(name)s (version: %(version)s) """) diff = "\n" diff += diff_header % { 'name': page.name, 'version': page.version, 'oldversion': page.version - 1 } for line in unified_diff(old_page.text.splitlines(), page.text.splitlines(), context=3): diff += "%s\n" % line data["diff"] = diff chrome = Chrome(self.env) dirs = [] for provider in chrome.template_providers: dirs += provider.get_templates_dirs() templates = TemplateLoader(dirs, variable_lookup='lenient') template = templates.load('wiki_email_plaintext.txt', cls=NewTextTemplate) if template: stream = template.generate(**data) output = stream.render('text') return output
def _format_plaintext(self, event): page = event.target data = dict( action=event.category, attachment=event.attachment, page=page, author=event.author, comment=event.comment, category=event.category, page_link=self.env.abs_href('wiki', page.name), project_name=self.env.project_name, project_desc=self.env.project_description, project_link=self.env.project_url or self.env.abs_href(), ) old_page = WikiPage(self.env, page.name, page.version - 1) if page.version: data['changed'] = True data['diff_link'] = self.env.abs_href('wiki', page.name, action='diff', version=page.version) if self.wiki_email_diff: # DEVEL: Formatter needs req object to get preferred language. diff_header = _(""" Index: %(name)s ============================================================================== --- %(name)s (version: %(oldversion)s) +++ %(name)s (version: %(version)s) """) diff = "\n" diff += diff_header % { 'name': page.name, 'version': page.version, 'oldversion': page.version - 1 } for line in unified_diff(old_page.text.splitlines(), page.text.splitlines(), context=3): diff += "%s\n" % line data['diff'] = diff chrome = Chrome(self.env) dirs = [] for provider in chrome.template_providers: dirs += provider.get_templates_dirs() templates = TemplateLoader(dirs, variable_lookup='lenient') template = templates.load('wiki_email_plaintext.txt', cls=NewTextTemplate) if template: stream = template.generate(**data) return stream.render('text')
def process_request(self, req): klass = self.__class__.__name__ m = re.match(r'^/blog_watch/(.*)', req.path_info) (name,) = m.groups() with self.env.db_transaction: attrs = SubscriptionAttribute.find_by_sid_class_and_target( self.env, req.session.sid, req.session.authenticated, klass, name) if attrs: SubscriptionAttribute.delete_by_sid_class_and_target( self.env, req.session.sid, req.session.authenticated, klass, name) req.session['_blog_watch_message_'] = \ _("You are no longer watching this blog post.") else: SubscriptionAttribute.add( self.env, req.session.sid, req.session.authenticated, klass, 'blog', (name,)) req.session['_blog_watch_message_'] = \ _("You are now watching this blog post.") req.redirect(req.href.blog(name))
def render_watcher(self, req): if not self.ctxtnav_names: return realm, target = self.path_info_to_realm_target(req.path_info) if self.is_watching(req.session.sid, req.session.authenticated, realm, target): action_name = len(self.ctxtnav_names) >= 2 and \ self.ctxtnav_names[1] or 'Unwatch This' else: action_name = len(self.ctxtnav_names) and \ self.ctxtnav_names[0] or 'Watch This' add_ctxtnav(req, tag.a( _(action_name), href=req.href.watch(realm, target) ) )
def render_watcher(self, req): if not self.ctxtnav_names: return resource = self.normalise_resource(req.path_info) parts = resource.split('/', 1) if len(parts) < 2: return realm, resource = parts if self.is_watching(req.session.sid, not req.authname == 'anonymous', realm, resource): action_name = len(self.ctxtnav_names) >= 2 and \ self.ctxtnav_names[1] or 'Unwatch This' else: action_name = len(self.ctxtnav_names) and \ self.ctxtnav_names[0] or 'Watch This' add_ctxtnav( req, tag.a(_(action_name), href=req.href.watch(realm, resource)))
def subscriptions(self, event): if event.realm == 'ticket': if event.category in ('created', 'changed', 'attachment added'): cc = event.target['cc'] or '' for chunk in re.split('\s|,', cc): chunk = chunk.strip() if not chunk or chunk.startswith('@'): continue if '@' in chunk: address = chunk name = None else: name = chunk address = None if name or address: self.log.debug(_("CarbonCopySubscriber added '%s " \ "<%s>' because of rule: carbon copied" \ %(name,address))) yield ('email', name, name and True or False, address)
def render_watcher(self, req): if not self.ctxtnav_names: return resource = self.normalise_resource(req.path_info) parts = resource.split('/', 1) if len(parts) < 2: return realm, resource = parts if self.is_watching(req.session.sid, not req.authname == 'anonymous', realm, resource): action_name = len(self.ctxtnav_names) >= 2 and \ self.ctxtnav_names[1] or 'Unwatch This' else: action_name = len(self.ctxtnav_names) and \ self.ctxtnav_names[0] or 'Watch This' add_ctxtnav(req, tag.a( _(action_name), href=req.href.watch(realm, resource) ) )
def subscriptions(self, event): if event.realm != 'ticket': return if event.category not in ('changed', 'created', 'attachment added'): return db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute(""" SELECT sid FROM session_attribute WHERE name='sub_all_tickets' """) for row in cursor.fetchall(): sid = row[0] b = BoolSubscriptionSetting(self.env, 'all_tickets') dist, value, authed = b.get_user_setting(sid) if value: self.log.debug(_("AllTicketSubscriber added '%s" \ "'."%sid)) yield ('email', sid, authed, None)
def send(self, from_addr, recipients, message): # use defaults to make sure connect() is called in the constructor smtpclass = smtplib.SMTP if self.use_ssl: smtpclass = smtplib.SMTP_SSL args = { 'host': self.server, 'port': self.port } # timeout isn't supported until python 2.6 vparts = sys.version_info[0:2] if vparts[0] >= 2 and vparts[1] >= 6: args['timeout'] = self.timeout smtp = smtpclass(**args) smtp.set_debuglevel(self.debuglevel) if self.use_tls: smtp.ehlo() if not smtp.esmtp_features.has_key('starttls'): raise TracError(_("TLS enabled but server does not support " \ "TLS")) smtp.starttls() smtp.ehlo() if self.user: smtp.login( self.user.encode('utf-8'), self.password.encode('utf-8') ) smtp.sendmail(from_addr, recipients, message) if self.use_tls or self.use_ssl: # avoid false failure detection when the server closes # the SMTP connection with TLS/SSL enabled import socket try: smtp.quit() except socket.sslerror: pass else: smtp.quit()
def _init_pref_encoding(self): self._charset = Charset() self._charset.input_charset = 'utf-8' pref = self.mime_encoding.lower() if pref == 'base64': self._charset.header_encoding = BASE64 self._charset.body_encoding = BASE64 self._charset.output_charset = 'utf-8' self._charset.input_codec = 'utf-8' self._charset.output_codec = 'utf-8' elif pref in ['qp', 'quoted-printable']: self._charset.header_encoding = QP self._charset.body_encoding = QP self._charset.output_charset = 'utf-8' self._charset.input_codec = 'utf-8' self._charset.output_codec = 'utf-8' elif pref == 'none': self._charset.header_encoding = None self._charset.body_encoding = None self._charset.input_codec = None self._charset.output_charset = 'ascii' else: raise TracError(_('Invalid email encoding setting: %s' % pref))
def _init_pref_encoding(self): self._charset = Charset() self._charset.input_charset = 'utf-8' pref = self.mime_encoding.lower() if pref == 'base64': self._charset.header_encoding = BASE64 self._charset.body_encoding = BASE64 self._charset.output_charset = 'utf-8' self._charset.input_codec = 'utf-8' self._charset.output_codec = 'utf-8' elif pref in ['qp', 'quoted-printable']: self._charset.header_encoding = QP self._charset.body_encoding = QP self._charset.output_charset = 'utf-8' self._charset.input_codec = 'utf-8' self._charset.output_codec = 'utf-8' elif pref == 'none': self._charset.header_encoding = None self._charset.body_encoding = None self._charset.input_codec = None self._charset.output_charset = 'ascii' else: raise TracError(_('Invalid email encoding setting: %s'%pref))
def get_announcement_preference_boxes(self, req): if req.authname != "anonymous": yield "emailaddress", _("Announcement Email Address")
def description(self): return _("notify me when a ticket that I own is created or modified")
def description(self): return _("notify me when I update a ticket")
def get_announcement_preference_boxes(self, req): if req.authname == "anonymous" and 'email' not in req.session: return yield "acct_mgr_subscription", _("Account Manager Subscription")
def description(self): return _("notify me when a wiki that matches my wiki watch pattern " "is created, or updated")
def description(self): if self.custom_cc_fields: return _("notify me when I'm listed in any of the (%s) " "fields" % (','.join(self.custom_cc_fields), ))
def get_announcement_preference_boxes(self, req): if req.authname == "anonymous" and 'email' not in req.session: return yield "watch_users", _("Watch Users")
class BittenAnnouncement(Component): """Send announcements on build status.""" implements(IAnnouncementEmailDecorator, IAnnouncementFormatter, IAnnouncementPreferenceProvider, IAnnouncementSubscriber, IBuildListener) readable_states = { Build.SUCCESS: _("Successful"), Build.FAILURE: _("Failed"), } # IBuildListener methods def build_started(self, build): """build started""" self._notify(build, 'started') def build_aborted(self, build): """build aborted""" self._notify(build, 'aborted') def build_completed(self, build): """build completed""" self._notify(build, 'completed') # IAnnouncementSubscriber methods def subscriptions(self, event): if event.realm == 'bitten': settings = self._settings() if event.category in settings.keys(): for subscriber in \ settings[event.category].get_subscriptions(): self.log.debug("BittenAnnouncementSubscriber added '%s " "(%s)'", subscriber[1], subscriber[2]) yield subscriber def matches(self, event): yield None def description(self): return _("notify me bitten changes NOT IMPLEMENTED") # IAnnouncementFormatter methods def styles(self, transport, realm): if realm == 'bitten': yield 'text/plain' def alternative_style_for(self, transport, realm, style): if realm == 'bitten' and style != 'text/plain': return 'text/plain' def format(self, transport, realm, style, event): if realm == 'bitten' and style == 'text/plain': return self._format_plaintext(event) # IAnnouncementEmailDecorator methods def decorate_message(self, event, message, decorates=None): if event.realm == "bitten": build_id = str(event.target.id) build_link = self._build_link(event.target) subject = '[%s Build] %s [%s] %s' % ( self.readable_states.get( event.target.status, event.target.status ), self.env.project_name, event.target.rev, event.target.config ) set_header(message, 'X-Trac-Build-ID', build_id) set_header(message, 'X-Trac-Build-URL', build_link) set_header(message, 'Subject', subject) return next_decorator(event, message, decorates) # IAnnouncementPreferenceProvider methods def get_announcement_preference_boxes(self, req): if req.authname == 'anonymous' and 'email' not in req.session: return yield 'bitten_subscription', _("Bitten Subscription") def render_announcement_preference_box(self, req, panel): settings = self._settings() if req.method == 'POST': for k, setting in settings.items(): setting.set_user_setting(req.session, value=req.args.get( 'bitten_%s_subscription' % k), save=False) req.session.save() data = {} for k, setting in settings.items(): data[k] = setting.get_user_setting(req.session.sid)[1] return 'prefs_announcer_bitten.html', data # Private methods def _notify(self, build, category): self.log.info("BittenAnnouncedEventProducer invoked for build %r", build) self.log.debug("build status: %s", build.status) self.log.info("Creating announcement for build %s", build) announcer = AnnouncementSystem(self.env) try: announcer.send(BittenAnnouncedEvent(build, category)) except Exception, e: self.log.exception("Failure creating announcement for build " "%s: %s", build.id, e)
def description(self): return _("notify me when any ticket changes")
def description(self): return _("notify me when one of my watched wiki or tickets is " "updated")
def get_announcement_preference_boxes(self, req): if req.authname == 'anonymous' and 'email' not in req.session: return yield 'watch_users', _("Watch Users")
def description(self): return _("notify me bitten changes NOT IMPLEMENTED")
def description(self): if self.custom_cc_fields: return _("notify me when I'm listed in any of the (%s) " "fields", ','.join(self.custom_cc_fields))
def get_announcement_preference_boxes(self, req): if req.authname == 'anonymous' and 'email' not in req.session: return yield 'joinable_components', _("Ticket Component Subscriptions")
def get_preference_panels(self, req): yield ('subscriptions', _('Subscriptions'))
def get_announcement_preference_boxes(self, req): if req.authname == "anonymous" and 'email' not in req.session: return yield "joinable_components", _("Ticket Component Subscriptions")
def get_preference_panels(self, req): if self.preference_boxes: yield ('announcer', _('Announcements'))
def description(self): return _("notify me when one of my watched users changes something")
def get_announcement_preference_boxes(self, req): if req.authname == 'anonymous' and 'email' not in req.session: return yield 'bitten_subscription', _("Bitten Subscription")
def get_announcement_preference_boxes(self, req): if req.perm.has_permission('WIKI_VIEW'): yield "general_wiki", _("General Wiki Announcements")
def description(self): return _("notify me when one of my watched wiki or tickets is updated")
def description(self): return _("notify me on ticket changes in one of my subscribed groups")
def description(self): return _("notify me when I'm listed in the CC field of a ticket " "that is modified")
def get_announcement_preference_boxes(self, req): if req.authname == "anonymous" and 'email' not in req.session: return if self.joinable_groups: yield "joinable_groups", _("Group Subscriptions")
def description(self): return _("notify me when a ticket that I reported is modified")
def description(self): return _("notify me when a ticket that belongs to a component " "that I own is created or modified")
def description(self): return _("notify me on user account changes (`ACCTMGR_USER_ADMIN` " "required)")
def description(self): return _("notify me when a ticket associated with " \ "a component I'm watching is modified")
def description(self): return _("notify me when a ticket associated with a component I'm " "watching is modified")