diff --git a/src/gam/__init__.py b/src/gam/__init__.py index 771f96cb..de2c7da4 100755 --- a/src/gam/__init__.py +++ b/src/gam/__init__.py @@ -4498,7 +4498,7 @@ def refreshCredentialsWithReauth(credentials): gcloud_path_result = subprocess.run(['gcloud', 'info', '--format=value(config.paths.global_config_dir)'], - capture_output=True, ckeck=False) + capture_output=True, check=False) except KeyboardInterrupt as e: # avoids loss of terminal echo on *nix if 'termios' in sys.modules: @@ -4516,7 +4516,7 @@ def refreshCredentialsWithReauth(credentials): f'Failed to run gcloud as {admin_email}. Please make sure it\'s setup') if not credentials._rapt_token: systemErrorExit(SYSTEM_ERROR_RC, - f'Failed to retrieve reauth token from gcloud. You may need to wait until gcloud is also prompted for reauth.') + 'Failed to retrieve reauth token from gcloud. You may need to wait until gcloud is also prompted for reauth.') def getClientCredentials(forceRefresh=False, forceWrite=False, filename=None, api=None, noDASA=False, refreshOnly=False, noScopes=False): """Gets OAuth2 credentials which are guaranteed to be fresh and valid. @@ -34781,6 +34781,7 @@ LIST_EVENTS_SELECT_PROPERTIES = { 'timemin': ('timeMin', {GC.VAR_TYPE: GC.TYPE_DATETIME}), 'updated': ('updatedMin', {GC.VAR_TYPE: GC.TYPE_DATETIME}), 'updatedmin': ('updatedMin', {GC.VAR_TYPE: GC.TYPE_DATETIME}), + 'eventtypes': ('eventTypes', {GC.VAR_TYPE: GC.TYPE_CHOICE_LIST}), } LIST_EVENTS_MATCH_FIELDS = { @@ -34815,9 +34816,12 @@ def _getCalendarListEventsProperty(myarg, attributes, kwargs): kwargs[attrName] = getChoice(attribute['choices'], mapChoice=True) elif attrType == GC.TYPE_DATETIME: kwargs[attrName] = getTimeOrDeltaFromNow() - else: # GC.TYPE_INTEGER + elif attrType == GC.TYPE_INTEGER: minVal, maxVal = attribute[GC.VAR_LIMITS] kwargs[attrName] = getInteger(minVal=minVal, maxVal=maxVal) + else: # elif attrType == GC.TYPE_CHOICE_LIST: + if attrName == 'eventTypes': + kwargs[attrName] = _getEventTypes() return True def _getCalendarListEventsDisplayProperty(myarg, calendarEventEntity): @@ -34915,6 +34919,41 @@ EVENT_JSONATTENDEES_SUBFIELD_CLEAR_FIELDS = { 'attendees': ['id', 'organizer', 'self'], } +WORKING_LOCATION_CHOICE_MAP = { + 'custom': 'customLocation', + 'home': 'homeOffice', + 'office': 'officeLocation', + } + +def getWorkingLocationProperties(body): + body.update({'eventType': 'workingLocation', 'workingLocationProperties': {}, + 'visibility': 'public', 'transparency':'transparent'}) + location = getChoice(WORKING_LOCATION_CHOICE_MAP, mapChoice=True) + body['workingLocationProperties']['type'] = location + if location == 'homeOffice': + pass + elif location == 'customLocation': + body['workingLocationProperties'][location] = {'label': getString(Cmd.OB_STRING)} + else: #officeLocation + body['workingLocationProperties'][location] = {'label': getString(Cmd.OB_STRING)} + entry = body['workingLocationProperties'][location] + while Cmd.ArgumentsRemaining(): + argument = getArgument() + if argument in {'building', 'buildingid'}: + entry['buildingId'] = _getBuildingByNameOrId(None) + elif argument in {'floor', 'floorname'}: + entry['floorId'] = getString(Cmd.OB_STRING, minLen=0) + elif argument in {'section', 'floorsection'}: + entry['floorSectionId'] = getString(Cmd.OB_STRING, minLen=0) + elif argument in {'desk', 'deskcode'}: + entry['deskId'] = getString(Cmd.OB_STRING, minLen=0) + elif argument == 'endlocation': + break + else: + Cmd.Backup() + break + return location + def _getCalendarEventAttribute(myarg, body, parameters, function): def clearJSONfields(body, clearFields): for field in clearFields: @@ -35062,6 +35101,8 @@ def _getCalendarEventAttribute(myarg, body, parameters, function): body['extendedProperties'].setdefault('shared', {}) key = getString(Cmd.OB_PROPERTY_KEY) body['extendedProperties']['shared'][key] = getString(Cmd.OB_PROPERTY_VALUE, minLen=0) + elif myarg == 'workinglocation': + getWorkingLocationProperties(body) elif function == 'update' and myarg == 'clearprivateproperty': body.setdefault('extendedProperties', {}) body['extendedProperties'].setdefault('private', {}) @@ -35337,12 +35378,12 @@ def _createCalendarEvents(user, origCal, function, calIds, count, body, paramete if function == 'insert': event = callGAPI(cal.events(), 'insert', throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.INVALID, GAPI.REQUIRED, GAPI.TIME_RANGE_EMPTY, GAPI.EVENT_DURATION_EXCEEDS_LIMIT, - GAPI.REQUIRED_ACCESS_LEVEL, GAPI.DUPLICATE, GAPI.FORBIDDEN], + GAPI.REQUIRED_ACCESS_LEVEL, GAPI.DUPLICATE, GAPI.FORBIDDEN, GAPI.MALFORMED_WORKING_LOCATION_EVENT], calendarId=calId, conferenceDataVersion=1, sendUpdates=parameters['sendUpdates'], supportsAttachments=True, body=body, fields=fields) else: event = callGAPI(cal.events(), 'import_', throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.INVALID, GAPI.REQUIRED, GAPI.TIME_RANGE_EMPTY, GAPI.EVENT_DURATION_EXCEEDS_LIMIT, - GAPI.REQUIRED_ACCESS_LEVEL, GAPI.DUPLICATE, GAPI.FORBIDDEN, + GAPI.REQUIRED_ACCESS_LEVEL, GAPI.DUPLICATE, GAPI.FORBIDDEN, GAPI.MALFORMED_WORKING_LOCATION_EVENT, GAPI.PARTICIPANT_IS_NEITHER_ORGANIZER_NOR_ATTENDEE], calendarId=calId, conferenceDataVersion=1, supportsAttachments=True, body=body, fields=fields) if parameters['csvPF'] is None: @@ -35352,7 +35393,7 @@ def _createCalendarEvents(user, origCal, function, calIds, count, body, paramete _getEventDaysOfWeek(event) _printCalendarEvent(user, calId, event, parameters['csvPF'], parameters['FJQC']) except (GAPI.invalid, GAPI.required, GAPI.timeRangeEmpty, GAPI.eventDurationExceedsLimit, - GAPI.requiredAccessLevel, GAPI.participantIsNeitherOrganizerNorAttendee) as e: + GAPI.requiredAccessLevel, GAPI.participantIsNeitherOrganizerNorAttendee, GAPI.malformedWorkingLocationEvent) as e: entityActionFailedWarning([Ent.CALENDAR, calId, Ent.EVENT, event['id']], str(e), i, count) except GAPI.duplicate as e: entityActionFailedWarning([Ent.CALENDAR, calId, Ent.EVENT, event['id']], str(e), i, count) @@ -35717,6 +35758,85 @@ def doCalendarsEmptyTrash(calIds): Act.Set(Act.PURGE) _emptyCalendarTrash(None, None, calIds, len(calIds)) +EVENT_SHOW_ORDER = ['id', 'summary', 'status', 'description', 'location', + 'start', 'end', 'endTimeUnspecified', + 'creator', 'organizer', 'created', 'updated', 'iCalUID'] +EVENT_PRINT_ORDER = ['id', 'summary', 'status', 'description', 'location', + 'created', 'updated', 'iCalUID'] + +EVENT_TIME_OBJECTS = {'created', 'updated', 'dateTime'} + +def _showCalendarEvent(primaryEmail, calId, eventEntityType, event, k, kcount, FJQC): + if FJQC.formatJSON: + if primaryEmail: + printLine(json.dumps(cleanJSON({'primaryEmail': primaryEmail, 'calendarId': calId, 'event': event}, + timeObjects=EVENT_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)) + else: + printLine(json.dumps(cleanJSON({'calendarId': calId, 'event': event}, + timeObjects=EVENT_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)) + return + printEntity([eventEntityType, event['id']], k, kcount) + skipObjects = {'id'} + Ind.Increment() + for field in EVENT_SHOW_ORDER: + if field in event: + showJSON(field, event[field], skipObjects, EVENT_TIME_OBJECTS) + skipObjects.add(field) + showJSON(None, event, skipObjects) + Ind.Decrement() + +def _printCalendarEvent(user, calId, event, csvPF, FJQC): + row = {'calendarId': calId, 'id': event['id']} + if user: + row['primaryEmail'] = user + flattenJSON(event, flattened=row, timeObjects=EVENT_TIME_OBJECTS) + if not FJQC.formatJSON: + csvPF.WriteRowTitles(row) + elif csvPF.CheckRowTitles(row): + row = {'calendarId': calId, 'id': event['id'], + 'JSON': json.dumps(cleanJSON(event, timeObjects=EVENT_TIME_OBJECTS), + ensure_ascii=False, sort_keys=False)} + if user: + row['primaryEmail'] = user + csvPF.WriteRowNoFilter(row) + +def _printShowCalendarEvents(origUser, user, origCal, calIds, count, calendarEventEntity, + csvPF, FJQC, fieldsList): + i = 0 + for calId in calIds: + i += 1 + if csvPF: + printGettingEntityItemForWhom(Ent.EVENT, calId, i, count) + calId, _, events, jcount = _validateCalendarGetEvents(origUser, user, origCal, calId, i, count, calendarEventEntity, + fieldsList, not csvPF and not FJQC.formatJSON and not calendarEventEntity['countsOnly']) + if not csvPF: + if not calendarEventEntity['countsOnly']: + Ind.Increment() + j = 0 + for event in events: + j += 1 + if calendarEventEntity['showDayOfWeek']: + _getEventDaysOfWeek(event) + _showCalendarEvent(user, calId, Ent.EVENT, event, j, jcount, FJQC) + Ind.Decrement() + else: + printKeyValueList([Ent.Singular(Ent.CALENDAR), calId, Ent.Choose(Ent.EVENT, jcount), jcount]) + else: + if not calendarEventEntity['countsOnly']: + if events: + for event in events: + if calendarEventEntity['showDayOfWeek']: + _getEventDaysOfWeek(event) + _printCalendarEvent(user, calId, event, csvPF, FJQC) + elif GC.Values[GC.CSV_OUTPUT_USERS_AUDIT] and user: + csvPF.WriteRowNoFilter({'calendarId': calId, 'primaryEmail': user, 'id': ''}) + else: + row = {'calendarId': calId} + if user: + row['primaryEmail'] = user + row['events'] = jcount + csvPF.WriteRow(row) + EVENT_FIELDS_CHOICE_MAP = { 'anyonecanaddself': 'anyoneCanAddSelf', 'attachments': 'attachments', @@ -35848,6 +35968,22 @@ def _addEventEntitySelectFields(calendarEventEntity, fieldsList): if calendarEventEntity['maxinstances'] != -1: fieldsList.append('recurrence') +EVENT_TYPES_CHOICE_MAP = { + 'default': 'default', + 'focustime': 'focusTime', + 'outofoffice': 'outOfOffice', + 'workinglocation': 'workingLocation', + } + +def _getEventTypes(): + typesList = [] + for field in _getFieldsList(): + if field in EVENT_TYPES_CHOICE_MAP: + addFieldToFieldsList(field, EVENT_TYPES_CHOICE_MAP, typesList) + else: + invalidChoiceExit(field, EVENT_TYPES_CHOICE_MAP, True) + return ','.join(typesList) + def _getCalendarInfoEventOptions(calendarEventEntity): FJQC = FormatJSONQuoteChar() fieldsList = [] @@ -35960,85 +36096,6 @@ def _getEventDaysOfWeek(event): except (iso8601.ParseError, OverflowError): pass -EVENT_SHOW_ORDER = ['id', 'summary', 'status', 'description', 'location', - 'start', 'end', 'endTimeUnspecified', - 'creator', 'organizer', 'created', 'updated', 'iCalUID'] -EVENT_PRINT_ORDER = ['id', 'summary', 'status', 'description', 'location', - 'created', 'updated', 'iCalUID'] - -EVENT_TIME_OBJECTS = {'created', 'updated', 'dateTime'} - -def _showCalendarEvent(primaryEmail, calId, eventEntityType, event, k, kcount, FJQC): - if FJQC.formatJSON: - if primaryEmail: - printLine(json.dumps(cleanJSON({'primaryEmail': primaryEmail, 'calendarId': calId, 'event': event}, - timeObjects=EVENT_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)) - else: - printLine(json.dumps(cleanJSON({'calendarId': calId, 'event': event}, - timeObjects=EVENT_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)) - return - printEntity([eventEntityType, event['id']], k, kcount) - skipObjects = {'id'} - Ind.Increment() - for field in EVENT_SHOW_ORDER: - if field in event: - showJSON(field, event[field], skipObjects, EVENT_TIME_OBJECTS) - skipObjects.add(field) - showJSON(None, event, skipObjects) - Ind.Decrement() - -def _printCalendarEvent(user, calId, event, csvPF, FJQC): - row = {'calendarId': calId, 'id': event['id']} - if user: - row['primaryEmail'] = user - flattenJSON(event, flattened=row, timeObjects=EVENT_TIME_OBJECTS) - if not FJQC.formatJSON: - csvPF.WriteRowTitles(row) - elif csvPF.CheckRowTitles(row): - row = {'calendarId': calId, 'id': event['id'], - 'JSON': json.dumps(cleanJSON(event, timeObjects=EVENT_TIME_OBJECTS), - ensure_ascii=False, sort_keys=False)} - if user: - row['primaryEmail'] = user - csvPF.WriteRowNoFilter(row) - -def _printShowCalendarEvents(origUser, user, origCal, calIds, count, calendarEventEntity, - csvPF, FJQC, fieldsList): - i = 0 - for calId in calIds: - i += 1 - if csvPF: - printGettingEntityItemForWhom(Ent.EVENT, calId, i, count) - calId, _, events, jcount = _validateCalendarGetEvents(origUser, user, origCal, calId, i, count, calendarEventEntity, - fieldsList, not csvPF and not FJQC.formatJSON and not calendarEventEntity['countsOnly']) - if not csvPF: - if not calendarEventEntity['countsOnly']: - Ind.Increment() - j = 0 - for event in events: - j += 1 - if calendarEventEntity['showDayOfWeek']: - _getEventDaysOfWeek(event) - _showCalendarEvent(user, calId, Ent.EVENT, event, j, jcount, FJQC) - Ind.Decrement() - else: - printKeyValueList([Ent.Singular(Ent.CALENDAR), calId, Ent.Choose(Ent.EVENT, jcount), jcount]) - else: - if not calendarEventEntity['countsOnly']: - if events: - for event in events: - if calendarEventEntity['showDayOfWeek']: - _getEventDaysOfWeek(event) - _printCalendarEvent(user, calId, event, csvPF, FJQC) - elif GC.Values[GC.CSV_OUTPUT_USERS_AUDIT] and user: - csvPF.WriteRowNoFilter({'calendarId': calId, 'primaryEmail': user, 'id': ''}) - else: - row = {'calendarId': calId} - if user: - row['primaryEmail'] = user - row['events'] = jcount - csvPF.WriteRow(row) - # gam calendars print events * # [fields ] [showdayofweek] # [countsonly] [formatjson [quotechar ]] [todrive *] @@ -47674,27 +47731,33 @@ def printShowCalendarEvents(users): csvPF.writeCSVfile('Calendar Events') def getWorkingLocationDate(dateType, dateList): - firstDate = getYYYYMMDD(minLen=1, returnDateTime=True) + firstDate = getYYYYMMDD(minLen=1, returnDateTime=True).replace(tzinfo=GC.Values[GC.TIMEZONE]) if dateType == 'range': - lastDate = getYYYYMMDD(minLen=1, returnDateTime=True) + lastDate = getYYYYMMDD(minLen=1, returnDateTime=True).replace(tzinfo=GC.Values[GC.TIMEZONE]) deltaDay = datetime.timedelta(days=1) deltaWeek = datetime.timedelta(weeks=1) if dateType == 'date': dateList.append({'first': firstDate, 'last': firstDate+deltaDay, - 'udelta': deltaDay, 'pdelta': deltaDay}) + 'ulast': firstDate, 'udelta': deltaDay}) elif dateType == 'range': dateList.append({'first': firstDate, 'last': lastDate+deltaDay, - 'udelta': deltaDay, 'pdelta': datetime.timedelta(days=(lastDate-firstDate).days+1)}) + 'ulast': lastDate, 'udelta': deltaDay}) elif dateType == 'daily': argRepeat = getInteger(minVal=1, maxVal=366) dateList.append({'first': firstDate, 'last': firstDate+datetime.timedelta(days=argRepeat), - 'udelta': deltaDay, 'pdelta': deltaDay}) + 'ulast': firstDate+datetime.timedelta(days=argRepeat), 'udelta': deltaDay}) else: #weekly argRepeat = getInteger(minVal=1, maxVal=52) - dateList.append({'first': firstDate, 'last': firstDate+datetime.timedelta(weeks=argRepeat), - 'udelta': deltaWeek, 'pdelta': deltaWeek}) + dateList.append({'first': firstDate, 'last': firstDate+deltaDay, 'pdelta': deltaWeek, 'repeats': argRepeat, + 'ulast': firstDate+datetime.timedelta(weeks=argRepeat), 'udelta': deltaWeek}) + +def getWorkingLocationTimeRange(timeList): + startTime = getEventTime() + endTime = getEventTime() + timeList.append({'start': startTime, 'end': endTime}) WORKING_LOCATION_DATE_CHOICES = {'date', 'range', 'daily', 'weekly'} +WORKING_LOCATION_TIME_CHOICES = {'timerange'} WORKING_LOCATION_CHOICE_MAP = { 'custom': 'customLocation', 'home': 'homeOffice', @@ -47709,7 +47772,7 @@ def _showCalendarWorkingLocation(primaryEmail, calId, eventEntityType, event, k, printEntity([eventEntityType, event['id']], k, kcount) skipObjects = {'id'} Ind.Increment() - showJSON(None, event, skipObjects) + showJSON(None, event, skipObjects, EVENT_TIME_OBJECTS) Ind.Decrement() # gam update workinglocation @@ -47720,76 +47783,91 @@ def _showCalendarWorkingLocation(primaryEmail, calId, eventEntityType, event, k, # ((date yyyy-mm-dd)| # (range yyyy-mm-dd yyyy-mm-dd)| # (daily yyyy-mm-dd N)| -# (weekly yyyy-mm-dd N))+ +# (weekly yyyy-mm-dd N)| +# (timerange