Package buildbot :: Package db :: Module users
[frames] | no frames]

Source Code for Module buildbot.db.users

  1  # This file is part of Buildbot.  Buildbot is free software: you can 
  2  # redistribute it and/or modify it under the terms of the GNU General Public 
  3  # License as published by the Free Software Foundation, version 2. 
  4  # 
  5  # This program is distributed in the hope that it will be useful, but WITHOUT 
  6  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
  8  # details. 
  9  # 
 10  # You should have received a copy of the GNU General Public License along with 
 11  # this program; if not, write to the Free Software Foundation, Inc., 51 
 12  # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 13  # 
 14  # Copyright Buildbot Team Members 
 15   
 16  import sqlalchemy as sa 
 17  from sqlalchemy.sql.expression import and_ 
 18   
 19  from buildbot.db import base 
20 21 -class UsDict(dict):
22 pass
23
24 -class UsersConnectorComponent(base.DBConnectorComponent):
25 # Documentation is in developer/database.rst 26
27 - def findUserByAttr(self, identifier, attr_type, attr_data, _race_hook=None):
28 def thd(conn, no_recurse=False): 29 tbl = self.db.model.users 30 tbl_info = self.db.model.users_info 31 32 self.check_length(tbl.c.identifier, identifier) 33 self.check_length(tbl_info.c.attr_type, attr_type) 34 self.check_length(tbl_info.c.attr_data, attr_data) 35 36 # try to find the user 37 q = sa.select([ tbl_info.c.uid ], 38 whereclause=and_(tbl_info.c.attr_type == attr_type, 39 tbl_info.c.attr_data == attr_data)) 40 rows = conn.execute(q).fetchall() 41 42 if rows: 43 return rows[0].uid 44 45 _race_hook and _race_hook(conn) 46 47 # try to do both of these inserts in a transaction, so that both 48 # the new user and the corresponding attributes appear at the same 49 # time from the perspective of other masters. 50 transaction = conn.begin() 51 try: 52 r = conn.execute(tbl.insert(), dict(identifier=identifier)) 53 uid = r.inserted_primary_key[0] 54 55 conn.execute(tbl_info.insert(), 56 dict(uid=uid, attr_type=attr_type, 57 attr_data=attr_data)) 58 59 transaction.commit() 60 except (sa.exc.IntegrityError, sa.exc.ProgrammingError): 61 transaction.rollback() 62 63 # try it all over again, in case there was an overlapping, 64 # identical call to findUserByAttr, but only retry once. 65 if no_recurse: 66 raise 67 return thd(conn, no_recurse=True) 68 69 return uid
70 d = self.db.pool.do(thd) 71 return d
72 73 @base.cached("usdicts")
74 - def getUser(self, uid):
75 def thd(conn): 76 tbl = self.db.model.users 77 tbl_info = self.db.model.users_info 78 79 q = tbl.select(whereclause=(tbl.c.uid == uid)) 80 users_row = conn.execute(q).fetchone() 81 82 if not users_row: 83 return None 84 85 # make UsDict to return 86 usdict = UsDict() 87 88 # gather all attr_type and attr_data entries from users_info table 89 q = tbl_info.select(whereclause=(tbl_info.c.uid == uid)) 90 rows = conn.execute(q).fetchall() 91 for row in rows: 92 usdict[row.attr_type] = row.attr_data 93 94 # add the users_row data *after* the attributes in case attr_type 95 # matches one of these keys. 96 usdict['uid'] = users_row.uid 97 usdict['identifier'] = users_row.identifier 98 usdict['bb_username'] = users_row.bb_username 99 usdict['bb_password'] = users_row.bb_password 100 101 return usdict
102 d = self.db.pool.do(thd) 103 return d 104
105 - def getUserByUsername(self, username):
106 def thd(conn): 107 tbl = self.db.model.users 108 tbl_info = self.db.model.users_info 109 110 q = tbl.select(whereclause=(tbl.c.bb_username == username)) 111 users_row = conn.execute(q).fetchone() 112 113 if not users_row: 114 return None 115 116 # make UsDict to return 117 usdict = UsDict() 118 119 # gather all attr_type and attr_data entries from users_info table 120 q = tbl_info.select(whereclause=(tbl_info.c.uid == users_row.uid)) 121 rows = conn.execute(q).fetchall() 122 for row in rows: 123 usdict[row.attr_type] = row.attr_data 124 125 # add the users_row data *after* the attributes in case attr_type 126 # matches one of these keys. 127 usdict['uid'] = users_row.uid 128 usdict['identifier'] = users_row.identifier 129 usdict['bb_username'] = users_row.bb_username 130 usdict['bb_password'] = users_row.bb_password 131 132 return usdict
133 d = self.db.pool.do(thd) 134 return d 135
136 - def getUsers(self):
137 def thd(conn): 138 tbl = self.db.model.users 139 rows = conn.execute(tbl.select()).fetchall() 140 141 dicts = [] 142 if rows: 143 for row in rows: 144 ud = dict(uid=row.uid, identifier=row.identifier) 145 dicts.append(ud) 146 return dicts
147 d = self.db.pool.do(thd) 148 return d 149
150 - def updateUser(self, uid=None, identifier=None, bb_username=None, 151 bb_password=None, attr_type=None, attr_data=None, 152 _race_hook=None):
153 def thd(conn): 154 transaction = conn.begin() 155 tbl = self.db.model.users 156 tbl_info = self.db.model.users_info 157 update_dict = {} 158 159 # first, add the identifier is it exists 160 if identifier is not None: 161 self.check_length(tbl.c.identifier, identifier) 162 update_dict['identifier'] = identifier 163 164 # then, add the creds if they exist 165 if bb_username is not None: 166 assert bb_password is not None 167 self.check_length(tbl.c.bb_username, bb_username) 168 self.check_length(tbl.c.bb_password, bb_password) 169 update_dict['bb_username'] = bb_username 170 update_dict['bb_password'] = bb_password 171 172 # update the users table if it needs to be updated 173 if update_dict: 174 q = tbl.update(whereclause=(tbl.c.uid == uid)) 175 res = conn.execute(q, update_dict) 176 177 # then, update the attributes, carefully handling the potential 178 # update-or-insert race condition. 179 if attr_type is not None: 180 assert attr_data is not None 181 182 self.check_length(tbl_info.c.attr_type, attr_type) 183 self.check_length(tbl_info.c.attr_data, attr_data) 184 185 # first update, then insert 186 q = tbl_info.update( 187 whereclause=(tbl_info.c.uid == uid) 188 & (tbl_info.c.attr_type == attr_type)) 189 res = conn.execute(q, attr_data=attr_data) 190 if res.rowcount == 0: 191 _race_hook and _race_hook(conn) 192 193 # the update hit 0 rows, so try inserting a new one 194 try: 195 q = tbl_info.insert() 196 res = conn.execute(q, 197 uid=uid, 198 attr_type=attr_type, 199 attr_data=attr_data) 200 except (sa.exc.IntegrityError, sa.exc.ProgrammingError): 201 # someone else beat us to the punch inserting this row; 202 # let them win. 203 transaction.rollback() 204 return 205 206 transaction.commit()
207 d = self.db.pool.do(thd) 208 return d 209
210 - def removeUser(self, uid):
211 def thd(conn): 212 # delete from dependent tables first, followed by 'users' 213 for tbl in [ 214 self.db.model.change_users, 215 self.db.model.users_info, 216 self.db.model.users, 217 ]: 218 conn.execute(tbl.delete(whereclause=(tbl.c.uid==uid)))
219 d = self.db.pool.do(thd) 220 return d 221
222 - def identifierToUid(self, identifier):
223 def thd(conn): 224 tbl = self.db.model.users 225 226 q = tbl.select(whereclause=(tbl.c.identifier == identifier)) 227 row = conn.execute(q).fetchone() 228 if not row: 229 return None 230 231 return row.uid
232 d = self.db.pool.do(thd) 233 return d 234