Skip to content

Commit 83ef70b

Browse files
authored
Merge pull request #232 from blackducksoftware/bulk-modify-users
Scripts to bulk edit user's email addresses and user group names from CSV
2 parents 693c633 + acdb21d commit 83ef70b

File tree

2 files changed

+265
-0
lines changed

2 files changed

+265
-0
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
'''
2+
Created on Jan 27, 2023
3+
@author: dnichol
4+
Bulk update user group names from CSV. CSV file requires two columns, titled 'Existing' and 'New'. This script is case sensitive.
5+
6+
This script requires a .restconfig.json file present to configure the connection details. For more details see : https://community.synopsys.com/s/article/How-to-use-the-hub-rest-api-python-for-Black-Duck
7+
8+
The .restconfig.json file should be in the following format:
9+
10+
{
11+
"baseurl": "https://your-hub-dns",
12+
"api_token": "insert-token-here",
13+
"insecure": true,
14+
"debug": false
15+
}
16+
17+
Copyright (C) 2023 Synopsys, Inc.
18+
http://www.synopsys.com/
19+
20+
Licensed to the Apache Software Foundation (ASF) under one
21+
or more contributor license agreements. See the NOTICE file
22+
distributed with this work for additional information
23+
regarding copyright ownership. The ASF licenses this file
24+
to you under the Apache License, Version 2.0 (the
25+
"License"); you may not use this file except in compliance
26+
with the License. You may obtain a copy of the License at
27+
28+
http://www.apache.org/licenses/LICENSE-2.0
29+
30+
Unless required by applicable law or agreed to in writing,
31+
software distributed under the License is distributed on an
32+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
33+
KIND, either express or implied. See the License for the
34+
specific language governing permissions and limitations
35+
under the License.
36+
'''
37+
38+
import csv
39+
import logging
40+
import argparse
41+
import sys
42+
import json
43+
import traceback
44+
from requests import HTTPError, RequestException
45+
46+
from blackduck import Client
47+
48+
def log_config():
49+
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(module)s: %(message)s', stream=sys.stderr, level=logging.DEBUG)
50+
logging.getLogger("requests").setLevel(logging.WARNING)
51+
logging.getLogger("urllib3").setLevel(logging.WARNING)
52+
logging.getLogger("blackduck").setLevel(logging.WARNING)
53+
54+
def parse_parameter():
55+
parser = argparse.ArgumentParser("Bulk update user groups from CSV file - modifies the name of the user groups given the existing name and new name")
56+
parser.add_argument("CSV", help="Location of the CSV file")
57+
# "CSV File requires two columns titled 'Existing' and 'New'",
58+
return parser.parse_args()
59+
60+
def get_user_group_by_name(hub_client, name):
61+
params = {
62+
'q': [f"name:{name}"]
63+
}
64+
for user_group in hub_client.get_items("/api/usergroups", params=params):
65+
if user_group['name'] == name:
66+
user_url = hub_client.list_resources(user_group)['href']
67+
print(f"Found user group: {name}")
68+
return user_group
69+
70+
71+
def read_csv(hub_client, csv_path):
72+
updated = 0
73+
failed = 0
74+
not_found = 0
75+
with open(csv_path, newline='') as csvfile:
76+
reader = csv.DictReader(csvfile)
77+
for row in reader:
78+
existing_name = (row['Existing'])
79+
new_name = (row['New'])
80+
try:
81+
user = get_user_group_by_name(hub_client, existing_name)
82+
if user:
83+
update_user_group(hub_client, existing_name, new_name, user)
84+
updated += 1
85+
else:
86+
logging.info(f"User group {existing_name} was not found")
87+
not_found += 1
88+
except RequestException as err:
89+
logging.error(f"Failed to update user group {existing_name}. Reason is " + str(err))
90+
failed += 1
91+
except Exception as err:
92+
raise err
93+
94+
logging.info(f"------------------------------")
95+
logging.info(f"Execution complete.")
96+
logging.info(f"{updated} user groups updated")
97+
logging.info(f"{not_found} user groups were not found")
98+
logging.info(f"{failed} user groups failed to update")
99+
100+
def update_user_group(hub_client, existing_name, new_name, user_group):
101+
user_group_url = hub_client.list_resources(user_group)['href']
102+
103+
# Update the name.
104+
user_group['name'] = new_name
105+
106+
logging.info(f"Updating user group {existing_name} to {user_group['name']} for user group {user_group_url}")
107+
hub_client.session.put(user_group_url, json=user_group)
108+
109+
110+
def main():
111+
log_config()
112+
args = parse_parameter()
113+
try:
114+
with open('.restconfig.json','r') as f:
115+
config = json.load(f)
116+
hub_client = Client(token=config['api_token'],
117+
base_url=config['baseurl'],
118+
verify=not config['insecure'],
119+
timeout=15,
120+
retries=3)
121+
122+
read_csv(hub_client, args.CSV)
123+
except HTTPError as err:
124+
hub_client.http_error_handler(err)
125+
except Exception as err:
126+
logging.error(f"Failed to perform the task. See the stack trace")
127+
traceback.print_exc()
128+
129+
if __name__ == '__main__':
130+
sys.exit(main())
131+

