Edgewall Software

Ticket #2456: user_API_r6033.diff

File user_API_r6033.diff, 22.0 kB (added by Morris, 10 months ago)

User API patch for trunk (0.11dev) r6033

  • trac/env.py

     
    2828from trac.core import Component, ComponentManager, implements, Interface, \ 
    2929                      ExtensionPoint, TracError 
    3030from trac.db import DatabaseManager 
     31from trac.user import UserManager, User 
    3132from trac.util import get_pkginfo 
    3233from trac.versioncontrol import RepositoryManager 
    3334from trac.web.href import Href 
     
    339340 
    340341        This function generates one tuple for every user, of the form 
    341342        (username, name, email) ordered alpha-numerically by username. 
    342  
    343         @param cnx: the database connection; if ommitted, a new connection is 
    344                     retrieved 
    345343        """ 
    346         if not cnx: 
    347             cnx = self.get_db_cnx() 
    348         cursor = cnx.cursor() 
    349         cursor.execute("SELECT DISTINCT s.sid, n.value, e.value " 
    350                        "FROM session AS s " 
    351                        " LEFT JOIN session_attribute AS n ON (n.sid=s.sid " 
    352                        "  and n.authenticated=1 AND n.name = 'name') " 
    353                        " LEFT JOIN session_attribute AS e ON (e.sid=s.sid " 
    354                        "  AND e.authenticated=1 AND e.name = 'email') " 
    355                        "WHERE s.authenticated=1 ORDER BY s.sid") 
    356         for username,name,email in cursor: 
    357             yield username, name, email 
     344        for user in UserManager(self).get_all_users(): 
     345            yield user.username, user['name'], user['email'] 
    358346 
    359347    def backup(self, dest=None): 
    360348        """Simple SQLite-specific backup of the database. 
  • 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 
     
    158159    smtp_port = 25 
    159160    from_email = 'trac+tickets@localhost' 
    160161    subject = '' 
     162    server = None 
    161163    template_name = None 
    162164    nodomaddr_re = re.compile(r'[\w\d_\.\-]+') 
    163165    addrsep_re = re.compile(r'[;\s,]+') 
     
    179181        self._init_pref_encoding() 
    180182        domains = self.env.config.get('notification', 'ignore_domains', '') 
    181183        self._ignore_domains = [x.strip() for x in domains.lower().split(',')] 
    182         # Get the email addresses of all known users 
    183         self.email_map = {} 
    184         for username, name, email in self.env.get_known_users(self.db): 
    185             if email: 
    186                 self.email_map[username] = email 
    187                  
     184 
    188185    def _init_pref_encoding(self): 
    189186        from email.Charset import Charset, QP, BASE64 
    190187        self._charset = Charset() 
     
    270267        if not is_email(address): 
    271268            if address == 'anonymous': 
    272269                return None 
    273             if self.email_map.has_key(address): 
    274                 address = self.email_map[address] 
     270             
     271            email = UserManager(self.env).get_user(address)['email'] 
     272            if email and len(email) > 0: 
     273                address = email 
    275274            elif NotifyEmail.nodomaddr_re.match(address): 
    276275                if self.config.getbool('notification', 'use_short_addr'): 
    277276                    return address 
  • trac/perm.py

     
    2020 
    2121from trac.config import ExtensionOption, OrderedExtensionsOption 
    2222from trac.core import * 
     23from trac.user import UserManager 
    2324from trac.util.compat import set 
    2425from trac.util.translation import _ 
    2526 
     
    160161        db = self.env.get_db_cnx() 
    161162        cursor = db.cursor() 
    162163        result = set() 
    163         users = set([u[0] for u in self.env.get_known_users()]) 
     164        users = set([username for username 
     165                    in UserManager(self.env).get_usernames()]) 
    164166        for user in users: 
    165167            userperms = self.get_user_permissions(user) 
    166168            for group in permissions: 
  • trac/prefs/web_ui.py

     
    2222 
    2323from trac.core import * 
    2424from trac.prefs.api import IPreferencePanelProvider 
     25from trac.user import UserManager, User 
    2526from trac.util.datefmt import all_timezones, get_timezone 
    2627from trac.util.translation import _ 
    2728from trac.web import HTTPNotFound, IRequestHandler 
     
    9394                self._do_save(req) 
    9495            req.redirect(req.href.prefs(panel or None)) 
    9596 
     97        name = email = '' 
     98        if req.authname != 'anonymous': 
     99            user = UserManager(self.env).get_user(req.authname) 
     100            name, email = user['name'], user['email'] 
     101        else: 
     102            name = req.session.get('name') 
     103            email = req.session.get('email') 
    96104        return 'prefs_%s.html' % (panel or 'general'), { 
    97             'settings': {'session': req.session, 'session_id': req.session.sid}, 
     105            'settings': {'session': req.session, 'session_id': req.session.sid, 
     106                         'name': name, 'email': email}, 
    98107            'timezones': all_timezones, 'timezone': get_timezone 
    99108        } 
    100109 
     
    118127                elif field == 'newsid' and val: 
    119128                    req.session.change_sid(val) 
    120129                else: 
    121                     req.session[field] = val 
    122             elif field in req.session and (field in req.args or 
    123                                            field + '_cb' in req.args): 
    124                 del req.session[field] 
     130                    if req.authname != 'anonymous' and \ 
     131                            field in ('name', 'email'): 
     132                        user = UserManager(self.env).get_user(req.authname) 
     133                        user[field] = val 
     134                    else: 
     135                        req.session[field] = val 
     136            elif field in req.args and field + '_cb' in req.args: 
     137                if req.authname != 'anonymous' and \ 
     138                        field in ('name', 'email'): 
     139                    user = UserManager(self.env).get_user(req.authname) 
     140                    user[field] = '' 
     141                elif field in req.session: 
     142                    del req.session[field] 
    125143 
    126144    def _do_load(self, req): 
    127145        if req.authname == 'anonymous': 
  • trac/ticket/admin.py

     
    107107 
    108108        if self.config.getbool('ticket', 'restrict_owner'): 
    109109            perm = PermissionSystem(self.env) 
    110             def valid_owner(username): 
    111                 return perm.get_user_permissions(username).get('TICKET_MODIFY') 
    112             data['owners'] = [username for username, name, email 
    113                               in self.env.get_known_users() 
    114                               if valid_owner(username)] 
     110            data['owners'] = perm.get_users_with_permission('TICKET_MODIFY') 
    115111        else: 
    116112            data['owners'] = None 
    117113 
  • trac/ticket/report.py

     
    2727from trac.core import * 
    2828from trac.db import get_column_names 
    2929from trac.perm import IPermissionRequestor 
     30from trac.user import UserManager 
    3031from trac.util import sorted 
    3132from trac.util.datefmt import format_datetime, format_time 
    3233from trac.util.text import to_unicode, unicode_urlencode 
     
    369370        # Get the email addresses of all known users 
    370371        email_map = {} 
    371372        if Chrome(self.env).show_email_addresses: 
    372             for username, name, email in self.env.get_known_users(): 
    373                 if email: 
    374                     email_map[username] = email 
     373            email_map = UserManager(self.env).get_attribute_mapper('email') 
    375374 
    376375        data.update({'header_groups': header_groups, 
    377376                     'row_groups': row_groups, 
  • trac/timeline/web_ui.py

     
    3030from trac.perm import IPermissionRequestor 
    3131from trac.timeline.api import ITimelineEventProvider, TimelineEvent 
    3232from trac.util.compat import sorted 
     33from trac.user import UserManager 
    3334from trac.util.datefmt import format_date, format_datetime, parse_date, \ 
    3435                              to_timestamp, utc, pretty_timedelta 
    3536from trac.util.text import to_unicode 
     
    167168            # Get the email addresses of all known users 
    168169            email_map = {} 
    169170            if Chrome(self.env).show_email_addresses: 
    170                 for username, name, email in self.env.get_known_users(): 
    171                     if email: 
    172                         email_map[username] = email 
     171                email_map = UserManager(self.env).get_attribute_mapper('email') 
    173172            data['email_map'] = email_map 
    174173            return 'timeline.rss', data, 'application/rss+xml' 
    175174 
  • 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 
     100class UserAttributeMapper(object): 
     101    """ 
     102    Dict that maps usernames to attributes and caches those values to 
     103    increase efficiency. 
     104    """ 
     105 
     106    _usernames_cache = None 
     107    _cache = {} 
     108 
     109    def __init__(self, attribute, manager): 
     110        self._attribute = attribute 
     111        self._manager = manager 
     112 
     113    def __getitem__(self, username): 
     114        if not self._usernames_cache: 
     115            self._usernames_cache = [username for username 
     116                                     in self._manager.get_usernames()] 
     117        if username not in self._usernames_cache: 
     118            return None 
     119        if username not in self._cache: 
     120            value = self._manager.get_user(username)[self._attribute] 
     121            if value: 
     122                self._cache[username] = value 
     123            return value 
     124        else: 
     125            return self._cache.get(username) 
     126 
     127    def __contains__(self, username): 
     128        value = self[username] 
     129        return value is not None and len(value) > 0 
     130 
     131    def __setitem__(self,key,value): 
     132        raise NotImplementedError, "dict is immutable" 
     133    def __delitem__(self,key): 
     134        raise NotImplementedError, "dict is immutable" 
     135    def clear(self): 
     136        raise NotImplementedError, "dict is immutable" 
     137    def setdefault(self,k,default=None): 
     138        raise NotImplementedError, "dict is immutable" 
     139    def popitem(self): 
     140        raise NotImplementedError, "dict is immutable" 
     141    def update(self,other): 
     142        raise NotImplementedError, "dict is immutable" 
     143 
     144 
     145class UserManager(Component): 
     146    """ 
     147    Component responsible for managing users and user attributes. 
     148    """ 
     149 
     150    store = ExtensionOption('users', 
     151        'store', IUserStore, 'SessionUserStore', 
     152        doc="""The user store that should be used for authentication 
     153            (''since 0.11'').""") 
     154    attribute_providers = OrderedExtensionsOption('users', 
     155        'attribute_providers', IUserAttributeProvider, 
     156        doc="""Ordered list of user attribute providers (''since 0.11'').""") 
     157 
     158    # public API 
     159 
     160    def supports_operation(self, operation): 
     161        if self.store.supports_user_operation(operation): 
     162            return True 
     163        for provider in self.attribute_providers: 
     164            if self.provider.supports_attribute_operation(operation): 
     165                return True 
     166        return False 
     167 
     168    # IUserStore methods 
     169 
     170    def create_user(self, username, password): 
     171        """ 
     172        Creates a new user with the given username and password. 
     173 
     174        @return User object or None if the user couldn't be created 
     175        """ 
     176        if not self.store.supports_user_operation('create_user'): 
     177            return None 
     178        if self.store.create_user(username, password): 
     179            return User(username, self.store, self.attribute_providers) 
     180 
     181    def get_user(self, username): 
     182        """ 
     183        Returns a User object for the username. 
     184 
     185        @return User object or None if the user doesn't exist 
     186        """ 
     187        return User(username, self.store, self.attribute_providers) 
     188 
     189    def get_all_users(self): 
     190        """ 
     191        Generator for User objects. 
     192        """ 
     193        if not self.store.supports_user_operation('get_usernames'): 
     194            return 
     195        for username in self.store.get_usernames(): 
     196            yield User(username, self.store, self.attribute_providers) 
     197 
     198    def get_usernames(self): 
     199        """ 
     200        Generator for usernames. 
     201        """ 
     202        if not self.store.supports_user_operation('get_usernames'): 
     203            return 
     204        return self.store.get_usernames() 
     205 
     206    def get_attribute_mapper(self, attribute): 
     207        return UserAttributeMapper(attribute, self) 
     208 
     209 
     210class User(object): 
     211    """ 
     212    Object representing a user. 
     213    """ 
     214 
     215    def __init__(self, username, store, attribute_providers): 
     216        self._username = username 
     217        self.store = store 
     218        self.attribute_providers = attribute_providers 
     219 
     220    # public API 
     221 
     222    @property 
     223    def username(self): 
     224        return self._username 
     225 
     226    def exists(self): 
     227        return self.username in [username for username 
     228                                 in self.store.get_usernames()] 
     229 
     230    # IUserStore methods 
     231 
     232    def check_password(self, password): 
     233        if not self.store.supports_user_operation('check_password'): 
     234            return False 
     235        return self.store.check_password(self.username, password) 
     236 
     237    def change_password(self, password): 
     238        if not self.store.supports_user_operation('change_password'): 
     239            return False 
     240        return self.store.change_password(self.username, password) 
     241 
     242    def delete(self): 
     243        if not self.store.supports_user_operation('delete_user'): 
     244            return False 
     245        self.delete_all_attributes() 
     246        return self.store.delete_user(self.username) 
     247 
     248    # IUserAttributeProvider methods 
     249 
     250    def __getitem__(self, attribute): 
     251        for provider in self.attribute_providers: 
     252            if not provider.supports_attribute_operation('get_user_attribute'): 
     253                continue 
     254            value = provider.get_user_attribute(self.username, attribute) 
     255            if value is not None: 
     256                return value 
     257        return None 
     258 
     259    def __setitem__(self, attribute, value): 
     260        for provider in self.attribute_providers: 
     261            if provider.supports_attribute_operation('set_user_attribute') \ 
     262                    and provider.set_user_attribute(self.username, attribute, 
     263                                                    value): 
     264                return True 
     265        return False 
     266 
     267    def delete_all_attributes(self): 
     268        for provider in self.attribute_providers: 
     269            if provider.supports_attribute_operation('delete_all_user_attributes'): 
     270                provider.delete_all_user_attributes(username) 
     271 
     272 
     273class SessionUserStore(Component): 
     274    """ 
     275    Component for managing authenticated users stored in sessions. 
     276    """ 
     277 
     278    implements(IUserStore) 
     279 
     280    def supports_user_operation(self, operation): 
     281        return hasattr(self, operation) 
     282 
     283    def get_usernames(self): 
     284        db = self.env.get_db_cnx() 
     285        cursor = db.cursor() 
     286        cursor.execute("SELECT sid FROM session " 
     287                       "WHERE authenticated=1 " 
     288                       "ORDER BY sid") 
     289        for row in cursor: 
     290            yield row[0] 
     291 
     292 
     293class SessionUserAttributeProvider(Component): 
     294    """ 
     295    Component for providing user attributes via Trac sessions. 
     296    """ 
     297 
     298    implements(IUserAttributeProvider) 
     299 
     300    def supports_attribute_operation(self, operation): 
     301        return hasattr(self, operation) 
     302 
     303    def get_user_attribute(self, username, attribute): 
     304        db = self.env.get_db_cnx() 
     305        cursor = db.cursor() 
     306        cursor.execute("SELECT value FROM session_attribute " 
     307                       "WHERE sid=%s AND name=%s AND authenticated=1", 
     308                       (username, attribute)) 
     309        row = cursor.fetchone() 
     310        if row: 
     311            return row[0] 
     312 
     313        # if the attribute doesn't exist we return an empty string to 
     314        # indicate that the attribute is supported, but not set 
     315        return '' 
     316 
     317    def set_user_attribute(self, username, attribute, value): 
     318        db = self.env.get_db_cnx() 
     319        cursor = db.cursor() 
     320 
     321        if not value or value == '': 
     322            cursor.execute("DELETE FROM session_attribute " 
     323                           "WHERE sid=%s AND name=%s AND authenticated=1", 
     324                          (username, attribute)) 
     325            db.commit() 
     326            return True 
     327 
     328        # check if attribute exists 
     329        cursor.execute("SELECT value FROM session_attribute " 
     330                       "WHERE sid=%s AND name=%s AND authenticated=1", 
     331                       (username, attribute)) 
     332        if cursor.fetchone(): 
     333            # update the attribute 
     334            cursor.execute("UPDATE session_attribute SET value=%s " 
     335                           "WHERE sid=%s AND name=%s AND authenticated=1", 
     336                           (value, username, attribute)) 
     337        else: 
     338            # create new attribute 
     339            cursor.execute("INSERT INTO session_attribute " 
     340                           "(sid,authenticated,name,value) " 
     341                           "VALUES(%s,1,%s,%s)", 
     342                           (username, attribute, value)) 
     343        db.commit() 
     344        return True 
     345 
     346    def delete_all_user_attributes(self, username): 
     347        db = self.env.get_db_cnx() 
     348        cursor = db.cursor() 
     349        cursor.execute("DELETE FROM session_attribute " 
     350                       "WHERE sid=%s AND authenticated=1", 
     351                      (username,)) 
     352        db.commit() 
  • trac/versioncontrol/web_ui/log.py

    Property changes on: trac\user.py
    ___________________________________________________________________
    Name: svn:keywords
       + URL HeadURL Author LastChangedBy Date LastChangedDate Rev Revision LastChangedRevision Id
    
     
    2323from trac.context import Context 
    2424from trac.core import * 
    2525from trac.perm import IPermissionRequestor 
     26from trac.user import UserManager 
    2627from trac.util import Ranges 
    2728from trac.util.datefmt import http_date 
    2829from trac.util.html import html 
     
    193194        if format == 'rss': 
    194195            # Get the email addresses of all known users 
    195196            if Chrome(self.env).show_email_addresses: 
    196                 for username,name,email in self.env.get_known_users(): 
    197                     if email: 
    198                         email_map[username] = email 
     197                email_map = UserManager(self.env).get_attribute_mapper('email') 
    199198        elif format == 'changelog': 
    200199            for rev in revs: 
    201200                changeset = changes[rev]