Edgewall Software

Ticket #1028: patch-emailnotify-r1106.diff

File patch-emailnotify-r1106.diff, 13.5 KB (added by pkou <pkou at ua.fm>, 4 years ago)

Patch for the changes

  • wiki-default/TracIni

     
    3232|| default_priority  || Default priority for newly created tickets || 
    3333|| default_milestone || Default milestone for newly created tickets || 
    3434|| default_component || Default component for newly created tickets || 
     35|| restrict_owner    || Select ticket owner from combo box that lists all logged users || 
    3536 
    3637See also: TracTicketsCustomFields 
    3738 
     
    4445|| smtp_from      || Sender address to use in notification emails || 
    4546|| smtp_replyto   || Reply-To address to use in notification emails || 
    4647|| smtp_always_cc || Email address(es) to always send notifications to || 
     48|| always_notify_owner || Always send notifications to ticket owners || 
    4749|| always_notify_reporter || Always send notifications to any address in the ''reporter'' field || 
    4850 
    4951See also: TracNotification 
  • wiki-default/TracNotification

     
    2121 * '''smtp_from''': Email address to use for ''Sender''-headers in notification emails. 
    2222 * '''smtp_replyto''': Email address to use for ''Reply-To''-headers in notification emails. 
    2323 * '''smtp_always_cc''': List of email addresses to always send notifications to. ''Typically used to post ticket changes to a dedicated mailing list.'' 
     24 * '''always_notify_owner''': Always send notifications to ticket owners. 
    2425 * '''always_notify_reporter''':  Always send notifications to any address in the reporter field. 
    2526 
    2627Either '''smtp_from''' or '''smtp_replyto''' (or both) ''must'' be set, otherwise Trac refuses to send notification mails. 
  • trac/db_default.py

     
    431431  ('ticket', 'default_priority', 'normal'), 
    432432  ('ticket', 'default_milestone', ''), 
    433433  ('ticket', 'default_component', 'component1'), 
     434  ('ticket', 'restrict_owner', 'false'), 
    434435  ('header_logo', 'link', 'http://trac.edgewall.com/'), 
    435436  ('header_logo', 'src', 'trac_banner.png'), 
    436437  ('header_logo', 'alt', 'Trac'), 
     
    442443  ('notification', 'smtp_enabled', 'false'), 
    443444  ('notification', 'smtp_server', 'localhost'), 
    444445  ('notification', 'smtp_always_cc', ''), 
     446  ('notification', 'always_notify_owner', 'false'), 
    445447  ('notification', 'always_notify_reporter', 'false'), 
    446448  ('notification', 'smtp_from', 'trac@localhost'), 
    447449  ('notification', 'smtp_replyto', 'trac@localhost'), 
  • trac/Session.py

     
    111111            or rows[0][0] == self.req.authname):  # Session is mine 
    112112            for u,k,v in rows: 
    113113                self.vars[k] = v 
     114            # For logged users: Load (new) global settings for new session 
     115            if self.req.authname != 'anonymous': 
     116                curs.execute("SELECT var_name,var_value FROM session" 
     117                             " WHERE sid ISNULL AND username = %s", self.req.authname) 
     118                rows = curs.fetchall() 
     119                for k,v in rows: 
     120                    if not self.vars.has_key(k): self.vars[k] = v 
    114121            self.update_sess_time() 
    115122            self.bake_cookie() 
    116123            self.populate_hdf() 
     
    143150            curs.execute('UPDATE session SET username=%s,var_value=%s' 
    144151                         ' WHERE sid=%s AND var_name=%s', 
    145152                         self.req.authname, val, self.sid, key) 
     153        # For logged users: Set global settings (ignore session-specific attributes) 
     154        if self.req.authname != 'anonymous' and \ 
     155                not key in ['mod_time', 'last_visit']: 
     156            curs.execute("DELETE FROM session WHERE sid ISNULL AND username = %s AND var_name = %s", 
     157                         self.req.authname, key) 
     158            curs.execute("INSERT INTO session(sid,username,var_name,var_value)" 
     159                         " VALUES(NULL,%s,%s,%s)", self.req.authname, key, val) 
    146160        self.db.commit() 
    147161        self.vars[key] = val 
    148162 
    149163    def create_new_sid(self): 
    150164        self.sid = hex_entropy(24) 
     165        # For logged users: Load (existing) global settings for new session 
     166        if self.req.authname != 'anonymous': 
     167            curs = self.db.cursor() 
     168            curs.execute("SELECT var_name,var_value FROM session" 
     169                         " WHERE sid ISNULL AND username = %s", self.req.authname) 
     170            rows = curs.fetchall() 
     171            for k,v in rows: 
     172                if not self.vars.has_key(k): self.vars[k] = v 
    151173        self.bake_cookie() 
    152174        self.populate_hdf() 
    153175 
     
    173195        curs.execute("DELETE FROM session WHERE sid IN" 
    174196                     " (SELECT sid FROM session WHERE var_name='mod_time'" 
    175197                     "  AND var_value  < %i)", mintime) 
     198        # For logged users: Delete global settings when all sessions are removed 
     199        curs.execute("DELETE FROM session WHERE sid ISNULL AND username NOT IN" 
     200                     " (SELECT username FROM session WHERE NOT sid ISNULL)") 
    176201        self.db.commit() 
    177202 
  • trac/Notify.py

     
    2424import time 
    2525import smtplib 
    2626import os.path 
     27import email.Utils 
    2728 
    2829import neo_cgi 
    2930import neo_cs 
     
    106107    from_email = 'trac+tickets@localhost' 
    107108    subject = '' 
    108109    server = None 
     110    useremails = {} 
    109111 
     112    def __init__(self, env, msg_template): 
     113        Notify.__init__(self, env, msg_template) 
     114        cursor = self.db.cursor() 
     115        cursor.execute("SELECT username,var_value FROM session WHERE sid ISNULL AND var_name = 'email'") 
     116        rows = cursor.fetchall() 
     117        for k,v in rows: self.useremails[k] = v 
     118 
    110119    def notify(self, resid, subject): 
    111120        self.subject = subject 
    112121 
     
    131140        Notify.notify(self, resid) 
    132141 
    133142    def get_email_addresses(self, txt): 
    134         import email.Utils 
    135         emails = [x[1] for x in  email.Utils.getaddresses([str(txt)])] 
     143        emails = [x[1] for x in email.Utils.getaddresses([str(txt), \ 
     144            self.useremails.has_key(txt) and self.useremails[txt] or ''])] 
    136145        return filter(lambda x: x.find('@') > -1, emails) 
    137146 
    138147    def begin_send(self): 
     
    279288        return txt 
    280289 
    281290    def parse_cc(self, txt): 
    282         return filter(lambda x: '@' in x, txt.replace(',', ' ').split()) 
     291        recipients = txt.replace(',', ' ').split() 
     292        additional = [] 
     293        for r in recipients: 
     294            if self.useremails.has_key(r): 
     295                additional.append(self.useremails[r]) 
     296        emails = [x[1] for x in email.Utils.getaddresses(recipients + additional)] 
     297        return filter(lambda x: '@' in x, emails) 
    283298 
    284299    def format_hdr(self): 
    285300        return '#%s: %s' % (self.ticket['id'], 
     
    295310        # is set to true 
    296311        val = self.env.get_config('notification', 'always_notify_reporter', 'false') 
    297312        notify_reporter = val.lower() in TRUE 
     313        val = self.env.get_config('notification', 'always_notify_owner', 'false') 
     314        notify_owner = val.lower() in TRUE 
    298315         
    299316        emails = self.prev_cc 
    300317        cursor = self.db.cursor() 
    301318        # Harvest email addresses from the cc field 
    302         cursor.execute('SELECT cc,reporter FROM ticket WHERE id=%s', tktid) 
     319        cursor.execute('SELECT cc,reporter,owner FROM ticket WHERE id=%s', tktid) 
    303320        row = cursor.fetchone() 
    304321        if row: 
    305322            emails += row[0] and self.parse_cc(row[0]) or [] 
    306323            if notify_reporter: 
    307324                emails += row[1] and self.get_email_addresses(row[1]) or [] 
     325            if notify_owner: 
     326                emails += row[2] and self.get_email_addresses(row[2]) or [] 
    308327 
    309328        if notify_reporter: 
    310329            cursor.execute('SELECT DISTINCT author,ticket FROM ticket_change ' 
  • trac/Ticket.py

     
    196196        return log 
    197197 
    198198 
     199def userlist_to_hdf(env, db, hdf, prefix): 
     200    val = env.get_config('ticket', 'restrict_owner') 
     201    if val.lower() in util.TRUE: 
     202        cursor = db.cursor() 
     203        cursor.execute("SELECT DISTINCT s1.username, s2.var_value " 
     204                       "FROM session s1 " 
     205                       "LEFT OUTER JOIN session s2 " 
     206                       "  ON (s2.sid ISNULL AND s1.username = s2.username " 
     207                       "      AND s2.var_name = 'name') " 
     208                       "WHERE s1.sid ISNULL " 
     209                       "ORDER BY s1.username") 
     210        idx = 0 
     211        hdf.setValue('%s.%d.name' % (prefix, idx), '') 
     212        idx = idx + 1 
     213        while 1: 
     214            row = cursor.fetchone() 
     215            if not row: 
     216                break 
     217            hdf.setValue('%s.%d.name' % (prefix, idx), row[0]) 
     218            if row[1]: 
     219                displaytext = '%s (%s)' % (row[0], row[1]) 
     220                hdf.setValue('%s.%d.text' % (prefix, idx), displaytext) 
     221            idx = idx + 1 
     222 
     223 
    199224def cmp_by_order(a, b): 
    200225    try: 
    201226        return int(a['order']) - int(b['order']) 
     
    327352                        self.req.hdf, 'newticket.milestones') 
    328353        util.sql_to_hdf(self.db, 'SELECT name FROM version ORDER BY name', 
    329354                        self.req.hdf, 'newticket.versions') 
     355        userlist_to_hdf(self.env, self.db, self.req.hdf, 'newticket.userlist') 
    330356 
    331357        insert_custom_fields(self.env, self.req.hdf, ticket) 
    332358 
     
    390416        util.sql_to_hdf(self.db, "SELECT name FROM enum WHERE type='resolution'" 
    391417                                 " ORDER BY value", 
    392418                        self.req.hdf, 'enums.resolution') 
     419        userlist_to_hdf(self.env, self.db, self.req.hdf, 'ticket.userlist') 
    393420        util.hdf_add_if_missing(self.req.hdf, 'ticket.components', ticket['component']) 
    394421        util.hdf_add_if_missing(self.req.hdf, 'ticket.milestones', ticket['milestone']) 
    395422        util.hdf_add_if_missing(self.req.hdf, 'ticket.versions', ticket['version']) 
  • templates/ticket.cs

     
    229229   <?cs call:hdf_select(enums.resolution, "resolve_resolution", args.resolve_resolution) ?><br /> 
    230230   <?cs call:action_radio('reassign') ?> 
    231231   <label for="reassign">reassign</label> 
    232    <label for="reassign_owner">to:</label> 
    233    <input type="text" id="reassign_owner" name="reassign_owner" size="40" value="<?cs 
    234      if:args.reassign_to ?><?cs var:args.reassign_to ?><?cs 
    235      else ?><?cs var:trac.authname ?><?cs /if ?>" /><?cs 
     232   <label for="reassign_owner">to:</label><?cs 
     233   if:args.reassign_to ?><?cs 
     234     set default_owner=args.reassign_to ?><?cs 
     235   else ?><?cs 
     236     set default_owner=trac.authname ?><?cs 
     237   /if ?><?cs 
     238   if:len(ticket.userlist) ?><?cs 
     239     call:hdf_select(ticket.userlist, "reassign_owner", default_owner) ?><?cs 
     240   else ?> 
     241     <input type="text" id="reassign_owner" name="reassign_owner" size="40" 
     242            value="<?cs var:default_owner ?>" /><?cs 
     243   /if ?><?cs 
    236244  /if ?><?cs 
    237245  if $ticket.status == "new" || $ticket.status == "assigned" || $ticket.status == "reopened" ?> 
    238246   <script type="text/javascript"> 
  • templates/macros.cs

     
    11<?cs def:hdf_select(options, name, selected) ?> 
    22 <select size="1" id="<?cs var:name ?>" name="<?cs var:name ?>"><?cs 
    3   each:option = options ?><?cs 
    4    if option.name == $selected ?> 
    5     <option selected="selected"><?cs var:option.name ?></option><?cs 
    6    else ?> 
    7     <option><?cs var:option.name ?></option><?cs 
    8    /if ?><?cs 
     3  each:option = options ?> 
     4    <option <?cs if option.name == $selected ?>selected="selected"<?cs /if ?>  
     5            <?cs if option.text ?>value="<?cs var:option.name ?>"<?cs /if ?> ><?cs 
     6      if option.text ?><?cs 
     7        var:option.text ?><?cs 
     8      else ?><?cs 
     9        var:option.name ?><?cs 
     10      /if ?> 
     11    </option><?cs 
    912  /each ?> 
    1013 </select><?cs 
    1114/def?> 
  • templates/newticket.cs

     
    5959   <label for="milestone">Milestone:</label><?cs 
    6060   call:hdf_select(newticket.milestones, "milestone", newticket.milestone) ?><br /> 
    6161   <label for="owner">Assign to:</label> 
     62   <?cs if:len(newticket.userlist) ?><?cs 
     63     call:hdf_select(newticket.userlist, "owner", newticket.owner) ?><br /><?cs 
     64   else ?> 
    6265   <input type="text" id="owner" name="owner" size="20" value="<?cs 
    6366     var:newticket.owner ?>" /><br /> 
     67   <?cs /if ?> 
    6468   <label for="cc">Cc:</label> 
    6569   <input type="text" id="cc" name="cc" size="30" value="<?cs var:newticket.cc ?>" /> 
    6670  </div>