Migrating AGOL User Accounts Using the ArcGIS API for Python

Sean Sweeney, GIS Senior Programmer Analyst

City of Cambridge, MA

NEARC - Newry, ME

October 21, 2019

Why?

  • One login
  • Simplified management
  • Enforce password policy
  • Better access control

What?

  • Profile
  • Folders
  • Items
  • Groups
  • Role
  • Credits
  • Esri access

Connect to ArcGIS Online

# Get username and password
# TODO: incorporate SSO login
username = input('Connection username: ')
password = getpass(prompt='Connection password: ')

# Connect to ArcGIS Online
try:
	gis = GIS("https://arcgis.com/", username, password)
except:
	print(sys.exc_info()[0])
	exit(1)

					

Connect to ArcGIS Online

# Get username and password
# TODO: incorporate SSO login
username = input('Connection username: ')
password = getpass(prompt='Connection password: ')

# Connect to ArcGIS Online
try:
	gis = GIS("https://arcgis.com/", username, password)
except:
	print(sys.exc_info()[0])
	exit(1)

					

Connect to ArcGIS Online

# Get username and password
# TODO: incorporate SSO login
username = input('Connection username: ')
password = getpass(prompt='Connection password: ')

# Connect to ArcGIS Online
try:
	gis = GIS(username=username,password=password)
except:
	print(sys.exc_info()[0])
	exit(1)

					

Get pointers to old and new users

# Get pointers to old and new users
agol_username = input('AGOL (old) username: ')

sso_username = input('SSO (new) username: ')

try:
	agol_user = gis.users.get(agol_username)
	sso_user = gis.users.get(sso_username)
except exceptions.Exception as e:
	print("Unexpected error: {}".format(e))
	raise e

				

Profile Items

Profile items

Profile Items

User.update()

agol_thumbnail_download = agol_user.download_thumbnail(os.getenv('TEMP'))

sso_user.update(access=agol_user.access, 
		preferred_view=agol_user.preferredView, 
		description=agol_user.description, 
		tags=agol_user.tags, 
		thumbnail=agol_thumbnail_download, 
		culture=agol_user.culture, 
		region=agol_user.region, 
		fullname=agol_user.fullName, 
		first_name=agol_user.firstName, 
		last_name=agol_user.lastName
		)
						
					
agol_thumbnail_download = agol_user.download_thumbnail(os.getenv('TEMP'))

sso_user.update(access=agol_user.access, 
		preferred_view=agol_user.preferredView, 
		description=agol_user.description, 
		tags=agol_user.tags, 
		thumbnail=agol_thumbnail_download, 
		culture=agol_user.culture, 
		region=agol_user.region, 
		fullname=agol_user.fullName, 
		first_name=agol_user.firstName, 
		last_name=agol_user.lastName
		)
						
					
agol_thumbnail_download = agol_user.download_thumbnail(os.getenv('TEMP'))
	
sso_user.update(access=agol_user.access, 
		preferred_view=agol_user.preferredView, 
		description=agol_user.description, 
		tags=agol_user.tags, 
		thumbnail=agol_thumbnail_download, 
		culture=agol_user.culture, 
		region=agol_user.region, 
		fullname=agol_user.fullName, 
		first_name=agol_user.firstName, 
		last_name=agol_user.lastName
		)

					

Profile Items

Role

builtin_roles = ['org_user', 'org_publisher', 'org_admin',
					'viewer', 'view_only', 'viewplusedit']
if (agol_user.roleId in builtin_roles):
	# Built-in user role (org_user, org_publisher, org_admin, 
	#                     viewer, view_only, viewplusedit)
	# Assign directly
	sso_user.update_role(role=agol_user.roleId)
else:
	# Custom role - first get role object from RoleManager
	role = gis.users.roles.get_role(agol_user.roleId)
	sso_user.update_role(role=role)

					
builtin_roles = ['org_user', 'org_publisher', 'org_admin',
					'viewer', 'view_only', 'viewplusedit']
if (agol_user.roleId in builtin_roles):
	# Built-in user role (org_user, org_publisher, org_admin, 
	#                     viewer, view_only, viewplusedit)
	# Assign directly
	sso_user.update_role(role=agol_user.roleId)
else:
	# Custom role - first get role object from RoleManager
	role = gis.users.roles.get_role(agol_user.roleId)
	sso_user.update_role(role=role)

				

Profile Items

Regionalization & Esri Access

# Regionalization #
sso_user.units = agol_user.units
sso_user.cultureFormat = agol_user.cultureFormat
			
# Esri access #
if (agol_user.esri_access == 'both'):
	sso_user.esri_access = True

				

Groups

for group in agol_user.groups:
	if (group.owner == agol_username):
		print('Changing ownership: ' + group.title)
		group.reassign_to(sso_username)
	else:
		print('Joining: ' + group.title)
		group.add_users([sso_username])	

					
for group in agol_user.groups:
	if (group.owner == agol_username):
		print('Changing ownership: ' + group.title)
		group.reassign_to(sso_username)
	else:
		print('Joining: ' + group.title)
		group.add_users([sso_username])	

					

Content

Share and update capabilities

What can members update?

item_reassign()

all_groups = gis.groups.search('-')
update_groups = [group.title for group in all_groups 
		if 'updateitemcontrol' in group.capabilities]
