Edgewall Software

Ticket #2456: user_API.diff

File user_API.diff, 21.2 kB (added by wkornewald, 22 months ago)

patch against trunk (0.11)

  • trac/prefs/web_ui.py

     
    2121 
    2222from trac.core import * 
    2323from trac.prefs.api import IPreferencePanelProvider 
     24from trac.user import UserManager, User 
    2425from trac.util.datefmt import all_timezones, utc 
    2526from trac.web import HTTPNotFound, IRequestHandler 
    2627from trac.web.chrome import add_stylesheet, INavigationContributor 
     
    9091                self._do_save(req) 
    9192            req.redirect(req.href.prefs(panel or None)) 
    9293 
     94        name = email = '' 
     95        if req.authname != 'anonymous': 
     96            user = UserManager(self.env).get_user(req.authname) 
     97            name, email = user['name'], user['email'] 
     98        else: 
     99            name = req.session.get('name') 
     100            email = req.session.get('email') 
    93101        return 'prefs_%s.html' % (panel or 'general'), { 
    94             'settings': {'session': req.session, 'session_id': req.session.sid}, 
     102            'settings': {'session': req.session, 'session_id': req.session.sid, 
     103                         'name': name, 'email': email}, 
    95104            'timezones': all_timezones 
    96105        } 
    97106 
     
    107116                elif field == 'newsid' and val: 
    108117                    req.session.change_sid(val) 
    109118                else: 
    110                     req.session[field] = val 
     119                    if req.authname != 'anonymous' and \ 
     120                            field in ('name', 'email'): 
     121                        user = UserManager(self.env).get_user(req.authname) 
     122                        user[field] = val 
     123                    else: 
     124                        req.session[field] = val 
    111125            elif field in req.args and req.session: 
    112                 del req.session[field] 
     126                if req.authname != 'anonymous' and \ 
     127                        field in ('name', 'email'): 
     128                    user = UserManager(self.env).get_user(req.authname) 
     129                    user[field] = '' 
     130                elif field in req.session: 
     131                    del req.session[field] 
    113132 
    114133    def _do_load(self, req): 
    115134        if req.authname == 'anonymous': 
  • trac/env.py

     
    2323from trac.core import Component, ComponentManager, implements, Interface, \ 
    2424                      ExtensionPoint, TracError 
    2525from trac.db import DatabaseManager 
     26from trac.user import UserManager, User 
    2627from trac.util import get_pkginfo 
    2728from trac.versioncontrol import RepositoryManager 
    2829from trac.web.href import Href 
     
    282283            logfile = os.path.join(self.get_log_dir(), logfile) 
    283284        self.log = logger_factory(logtype, logfile, self.log_level, self.path) 
    284285 
    285     def get_known_users(self, cnx=None): 
     286    def get_known_users(self): 
    286287        """Generator that yields information about all known users, i.e. users 
    287288        that have logged in to this Trac environment and possibly set their name 
    288289        and email. 
    289290 
    290291        This function generates one tuple for every user, of the form 
    291292        (username, name, email) ordered alpha-numerically by username. 
    292  
    293         @param cnx: the database connection; if ommitted, a new connection is 
    294                     retrieved 
    295293        """ 
    296         if not cnx: 
    297             cnx = self.get_db_cnx() 
    298         cursor = cnx.cursor() 
    299         cursor.execute("SELECT DISTINCT s.sid, n.value, e.value " 
    300                        "FROM session AS s " 
    301                        " LEFT JOIN session_attribute AS n ON (n.sid=s.sid " 
    302                        "  and n.authenticated=1 AND n.name = 'name') " 
    303                        " LEFT JOIN session_attribute AS e ON (e.sid=s.sid " 
    304                        "  AND e.authenticated=1 AND e.name = 'email') " 
    305                        "WHERE s.authenticated=1 ORDER BY s.sid") 
    306         for username,name,email in cursor: 
    307             yield username, name, email 
     294        for user in UserManager(self).get_all_users(): 
     295            yield user.username, user['name'], user['email'] 
    308296 
    309297    def backup(self, dest=None): 
    310298        """Simple SQLite-specific backup of the database. 
  • trac/ticket/admin.py

     
    1717from trac.core import * 
    1818from trac.perm import PermissionSystem 
    1919from trac.ticket import model 
     20from trac.user import UserManager 
    2021from trac.util import datefmt 
    2122from trac.web.chrome import add_link, add_script 
    2223 
     
    9192            perm = PermissionSystem(self.env) 
    9293            def valid_owner(username): 
    9394                return perm.get_user_permissions(username).get('TICKET_MODIFY') 
    94             data['owners'] = [username for username, name, email 
    95                               in self.env.get_known_users() 
     95            data['owners'] = [username for username 
     96                              in UserManager(self.env).get_usernames() 
    9697                              if valid_owner(username)] 
    9798 
    9899        return 'admin_components.html', data 
  • trac/ticket/api.py

     
    2020from trac.config import * 
    2121from trac.core import * 
    2222from trac.perm import IPermissionRequestor, PermissionSystem 
     23from trac.user import UserManager 
    2324from trac.util import Ranges 
    2425from trac.util.html import html 
    2526from trac.util.text import shorten_line 
     
    102103        field = {'name': 'owner', 'label': 'Owner'} 
    103104        if self.restrict_owner: 
    104105            field['type'] = 'select' 
    105             users = [''] # for clearing assignment 
     106            users = [] 
    106107            perm = PermissionSystem(self.env) 
    107             for username, name, email in self.env.get_known_users(db): 
     108            for username in UserManager(self.env).get_usernames(): 
    108109                if perm.get_user_permissions(username).get('TICKET_MODIFY'): 
    109110                    users.append(username) 
    110111            field['options'] = users 
  • trac/ticket/report.py

     
    2222from trac.core import * 
    2323from trac.db import get_column_names 
    2424from trac.perm import IPermissionRequestor 
     25from trac.user import UserManager 
    2526from trac.util import sorted 
    2627from trac.util.text import to_unicode, unicode_urlencode 
    2728from trac.util.html import html 
     
    275276            header_group.append(header) 
    276277 
    277278        # Get the email addresses of all known users 
    278         email_map = {} 
    279         for username, name, email in self.env.get_known_users(): 
    280             if email: 
    281                 email_map[username] = email 
     279        email_map = UserManager(self.env).get_email_map() 
    282280 
    283281        # Structure the rows and cells: 
    284282        #  - group rows according to __group__ value, if defined 
  • trac/versioncontrol/web_ui/log.py

     
    2121 
    2222from trac.core import * 
    2323from trac.perm import IPermissionRequestor 
     24from trac.user import UserManager 
    2425from trac.util import Ranges 
    2526from trac.util.datefmt import http_date 
    2627from trac.util.html import html 
     
    181182        email_map = {} 
    182183        if format == 'rss': 
    183184            # Get the email addresses of all known users 
    184             email_map = {} 
    185             for username,name,email in self.env.get_known_users(): 
    186                 if email: 
    187                     email_map[username] = email 
     185            email_map = UserManager(self.env).get_email_map() 
    188186        elif format == 'changelog': 
    189187            for rev in revs: 
    190188                changeset = changes[rev] 
  • trac/user.py

     
     1# -*- coding: utf-8 -*- 
     2# 
     3# Copyright 2006 Waldemar Kornewald, wkornewald@haiku-os.org 
     4# All rights reserved. 
     5# 
     6# This software is licensed as described in the file COPYING, which 
     7# you should have received as part of this distribution. The terms 
     8# are also available at http://trac.edgewall.org/wiki/TracLicense. 
     9# 
     10# This software consists of voluntary contributions made by many 
     11# individuals. For the exact contribution history, see the revision 
     12# history and logs, available at http://trac.edgewall.org/log/. 
     13# 
     14# Author: Waldemar Kornewald, wkornewald@haiku-os.org 
     15 
     16from trac.core import * 
     17from trac.config import * 
     18 
     19 
     20class IUserStore(Interface): 
     21    """ 
     22    Extension point interface for backends that store known users. 
     23    """ 
     24 
     25    def supports_user_operation(self, operation): 
     26        """ 
     27        Returns whether the operation (a method name) is supported. 
     28 
     29        @return supported 
     30        """ 
     31 
     32    def create_user(self, username, password): 
     33        """ 
     34        Creates a new user with the given username and password. 
     35 
     36        @return success 
     37        """ 
     38 
     39    def get_usernames(self): 
     40        """ 
     41        Generator that yields an ordered list of known usernames. 
     42 
     43        @return username 
     44        """ 
     45 
     46    def check_password(self, username, password): 
     47        """ 
     48        Checks if the password is correct for the given user. 
     49        """ 
     50 
     51    def change_password(self, username, password): 
     52        """ 
     53        Changes a user's password. 
     54 
     55        @return success 
     56        """ 
     57 
     58    def delete_user(self, username): 
     59        """ 
     60        Deletes a user. 
     61 
     62        @return success 
     63            Returns False if the user didn't exist. 
     64        """ 
     65 
     66 
     67class IUserAttributeProvider(Interface): 
     68    """ 
     69    Extension point interface for backends that store user attributes. 
     70    """ 
     71 
     72    def supports_attribute_operation(self, operation): 
     73        """ 
     74        Returns whether the operation (a method name) is supported. 
     75 
     76        @return supported 
     77        """ 
     78 
     79    def get_user_attribute(self, username, attribute): 
     80        """ 
     81        Returns a user attribute. 
     82 
     83        If the attribute is not set it returs an empty string. 
     84        If the attribute is not supported None is returned. 
     85        """ 
     86 
     87    def set_user_attribute(self, username, attribute, value): 
     88        """ 
     89        Sets a user attribute. 
     90 
     91        @return success 
     92            Returns False if setting the attribute is not supported. 
     93        """ 
     94 
     95    def delete_all_user_attributes(self, username): 
     96        """ 
     97        Deletes all of the given user's attributes. 
     98        """ 
     99 
     100 
     101class UserManager(Component): 
     102    """ 
     103    Component responsible for managing users and user attributes. 
     104    """ 
     105 
     106    store = ExtensionOption('users', 
     107        'store', IUserStore, 'SessionUserStore', 
     108        doc="""The user store that should be used for authentication 
     109            (''since 0.11'').""") 
     110    attribute_providers = OrderedExtensionsOption('users', 
     111        'attribute_providers', IUserAttributeProvider, 
     112        doc="""Ordered list of user attribute providers (''since 0.11'').""") 
     113 
     114    # public API 
     115 
     116    def supports_operation(self, operation): 
     117        if self.store.supports_user_operation(operation): 
     118            return True 
     119        for provider in self.attribute_providers: 
     120            if self.provider.supports_attribute_operation(operation): 
     121                return True 
     122        return False 
     123 
     124    # IUserStore methods 
     125 
     126    def create_user(self, username, password): 
     127        """ 
     128        Creates a new user with the given username and password. 
     129 
     130        @return User object or None if the user couldn't be created 
     131        """ 
     132        if not self.store.supports_user_operation('create_user'): 
     133            return None 
     134        if self.store.create_user(username, password): 
     135            return User(username, self.store, self.attribute_providers) 
     136 
     137    def get_user(self, username): 
     138        """ 
     139        Returns a User object for the username. 
     140 
     141        @return User object or None if the user doesn't exist 
     142        """ 
     143        if username in self.get_usernames(): 
     144            return User(username, self.store, self.attribute_providers) 
     145        return None 
     146 
     147    def get_all_users(self): 
     148        """ 
     149        Generator for User objects. 
     150        """ 
     151        if not self.store.supports_user_operation('get_usernames'): 
     152            return 
     153        for username in self.store.get_usernames(): 
     154            yield User(username, self.store, self.attribute_providers) 
     155 
     156    def get_usernames(self): 
     157        """ 
     158        Generator for usernames. 
     159        """ 
     160        if not self.store.supports_user_operation('get_usernames'): 
     161            return 
     162        return self.store.get_usernames() 
     163 
     164    # often-used specialized methods 
     165 
     166    def get_email_map(self): 
     167        """ 
     168        Returns a hash mapping usernames to email addresses. 
     169        """ 
     170        email_map = {} 
     171        for user in self.get_all_users(): 
     172            email = user['email'] 
     173            if email: 
     174                email_map[user.username] = email 
     175        return email_map 
     176 
     177 
     178class User(object): 
     179    """ 
     180    Object representing a user. 
     181    """ 
     182 
     183    def __init__(self, username, store, attribute_providers): 
     184        self._username = username 
     185        self.store = store 
     186        self.attribute_providers = attribute_providers 
     187 
     188    # public API 
     189 
     190    @property 
     191    def username(self): 
     192        return self._username 
     193 
     194    # IUserStore methods 
     195 
     196    def check_password(self, password): 
     197        if not self.store.supports_user_operation('check_password'): 
     198            return False 
     199        return self.store.check_password(self.username, password) 
     200 
     201    def change_password(self, password): 
     202        if not self.store.supports_user_operation('change_password'): 
     203            return False 
     204        return self.store.change_password(self.username, password) 
     205 
     206    def delete(self): 
     207        if not self.store.supports_user_operation('delete_user'): 
     208            return False 
     209        self.delete_all_attributes() 
     210        return self.store.delete_user(self.username) 
     211 
     212    # IUserAttributeProvider methods 
     213 
     214    def __getitem__(self, attribute): 
     215        for provider in self.attribute_providers: 
     216            if not provider.supports_attribute_operation('get_user_attribute'): 
     217                continue 
     218            value = provider.get_user_attribute(self.username, attribute) 
     219            if value is not None: 
     220                return value 
     221        return None 
     222 
     223    def __setitem__(self, attribute, value): 
     224        for provider in self.attribute_providers: 
     225            if provider.supports_attribute_operation('set_user_attribute') \ 
     226                    and provider.set_user_attribute(self.username, attribute, 
     227                                                    value): 
     228                return True 
     229        return False 
     230 
     231    def delete_all_attributes(self): 
     232        for provider in self.attribute_providers: 
     233            if provider.supports_attribute_operation('delete_all_user_attributes'): 
     234                provider.delete_all_user_attributes(username) 
     235 
     236 
     237class SessionUserStore(Component): 
     238    """ 
     239    Component for managing authenticated users stored in sessions. 
     240    """ 
     241 
     242    implements(IUserStore) 
     243 
     244    def supports_user_operation(self, operation): 
     245        return hasattr(self, operation) 
     246 
     247    def get_usernames(self): 
     248        db = self.env.get_db_cnx() 
     249        cursor = db.cursor() 
     250        cursor.execute("SELECT sid FROM session " 
     251                       "WHERE authenticated=1 " 
     252                       "ORDER BY sid") 
     253        for row in cursor: 
     254            yield row[0] 
     255 
     256 
     257class SessionUserAttributeProvider(Component): 
     258    """ 
     259    Component for providing user attributes via Trac sessions. 
     260    """ 
     261 
     262    implements(IUserAttributeProvider) 
     263 
     264    def supports_attribute_operation(self, operation): 
     265        return hasattr(self, operation) 
     266 
     267    def get_user_attribute(self, username, attribute): 
     268        db = self.env.get_db_cnx() 
     269        cursor = db.cursor() 
     270        cursor.execute("SELECT value FROM session_attribute " 
     271                       "WHERE sid=%s AND name=%s AND authenticated=1", 
     272                       (username, attribute)) 
     273        row = cursor.fetchone() 
     274        if row: 
     275            return row[0] 
     276 
     277        # if the attribute doesn't exist we return an empty string to 
     278        # indicate that the attribute is supported, but not set 
     279        return '' 
     280 
     281    def set_user_attribute(self, username, attribute, value): 
     282        db = self.env.get_db_cnx() 
     283        cursor = db.cursor() 
     284 
     285        if not value or value == '': 
     286            cursor.execute("DELETE FROM session_attribute " 
     287                           "WHERE sid=%s AND name=%s AND authenticated=1", 
     288                          (username, attribute)) 
     289            db.commit() 
     290            return True 
     291 
     292        # check if attribute exists 
     293        cursor.execute("SELECT value FROM session_attribute " 
     294                       "WHERE sid=%s AND name=%s AND authenticated=1", 
     295                       (username, attribute)) 
     296        if cursor.fetchone(): 
     297            # update the attribute 
     298            cursor.execute("UPDATE session_attribute SET value=%s " 
     299                           "WHERE sid=%s AND name=%s AND authenticated=1", 
     300                           (value, username, attribute)) 
     301        else: 
     302            # create new attribute 
     303            cursor.execute("INSERT INTO session_attribute " 
     304                           "(sid,authenticated,name,value) " 
     305                           "VALUES(%s,1,%s,%s)", 
     306                           (username, attribute, value)) 
     307        db.commit() 
     308        return True 
     309 
     310    def delete_all_user_attributes(self, username): 
     311        db = self.env.get_db_cnx() 
     312        cursor = db.cursor() 
     313        cursor.execute("DELETE FROM session_attribute " 
     314                       "WHERE sid=%s AND authenticated=1", 
     315                      (username,)) 
     316        db.commit() 
  • trac/timeline/web_ui.py

     
    2626from trac.core import * 
    2727from trac.perm import IPermissionRequestor 
    2828from trac.timeline.api import ITimelineEventProvider, TimelineEvent 
     29from trac.user import UserManager 
    2930from trac.util.datefmt import format_date, parse_date, to_timestamp, utc 
    3031from trac.util.html import html, Markup 
    3132from trac.util.text import to_unicode 
     
    138139 
    139140        if format == 'rss': 
    140141            # Get the email addresses of all known users 
    141             email_map = {} 
    142             for username, name, email in self.env.get_known_users(): 
    143                 if email: 
    144                     email_map[username] = email 
     142            email_map = UserManager(self.env).get_email_map() 
    145143            data['email_map'] = email_map 
    146144            return 'timeline.rss', data, 'application/rss+xml' 
    147145 
  • trac/test.py

     
    174174    def get_db_cnx(self): 
    175175        return self.db 
    176176 
    177     def get_known_users(self, db): 
     177    def get_known_users(self): 
    178178        return self.known_users 
    179179 
    180180 
  • trac/notification.py

     
    2222from trac import __version__ 
    2323from trac.config import BoolOption, IntOption, Option 
    2424from trac.core import * 
     25from trac.user import UserManager 
    2526from trac.util.text import CRLF 
    2627from trac.web.chrome import Chrome 
    2728 
     
    162163        self._use_tls = self.env.config.getbool('notification', 'use_tls') 
    163164        self._init_pref_encoding() 
    164165        # Get the email addresses of all known users 
    165         self.email_map = {} 
    166         for username, name, email in self.env.get_known_users(self.db): 
    167             if email: 
    168                 self.email_map[username] = email 
    169                  
     166        self.email_map = UserManager(self.env).get_email_map() 
     167 
    170168    def _init_pref_encoding(self): 
    171169        from email.Charset import Charset, QP, BASE64 
    172170        self._charset = Charset() 
  • templates/prefs_general.html

     
    1414      <tr class="field"> 
    1515        <th><label for="name">Full name:</label></th> 
    1616        <td><input type="text" id="name" name="name" size="30" 
    17             value="${settings.session.name}" /></td> 
     17            value="${settings.name}" /></td> 
    1818      </tr> 
    1919      <tr class="field"> 
    2020        <th><label for="email">Email address:</label></th> 
    2121        <td><input type="text" id="email" name="email" size="30" 
    22             value="${settings.session.email}" /></td> 
     22            value="${settings.email}" /></td> 
    2323      </tr> 
    2424    </table> 
    2525    <p py:choose="" class="hint">