Changeset 3798

Show
Ignore:
Timestamp:
06/07/08 17:22:33 (7 months ago)
Author:
eblot
Message:

Closes #3122. Implements user settings and user preference panel.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • growlplugin/0.11/growl/htdocs/css/growl.css

    r3781 r3798  
    1 div#growl-icon { 
    2   float: right; 
    3   margin-right: 40px; 
    4   min-width: 64px; min-height: 64px; 
    5   /* TODO: ask Growl team if growl icon inclusion is ok in the plugin...  
    6      and/or remove it */ 
    7   background: url(../images/growl.png) no-repeat 0 0; 
     1div.growl { 
     2  /* TODO: waiting for Growl team to validate use of the growl image  
     3     in the plugin... */ 
     4  /*background: url(../images/growl-180.png) no-repeat 380px -15px;*/ 
     5  min-height: 150px; 
    86} 
    9  
     7div.buttons { 
     8  position: relative; 
     9  background: transparent; 
     10  margin-top: -30px; 
     11
    1012label.growl { 
    1113  padding-right: 1em; 
  • growlplugin/0.11/growl/notifier.py

    r3794 r3798  
    1919from trac.ticket import ITicketChangeListener  
    2020from trac.wiki import IWikiChangeListener 
    21 from socket import AF_INET, SOCK_DGRAM, SOL_SOCKET, SO_BROADCAST, socket 
     21from socket import AF_INET, SOCK_DGRAM, SOL_SOCKET, SO_BROADCAST, \ 
     22                   socket, gaierror, gethostbyname 
    2223from netgrowl import GrowlRegistrationPacket, GrowlNotificationPacket 
    2324 
     
    3738        payload = growlpacket.payload() 
    3839        broadcast = False 
     40        # we do not want a Growl notification failure to be dispatched 
     41        # to the web client, so any error is catched, logged and ignored 
    3942        for host in hosts: 
    4043            if host != '<broadcast>': 
    41                 self.log.info("Growl: send to %s" % host) 
    42                 s.sendto(payload, (host, self.GROWL_UDP_PORT)) 
     44                self.log.debug("Growl: sendto %s" % host) 
     45                try: 
     46                    s.sendto(payload, (host, self.GROWL_UDP_PORT)) 
     47                except Exception, e: 
     48                    self.log.error('Grow notification error: %s', e) 
    4349            else: 
    4450                broadcast = True 
    4551        if broadcast: 
    4652            self.log.info("Growl: broadcast") 
    47             s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) 
    48             s.sendto(payload, ('<broadcast>', self.GROWL_UDP_PORT)) 
     53            try: 
     54                s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) 
     55                s.sendto(payload, ('<broadcast>', self.GROWL_UDP_PORT)) 
     56            except Exception, e: 
     57                self.log.error('Grow notification error: %s', e) 
    4958        s.close() 
    5059 
     
    7079 
    7180 
    72     # settings 
     81    # project settings 
    7382    userprefs_enabled = BoolOption('growl', 'userprefs', 'false', 
    7483        doc="""Enable per-user to define Growl notification option.""") 
     
    7988    avail_sources = ListOption('growl', 'sources', ','.join(SOURCES), 
    8089        doc="""List of event sources (default: all available sources)""") 
    81  
     90         
    8291 
    8392    # IAttachmentChangeListener Interface 
     
    9099                                      title='Attachment added', 
    91100                                      description=attachment.title) 
    92         self._notify(self._get_hosts('attachment'), gnp) 
     101        gs = GrowlSender(self.env) 
     102        gs.notify(self._get_hosts('attachment'), gnp) 
    93103 
    94104    def attachment_deleted(self, attachment): 
     
    99109                                      title='Attachment deleted', 
    100110                                      description=attachment.title) 
    101         self._notify(self._get_hosts('attachment'), gnp) 
     111        gs = GrowlSender(self.env) 
     112        gs.notify(self._get_hosts('attachment'), gnp) 
    102113 
    103114 
     
    111122                                      title='Ticket #%d created' % ticket.id, 
    112123                                      description=self._ticket_repr(ticket)) 
    113         self._notify(self._get_hosts('ticket'), gnp) 
     124        gs = GrowlSender(self.env) 
     125        gs.notify(self._get_hosts('ticket'), gnp) 
    114126 
    115127    def ticket_changed(self, ticket, comment, author, old_values): 
     
    120132                                      title='Ticket #%d updated' % ticket.id, 
    121133                                      description=self._ticket_repr(ticket)) 
    122         self._notify(self._get_hosts('ticket'), gnp) 
     134        gs = GrowlSender(self.env) 
     135        gs.notify(self._get_hosts('ticket'), gnp) 
    123136 
    124137    def ticket_deleted(self, ticket): 
     
    129142                                      title='Ticket #%d deleted' % ticket.id, 
    130143                                      description=self._ticket_repr(ticket)) 
    131         self._notify(self._get_hosts('ticket'), gnp) 
     144        gs = GrowlSender(self.env) 
     145        gs.notify(self._get_hosts('ticket'), gnp) 
    132146 
    133147 
     
    141155                                      title='Page created', 
    142156                                      description=page.name) 
    143         self._notify(self._get_hosts('wiki'), gnp) 
     157        gs = GrowlSender(self.env) 
     158        gs.notify(self._get_hosts('wiki'), gnp) 
    144159 
    145160    def wiki_page_changed(self, page, version, t, comment, author, ipnr): 
     
    151166                                      description=self._wiki_repr(page, 
    152167                                                                  comment)) 
    153         self._notify(self._get_hosts('wiki'), gnp) 
     168        gs = GrowlSender(self.env) 
     169        gs.notify(self._get_hosts('wiki'), gnp) 
    154170 
    155171    def wiki_page_deleted(self, page): 
     
    160176                                      title='Page deleted', 
    161177                                      description=self._wiki_repr(page)) 
    162         self._notify(self._get_hosts('wiki'), gnp) 
     178        gs = GrowlSender(self.env) 
     179        gs.notify(self._get_hosts('wiki'), gnp) 
    163180 
    164181    def wiki_page_version_deleted(self, page): 
     
    169186                                      title='Page suppressed', 
    170187                                      description=self._wiki_repr(page)) 
    171         self._notify(self._get_hosts('wiki'), gnp) 
     188        gs = GrowlSender(self.env) 
     189        gs.notify(self._get_hosts('wiki'), gnp) 
    172190 
    173191 
     
    182200                                      description=self._bitten_repr(build), 
    183201                                      priority=-2) 
    184         self._notify(self._get_hosts('bitten'), gnp) 
     202        gs = GrowlSender(self.env) 
     203        gs.notify(self._get_hosts('bitten'), gnp) 
    185204     
    186205    def build_aborted(build): 
     
    191210                                      title='Build aborted', 
    192211                                      description=self._bitten_repr(build)) 
    193         self._notify(self._get_hosts('bitten'), gnp) 
     212        gs = GrowlSender(self.env) 
     213        gs.notify(self._get_hosts('bitten'), gnp) 
    194214     
    195215    def build_completed(build): 
     
    205225                                      sticky=failure, 
    206226                                      priority=failure and 2 or 0) 
    207         self._notify(self._get_hosts('bitten'), gnp) 
     227        gs = GrowlSender(self.env) 
     228        gs.notify(self._get_hosts('bitten'), gnp) 
    208229 
    209230 
     
    223244        for n in self.avail_sources: 
    224245            grp.addNotification(n, n in self.sources) 
    225         self._notify(hosts, grp) 
     246        gs = GrowlSender(self.env) 
     247        gs.notify(hosts, grp) 
    226248 
    227249    def validate_host(self, admin, host): 
    228250        if host == '<broadcast>': 
    229             raise PermissionError("Broadcast: GROWL_ADMIN") 
     251            if not admin: 
     252                raise PermissionError('Broadcast: GROWL_ADMIN') 
     253            return True 
    230254        # TODO: implement host validation 
     255        try: 
     256            r = gethostbyname(host) 
     257            self.log.info("Address of %s: %s" % (host, r)) 
     258        except gaierror: 
     259            raise TracError("Host '%s' is invalid" % host) 
    231260        return True 
    232261 
     
    239268        self.register_notifications(self.hosts) 
    240269         
    241     def _notify(self, hosts, gp): 
    242         """Wrapper to notify growl clients""" 
    243         try: 
    244             # we do not want a Growl notification failure to be dispatched 
    245             # to the web client 
    246             gs = GrowlSender(self.env) 
    247             gs.notify(hosts, gp) 
    248         except IOError, e: 
    249             self.log.error('Grow notification error: %s', e) 
    250  
    251270    def _ticket_repr(self, ticket): 
    252271        """String representation of a Trac ticket""" 
     
    272291    def _get_hosts(self, source): 
    273292        # get user-specific hosts 
    274         hosts = self._get_users_hosts(
     293        hosts = self._get_user_hosts(source
    275294        # add hosts defined in the project config, removing duplicates 
    276295        hosts.extend([h for h in self.hosts if h not in hosts]) 
     296        return hosts 
    277297 
    278298    def _get_user_hosts(self, source): 
    279299        db = self.env.get_db_cnx() 
    280300        cursor = db.cursor() 
    281         cursor.execute("SELECT DISTINCT H.value" \ 
    282             "FROM session_attribute src, session_attribute h" \ 
    283             "WHERE (S.name=%s AND S.value='1')" \ 
    284             "AND H.name='growl.host' AND S.sid=H.sid", 
    285             ('growl.source.%s' % source),
     301        cursor.execute("SELECT DISTINCT H.value " \ 
     302            "FROM session_attribute S, session_attribute H " \ 
     303            "WHERE (S.name=%s AND S.value='1') " \ 
     304            "AND H.name='growl.host' AND S.sid=H.sid",  
     305            ("growl.source.%s" % source,)
    286306        hosts = [] 
    287         for host in cursor: 
     307        for host, in cursor: 
    288308            if host: 
    289309                hosts.append(host) 
    290         self.log.info("Hosts for %s: %s" % (source, hosts)) 
     310        self.log.debug("Hosts for %s: %s" % (source, hosts)) 
    291311        # filter out empty hosts 
    292312        return filter(None, hosts) 
  • growlplugin/0.11/growl/templates/pref_growl.html

    r3781 r3798  
    1212 
    1313    <div class="field growl"> 
    14       <p class="hint">Trac notifies Growl-enabled clients.</p> 
     14      <p class="hint">Notify remote Growl clients when Trac events occur.<br/> 
     15      This plugin sends notifications onto standard Growl UDP port 9887.</p> 
    1516      <div id="growl-icon"></div> 
    1617      <table> 
    1718        <tr class="field"> 
    18           <th><label for="host">Host address:</label></th> 
     19          <th><label for="host">Remote host address:</label></th> 
    1920          <td><input type="text" id="host" name="host" size="30" 
    2021            value="${host}" /></td> 
  • growlplugin/0.11/growl/web_ui.py

    r3794 r3798  
    5656            self.log.info("Growl: User notifications not enabled") 
    5757            return 
    58         if not req.perm.has_permission('GROWL_MODIFY')
     58        if 'GROWL_MODIFY' not in req.perm
    5959            self.log.info("Growl: User does not have GROWL_MODIFY permission") 
    6060            return 
     
    6767 
    6868        if req.method == 'POST': 
    69             if not req.perm.has_permission('GROWL_MODIFY')
     69            if 'GROWL_MODIFY' not in req.perm
    7070                raise PermissionError("No permission to change Growl settings") 
    7171            host = req.args.get('host') 
    72             if notifier.validate_host(req.perm.has_permission('GROWL_ADMIN'), 
    73                                       host): 
     72            if notifier.validate_host('GROWL_ADMIN' in req.perm, host): 
    7473                req.session['growl.host'] = host 
    7574                # send a registration request to the host 
  • growlplugin/0.11/setup.py

    r3781 r3798  
    1616 
    1717PACKAGE = 'TracGrowlPlugin' 
    18 VERSION = '0.1.0' 
     18VERSION = '0.2.0' 
    1919 
    2020setup ( 
     
    3131    package_data={ 
    3232        'revtree': [ 
     33            'htdocs/css/*.css', 
    3334            'htdocs/images/*.png', 
    3435            'templates/*.html' 
     
    3839        'trac.plugins': [ 
    3940            'growl.notifier = growl.notifier', 
     41            'growl.web_ui = growl.web_ui' 
    4042        ] 
    4143    }