Add resource options to event commands
Some checks failed
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-apis (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled

This commit is contained in:
Ross Scroggs
2025-01-18 10:52:21 -08:00
parent 6af38e24af
commit bad376ea82
3 changed files with 49 additions and 13 deletions

View File

@@ -1677,6 +1677,7 @@ gam calendar <CalendarEntity> printacl [todrive <ToDriveAttribute>*]
(range <Date> <Date>)| (range <Date> <Date>)|
(recurrence <RRULE, EXRULE, RDATE and EXDATE line>)| (recurrence <RRULE, EXRULE, RDATE and EXDATE line>)|
(reminder <Number> email|popup))| (reminder <Number> email|popup))|
(resource <ResourceID>)|
(selectattendees [<AttendeeAttendance>] [<AttendeeStatus>] <UserTypeEntity>)| (selectattendees [<AttendeeAttendance>] [<AttendeeStatus>] <UserTypeEntity>)|
(sequence <Integer>)| (sequence <Integer>)|
(sharedproperty <PropertyKey> <PropertyValue>)| (sharedproperty <PropertyKey> <PropertyValue>)|
@@ -1707,8 +1708,10 @@ The following attributes are equivalent:
clearattendees| clearattendees|
clearhangoutsmeet| clearhangoutsmeet|
(clearprivateproperty <PropertyKey>)| (clearprivateproperty <PropertyKey>)|
clearresources|
(clearsharedproperty <PropertyKey>)| (clearsharedproperty <PropertyKey>)|
(removeattendee <EmailAddress>)| (removeattendee <EmailAddress>)|
(removeresource <ResourceID>)|
(replacedescription <RegularExpression> <String>)| (replacedescription <RegularExpression> <String>)|
(selectremoveattendees <UserTypeEntity>) (selectremoveattendees <UserTypeEntity>)

View File

@@ -1,3 +1,17 @@
7.02.09
Added option `clearresources` to `<EventUpdateAttribute>` for use in `gam <UserTypeEntity> update events`
that allows clearing all resources from a user's calendar events. For example, to clear all resources from a user's future events:
```
gam user user@domain.com update events primary matchfield attendeespattern @resource.calendar.google.com after now clearresources
```
Added option `resource <ResourceID>` to `<EventAttribute>` for use in `gam <UserTypeEntity> create|update events`
that adds a resource to an event.
Added option `removeresource <ResourceID>` to `<EventUpdateAttribute>` for use in `gam <UserTypeEntity> update events`
that removes a resource from an event.
7.02.08 7.02.08
Fixed bug in `gam print|show chromepolicies` that caused a trap when neither Fixed bug in `gam print|show chromepolicies` that caused a trap when neither

View File

