Skip to content

Commit

Permalink
Merge pull request #44 from ssciolla/issues-34-and-43-update-adding-a…
Browse files Browse the repository at this point in the history
…nd-removing-users

Updating, combining functions for adding, removing users from ArcGIS groups (#34 and #43)
  • Loading branch information
ssciolla authored Dec 19, 2019
2 parents 9690989 + 24b9043 commit 0ee1f96
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 79 deletions.
135 changes: 68 additions & 67 deletions arcgisUM.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

# standard modules
import datetime, logging, json, traceback
from operator import itemgetter
from io import StringIO

# third-party modules
Expand All @@ -24,6 +25,21 @@ def handleError(self, record): # @UnusedVariable
RUN_START_TIME = datetime.datetime.now(tz=TIMEZONE_UTC)
RUN_START_TIME_FORMATTED = RUN_START_TIME.strftime('%Y%m%d%H%M%S')

MODIFY_MODES = {
"add": {
"verb": "add",
"verbStem": "add",
"verbPrep": "to",
"methodName": "add_users"
},
"remove": {
"verb": "remove",
"verbStem": "remov",
"verbPrep": "from",
"methodName": "remove_users"
}
}

# Hold parsed options
options = None

Expand Down Expand Up @@ -88,39 +104,61 @@ def getArcGISGroupByTitle(arcGISAdmin, title):
return None


def addCanvasUsersToGroup(instructorLog, group, courseUsers):
"""Add new users to the ArcGIS group. """
def modifyUsersInGroup(group: object, users: list, mode: str, instructorLog: str):
"""Depending on the mode, add or remove users from the given ArcGIS group"""

logger.info("modifyUsersInGroup: enter")
groupNameAndID = util.formatNameAndID(group)

logger.info("addCanvasUsersToGroup: enter")

if len(courseUsers) == 0:
logger.info('No new users to add to ArcGIS Group {}'.format(groupNameAndID))

# Set mode-specific methods and variables
if mode in MODIFY_MODES:
modeDict = MODIFY_MODES[mode]
verb, verbStem, verbPrep, methodName = itemgetter("verb", "verbStem", "verbPrep", "methodName")(modeDict)
modifyUsersMethod = getattr(group, methodName)
logger.debug(modifyUsersMethod)
else:
logger.error("Function was called with an invalid mode: " + mode)

if len(users) == 0:
logger.info(f"No users to {verb} {verbPrep} ArcGIS Group {groupNameAndID}")
instructorLog += f"No users were {verbStem}ed.\n\n"
logger.debug(f"modifyUsersInGroup: instructorLog: [\n{instructorLog}\n]")
return instructorLog

logger.info('Adding Canvas Users to ArcGIS Group {}: {}'.format(groupNameAndID, courseUsers))
# ArcGIS usernames are U-M uniqnames with the ArcGIS organization name appended.
arcGISFormatUsers = formatUsersNamesForArcGIS(courseUsers)
logger.debug("addCanvasUsersToGroup: formatted: {}".format(arcGISFormatUsers))

results = group.add_users(arcGISFormatUsers)
logger.debug("adding: results: {}".format(results))

usersNotAdded = results.get('notAdded')
""":type usersNotAdded: list"""
usersCount = len(arcGISFormatUsers)
usersCount -= len(usersNotAdded) if usersNotAdded else 0
logger.debug("usersCount: {}".format(usersCount))
logger.debug("aCUTG: instructorLog 1: [{}]".format(instructorLog))
instructorLog += 'Number of users added to group: [{}]\n\n'.format(usersCount)
logger.debug("aCUTG: instructorLog 2: [{}]".format(instructorLog))
if usersNotAdded:
logger.warning('Warning: Some or all users not added to ArcGIS group {}: {}'.format(groupNameAndID, usersNotAdded))
instructorLog += 'Users not in group (these users need ArcGIS accounts created for them):\n' + '\n'.join(['* ' + userNotAdded for userNotAdded in usersNotAdded]) + '\n\n' + 'ArcGIS group ID number:\n{}\n\n'.format(group.id)
instructorLog += '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n'
logger.debug("aCUTG: instructorLog 3: [{}]".format(instructorLog))

logger.info("addCanvasUsersToGroup: instructorLog: [{}]".format(instructorLog))
logger.info(f"{verbStem}ing Canvas Users {verbPrep} ArcGIS Group {groupNameAndID}: {users}")

# Change Canvas usernames to the ArcGIS format
# (ArcGIS usernames are U-M uniqnames with the ArcGIS organization name appended)
arcGISFormatUsers = formatUsersNamesForArcGIS(users)
logger.debug(f"modifyUsersInGroup: formatted: {arcGISFormatUsers}")

listsOfFormattedUsernames = util.splitListIntoSublists(arcGISFormatUsers, 20)
usersNotModified = []

for listOfFormattedUsernames in listsOfFormattedUsernames:
try:
results = modifyUsersMethod(listOfFormattedUsernames)
logger.debug(f"{verbStem}ing: results: {results}")
usersNotModified += results.get(f"not{verbStem.capitalize()}ed")
except RuntimeError as exception:
logger.error(f"Exception while {verbStem}ing users {verbPrep} ArcGIS group '{groupNameAndID}': {exception}")
return None

usersModifiedCount = len(arcGISFormatUsers) - len(usersNotModified)
logger.debug(f"usersModifiedCount: {usersModifiedCount}")
instructorLog += f"Number of users {verbStem}ed {verbPrep} group: [{usersModifiedCount}]\n\n"
if usersNotModified:
notModifiedMessage = f"Some or all users not {verbStem}ed {verbPrep} ArcGIS group"
if mode == "add":
notModifiedMessage += " (These users likely need ArcGIS accounts set up)"
logger.warning(
f"Warning: {notModifiedMessage} {groupNameAndID} : {usersNotModified}"
)
instructorLog += f"{notModifiedMessage}:\n" + "\n".join(
["* " + userNotModified for userNotModified in usersNotModified]
) + "\n"

logger.debug(f"modifyUsersInGroup: instructorLog: [\n{instructorLog}\n]")
return instructorLog


Expand All @@ -137,43 +175,6 @@ def getCurrentArcGISMembers(group, groupNameAndID):
return groupUsers


def removeListOfUsersFromArcGISGroup(group, groupNameAndID, groupUsers):
"""Remove only listed users from ArcGIS group."""

if len(groupUsers) == 0:
logger.info('No obsolete users to remove from ArcGIS Group {}'.format(groupNameAndID))
return None

logger.info('ArcGIS Users to be removed from ArcGIS Group [{}] [{}]'.format(groupNameAndID, ','.join(groupUsers)))
try:
results = group.removeUsersFromGroup(','.join(groupUsers))
except RuntimeError as exception:
logger.error('Exception while removing users from ArcGIS group "{}": {}'.format(groupNameAndID, exception))
return None

usersNotRemoved = results.get('notRemoved')
""":type usersNotRemoved: list"""
if usersNotRemoved:
logger.warning('Warning: Some or all users not removed from ArcGIS group {}: {}'.format(groupNameAndID, usersNotRemoved))

return results


def removeSomeExistingGroupMembers(groupTitle, group,instructorLog,groupUsers):
"""Get list of ArgGIS users to remove from group and call method to remove them."""
results = ''
groupNameAndID = util.formatNameAndID(group)
logger.info('Found ArcGIS group: {}'.format(groupNameAndID))
instructorLog += 'Updating ArcGIS group: "{}"\n'.format(groupTitle)

if not groupUsers:
logger.info('Existing ArcGIS group {} does not have users to remove.'.format(groupNameAndID))
else:
results = removeListOfUsersFromArcGISGroup(group, groupNameAndID, groupUsers)

return instructorLog, results


def createNewArcGISGroup(arcGIS, groupTags, groupTitle,instructorLog):
"""Create a new ArgGIS group. Return group and any creation messages."""
group=None
Expand Down
23 changes: 11 additions & 12 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,19 +132,18 @@ def updateGroupUsers(courseUserDictionary, course, instructorLog, groupTitle, gr
canvasCourseUsers = [user.login_id for user in courseUserDictionary[course.id] if user.login_id is not None]
logger.debug('All Canvas users in course for Group {}: Canvas Users: {}'.format(groupNameAndID, canvasCourseUsers))

# compute the exact sets of users to change.
changedArcGISGroupUsers, changedCourseUsers = minimizeUserChanges(groupUsersTrimmed, canvasCourseUsers)
# added to avoid undefined variable warning

# fix up the user name format for ArcGIS users names
changedArcGISGroupUsers = arcgisUM.formatUsersNamesForArcGIS(changedArcGISGroupUsers)
logger.info('Users to remove from ArcGIS: Group {}: ArcGIS Users: {}'.format(groupNameAndID, changedArcGISGroupUsers))
logger.info('Users to add from Canvas course for ArcGIS: Group {}: Canvas Users: {}'.format(groupNameAndID, changedCourseUsers))

# Compute the exact sets of users to change.
usersToRemove, usersToAdd = minimizeUserChanges(groupUsersTrimmed, canvasCourseUsers)

logger.info('Users to remove from ArcGIS: Group {}: Users: {}'.format(groupNameAndID, usersToRemove))
logger.info('Users to add to ArcGIS: Group {}: Users: {}'.format(groupNameAndID, usersToAdd))

# Now update only the users in the group that have changed.
instructorLog, results = arcgisUM.removeSomeExistingGroupMembers(groupTitle, group, instructorLog, changedArcGISGroupUsers) # @UnusedVariable
instructorLog = arcgisUM.addCanvasUsersToGroup(instructorLog, group, changedCourseUsers)

instructorLog += f"Group: {groupNameAndID} \n\n"
instructorLog = arcgisUM.modifyUsersInGroup(group, usersToRemove, "remove", instructorLog)
instructorLog = arcgisUM.modifyUsersInGroup(group, usersToAdd, "add", instructorLog)
instructorLog += "- - -\n"

return instructorLog


Expand Down
6 changes: 6 additions & 0 deletions util.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ def elideString(string):
return string


def splitListIntoSublists(origList: list, sublistLength: int=10):
"""Transform a given list into a list of lists of a specified maximum length"""
sublists = [origList[x:x + sublistLength] for x in range(0, len(origList), sublistLength)]
return sublists


class Iso8601UTCTimeFormatter(logging.Formatter):
"""
A logging Formatter class giving timestamps in a more common ISO 8601 format.
Expand Down

0 comments on commit 0ee1f96

Please sign in to comment.