examples/update_users_from_csv.py

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
'''
2+
Created on Jan 27, 2023
3+
@author: dnichol
4+
Bulk update users email addresses from CSV. CSV file requires two columns, titled 'Existing' and 'New'. This script is case sensitive.
5+
6+
This script requires a .restconfig.json file present to configure the connection details. For more details see : https://community.synopsys.com/s/article/How-to-use-the-hub-rest-api-python-for-Black-Duck
7+
8+
The .restconfig.json file should be in the following format:
9+
10+
{
11+
"baseurl": "https://your-hub-dns",
12+
"api_token": "insert-token-here",
13+
"insecure": true,
14+
"debug": false
15+
}
16+
17+
Licensed to the Apache Software Foundation (ASF) under one
18+
or more contributor license agreements. See the NOTICE file
19+
distributed with this work for additional information
20+
regarding copyright ownership. The ASF licenses this file
21+
to you under the Apache License, Version 2.0 (the
22+
"License"); you may not use this file except in compliance
23+
with the License. You may obtain a copy of the License at
24+
25+
http://www.apache.org/licenses/LICENSE-2.0
26+
27+
Unless required by applicable law or agreed to in writing,
28+
software distributed under the License is distributed on an
29+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
30+
KIND, either express or implied. See the License for the
31+
specific language governing permissions and limitations
32+
under the License.
33+
'''
34+
35+
import csv
36+
import logging
37+
import argparse
38+
import sys
39+
import json
40+
import traceback
41+
from requests import HTTPError, RequestException
42+
43+
from blackduck import Client
44+
45+
def log_config():
46+
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(module)s: %(message)s', stream=sys.stderr, level=logging.DEBUG)
47+
logging.getLogger("requests").setLevel(logging.WARNING)
48+
logging.getLogger("urllib3").setLevel(logging.WARNING)
49+
logging.getLogger("blackduck").setLevel(logging.WARNING)
50+
51+
def parse_parameter():
52+
parser = argparse.ArgumentParser("Bulk update users from CSV file - modifies the email addresses of the users given the existing email and new email address")
53+
parser.add_argument("CSV", help="Location of the CSV file")
54+
# "CSV File requires two columns titled 'Existing' and 'New'",
55+
return parser.parse_args()
56+
57+
def get_user_by_email(hub_client, email):
58+
params = {
59+
'q': [f"name:{email}"]
60+
}
61+
for user in hub_client.get_items("/api/users", params=params):
62+
if user['email'] == email:
63+
user_url = hub_client.list_resources(user)['href']
64+
print(f"Found user: {email}")
65+
return user
66+
67+
68+
def read_csv(hub_client, csv_path):
69+
updated = 0
70+
failed = 0
71+
not_found = 0
72+
with open(csv_path, newline='') as csvfile:
73+
reader = csv.DictReader(csvfile)
74+
for row in reader:
75+
existing_email = (row['Existing'])
76+
new_email = (row['New'])
77+
try:
78+
user = get_user_by_email(hub_client, existing_email)
79+
if user:
80+
update_user(hub_client, existing_email, new_email, user)
81+
updated += 1
82+
else:
83+
logging.info(f"User {existing_email} was not found")
84+
not_found += 1
85+
except RequestException as err:
86+
logging.error(f"Failed to update user {existing_email}. Reason is " + str(err))
87+
failed += 1
88+
except Exception as err:
89+
raise err
90+
91+
logging.info(f"------------------------------")
92+
logging.info(f"Execution complete.")
93+
logging.info(f"{updated} users updated")
94+
logging.info(f"{not_found} users were not found")
95+
logging.info(f"{failed} users failed to update")
96+
97+
def update_user(hub_client, existing_email, new_email, user):
98+
user_url = hub_client.list_resources(user)['href']
99+
100+
# Update the email address.
101+
user['email'] = new_email
102+
103+
# Not just update the email address. If the email is also used as userName and externalUserName then update them too.
104+
if user['userName'] == existing_email:
105+
user['userName'] = new_email
106+
if user.get('externalUserName') and user['externalUserName'] == existing_email:
107+
user['externalUserName'] = new_email
108+
109+
logging.info(f"Updating user {existing_email} to {user['email']} for user {user_url}")
110+
hub_client.session.put(user_url, json=user)
111+
112+
113+
def main():
114+
log_config()
115+
args = parse_parameter()
116+
try:
117+
with open('.restconfig.json','r') as f:
118+
config = json.load(f)
119+
hub_client = Client(token=config['api_token'],
120+
base_url=config['baseurl'],
121+
verify=not config['insecure'],
122+
timeout=15,
123+
retries=3)
124+
125+
read_csv(hub_client, args.CSV)
126+
except HTTPError as err:
127+
hub_client.http_error_handler(err)
128+
except Exception as err:
129+
logging.error(f"Failed to perform the task. See the stack trace")
130+
traceback.print_exc()
131+
132+
if __name__ == '__main__':
133+
sys.exit(main())
134+

0 commit comments

Comments
 (0)