@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
""" """
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>' __author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
__version__ = '7.02.08' __version__ = '7.02.09'
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)' __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
#pylint: disable=wrong-import-position #pylint: disable=wrong-import-position
@@ -38327,6 +38327,7 @@ def _getCalendarEventAttribute(myarg, body, parameters, function):
for subfield in subfields: for subfield in subfields:
body.pop(subfield, None) body.pop(subfield, None)
cd = None
if function == 'insert' and myarg in {'id', 'eventid'}: if function == 'insert' and myarg in {'id', 'eventid'}:
body['id'] = getEventID() body['id'] = getEventID()
elif function == 'import' and myarg == 'icaluid': elif function == 'import' and myarg == 'icaluid':
@@ -38407,6 +38408,17 @@ def _getCalendarEventAttribute(myarg, body, parameters, function):
if responseStatus is not None: if responseStatus is not None:
addAttendee['responseStatus'] = responseStatus addAttendee['responseStatus'] = responseStatus
parameters['attendees'].append(addAttendee) parameters['attendees'].append(addAttendee)
elif function == 'update' and myarg == 'clearresources':
parameters['clearResources'] = True
elif myarg == 'resource':
if cd is None:
cd = buildGAPIObject(API.DIRECTORY)
parameters['attendees'].append({'email': _validateResourceId(cd, getString(Cmd.OB_RESOURCE_ID), 0, 0, True),
'responseStatus': 'accepted', 'resource': True})
elif myarg == 'removeresource':
if cd is None:
cd = buildGAPIObject(API.DIRECTORY)
parameters['removeAttendees'].add(_validateResourceId(cd, getString(Cmd.OB_RESOURCE_ID), 0, 0, True))
elif myarg == 'json': elif myarg == 'json':
jsonData = getJSON(EVENT_JSON_CLEAR_FIELDS) jsonData = getJSON(EVENT_JSON_CLEAR_FIELDS)
if function == 'insert': if function == 'insert':
@@ -38716,7 +38728,7 @@ def _validateCalendarGetEvents(origUser, user, origCal, calId, j, jcount, calend
def _getCalendarCreateImportUpdateEventOptions(function, entityType): def _getCalendarCreateImportUpdateEventOptions(function, entityType):
body = {} body = {}
parameters = {'clearAttendees': False, 'replaceMode': False, parameters = {'clearAttendees': False, 'replaceMode': False, 'clearResources': False,
'attendees': [], 'removeAttendees': set(), 'attendees': [], 'removeAttendees': set(),
'replaceDescription': [], 'sendUpdates': 'none', 'replaceDescription': [], 'sendUpdates': 'none',
'csvPF': None, 'FJQC': FormatJSONQuoteChar(None), 'showDayOfWeek': False} 'csvPF': None, 'FJQC': FormatJSONQuoteChar(None), 'showDayOfWeek': False}
@@ -38827,7 +38839,7 @@ def _updateCalendarEvents(origUser, user, origCal, calIds, count, calendarEventE
updateFieldList = [] updateFieldList = []
if parameters['replaceDescription']: if parameters['replaceDescription']:
updateFieldList.append('description') updateFieldList.append('description')
if not parameters['replaceMode'] and (parameters['attendees'] or parameters['removeAttendees']): if not parameters['replaceMode'] and (parameters['attendees'] or parameters['removeAttendees'] or parameters['clearResources']):
updateFieldList.append('attendees') updateFieldList.append('attendees')
updateFields = ','.join(updateFieldList) updateFields = ','.join(updateFieldList)
if 'attendees' not in updateFieldList: if 'attendees' not in updateFieldList:
@@ -38878,6 +38890,8 @@ def _updateCalendarEvents(origUser, user, origCal, calIds, count, calendarEventE
body['attendees'] = [] body['attendees'] = []
if parameters['removeAttendees']: if parameters['removeAttendees']:
body['attendees'] = [attendee for attendee in body['attendees'] if attendee['email'].lower() not in parameters['removeAttendees']] body['attendees'] = [attendee for attendee in body['attendees'] if attendee['email'].lower() not in parameters['removeAttendees']]
if parameters['clearResources']:
body['attendees'] = [attendee for attendee in body['attendees'] if not attendee['email'].lower().endswith('@resource.calendar.google.com')]
event = callGAPI(cal.events(), 'patch', event = callGAPI(cal.events(), 'patch',
throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.DELETED, GAPI.FORBIDDEN, throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.DELETED, GAPI.FORBIDDEN,
GAPI.INVALID, GAPI.REQUIRED, GAPI.TIME_RANGE_EMPTY, GAPI.EVENT_DURATION_EXCEEDS_LIMIT, GAPI.INVALID, GAPI.REQUIRED, GAPI.TIME_RANGE_EMPTY, GAPI.EVENT_DURATION_EXCEEDS_LIMIT,
@@ -39627,18 +39641,19 @@ def doCalendarsPrintShowSettings(calIds):
if csvPF: if csvPF:
csvPF.writeCSVfile('Calendar Settings') csvPF.writeCSVfile('Calendar Settings')
def _validateResourceId(resourceId, i, count): def _validateResourceId(cd, resourceId, i, count, exitOnNotFound):
cd = buildGAPIObject(API.DIRECTORY)
try: try:
return callGAPI(cd.resources().calendars(), 'get', return callGAPI(cd.resources().calendars(), 'get',
throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN], throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
customer=GC.Values[GC.CUSTOMER_ID], calendarResourceId=resourceId, fields='resourceEmail')['resourceEmail'] customer=GC.Values[GC.CUSTOMER_ID], calendarResourceId=resourceId, fields='resourceEmail')['resourceEmail']
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden): except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
if exitOnNotFound:
entityDoesNotExistExit(Ent.RESOURCE_CALENDAR, resourceId, i, count)
checkEntityAFDNEorAccessErrorExit(cd, Ent.RESOURCE_CALENDAR, resourceId, i, count) checkEntityAFDNEorAccessErrorExit(cd, Ent.RESOURCE_CALENDAR, resourceId, i, count)
return None return None
def _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity, showAction=True): def _normalizeResourceIdGetRuleIds(cd, resourceId, i, count, ACLScopeEntity, showAction=True):
calId = _validateResourceId(resourceId, i, count) calId = _validateResourceId(cd, resourceId, i, count, False)
if not calId: if not calId:
return (None, None, 0) return (None, None, 0)
if ACLScopeEntity['dict']: if ACLScopeEntity['dict']:
@@ -39656,23 +39671,25 @@ def _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity, showAct
# gam resources <ResourceEntity> create calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>] # gam resources <ResourceEntity> create calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
def doResourceCreateCalendarACLs(entityList): def doResourceCreateCalendarACLs(entityList):
cal = buildGAPIObject(API.CALENDAR) cal = buildGAPIObject(API.CALENDAR)
cd = buildGAPIObject(API.DIRECTORY)
role, ACLScopeEntity, sendNotifications = getCalendarCreateUpdateACLsOptions(True) role, ACLScopeEntity, sendNotifications = getCalendarCreateUpdateACLsOptions(True)
i = 0 i = 0
count = len(entityList) count = len(entityList)
for resourceId in entityList: for resourceId in entityList:
i += 1 i += 1
calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity) calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(cd, resourceId, i, count, ACLScopeEntity)
if jcount == 0: if jcount == 0:
continue continue
_createCalendarACLs(cal, Ent.RESOURCE_CALENDAR, calId, i, count, role, ruleIds, jcount, sendNotifications) _createCalendarACLs(cal, Ent.RESOURCE_CALENDAR, calId, i, count, role, ruleIds, jcount, sendNotifications)
def _resourceUpdateDeleteCalendarACLs(entityList, function, ACLScopeEntity, role, sendNotifications): def _resourceUpdateDeleteCalendarACLs(entityList, function, ACLScopeEntity, role, sendNotifications):
cal = buildGAPIObject(API.CALENDAR) cal = buildGAPIObject(API.CALENDAR)
cd = buildGAPIObject(API.DIRECTORY)
i = 0 i = 0
count = len(entityList) count = len(entityList)
for resourceId in entityList: for resourceId in entityList:
i += 1 i += 1
calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity) calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(cd, resourceId, i, count, ACLScopeEntity)
if jcount == 0: if jcount == 0:
continue continue
_updateDeleteCalendarACLs(cal, function, Ent.RESOURCE_CALENDAR, calId, i, count, role, ruleIds, jcount, sendNotifications) _updateDeleteCalendarACLs(cal, function, Ent.RESOURCE_CALENDAR, calId, i, count, role, ruleIds, jcount, sendNotifications)
@@ -39695,13 +39712,14 @@ def doResourceDeleteCalendarACLs(entityList):
# [formatjson] # [formatjson]
def doResourceInfoCalendarACLs(entityList): def doResourceInfoCalendarACLs(entityList):
cal = buildGAPIObject(API.CALENDAR) cal = buildGAPIObject(API.CALENDAR)
cd = buildGAPIObject(API.DIRECTORY)
ACLScopeEntity = getCalendarSiteACLScopeEntity() ACLScopeEntity = getCalendarSiteACLScopeEntity()
FJQC = _getCalendarInfoACLOptions() FJQC = _getCalendarInfoACLOptions()
i = 0 i = 0
count = len(entityList) count = len(entityList)
for resourceId in entityList: for resourceId in entityList:
i += 1 i += 1
calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity, showAction=not FJQC.formatJSON) calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(cd, resourceId, i, count, ACLScopeEntity, showAction=not FJQC.formatJSON)
if jcount == 0: if jcount == 0:
continue continue
_infoCalendarACLs(cal, resourceId, Ent.RESOURCE_CALENDAR, calId, i, count, ruleIds, jcount, FJQC) _infoCalendarACLs(cal, resourceId, Ent.RESOURCE_CALENDAR, calId, i, count, ruleIds, jcount, FJQC)
@@ -39720,12 +39738,13 @@ def doResourceInfoCalendarACLs(entityList):
# [formatjson] # [formatjson]
def doResourcePrintShowCalendarACLs(entityList): def doResourcePrintShowCalendarACLs(entityList):
cal = buildGAPIObject(API.CALENDAR) cal = buildGAPIObject(API.CALENDAR)
cd = buildGAPIObject(API.DIRECTORY)
csvPF, FJQC, noSelfOwner, addCSVData = _getCalendarPrintShowACLOptions(['resourceId', 'resourceEmail']) csvPF, FJQC, noSelfOwner, addCSVData = _getCalendarPrintShowACLOptions(['resourceId', 'resourceEmail'])
i = 0 i = 0
count = len(entityList) count = len(entityList)
for resourceId in entityList: for resourceId in entityList:
i += 1 i += 1
calId = _validateResourceId(resourceId, i, count) calId = _validateResourceId(cd, resourceId, i, count, False)
if not calId: if not calId:
continue continue
_printShowCalendarACLs(cal, resourceId, Ent.RESOURCE_CALENDAR, calId, i, count, csvPF, FJQC, noSelfOwner, addCSVData) _printShowCalendarACLs(cal, resourceId, Ent.RESOURCE_CALENDAR, calId, i, count, csvPF, FJQC, noSelfOwner, addCSVData)
@@ -67554,10 +67573,10 @@ def updatePhoto(users):
body = {'photoData': base64.urlsafe_b64encode(image_data).decode(UTF8)} body = {'photoData': base64.urlsafe_b64encode(image_data).decode(UTF8)}
try: try:
callGAPI(cd.users().photos(), 'update', callGAPI(cd.users().photos(), 'update',
throwReasons=[GAPI.USER_NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_INPUT], throwReasons=[GAPI.USER_NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_INPUT, GAPI.CONDITION_NOT_MET],
userKey=user, body=body, fields='') userKey=user, body=body, fields='')
entityActionPerformed([Ent.USER, user, Ent.PHOTO, filename], i, count) entityActionPerformed([Ent.USER, user, Ent.PHOTO, filename], i, count)
except GAPI.invalidInput as e: except (GAPI.invalidInput, GAPI.conditionNotMet) as e:
entityActionFailedWarning([Ent.USER, user, Ent.PHOTO, filename], str(e), i, count) entityActionFailedWarning([Ent.USER, user, Ent.PHOTO, filename], str(e), i, count)
except (GAPI.userNotFound, GAPI.forbidden): except (GAPI.userNotFound, GAPI.forbidden):
entityUnknownWarning(Ent.USER, user, i, count) entityUnknownWarning(Ent.USER, user, i, count)