From 3da712347d546761a9d9ade52ef0eb2e781c7694 Mon Sep 17 00:00:00 2001 From: Georg Klein Date: Fri, 19 Mar 2021 01:53:36 +0100 Subject: [PATCH] - Modified file structure to add arbitrary group support - Removed hardcoded segments - cleaned up print statements - removed she-bang, run with python importUsers.py --- importUsers.py | 52 +++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/importUsers.py b/importUsers.py index d222c10..4889615 100755 --- a/importUsers.py +++ b/importUsers.py @@ -1,27 +1,32 @@ -#!/usr/bin/python3 - # Simple Cloudron bulk user import script -# Uses the cloudron REST API v1 +# Uses the Cloudron REST API v1 +# Rev 1.2, 03/019/21, changes: +# - removed the she-bang because it was interfering with alternate python paths. Use python importUsers.py to run +# - changed the CSV file format. The person_id field is gone, user_groups is in. This change allows flexibility +# on group membership (arbitrary number of groups) +# - got rid of the hardcoded values for group membership, use the new user_groups field +# - cleaned up the print statements to use formatted strings instead of awkward concatenations # Rev 1.1, 03/07/21, changes: # - added additional code and option -m to automatically create mailboxes on the appropriate domain. # This should only be used if the mailaddress in the CSV-file belongs to the current cloudron (sub)domain # CVS file requirements: # - csv separator is ';' not ',' (which makes it a not-standard csv file, actually) -# - fieldnames [first_name, last_name, email_address, sis_username, person_id] +# - fieldnames [first_name; last_name; email_address; sis_username; user_groups] # - first three are self explanatory. # Of these, only email_address is required by cloudron. the other fields must exist but can be empty # - sis_username is turned into the optional username in cloudron, field must exist but can be empty -# - person_id follows a DATA-DATA-nn scheme, where only the nn part is used +# - user_groups is a comma-separated list of groups the user should be added to # - example for a minimum CSV file: -# person_id;first_name;last_name;email_address;sis_username -# SOME-STUFF-01;Douglas;Adams;douglas.adams@example.com;d.adams +# first_name;last_name;email_address;sis_username;user_groups +# Douglas;Adams;douglas.adams@example.com;d.adams;staff,writers # ToDo: -# - group membership is hardcoded to our needs right now (s. FIX ME below), this is a Really Bad Idea (tm) -# - csv input format follows the AppleSchoolManager students.csv format, this should be more general -# see https://support.apple.com/guide/apple-school-manager/students-template-tes1bd5a3b1e/web for details +# - groups from the user_group field must already exist. If a specified group is not available, an error is displayed. +# Future revisions could ask whether missing groups should be created # - currently, a new access token is generated for every run of the script. # This could be stored somewhere for consecutive runs, the standard expiry is a year # - could use some sanity checks for input (low priority, if you want to sabotage yourself, go ahead) +# - totpTokens are always requested, even if the user hasn't configured token 2FA (they probably should) +# - Check, if the supplied email address is in the same domain as the Cloudron if the -m option is set import sys, getopt import getpass @@ -40,7 +45,7 @@ def requestAccessToken(domain, username=''): if( a.status_code == requests.codes.ok ): return a.json()['accessToken'] else: - print("Error requesting access token: ", a.status_code) + print(f"Error requesting access token: {a.status_code}") sys.exit(2) def main(argv): @@ -94,19 +99,26 @@ def main(argv): r = requests.post(requestUrl, json=payload) if( r.status_code == requests.codes.created ): - print("User " + displayName + " succesfully created") + print(f"User {displayName} succesfully created") curUserId = r.json()['id'] userUrl = apiBasePath + '/users/'+curUserId+'/groups?access_token='+accessToken # look up current user's group id and prepare the groups array for adding the user to the groups - # FIX ME: this section uses hardcoded information to calculate the appropriate group names for our naming scheme - classGroup = 'schueler-hd-' + entry['person_id'].split('-')[2].lower() - userGroups = {"groupIds":[groups['Schueler'],groups[classGroup]]} + groupNames = entry['user_groups'].split(',') + userGroupsIDs = [] + for curGroup in groupNames: + try: + userGroupsIDs.append(groups[curGroup]) + except: + print(f"Group {curGroup} doesn't exist on this Cloudron.") + + userGroups = {"groupIds":userGroupsIDs} + p = requests.put(userUrl,userGroups) if( p.status_code == requests.codes.no_content): - print("User " + displayName + " added to groups 'Schueler' & " + classGroup) + print(f"User {displayName} added to groups {groupNames}") else: - print("Could not add user " + displayName + " to groups!") + print(f"Could not add user {displayName} to groups!") # If a mailbox was to be added, do that now (we have the id already) if( addmailbox == True ): @@ -115,12 +127,12 @@ def main(argv): mailUrl = apiBasePath + '/mail/'+userDomain+'/mailboxes?access_token='+accessToken p = requests.post(mailUrl, json=payload) if( p.status_code == requests.codes.created ): - print("Mailbox for user " + displayName + " created as " + entry['email_address']) + print(f"Mailbox for user {displayName} created as {entry['email_address']}") else: - print("Could not create mailbox for user " + displayName + ", error code " + p.status_code) + print(f"Could not create mailbox for user {displayName}, error code {p.status_code}") else: - print('User ' + displayName + ' could not be created, statuscode ', r.status_code) + print(f"User {displayName} could not be created, statuscode {r.status_code}") if __name__ == "__main__": main(sys.argv[1:]) \ No newline at end of file