def normalizeCalendarId(calname, checkPrimary=False): if checkPrimary and calname.lower() == 'primary': return calname if not GC_Values[GC_DOMAIN]: GC_Values[GC_DOMAIN] = gam._getValueFromOAuth('hd') return gam.convertUIDtoEmailAddress(calname, email_types=['user', 'resource'])
def buildCalendarDataGAPIObject(calname): calendarId = normalizeCalendarId(calname) # Try to impersonate the calendar owner. If we fail, fall back to using # admin for authentication. Resource calendars cannot be impersonated, # so we need to access them as the admin. cal = None if not calname.endswith('.calendar.google.com'): cal = gam.buildGAPIServiceObject('calendar', calendarId, False) if cal is None: _, cal = buildCalendarGAPIObject(gam._getValueFromOAuth('email')) return (calendarId, cal)
def write_csv_file(csvRows, titles, list_type, todrive): def rowDateTimeFilterMatch(dateMode, rowDate, op, filterDate): if not rowDate or not isinstance(rowDate, str): return False try: rowTime = dateutil.parser.parse(rowDate, ignoretz=True) if dateMode: rowDate = datetime.datetime(rowTime.year, rowTime.month, rowTime.day).isoformat() + 'Z' except ValueError: rowDate = NEVER_TIME if op == '<': return rowDate < filterDate if op == '<=': return rowDate <= filterDate if op == '>': return rowDate > filterDate if op == '>=': return rowDate >= filterDate if op == '!=': return rowDate != filterDate return rowDate == filterDate def rowCountFilterMatch(rowCount, op, filterCount): if isinstance(rowCount, str): if not rowCount.isdigit(): return False rowCount = int(rowCount) elif not isinstance(rowCount, int): return False if op == '<': return rowCount < filterCount if op == '<=': return rowCount <= filterCount if op == '>': return rowCount > filterCount if op == '>=': return rowCount >= filterCount if op == '!=': return rowCount != filterCount return rowCount == filterCount def rowBooleanFilterMatch(rowBoolean, filterBoolean): if not isinstance(rowBoolean, bool): return False return rowBoolean == filterBoolean def headerFilterMatch(filters, title): for filterStr in filters: if filterStr.match(title): return True return False if GC_Values[GC_CSV_ROW_FILTER]: for column, filterVal in iter(GC_Values[GC_CSV_ROW_FILTER].items()): if column not in titles: sys.stderr.write( f'WARNING: Row filter column "{column}" is not in output columns\n' ) continue if filterVal[0] == 'regex': csvRows = [ row for row in csvRows if filterVal[1].search(str(row.get(column, ''))) ] elif filterVal[0] == 'notregex': csvRows = [ row for row in csvRows if not filterVal[1].search(str(row.get(column, ''))) ] elif filterVal[0] in ['date', 'time']: csvRows = [ row for row in csvRows if rowDateTimeFilterMatch( filterVal[0] == 'date', row.get(column, ''), filterVal[1], filterVal[2]) ] elif filterVal[0] == 'count': csvRows = [ row for row in csvRows if rowCountFilterMatch( row.get(column, 0), filterVal[1], filterVal[2]) ] else: #boolean csvRows = [ row for row in csvRows if rowBooleanFilterMatch( row.get(column, False), filterVal[1]) ] if GC_Values[GC_CSV_HEADER_FILTER] or GC_Values[GC_CSV_HEADER_DROP_FILTER]: if GC_Values[GC_CSV_HEADER_DROP_FILTER]: titles = [ t for t in titles if not headerFilterMatch(GC_Values[GC_CSV_HEADER_DROP_FILTER], t) ] if GC_Values[GC_CSV_HEADER_FILTER]: titles = [ t for t in titles if headerFilterMatch(GC_Values[GC_CSV_HEADER_FILTER], t) ] if not titles: controlflow.system_error_exit( 3, 'No columns selected with GAM_CSV_HEADER_FILTER and GAM_CSV_HEADER_DROP_FILTER\n' ) return csv.register_dialect('nixstdout', lineterminator='\n') if todrive: write_to = io.StringIO() else: write_to = sys.stdout writer = csv.DictWriter(write_to, fieldnames=titles, dialect='nixstdout', extrasaction='ignore', quoting=csv.QUOTE_MINIMAL) try: writer.writerow(dict((item, item) for item in writer.fieldnames)) writer.writerows(csvRows) except IOError as e: controlflow.system_error_exit(6, e) if todrive: admin_email = gam._getValueFromOAuth('email') _, drive = gam.buildDrive3GAPIObject(admin_email) if not drive: print(f'''\nGAM is not authorized to create Drive files. Please run: gam user {admin_email} check serviceaccount and follow recommend steps to authorize GAM for Drive access.''') sys.exit(5) result = gapi.call(drive.about(), 'get', fields='maxImportSizes') columns = len(titles) rows = len(csvRows) cell_count = rows * columns data_size = len(write_to.getvalue()) max_sheet_bytes = int(result['maxImportSizes'][MIMETYPE_GA_SPREADSHEET]) if cell_count > MAX_GOOGLE_SHEET_CELLS or data_size > max_sheet_bytes: print( f'{WARNING_PREFIX}{MESSAGE_RESULTS_TOO_LARGE_FOR_GOOGLE_SPREADSHEET}' ) mimeType = 'text/csv' else: mimeType = MIMETYPE_GA_SPREADSHEET body = { 'description': QuotedArgumentList(sys.argv), 'name': f'{GC_Values[GC_DOMAIN]} - {list_type}', 'mimeType': mimeType } result = gapi.call(drive.files(), 'create', fields='webViewLink', body=body, media_body=googleapiclient.http.MediaInMemoryUpload( write_to.getvalue().encode(), mimetype='text/csv')) file_url = result['webViewLink'] if GC_Values[GC_NO_BROWSER]: msg_txt = f'Drive file uploaded to:\n {file_url}' msg_subj = f'{GC_Values[GC_DOMAIN]} - {list_type}' gam.send_email(msg_subj, msg_txt) print(msg_txt) else: webbrowser.open(file_url)
def showUsageParameters(): rep = buildGAPIObject() throw_reasons = [ gapi.errors.ErrorReason.INVALID, gapi.errors.ErrorReason.BAD_REQUEST ] todrive = False if len(sys.argv) == 3: controlflow.missing_argument_exit('user or customer', 'report usageparameters') report = sys.argv[3].lower() titles = ['parameter'] if report == 'customer': endpoint = rep.customerUsageReports() kwargs = {} elif report == 'user': endpoint = rep.userUsageReport() kwargs = {'userKey': gam._getValueFromOAuth('email')} else: controlflow.expected_argument_exit('usageparameters', ['user', 'customer'], report) customerId = GC_Values[GC_CUSTOMER_ID] if customerId == MY_CUSTOMER: customerId = None tryDate = datetime.date.today().strftime(YYYYMMDD_FORMAT) all_parameters = set() i = 4 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'todrive': todrive = True i += 1 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam report usageparameters') fullDataRequired = ['all'] while True: try: result = gapi.call(endpoint, 'get', throw_reasons=throw_reasons, date=tryDate, customerId=customerId, fields='warnings,usageReports(parameters(name))', **kwargs) warnings = result.get('warnings', []) usage = result.get('usageReports') has_reports = bool(usage) fullData, tryDate = _check_full_data_available( warnings, tryDate, fullDataRequired, has_reports) if fullData < 0: print('No usage parameters available.') sys.exit(1) if has_reports: for parameter in usage[0]['parameters']: name = parameter.get('name') if name: all_parameters.add(name) if fullData == 1: break except gapi.errors.GapiInvalidError as e: tryDate = _adjust_date(str(e)) csvRows = [] for parameter in sorted(all_parameters): csvRows.append({'parameter': parameter}) display.write_csv_file(csvRows, titles, f'{report.capitalize()} Report Usage Parameters', todrive)
def showUsageParameters(): rep = buildGAPIObject() throw_reasons = [ gapi.errors.ErrorReason.INVALID, gapi.errors.ErrorReason.BAD_REQUEST ] todrive = False if len(sys.argv) == 3: controlflow.missing_argument_exit('user or customer', 'report usageparameters') report = sys.argv[3].lower() titles = ['parameter'] if report == 'customer': endpoint = rep.customerUsageReports() kwargs = {} elif report == 'user': endpoint = rep.userUsageReport() kwargs = {'userKey': gam._getValueFromOAuth('email')} else: controlflow.expected_argument_exit('usageparameters', ['user', 'customer'], report) customerId = GC_Values[GC_CUSTOMER_ID] if customerId == MY_CUSTOMER: customerId = None tryDate = datetime.date.today().strftime(YYYYMMDD_FORMAT) partial_apps = [] all_parameters = [] one_day = datetime.timedelta(days=1) i = 4 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'todrive': todrive = True i += 1 else: controlflow.invalid_argument_exit(sys.argv[i], "gam report usageparameters") while True: try: response = gapi.call(endpoint, 'get', throw_reasons=throw_reasons, date=tryDate, customerId=customerId, **kwargs) partial_on_thisday = [] for warning in response.get('warnings', []): for data in warning.get('data', []): if data.get('key') == 'application': partial_on_thisday.append(data['value']) if partial_apps: partial_apps = [ app for app in partial_apps if app in partial_on_thisday ] else: partial_apps = partial_on_thisday for parameter in response['usageReports'][0]['parameters']: name = parameter.get('name') if name and name not in all_parameters: all_parameters.append(name) if not partial_apps: break tryDate = (utils.get_yyyymmdd(tryDate, returnDateTime=True) - \ one_day).strftime(YYYYMMDD_FORMAT) except gapi.errors.GapiInvalidError as e: tryDate = _adjust_date(str(e)) all_parameters.sort() csvRows = [] for parameter in all_parameters: csvRows.append({'parameter': parameter}) display.write_csv_file(csvRows, titles, f'{report.capitalize()} Report Usage Parameters', todrive)