#...
item_groups = [group.title for group in item.shared_with['groups']]
item_update_groups = [title for title in item_groups 
			if title in update_groups]
if item_update_groups:
	item.unshare(item_update_groups)
	
try:
	item.reassign_to(user, target_folder=folder)
except Exception as e:
	print(e)
	raise e

if item_update_groups:
	item.share(groups=item_update_groups, allow_members_to_edit=True)

					

item_reassign()

all_groups = gis.groups.search('-')
update_groups = [group.title for group in all_groups 
		if 'updateitemcontrol' in group.capabilities]
#...
item_groups = [group.title for group in item.shared_with['groups']]
item_update_groups = [title for title in item_groups 
			if title in update_groups]
if item_update_groups:
	item.unshare(item_update_groups)
	
try:
	item.reassign_to(user, target_folder=folder)
except Exception as e:
	print(e)
	raise e

if item_update_groups:
	item.share(groups=item_update_groups, allow_members_to_edit=True)

					

item_reassign()

all_groups = gis.groups.search('-')
update_groups = [group.title for group in all_groups 
		if 'updateitemcontrol' in group.capabilities]
#...
item_groups = [group.title for group in item.shared_with['groups']]
item_update_groups = [title for title in item_groups 
			if title in update_groups]
if item_update_groups:
	item.unshare(item_update_groups)
	
try:
	item.reassign_to(user, target_folder=folder)
except Exception as e:
	print(e)
	raise e

if item_update_groups:
	item.share(groups=item_update_groups, allow_members_to_edit=True)

					

item_reassign()

all_groups = gis.groups.search('-')
update_groups = [group.title for group in all_groups 
		if 'updateitemcontrol' in group.capabilities]
#...
item_groups = [group.title for group in item.shared_with['groups']]
item_update_groups = [title for title in item_groups 
			if title in update_groups]
if item_update_groups:
	item.unshare(item_update_groups)
	
try:
	item.reassign_to(user, target_folder=folder)
except Exception as e:
	print(e)
	raise e

if item_update_groups:
	item.share(groups=item_update_groups, allow_members_to_edit=True)

					

Root Content

Root folder

Root Content

# Root Content #
agol_root_items = agol_user.items()
print('Folder: Root')
for item in agol_root_items:
	try:
		print('* Moving: ' + item.title)
		item_reassign(item=item, user=sso_username, folder=None)
	except Exception as e:
		print(e)
		print("Item may have already been assigned to user.")

					

Root Content

# Root Content #
agol_root_items = agol_user.items()
print('Folder: Root')
for item in agol_root_items:
	try:
		print('* Moving: ' + item.title)
		item_reassign(item=item, user=sso_username, folder=None)
	except Exception as e:
		print(e)
		print("Item may have already been assigned to user.")

					

Folder Content

agol_folders = agol_user.folders
sso_folders = sso_user.folders
sso_foldernames = [folder['title'] for folder in sso_folders]
for agol_folder in agol_folders:
	gis.content.create_folder(agol_folder['title'], sso_username)
	agol_folder_items = agol_user.items(folder=agol_folder['title']) 
	for item in agol_folder_items:
		print('* Moving ' + item.title)
		item_reassign(item=item, user=sso_username, 
				folder=agol_folder['title'])

					

Folder Content

agol_folders = agol_user.folders
sso_folders = sso_user.folders
sso_foldernames = [folder['title'] for folder in sso_folders]
for agol_folder in agol_folders:
	gis.content.create_folder(agol_folder['title'], sso_username)
	agol_folder_items = agol_user.items(folder=agol_folder['title']) 
	for item in agol_folder_items:
		print('* Moving ' + item.title)
		item_reassign(item=item, user=sso_username, 
				folder=agol_folder['title'])

					

Folder Content

agol_folders = agol_user.folders
sso_folders = sso_user.folders
sso_foldernames = [folder['title'] for folder in sso_folders]
for agol_folder in agol_folders:
	gis.content.create_folder(agol_folder['title'], sso_username)
	agol_folder_items = agol_user.items(folder=agol_folder['title']) 
	for item in agol_folder_items:
		print('* Moving ' + item.title)
		item_reassign(item=item, user=sso_username, 
				folder=agol_folder['title'])

					

Things we can't do

Favorites

agol_fav_items = gis.groups.get(agol_user.favGroupId)
agol_favs = [content.title for content in agol_fav_items.content()]
if agol_favs:
	print("Old User's Favorites".center(40,'-'))
	print(agol_favs)			

						

Credits

print(f'Old user account had {agol_user.assignedCredits} credits')
gis.admin.credits.allocate(username=sso_user.username, 
							credits=agol_user.assignedCredits)

						

Licenses

# Licenses #
# Not yet available in AGOL (Enterprise only) #
# print("Old User's Licenses".center(40,'-'))
# print(agol_user.provisions)

						

Link your ArcGIS accounts

Requires authenticating to linked account.

Demos

More Info

Me

Email: ssweeney@cambridgema.gov Twitter: @hiker4k GitHub: seansweeney

This Presentation: https://github.com/seansweeney/NEARC-2019

Us

Web: http://cambridgema.gov/gis Twitter: @CambridgeGIS