edd8501bd7b13447ac9921166dc2ab6a9046c528
[be.git] / libbe / ui / util / user.py
1 # Copyright (C) 2009-2012 Chris Ball <cjb@laptop.org>
2 #                         W. Trevor King <wking@tremily.us>
3 #
4 # This file is part of Bugs Everywhere.
5 #
6 # Bugs Everywhere is free software: you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the Free
8 # Software Foundation, either version 2 of the License, or (at your option) any
9 # later version.
10 #
11 # Bugs Everywhere is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14 # more details.
15 #
16 # You should have received a copy of the GNU General Public License along with
17 # Bugs Everywhere.  If not, see <http://www.gnu.org/licenses/>.
18
19 """Tools for getting, setting, creating, and parsing the user's ID.
20
21 IDs will look like 'John Doe <jdoe@example.com>'.  Note that the
22 :mod:`libbe.storage.vcs.arch <Arch VCS backend>` *enforces* IDs with
23 this format.
24
25 Do not confuse the user IDs discussed in this module, which refer to
26 humans, with the "user IDs" discussed in :mod:`libbe.util.id`, which
27 are human-readable tags refering to objects.
28 """
29
30 try:
31     from email.utils import formataddr, parseaddr
32 except ImportErrror:  # adjust to old python < 2.5
33     from email.Utils import formataddr, parseaddr
34 import os
35 try:
36     import pwd
37 except ImportError:  # handle non-Unix systems
38     pwd = None
39 import re
40 from socket import gethostname
41
42 import libbe
43 import libbe.storage.util.config
44
45
46 def get_fallback_username():
47     """Return a username extracted from environmental variables.
48     """
49     name = None
50     for env in ['LOGNAME', 'USERNAME']:
51         if os.environ.has_key(env):
52             name = os.environ[env]
53             break
54     if name is None and pwd:
55         pw_ent = pwd.getpwuid(os.getuid())
56         name = pw_ent.pw_name
57     assert name is not None
58     return name
59
60 def get_fallback_fullname():
61     """Return a full name extracted from environmental variables.
62     """
63     name = None
64     for env in ['FULLNAME']:
65         if os.environ.has_key(env):
66             name = os.environ[env]
67             break
68     if pwd and not name:
69         pw_ent = pwd.getpwuid(os.getuid())
70         name = pw_ent.pw_gecos.split(',', 1)[0]
71     if not name:
72         name = get_fallback_username()
73     return name
74
75 def get_fallback_email():
76     """Return an email address extracted from environmental variables.
77     """
78     return os.getenv('EMAIL') or '%s@%s' % (
79         get_fallback_username(), gethostname())
80
81 def create_user_id(name, email=None):
82     """Create a user ID string from given `name` and `email` strings.
83
84     Examples
85     --------
86
87     >>> create_user_id("John Doe", "jdoe@example.com")
88     'John Doe <jdoe@example.com>'
89     >>> create_user_id("John Doe")
90     'John Doe'
91
92     See Also
93     --------
94     parse_user_id : inverse
95     """
96     assert len(name) > 0
97     if email == None or len(email) == 0:
98         return name
99     else:
100         return formataddr((name, email))
101
102 def parse_user_id(value):
103     """Parse a user ID string into `name` and `email` strings.
104
105     Examples
106     --------
107
108     >>> parse_user_id("John Doe <jdoe@example.com>")
109     ('John Doe', 'jdoe@example.com')
110     >>> parse_user_id("John Doe")
111     ('John Doe', None)
112     >>> parse_user_id("John Doe <jdoe@example.com><what?>")
113     ('John Doe', 'jdoe@example.com')
114  
115     See Also
116     --------
117     create_user_id : inverse
118     """
119     if '<' not in value:
120         return (value, None)
121     return parseaddr(value)
122
123 def get_user_id(storage=None):
124     """Return a user ID, checking a list of possible sources.
125
126     The source order is:
127
128     1. Global BE configuration [#]_ (default section, setting 'user').
129     2. `storage.get_user_id`, if that function is defined.
130     3. :func:`get_fallback_username` and :func:`get_fallback_email`.
131
132     .. [#] See :mod:`libbe.storage.util.config`.
133
134     Notes
135     -----
136     Sometimes the storage will keep track of the user ID (e.g. most
137     VCSs, see :meth:`libbe.storage.vcs.base.VCS.get_user_id`).  If so,
138     we prefer that ID to the fallback, since the user has likely
139     configured it directly.
140     """
141     user = libbe.storage.util.config.get_val('user')
142     if user != None:
143         return user
144     if storage != None and hasattr(storage, 'get_user_id'):
145         user = storage.get_user_id()
146         if user != None:
147             return user
148     name = get_fallback_fullname()
149     email = get_fallback_email()
150     user = create_user_id(name, email)
151     return user
152
153 def set_user_id(user_id):
154     """Set the user ID in a user's BE configuration.
155
156     See Also
157     --------
158     libbe.storage.util.config.set_val
159     """
160     user = libbe.storage.util.config.set_val('user', user_id)