From a017621a3d64b5dc61e58fa89f6ff64dd3b99e94 Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Tue, 15 Aug 2023 07:58:23 -0700 Subject: [PATCH] Added support for alternative output when creating contacts --- docs/Domain-SharedContacts-GAL.md | 14 ++++ docs/GamUpdates.md | 24 ++++++ docs/How-to-Upgrade-from-Standard-GAM.md | 4 +- docs/Users-People-Contacts-Profiles.md | 30 ++++++- docs/Version-and-Help.md | 12 +-- src/GamCommands.txt | 3 + src/GamUpdate.txt | 24 ++++++ src/gam/__init__.py | 101 ++++++++++++++++++++--- 8 files changed, 193 insertions(+), 19 deletions(-) diff --git a/docs/Domain-SharedContacts-GAL.md b/docs/Domain-SharedContacts-GAL.md index 86708985..6b2b98c7 100644 --- a/docs/Domain-SharedContacts-GAL.md +++ b/docs/Domain-SharedContacts-GAL.md @@ -185,7 +185,21 @@ ## Create domain shared contacts ``` gam create contact + + [(csv [todrive *] (addcsvdata )*))| returnidonly] ``` +By default, the domain name and contact ID are displayed on stdout. +* `csv [todrive *]` - Write domain name and contact ID values to a CSV file. + * `addcsvdata ` - Add additional columns of data from the command line to the output +* `returnidonly` - Display just the contact ID on stdout + +To retrieve the contact ID with `returnidonly`: +``` +Linux/MacOS +contactId=$(gam create contact ... returnidonly) +Windows PowerShell +$contactId = & gam create contact ... returnidonly +``` + ## Select domain shared contacts You specify contacts by ID or by selection qualifiers. ``` diff --git a/docs/GamUpdates.md b/docs/GamUpdates.md index 1aeed84a..166a5901 100644 --- a/docs/GamUpdates.md +++ b/docs/GamUpdates.md @@ -10,6 +10,30 @@ Add the `-s` option to the end of the above commands to suppress creating the `g See [Downloads](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads) for Windows or other options, including manual installation. +### 6.62.08 + +Added option `addcsvdata ` to these commands. This adds additional columns of data to the CSV file output +when the `csv` option is used. +``` +gam create contact +gam create contact +gam create contactgroup +``` + +### 6.62.07 + +Added option `csv [todrive *]` to these commands that causes GAM to output +the contact creator and contact ID in CSV form. This will be useful when bulk contacts are created. + +Added `returnidonly` to these commands that causes GAM to return just the +contact ID as output. This will be useful in scripts that create a contact and then +want to perform subsequent GAM commands on the contact. +``` +gam create contact +gam create contact +gam create contactgroup +``` + ### 6.62.06 Added output `Item cap` to `gam print filecounts select select ` that diff --git a/docs/How-to-Upgrade-from-Standard-GAM.md b/docs/How-to-Upgrade-from-Standard-GAM.md index 364b636f..8d6c8000 100644 --- a/docs/How-to-Upgrade-from-Standard-GAM.md +++ b/docs/How-to-Upgrade-from-Standard-GAM.md @@ -329,7 +329,7 @@ writes the credentials into the file oauth2.txt. admin@server:/Users/admin/bin/gamadv-xtd3$ rm -f /Users/admin/GAMConfig/oauth2.txt admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam version WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found -GAMADV-XTD3 6.62.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource +GAMADV-XTD3 6.62.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource Ross Scroggs Python 3.10.8 64-bit final MacOS High Sierra 10.13.6 x86_64 @@ -969,7 +969,7 @@ writes the credentials into the file oauth2.txt. C:\GAMADV-XTD3>del C:\GAMConfig\oauth2.txt C:\GAMADV-XTD3>gam version WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found -GAMADV-XTD3 6.62.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource +GAMADV-XTD3 6.62.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource Ross Scroggs Python 3.11.4 64-bit final Windows-10-10.0.17134 AMD64 diff --git a/docs/Users-People-Contacts-Profiles.md b/docs/Users-People-Contacts-Profiles.md index e5e87f4c..0ba59d35 100644 --- a/docs/Users-People-Contacts-Profiles.md +++ b/docs/Users-People-Contacts-Profiles.md @@ -250,10 +250,24 @@ then filters the list to only those in ``; quota limits gam create contact [+] (contactgroup )* + [(csv [todrive *] (addcsvdata )*))| returnidonly] ``` You may specify zero or more contact groups with `(contactgroup )*`; these contact groups define the complete contact group list for the contact. +By default, the user name and contact ID are displayed on stdout. +* `csv [todrive *]` - Write user name and contact ID values to a CSV file. + * `addcsvdata ` - Add additional columns of data from the command line to the output +* `returnidonly` - Display just the contact ID on stdout + +To retrieve the contact ID with `returnidonly`: +``` +Linux/MacOS +contactId=$(gam user user@domain.com create contact ... returnidonly) +Windows PowerShell +$contactId = & gam user user@domain.com create contact ... returnidonly +``` + ## Update User Contacts ``` gam update contacts @@ -546,6 +560,21 @@ The `quotechar ` option allows you to choose an alternate quote chara ## Manage User Contact Groups ``` gam create contactgroup + + [(csv [todrive *] (addcsvdata )*))| returnidonly] +``` +By default, the user name and contactgroup ID are displayed on stdout. +* `csv [todrive *]` - Write user name and contactgroup ID values to a CSV file. + * `addcsvdata ` - Add additional columns of data from the command line to the output +* `returnidonly` - Display just the contactgroup ID on stdout + +To retrieve the contactgroup ID with `returnidonly`: +``` +Linux/MacOS +contactGroupId=$(gam user user@domain.com create contactgroup ... returnidonly) +Windows PowerShell +$contactGroupId = & gam user user@domain.com create contactgroup ... returnidonly +``` +``` gam update contactgroup + gam delete contactgroups ``` @@ -614,4 +643,3 @@ the quote character itself, the column delimiter (comma by default) and new-line When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output. The `quotechar ` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output. `quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used. - diff --git a/docs/Version-and-Help.md b/docs/Version-and-Help.md index 2551bdaf..3f00c358 100644 --- a/docs/Version-and-Help.md +++ b/docs/Version-and-Help.md @@ -3,7 +3,7 @@ Print the current version of Gam with details ``` gam version -GAMADV-XTD3 6.22.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource +GAMADV-XTD3 6.62.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource Ross Scroggs Python 3.11.4 64-bit final MacOS Monterey 12.6.6 x86_64 @@ -15,7 +15,7 @@ Time: 2023-06-02T21:10:00-07:00 Print the current version of Gam with details and time offset information ``` gam version timeoffset -GAMADV-XTD3 6.22.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource +GAMADV-XTD3 6.62.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource Ross Scroggs Python 3.11.4 64-bit final MacOS Monterey 12.6.6 x86_64 @@ -27,7 +27,7 @@ Your system time differs from www.googleapis.com by less than 1 second Print the current version of Gam with extended details and SSL information ``` gam version extended -GAMADV-XTD3 6.22.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource +GAMADV-XTD3 6.62.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource Ross Scroggs Python 3.11.4 64-bit final MacOS Monterey 12.6.6 x86_64 @@ -64,7 +64,7 @@ MacOS High Sierra 10.13.6 x86_64 Path: /Users/Admin/bin/gamadv-xtd3 Version Check: Current: 5.35.08 - Latest: 6.22.00 + Latest: 6.62.08 echo $? 1 ``` @@ -72,7 +72,7 @@ echo $? Print the current version number without details ``` gam version simple -6.22.00 +6.62.08 ``` In Linux/MacOS you can do: ``` @@ -82,7 +82,7 @@ echo $VER Print the current version of Gam and address of this Wiki ``` gam help -GAM 6.22.00 - https://github.com/taers232c/GAMADV-XTD3 +GAM 6.62.08 - https://github.com/taers232c/GAMADV-XTD3 Ross Scroggs Python 3.11.4 64-bit final MacOS Monterey 12.6.6 x86_64 diff --git a/src/GamCommands.txt b/src/GamCommands.txt index 455cf7f6..68ac327b 100644 --- a/src/GamCommands.txt +++ b/src/GamCommands.txt @@ -3162,6 +3162,7 @@ gam show domainaliases|aliasdomains [formatjson] [updated_min ] gam create contact + + [(csv [todrive *] (addcsvdata )*))| returnidonly] gam update contacts | + gam clear contacts | [emailclearpattern ] [emailcleartype work|home|other|] @@ -7141,6 +7142,7 @@ gam sync license [product|productid ] [a gam create contact [+] (contactgroup )* + [(csv [todrive *] (addcsvdata )*))| returnidonly] gam update contacts |( endquery) [+] @@ -7237,6 +7239,7 @@ gam print othercontacts [todrive *] ::= "(,)*" gam create contactgroup + + [(csv [todrive *] (addcsvdata )*))| returnidonly] gam update contactgroup + gam delete contactgroups diff --git a/src/GamUpdate.txt b/src/GamUpdate.txt index 48d5c304..69380607 100644 --- a/src/GamUpdate.txt +++ b/src/GamUpdate.txt @@ -2,6 +2,30 @@ Merged GAM-Team version +6.62.08 + +Added option `addcsvdata ` to these commands. This adds additional columns of data to the CSV file output +when the `csv` option is used. +``` +gam create contact +gam create contact +gam create contactgroup +``` + +6.62.07 + +Added option `csv [todrive *]` to these commands that causes GAM to output +the contact creator and contact ID in CSV form. This will be useful when bulk contacts are created. + +Added `returnidonly` to these commands that causes GAM to return just the +contact ID as output. This will be useful in scripts that create a contact and then +want to perform subsequent GAM commands on the contact. +``` +gam create contact +gam create contact +gam create contactgroup +``` + 6.62.06 Added output `Item cap` to `gam print filecounts select select ` that diff --git a/src/gam/__init__.py b/src/gam/__init__.py index 78e97d8b..f1a07c4c 100755 --- a/src/gam/__init__.py +++ b/src/gam/__init__.py @@ -17637,6 +17637,21 @@ def doPrintAddresses(): # Contact commands utilities # +def _getCreateContactReturnOptions(parameters): + myarg = getArgument() + if myarg == 'returnidonly': + parameters['returnIdOnly'] = True + elif myarg == 'csv': + parameters['csvPF'] = CSVPrintFile(parameters['titles'], 'sortall') + elif parameters['csvPF'] and myarg == 'todrive': + parameters['csvPF'].GetTodriveParameters() + elif parameters['csvPF'] and myarg == 'addcsvdata': + k = getString(Cmd.OB_STRING) + parameters['addCSVData'][k] = getString(Cmd.OB_STRING, minLen=0) + else: + return False + return True +# CONTACT_JSON = 'JSON' CONTACT_ID = 'ContactID' @@ -18104,7 +18119,7 @@ class ContactsManager(): return full_id[full_id.rfind('/')+1:] @staticmethod - def GetContactFields(): + def GetContactFields(parameters=None): fields = {} @@ -18155,6 +18170,10 @@ class ContactsManager(): primary = {} while Cmd.ArgumentsRemaining(): + if parameters is not None: + if _getCreateContactReturnOptions(parameters): + continue + Cmd.Backup() fieldName = getChoice(ContactsManager.CONTACT_ARGUMENT_TO_PROPERTY_MAP, mapChoice=True) if fieldName == CONTACT_BIRTHDAY: fields[fieldName] = getYYYYMMDD(minLen=0) @@ -18690,7 +18709,13 @@ def dedupEmailAddressMatches(contactsManager, emailMatchType, fields): def _createContact(): entityType = Ent.DOMAIN contactsManager = ContactsManager() - fields = contactsManager.GetContactFields() + parameters = {'csvPF': None, 'titles': ['Domain', CONTACT_ID], 'addCSVData': {}, 'returnIdOnly': False} + fields = contactsManager.GetContactFields(parameters) + csvPF = parameters['csvPF'] + addCSVData = parameters['addCSVData'] + if addCSVData: + csvPF.AddTitles(sorted(addCSVData.keys())) + returnIdOnly = parameters['returnIdOnly'] contactEntry = contactsManager.FieldsToContact(fields) user, contactsObject = getContactsObject(True) try: @@ -18698,15 +18723,27 @@ def _createContact(): throwErrors=[GDATA.BAD_REQUEST, GDATA.SERVICE_NOT_APPLICABLE, GDATA.FORBIDDEN], retryErrors=[GDATA.INTERNAL_SERVER_ERROR], new_contact=contactEntry, insert_uri=contactsObject.GetContactFeedUri(contact_list=user)) - entityActionPerformed([entityType, user, Ent.CONTACT, contactsManager.GetContactShortId(contact)]) + contactId = contactsManager.GetContactShortId(contact) + if returnIdOnly: + writeStdout(f'{contactId}\n') + elif not csvPF: + entityActionPerformed([entityType, user, Ent.CONTACT, contactId]) + else: + row = {'Domain': user, CONTACT_ID: contactId} + if addCSVData: + row.update(addCSVData) + csvPF.WriteRow(row) except GDATA.badRequest as e: entityActionFailedWarning([entityType, user, Ent.CONTACT, ''], str(e)) except GDATA.forbidden: entityServiceNotApplicableWarning(entityType, user) except GDATA.serviceNotApplicable: entityUnknownWarning(entityType, user) + if csvPF: + csvPF.writeCSVfile('Contacts') # gam create contact + +# [(csv [todrive *] (addcsvdata )*))| returnidonly] def doCreateDomainContact(): _createContact() @@ -19648,7 +19685,7 @@ class PeopleManager(): } @staticmethod - def GetPersonFields(entityType, allowAddRemove): + def GetPersonFields(entityType, allowAddRemove, parameters=None): person = {} contactGroupsLists = { PEOPLE_GROUPS_LIST: [], @@ -19717,6 +19754,10 @@ class PeopleManager(): person[fieldName].append(entry) while Cmd.ArgumentsRemaining(): + if parameters is not None: + if _getCreateContactReturnOptions(parameters): + continue + Cmd.Backup() locations['fieldName'] = Cmd.Location() fieldName = getChoice(PeopleManager.PEOPLE_ARGUMENT_TO_PROPERTY_MAP, mapChoice=True) if '.' in fieldName: @@ -19890,9 +19931,13 @@ class PeopleManager(): contactEntry[PEOPLE_MEMBERSHIPS].append({'contactGroupMembership': {'contactGroupResourceName': groupId}}) @staticmethod - def GetContactGroupFields(): + def GetContactGroupFields(parameters=None): contactGroup = {} while Cmd.ArgumentsRemaining(): + if parameters is not None: + if _getCreateContactReturnOptions(parameters): + continue + Cmd.Backup() fieldName = getChoice(PeopleManager.PEOPLE_GROUP_ARGUMENT_TO_PROPERTY_MAP, mapChoice=True) if fieldName == PEOPLE_GROUP_NAME: contactGroup[PEOPLE_GROUP_NAME] = getString(Cmd.OB_STRING) @@ -20238,12 +20283,19 @@ def validatePeopleContactGroupsList(people, contactId, # gam create contact + # (contactgroup )* +# [(csv [todrive *] (addcsvdata )*))| returnidonly] def createUserPeopleContact(users): entityType = Ent.USER peopleManager = PeopleManager() peopleEntityType = Ent.CONTACT sources = PEOPLE_READ_SOURCES_CHOICE_MAP['contact'] - body, personFields, contactGroupsLists = peopleManager.GetPersonFields(entityType, False) + parameters = {'csvPF': None, 'titles': ['User', 'resourceName'], 'addCSVData': {}, 'returnIdOnly': False} + body, personFields, contactGroupsLists = peopleManager.GetPersonFields(entityType, False, parameters) + csvPF = parameters['csvPF'] + addCSVData = parameters['addCSVData'] + if addCSVData: + csvPF.AddTitles(sorted(addCSVData.keys())) + returnIdOnly = parameters['returnIdOnly'] i, count, users = getEntityArgument(users) for user in users: i += 1 @@ -20260,15 +20312,26 @@ def createUserPeopleContact(users): else: personFields.discard(PEOPLE_MEMBERSHIPS) try: - person = callGAPI(people.people(), 'createContact', + result = callGAPI(people.people(), 'createContact', throwReasons=GAPI.PEOPLE_ACCESS_THROW_REASONS+[GAPI.INVALID_ARGUMENT], retryReasons=[GAPI.SERVICE_NOT_AVAILABLE], personFields=','.join(personFields), body=body, sources=sources) - entityActionPerformed([entityType, user, peopleEntityType, person['resourceName']], i, count) + resourceName = result['resourceName'] + if returnIdOnly: + writeStdout(f'{resourceName}\n') + elif not csvPF: + entityActionPerformed([entityType, user, peopleEntityType, resourceName], i, count) + else: + row = {'User': user, 'resourceName': resourceName} + if addCSVData: + row.update(addCSVData) + csvPF.WriteRow(row) except GAPI.invalidArgument as e: entityActionFailedWarning([entityType, user, peopleEntityType, None], str(e), i, count) except (GAPI.serviceNotAvailable, GAPI.forbidden): ClientAPIAccessDeniedExit() + if csvPF: + csvPF.writeCSVfile('People Contacts') def localPeopleContactSelects(contactQuery, contact): if contactQuery['emailMatchPattern']: @@ -21602,10 +21665,17 @@ def deleteUserPeopleContactPhoto(users): _processPeopleContactPhotos(users, 'deleteContactPhoto') # gam create contactgroup + +# [(csv [todrive *] (addcsvdata )*))| returnidonly] def createUserPeopleContactGroup(users): peopleManager = PeopleManager() entityType = Ent.USER - body, _ = peopleManager.GetContactGroupFields() + parameters = {'csvPF': None, 'titles': ['User', 'resourceName'], 'addCSVData': {}, 'returnIdOnly': False} + body, _ = peopleManager.GetContactGroupFields(parameters) + csvPF = parameters['csvPF'] + addCSVData = parameters['addCSVData'] + if addCSVData: + csvPF.AddTitles(sorted(addCSVData.keys())) + returnIdOnly = parameters['returnIdOnly'] i, count, users = getEntityArgument(users) for user in users: i += 1 @@ -21623,11 +21693,22 @@ def createUserPeopleContactGroup(users): result = callGAPI(people.contactGroups(), 'create', throwReasons=GAPI.PEOPLE_ACCESS_THROW_REASONS, body={'contactGroup': body}, fields='resourceName') - entityActionPerformed([entityType, user, Ent.CONTACT_GROUP, result['resourceName']], i, count) + resourceName = result['resourceName'] + if returnIdOnly: + writeStdout(f'{resourceName}\n') + elif not csvPF: + entityActionPerformed([entityType, user, Ent.CONTACT_GROUP, resourceName], i, count) + else: + row = {'User': user, 'resourceName': resourceName} + if addCSVData: + row.update(addCSVData) + csvPF.WriteRow(row) except GAPI.forbidden: entityServiceNotApplicableWarning(entityType, user, i, count) except GAPI.serviceNotAvailable: entityUnknownWarning(entityType, user, i, count) + if csvPF: + csvPF.writeCSVfile('People Contact Groups') # gam update contactgroups + def updateUserPeopleContactGroup(users):