diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 79db1047..7078c4dd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -547,8 +547,8 @@ jobs: - name: Lint with ruff run: | "$PYTHON" -m pip install ruff - ruff check ../src/gam/ - ruff check ../tests/ + "$PYTHON" -m ruff check ../src/gam/ + "$PYTHON" -m ruff check ../tests/ - name: Install PyInstaller if: matrix.goal == 'build' diff --git a/src/gam/__init__.py b/src/gam/__init__.py index f88164a7..31474788 100755 --- a/src/gam/__init__.py +++ b/src/gam/__init__.py @@ -29,39 +29,149 @@ __version__ = '7.46.03' __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)' # pylint: disable=wrong-import-position +import base64 +import codecs +import collections +import configparser +import csv +from email.charset import add_charset, QP +from email.generator import Generator +from email.header import decode_header, Header +from email import message_from_string +from email.mime.application import MIMEApplication +from email.mime.audio import MIMEAudio +from email.mime.base import MIMEBase +from email.mime.image import MIMEImage +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +from email.utils import formatdate +from email.policy import SMTP as policySMTP +import hashlib +from html.entities import name2codepoint +from html.parser import HTMLParser import http.client import importlib +from importlib.metadata import version as lib_version +import io +import ipaddress +import json import logging +from logging.handlers import RotatingFileHandler +import mimetypes +import multiprocessing import os import platform +import queue +import random import re +from secrets import SystemRandom +import shlex +import signal +import smtplib +import socket +import sqlite3 +import ssl +import string +import struct +import subprocess import sys +from tempfile import TemporaryFile +try: + import termios +except ImportError: + # termios does not exist for Windows + pass +import threading +import time from traceback import print_exc import types +from urllib.parse import quote, quote_plus, unquote, urlencode, urlparse, parse_qs +import uuid +import warnings +import webbrowser +import wsgiref.simple_server +import wsgiref.util +import zipfile # disable legacy stuff we don't use and isn't secure os.environ['CRYPTOGRAPHY_OPENSSL_NO_LEGACY'] = "1" +from cryptography import x509 +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.x509.oid import NameOID # Add package directory to sys.path for source installs (not needed for frozen/PyInstaller builds) if not getattr(sys, 'frozen', False): sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) +import arrow + +from pathvalidate import sanitize_filename, sanitize_filepath + +import google.oauth2.credentials +import google.oauth2.id_token +import google.auth +import google.auth.transport.requests +from google.auth.compute_engine import _metadata as gce_metadata +from google.auth.jwt import Credentials as JWTCredentials +import google.oauth2.service_account +import google_auth_oauthlib.flow +import google_auth_httplib2 +import googleapiclient +import googleapiclient.discovery +import googleapiclient.errors +import googleapiclient.http import httplib2 + httplib2.RETRIES = 5 +from passlib.hash import sha512_crypt +from filelock import FileLock + +if platform.system() == 'Linux': + import distro + +from gamlib import action from gamlib import api as API from gamlib import settings as GC +from gamlib import clargs +from gamlib import entity from gamlib import gapi as GAPI +from gamlib import gdata as GDATA from gamlib import state as GM +from gamlib import indent from gamlib import msgs as Msg +from gamlib import skus as SKU +from gamlib import uprop as UProp +from gamlib import verlibs -from gam.util.api import SvcAcctAPIDisabledExit # noqa: E402 -from gam.util.email import send_email # noqa: E402 +import gdata.apps.service +import gdata.apps.audit +import gdata.apps.audit.service +import gdata.apps.contacts +import gdata.apps.contacts.service + +from gam.util.html import _DeHTMLParser, dehtml # noqa: F401 # re-export +from gam.util.access import ( # noqa: F401 # re-export + accessErrorMessage, accessErrorExit, accessErrorExitNonDirectory, + checkEntityDNEorAccessErrorExit, checkEntityAFDNEorAccessErrorExit, + checkEntityItemValueAFDNEorAccessErrorExit, + entityUnknownWarning, entityOrEntityUnknownWarning, duplicateAliasGroupUserWarning, +) +from gam.util.api import ( # noqa: F401 # re-export (moved from access.py) + ClientAPIAccessDeniedExit, SvcAcctAPIAccessDenied, SvcAcctAPIAccessDeniedExit, + SvcAcctAPIDisabledExit, APIAccessDeniedExit, +) +from gam.util.email import ( # noqa: F401 # re-export + _addAttachmentsToMessage, _addEmbeddedImagesToMessage, send_email, +) from gam.constants import * -from util.fileio import adjustRedirectedSTDFilesIfNotMultiprocessing, closeSTDFilesIfNotMultiprocessing # noqa: E402 +from util.output import ISOformatTimeStamp, currentISOformatTimeStamp # noqa: E402,F401 +from util.fileio import adjustRedirectedSTDFilesIfNotMultiprocessing, closeSTDFilesIfNotMultiprocessing # noqa: E402,F401 from gam.var import Act, Cmd, Ent, Ind # noqa: E402,F401 @@ -80,18 +190,20 @@ else: GM.Globals[GM.GAM_TYPE] = 'pythonsource' -from util.output import showAPICallsRetryData # noqa: E402 +from util.output import redactable_debug_print, showAPICallsRetryData # noqa: E402,F401 # Multiprocessing lock mplock = None # Imports used by __init__.py's own dispatch tables and functions -from util.output import setSysExitRC, printErrorMessage # noqa: E402 -from util.args import getChoice # noqa: E402 -from util.args import checkArgumentPresent, NO_DEFAULT # noqa: E402 +from util.output import setSysExitRC, systemErrorExit, printErrorMessage # noqa: E402 +from util.output import writeStderr, formatKeyValueList # noqa: E402 +from util.errors import unknownArgumentExit # noqa: E402 +from util.args import getArgument, getChoice, getInteger, getStringReturnInList # noqa: E402 +from util.args import checkArgumentPresent, normalizeEmailAddressOrUID, NO_DEFAULT # noqa: E402 from util.connection import doCheckConnection, doComment, doVersion, doUsage # noqa: E402 -from util.entity import getEntityArgument, getEntityToModify # noqa: E402 +from util.entity import getEntityArgument, getEntityList, getEntityToModify # noqa: E402 from util.config import SetGlobalVariables # noqa: E402 from util.fileio import closeGAMCommandLog, writeGAMCommandLog # noqa: E402 from util.batch import ( # noqa: E402 diff --git a/src/gam/cmd/admin.py b/src/gam/cmd/admin.py index 864d3246..54a9b538 100644 --- a/src/gam/cmd/admin.py +++ b/src/gam/cmd/admin.py @@ -3,6 +3,7 @@ import json +import re from gamlib import api as API from gamlib import settings as GC diff --git a/src/gam/cmd/alerts.py b/src/gam/cmd/alerts.py index 59a2fd72..d3261bc7 100644 --- a/src/gam/cmd/alerts.py +++ b/src/gam/cmd/alerts.py @@ -1,11 +1,15 @@ """GAM alert center management.""" import json +import sys from gam.util.args import formatLocalTime from gamlib import api as API +from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM +from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.api import _getAdminEmail from gam.util.svcacct import buildGAPIServiceObject diff --git a/src/gam/cmd/aliases.py b/src/gam/cmd/aliases.py index ea7e739d..10b36014 100644 --- a/src/gam/cmd/aliases.py +++ b/src/gam/cmd/aliases.py @@ -6,6 +6,7 @@ import time from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.access import entityUnknownWarning @@ -44,6 +45,7 @@ from gam.util.entity import ( getEntityArgument, getEntityList, getEntityToModify, + getQueries, ) from gam.util.errors import entityActionFailedExit, unknownArgumentExit from gam.util.orgunits import getOrgUnitItem diff --git a/src/gam/cmd/analytics.py b/src/gam/cmd/analytics.py index 111c3346..2913460e 100644 --- a/src/gam/cmd/analytics.py +++ b/src/gam/cmd/analytics.py @@ -5,6 +5,8 @@ import json from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM +from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPIpages diff --git a/src/gam/cmd/audit.py b/src/gam/cmd/audit.py index 2886fded..c12b720d 100644 --- a/src/gam/cmd/audit.py +++ b/src/gam/cmd/audit.py @@ -3,8 +3,13 @@ Mailbox monitor creation/deletion/listing and the doWhatIs command. """ +import re +from gamlib import api as API +from gamlib import settings as GC +from gamlib import gapi as GAPI from gamlib import state as GM +from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.access import entityUnknownWarning from gam.util.api import getEmailAuditObject diff --git a/src/gam/cmd/browsers.py b/src/gam/cmd/browsers.py index 72479e19..22b87b4a 100644 --- a/src/gam/cmd/browsers.py +++ b/src/gam/cmd/browsers.py @@ -5,6 +5,7 @@ import json from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.access import checkEntityAFDNEorAccessErrorExit diff --git a/src/gam/cmd/caa.py b/src/gam/cmd/caa.py index c9f09219..40dabcc8 100644 --- a/src/gam/cmd/caa.py +++ b/src/gam/cmd/caa.py @@ -4,7 +4,9 @@ import json import string from gamlib import api as API +from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.svcacct import buildGAPIServiceObject diff --git a/src/gam/cmd/chat/setup.py b/src/gam/cmd/chat/setup.py index af782c49..df47735c 100644 --- a/src/gam/cmd/chat/setup.py +++ b/src/gam/cmd/chat/setup.py @@ -6,6 +6,7 @@ Part of the _chat_tmp sub-package.""" import re import json +import sys import base64 import os diff --git a/src/gam/cmd/chat/spaces.py b/src/gam/cmd/chat/spaces.py index 70152c8a..da6a9407 100644 --- a/src/gam/cmd/chat/spaces.py +++ b/src/gam/cmd/chat/spaces.py @@ -5,11 +5,13 @@ Part of the _chat_tmp sub-package.""" """GAM Google Chat management.""" import json +import sys import uuid from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.api import buildGAPIObject from gam.util.api_call import callGAPI, callGAPIpages diff --git a/src/gam/cmd/chromeapps.py b/src/gam/cmd/chromeapps.py index 5add58c5..e0bf1a91 100644 --- a/src/gam/cmd/chromeapps.py +++ b/src/gam/cmd/chromeapps.py @@ -6,6 +6,7 @@ import json from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.access import checkEntityAFDNEorAccessErrorExit diff --git a/src/gam/cmd/chromepolicies.py b/src/gam/cmd/chromepolicies.py index 20a67ed4..6c2943dd 100644 --- a/src/gam/cmd/chromepolicies.py +++ b/src/gam/cmd/chromepolicies.py @@ -8,6 +8,7 @@ import os from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.access import entityUnknownWarning @@ -70,6 +71,7 @@ from gam.util.errors import ( usageErrorExit, ) from gam.util.fileio import UNKNOWN, setFilePath +from gam.util.orgunits import getOrgUnitId from gam.constants import DFA_URL diff --git a/src/gam/cmd/cigroups/members.py b/src/gam/cmd/cigroups/members.py index 6dde6cb5..999e409c 100644 --- a/src/gam/cmd/cigroups/members.py +++ b/src/gam/cmd/cigroups/members.py @@ -12,6 +12,7 @@ from gam.util.args import formatLocalTime from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind @@ -123,7 +124,7 @@ def getCIGroupMemberTypes(myarg, typesSet): def doInfoCIGroups(): from gam.cmd.groups.members import CIGROUP_FIELDS_CHOICE_MAP, CIGROUP_TIME_OBJECTS, _checkCIMemberMatch, _showCIGroup, finalizeIPSGMGroupRolesMemberDisplayOptions, getIPSGMGroupRolesMemberDisplayOptions, getMemberMatchOptions, initIPSGMGroupMemberDisplayOptions, initMemberOptions def printCIGroupMemberTree(group_id, showRole): - if group_id not in cachedGroupMembers: + if not group_id in cachedGroupMembers: try: cachedGroupMembers[group_id] = callGAPIpages(ci.groups().memberships(), 'list', 'memberships', throwReasons=GAPI.MEMBERS_THROW_REASONS, diff --git a/src/gam/cmd/ciuserinvitations.py b/src/gam/cmd/ciuserinvitations.py index c59e8632..2141c643 100644 --- a/src/gam/cmd/ciuserinvitations.py +++ b/src/gam/cmd/ciuserinvitations.py @@ -4,7 +4,10 @@ import re import json from gamlib import api as API +from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM +from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.access import entityUnknownWarning from gam.util.api import buildGAPIObject diff --git a/src/gam/cmd/cloudstorage.py b/src/gam/cmd/cloudstorage.py index 10e16c2e..9a546e32 100644 --- a/src/gam/cmd/cloudstorage.py +++ b/src/gam/cmd/cloudstorage.py @@ -4,6 +4,7 @@ import re import googleapiclient.http import hashlib +import copy import base64 import os import time @@ -11,6 +12,7 @@ import time from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.api import buildGAPIObject diff --git a/src/gam/cmd/contacts.py b/src/gam/cmd/contacts.py index 885110bb..0c246919 100644 --- a/src/gam/cmd/contacts.py +++ b/src/gam/cmd/contacts.py @@ -5,7 +5,10 @@ import json import gdata.apps.contacts +from gamlib import api as API from gamlib import settings as GC +from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.constants import NO_ENTITIES_FOUND_RC @@ -51,6 +54,7 @@ from gam.util.display import ( from gam.util.entity import getEntityList from gam.util.errors import invalidChoiceExit, missingArgumentExit, unknownArgumentExit, usageErrorExit from gam.util.output import setSysExitRC, writeStdout +from gam.cmd.users.manage import ADDRESS_ARGUMENT_TO_FIELD_MAP, ORGANIZATION_ARGUMENT_TO_FIELD_MAP def _getCreateContactReturnOptions(parameters): @@ -107,7 +111,7 @@ CONTACT_RELATIONS = 'Relations' CONTACT_USER_DEFINED_FIELDS = 'User Defined Fields' CONTACT_WEBSITES = 'Websites' # -class ContactsManager: +class ContactsManager(): CONTACT_ARGUMENT_TO_PROPERTY_MAP = { 'json': CONTACT_JSON, @@ -1663,7 +1667,7 @@ PEOPLE_REMOVE_GROUPS_LIST = 'ContactRemoveGroupsList' PEOPLE_GROUP_NAME = 'name' PEOPLE_GROUP_CLIENT_DATA = 'clientData' # -class PeopleManager: +class PeopleManager(): PEOPLE_ARGUMENT_TO_PROPERTY_MAP = { 'json': PEOPLE_JSON, 'additionalname': PEOPLE_NAMES_MIDDLE_NAME, diff --git a/src/gam/cmd/courses/content.py b/src/gam/cmd/courses/content.py index 6df04c5a..b5a221a7 100644 --- a/src/gam/cmd/courses/content.py +++ b/src/gam/cmd/courses/content.py @@ -4,12 +4,15 @@ Part of the _courses_tmp sub-package.""" """GAM Google Classroom course management.""" +import re import json +import sys from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI from gamlib import state as GM +from gamlib import msgs as Msg from gam.util.api import buildGAPIObject from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIpages @@ -32,7 +35,7 @@ from gam.util.csv_pf import ( from gam.util.display import entityActionFailedWarning, entityDoesNotHaveItemWarning, getPageMessageForWhom, printGettingAllEntityItemsForWhom from gam.util.entity import getEntityList -from gam.var import Cmd, Ent +from gam.var import Act, Cmd, Ent, Ind def doPrintCourseAnnouncements(): def _printCourseAnnouncement(course, courseAnnouncement, i, count): diff --git a/src/gam/cmd/courses/courses.py b/src/gam/cmd/courses/courses.py index 1f09f59e..cca093a9 100644 --- a/src/gam/cmd/courses/courses.py +++ b/src/gam/cmd/courses/courses.py @@ -143,7 +143,7 @@ def _gettingCourseEntityQuery(entityType, courseWorkStates): query = query[:-2] return query -class CourseAttributes: +class CourseAttributes(): def __init__(self, croom, updateMode): self.croom = croom diff --git a/src/gam/cmd/courses/guardians.py b/src/gam/cmd/courses/guardians.py index e3bac32b..a6f867b4 100644 --- a/src/gam/cmd/courses/guardians.py +++ b/src/gam/cmd/courses/guardians.py @@ -4,6 +4,7 @@ Part of the _courses_tmp sub-package.""" """GAM Google Classroom course management.""" +import re import json from gamlib import uprop as UProp @@ -11,6 +12,7 @@ from gamlib import uprop as UProp from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.access import entityUnknownWarning from gam.util.api import buildGAPIObject diff --git a/src/gam/cmd/cros.py b/src/gam/cmd/cros.py index e502cacb..1bd40d5c 100644 --- a/src/gam/cmd/cros.py +++ b/src/gam/cmd/cros.py @@ -1,6 +1,7 @@ """GAM ChromeOS device management.""" import json +import sys from gam.util.args import formatLocalTime @@ -39,6 +40,7 @@ from gam.util.args import ( getString, getStringWithCRsNLs, getTimeOrDeltaFromNow, + getYYYYMMDD, makeOrgUnitPathAbsolute, makeOrgUnitPathRelative, substituteQueryTimes, diff --git a/src/gam/cmd/customer.py b/src/gam/cmd/customer.py index 0ec0a8e6..f46ca687 100644 --- a/src/gam/cmd/customer.py +++ b/src/gam/cmd/customer.py @@ -5,11 +5,12 @@ import json from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.access import accessErrorExit from gam.util.api import buildGAPIObject -from gam.util.api_call import callGAPI +from gam.util.api_call import callGAPI, callGAPIitems from gam.util.args import ( LANGUAGE_CODES_MAP, YYYYMMDD_FORMAT, @@ -34,8 +35,13 @@ from gam.util.errors import unknownArgumentExit from gam.util.fileio import UNKNOWN from gam.util.output import printWarningMessage, writeStdout from gam.util.entity import ( + PRINT_PRIVILEGES_FIELDS, _getCustomerId, + _getCustomerIdNoC, + _getCustomersCustomerIdNoC, + _getCustomersCustomerIdWithC, _getDomainList, + setTrueCustomerId, ) from gam.constants import DATA_NOT_AVALIABLE_RC from gam.cmd.domains import CUSTOMER_LICENSE_MAP diff --git a/src/gam/cmd/datatransfer.py b/src/gam/cmd/datatransfer.py index d27115ec..25c44736 100644 --- a/src/gam/cmd/datatransfer.py +++ b/src/gam/cmd/datatransfer.py @@ -1,5 +1,6 @@ """GAM data transfer operations.""" +import sys from gam.util.args import formatLocalTime import time @@ -7,6 +8,7 @@ import time from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.api import buildGAPIObject diff --git a/src/gam/cmd/delegates.py b/src/gam/cmd/delegates.py index e8d296ae..0b562b29 100644 --- a/src/gam/cmd/delegates.py +++ b/src/gam/cmd/delegates.py @@ -4,6 +4,8 @@ from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM +from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.api import buildGAPIObject from gam.util.api_call import callGAPI, callGAPIpages diff --git a/src/gam/cmd/domains.py b/src/gam/cmd/domains.py index ffacf56e..ccb82e3e 100644 --- a/src/gam/cmd/domains.py +++ b/src/gam/cmd/domains.py @@ -1,11 +1,14 @@ """GAM domain and domain alias management.""" import json +import sys +import re from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.access import accessErrorExit diff --git a/src/gam/cmd/drive/activity.py b/src/gam/cmd/drive/activity.py index 3a15f261..6ac5295d 100644 --- a/src/gam/cmd/drive/activity.py +++ b/src/gam/cmd/drive/activity.py @@ -4,13 +4,17 @@ """GAM Google Drive file, permission, shared drive, and label management.""" +import re import json +import sys from gam.util.args import formatLocalTime from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM +from gamlib import msgs as Msg from gam.util.api import _getAdminEmail, buildGAPIObject from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIitems, callGAPIpages, yieldGAPIpages diff --git a/src/gam/cmd/drive/copymove/copymove_move.py b/src/gam/cmd/drive/copymove/copymove_move.py index 6c19fac7..fe5037f6 100644 --- a/src/gam/cmd/drive/copymove/copymove_move.py +++ b/src/gam/cmd/drive/copymove/copymove_move.py @@ -8,13 +8,16 @@ Part of the copymove sub-package.""" """GAM Google Drive file, permission, shared drive, and label management.""" +import re from gam.cmd.drive.core import DFA_SEARCHARGS from gam.cmd.drive.copymove.copymove_util import _checkForDuplicateTargetFile, _checkForExistingShortcut, _copyPermissions, _getCopyFolderNonInheritedPermissions, _getCopyMoveParentInfo, _getCopyMoveTargetInfo, _getUniqueFilename, _identicalSourceTarget, _printStatistics, _targetFilenameExists, _verifyUserIsOrganizer, getCopyMoveOptions, initCopyMoveOptions +from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.api_call import callGAPI, callGAPIpages from gam.util.args import getArgument, getBoolean diff --git a/src/gam/cmd/drive/copymove/copymove_util.py b/src/gam/cmd/drive/copymove/copymove_util.py index 241e681e..a8eeaf2f 100644 --- a/src/gam/cmd/drive/copymove/copymove_util.py +++ b/src/gam/cmd/drive/copymove/copymove_util.py @@ -16,6 +16,7 @@ import os from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIpages @@ -1490,9 +1491,9 @@ def copyDriveFile(users): elif (sourceMimeType == MIMETYPE_GA_FOLDER) and copyMoveOptions['mergeWithParent']: destName = dest['name'] elif ((newParentsSpecified and newParentId not in sourceParents) or - (newParentId in sourceParents and + ((newParentId in sourceParents and (sourceMimeType == MIMETYPE_GA_FOLDER and copyMoveOptions['duplicateFolders'] != DUPLICATE_FOLDER_MERGE) or - (sourceMimeType != MIMETYPE_GA_FOLDER and copyMoveOptions['duplicateFiles'] not in [DUPLICATE_FILE_OVERWRITE_ALL, DUPLICATE_FILE_OVERWRITE_OLDER]))): + (sourceMimeType != MIMETYPE_GA_FOLDER and copyMoveOptions['duplicateFiles'] not in [DUPLICATE_FILE_OVERWRITE_ALL, DUPLICATE_FILE_OVERWRITE_OLDER])))): if copyMoveOptions['replaceFilename']: destName = processFilenameReplacements(sourceName, copyMoveOptions['replaceFilename']) else: diff --git a/src/gam/cmd/drive/core.py b/src/gam/cmd/drive/core.py index 9648b3df..1d768ae6 100644 --- a/src/gam/cmd/drive/core.py +++ b/src/gam/cmd/drive/core.py @@ -64,7 +64,7 @@ from gam.util.fileio import FILE_ERROR_RC, fileErrorMessage, setFilePath from gam.util.output import setSysExitRC, stderrWarningMsg, systemErrorExit from gam.constants import ANY_NON_TRASHED_FOLDER_NAME, MY_NON_TRASHED_FOLDER_NAME, NO_ENTITIES_FOUND_RC, TEAM_DRIVE -from gam.var import Cmd, Ent +from gam.var import Act, Cmd, Ent, Ind APPLICATION_VND_GOOGLE_APPS = 'application/vnd.google-apps.' MIMETYPE_GA_DOCUMENT = f'{APPLICATION_VND_GOOGLE_APPS}document' @@ -649,7 +649,7 @@ def _getDriveFileParentInfo(drive, user, i, count, body, parameters, emptyQueryO fileId=parameters[DFA_PARENTID], fields='id,name,mimeType,driveId', supportsAllDrives=True) if result['mimeType'] != MIMETYPE_GA_FOLDER: entityActionNotPerformedWarning([Ent.USER, user, entityType, None], - f'parentid: {parameters[DFA_PARENTID]}, {Msg.NOT_AN_ENTITY.format(Ent.Singular(Ent.DRIVE_FOLDER))}', i, count) + f'parentid: {parameters[DFA_PARENTID]}, {Msg.NOT_AN_ENTITY.format((Ent.Singular(Ent.DRIVE_FOLDER)))}', i, count) return False body['parents'].append(result['id']) if result.get('driveId'): @@ -833,7 +833,7 @@ def validateMimeType(mimeType): def getMimeType(): return validateMimeType(getString(Cmd.OB_MIMETYPE).lower()) -class MimeTypeCheck: +class MimeTypeCheck(): def __init__(self): self.mimeTypes = set() diff --git a/src/gam/cmd/drive/fileinfo.py b/src/gam/cmd/drive/fileinfo.py index fbb2a2f3..9752ad42 100644 --- a/src/gam/cmd/drive/fileinfo.py +++ b/src/gam/cmd/drive/fileinfo.py @@ -4,14 +4,16 @@ """GAM Google Drive file, permission, shared drive, and label management.""" +import re import platform -from gam.cmd.drive.core import _validateUserGetFileIDs, getDriveFileEntity +from gam.cmd.drive.core import _getDriveFileNameFromId, _validateUserGetFileIDs, getDriveFileEntity import os from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.constants import WITH_PARENTS @@ -46,7 +48,7 @@ SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' from gam.cmd.drive.core import ( - _getSharedDriveNameFromId, _simpleFileIdEntityList, + MimeTypeCheck, _getSharedDriveNameFromId, _simpleFileIdEntityList, _validateUserGetFileIDs, _validateUserSharedDrive, cleanFileIDsList, getDriveFileEntity, getSharedDriveEntity, initDriveFileEntity, ) diff --git a/src/gam/cmd/drive/filelist.py b/src/gam/cmd/drive/filelist.py index 42c30977..966b84a1 100644 --- a/src/gam/cmd/drive/filelist.py +++ b/src/gam/cmd/drive/filelist.py @@ -4,6 +4,7 @@ """GAM Google Drive file, permission, shared drive, and label management.""" +import re import json from gam.util.args import formatLocalTime @@ -13,6 +14,7 @@ from gam.cmd.drive.filepaths import _finalizeIncludeLabels, _finalizeIncludePerm from gam.util.csv_pf import DEFAULT_SKIP_OBJECTS +from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI from gamlib import state as GM diff --git a/src/gam/cmd/drive/filepaths.py b/src/gam/cmd/drive/filepaths.py index 89525f12..05831b75 100644 --- a/src/gam/cmd/drive/filepaths.py +++ b/src/gam/cmd/drive/filepaths.py @@ -4,6 +4,7 @@ """GAM Google Drive file, permission, shared drive, and label management.""" +import re import json from gam.cmd.drive.core import _getSharedDriveNameFromId, _validateUserGetFileIDs, getDriveFileEntity @@ -12,11 +13,14 @@ from gam.cmd.drive.labels import normalizeDriveLabelID from gam.util.csv_pf import DEFAULT_SKIP_OBJECTS +from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM +from gamlib import msgs as Msg from gam.constants import MY_DRIVE, TEAM_DRIVE -from gam.var import Cmd, Ent, Ind +from gam.var import Act, Cmd, Ent, Ind APPLICATION_VND_GOOGLE_APPS = 'application/vnd.google-apps.' MIMETYPE_GA_DOCUMENT = f'{APPLICATION_VND_GOOGLE_APPS}document' @@ -50,6 +54,8 @@ from gam.cmd.drive.core import DRIVE_LABEL_CHOICE_MAP # cross-module ref from gam.util.api_call import callGAPI, callGAPIitems, callGAPIpages from gam.util.args import ( OrderBy, + StartEndTime, + checkArgumentPresent, escapeCRsNLs, getArgument, getBoolean, @@ -569,7 +575,7 @@ def _getDriveFieldSubField(field, fieldsList, parentsSubFields): else: invalidChoiceExit(field, list(DRIVE_SUBFIELDS_CHOICE_MAP), True) -class DriveFileFields: +class DriveFileFields(): def __init__(self): self.showSharedDriveNames = False self.allFields = False diff --git a/src/gam/cmd/drive/files.py b/src/gam/cmd/drive/files.py index 88e5d530..573491a5 100644 --- a/src/gam/cmd/drive/files.py +++ b/src/gam/cmd/drive/files.py @@ -8,10 +8,12 @@ import re from gam.cmd.drive.core import DFA_IGNORE_DEFAULT_VISIBILITY, DFA_KEEP_REVISION_FOREVER, DFA_LOCALFILENAME, DFA_LOCALFILEPATH, DFA_LOCALMIMETYPE, DFA_OCRLANGUAGE, DFA_PARENTID, DFA_PRESERVE_FILE_TIMES, DFA_REPLACEFILENAME, DFA_SHAREDDRIVE_PARENT, DFA_STRIPNAMEPREFIX, DFA_TIMEFORMAT, DFA_TIMESTAMP, DFA_URL, DFA_USE_CONTENT_AS_INDEXABLE_TEXT, _getDriveFileAddRemoveParentInfo, _getDriveFileParentInfo, _validateUserGetFileIDs, escapeDriveFileName, getDriveFileAddRemoveParentAttribute, getDriveFileAttribute, getDriveFileEntity, getDriveFileParentAttribute, getMediaBody, initDriveFileAttributes, setPreservedFileTimes from gam.cmd.drive.fileinfo import writeReturnIdLink +import time from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIitems, callGAPIpages diff --git a/src/gam/cmd/drive/filetree.py b/src/gam/cmd/drive/filetree.py index 942849b9..6dd11732 100644 --- a/src/gam/cmd/drive/filetree.py +++ b/src/gam/cmd/drive/filetree.py @@ -9,12 +9,15 @@ import re from gam.cmd.drive.core import _getSharedDriveNameFromId, _mapDrive2QueryToDrive3, cleanFileIDsList, escapeDriveFileName, getEscapedDriveFileName, initDriveFileEntity from gam.cmd.drive.revisions import _stripMeInOwners, _stripNotMeInOwners, _updateAnyOwnerQuery +from gamlib import api as API +from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.entity import QUERY_SHORTCUTS_MAP from gam.constants import MY_DRIVE, TEAM_DRIVE -from gam.var import Cmd, Ent +from gam.var import Act, Cmd, Ent, Ind APPLICATION_VND_GOOGLE_APPS = 'application/vnd.google-apps.' MIMETYPE_GA_DOCUMENT = f'{APPLICATION_VND_GOOGLE_APPS}document' @@ -62,6 +65,7 @@ from gam.util.args import ( StartEndTime, checkArgumentPresent, checkGetArgument, + escapeCRsNLs, getArgument, getBoolean, getChoice, @@ -254,7 +258,7 @@ DRIVEFILE_ACL_ROLES_MAP = { DRIVEFILE_ACL_PERMISSION_TYPES = ['anyone', 'domain', 'group', 'user'] # anyone must be first element DRIVEFILE_ACL_PERMISSION_DETAILS_TYPES = ['file', 'member'] -class PermissionMatch: +class PermissionMatch(): _PERMISSION_MATCH_ACTION_MAP = {'process': True, 'skip': False} _PERMISSION_MATCH_MODE_MAP = {'or': True, 'and': False} @@ -501,7 +505,7 @@ def noFileSelectFileIdEntity(fileIdEntity): SHOW_OWNED_BY_CHOICE_MAP = {'any': None, 'me': True, 'others': False} -class DriveListParameters: +class DriveListParameters(): def __init__(self, myargOptions): self.PM = PermissionMatch() self.myargOptions = myargOptions diff --git a/src/gam/cmd/drive/labels.py b/src/gam/cmd/drive/labels.py index 07b3240e..7540e177 100644 --- a/src/gam/cmd/drive/labels.py +++ b/src/gam/cmd/drive/labels.py @@ -10,7 +10,9 @@ import json from gam.cmd.drive.core import _validateUserGetFileIDs, getDriveFileEntity from gamlib import api as API +from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.api import _getAdminEmail from gam.util.svcacct import buildGAPIServiceObject diff --git a/src/gam/cmd/drive/looker.py b/src/gam/cmd/drive/looker.py index 7a8ed9c7..290a0ad3 100644 --- a/src/gam/cmd/drive/looker.py +++ b/src/gam/cmd/drive/looker.py @@ -4,11 +4,15 @@ """GAM Google Drive file, permission, shared drive, and label management.""" +import re import json +import sys from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM +from gamlib import msgs as Msg from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIpages from gam.util.args import ( diff --git a/src/gam/cmd/drive/permissions.py b/src/gam/cmd/drive/permissions.py index 4325a430..5962edeb 100644 --- a/src/gam/cmd/drive/permissions.py +++ b/src/gam/cmd/drive/permissions.py @@ -4,6 +4,7 @@ """GAM Google Drive file, permission, shared drive, and label management.""" +import re import json from gam.cmd.drive.core import _getDriveFileNameFromId, _getSharedDriveNameFromId, _validateUserGetFileIDs, _validateUserSharedDrive, cleanFileIDsList, getDriveFileEntity, getSharedDriveEntity, initDriveFileEntity diff --git a/src/gam/cmd/drive/revisions.py b/src/gam/cmd/drive/revisions.py index c44a6973..11df4e80 100644 --- a/src/gam/cmd/drive/revisions.py +++ b/src/gam/cmd/drive/revisions.py @@ -4,9 +4,11 @@ """GAM Google Drive file, permission, shared drive, and label management.""" +import re from gam.cmd.drive.core import _getDriveFileNameFromId, _validateUserGetFileIDs, getDriveFileEntity +from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI from gamlib import state as GM diff --git a/src/gam/cmd/drive/shareddrives.py b/src/gam/cmd/drive/shareddrives.py index a1561971..c20b347c 100644 --- a/src/gam/cmd/drive/shareddrives.py +++ b/src/gam/cmd/drive/shareddrives.py @@ -6,6 +6,7 @@ import re import json +import sys from gam.util.args import formatLocalTime @@ -21,6 +22,7 @@ from gam.cmd.drive.core import getSharedDriveEntity, _validateUserSharedDrive from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.api import _getAdminEmail, _getValueFromOAuth, buildGAPIObject from gam.util.svcacct import buildGAPIServiceObject diff --git a/src/gam/cmd/drive/transfer/ownership.py b/src/gam/cmd/drive/transfer/ownership.py index fcddde12..7bb766b1 100644 --- a/src/gam/cmd/drive/transfer/ownership.py +++ b/src/gam/cmd/drive/transfer/ownership.py @@ -8,6 +8,8 @@ Part of the transfer sub-package.""" """GAM Google Drive file, permission, shared drive, and label management.""" +import re +import sys from gamlib import api as API from gamlib import settings as GC diff --git a/src/gam/cmd/gmail/cse.py b/src/gam/cmd/gmail/cse.py index f7ff3c14..d6ff651b 100644 --- a/src/gam/cmd/gmail/cse.py +++ b/src/gam/cmd/gmail/cse.py @@ -4,12 +4,15 @@ Part of the _gmail_monolith sub-package.""" """GAM Gmail management: labels, messages, filters, forwarding, sendas, S/MIME, CSE, vacation.""" +import re import json +import sys import os from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIpages diff --git a/src/gam/cmd/gmail/delegates.py b/src/gam/cmd/gmail/delegates.py index fa332f21..34579ef6 100644 --- a/src/gam/cmd/gmail/delegates.py +++ b/src/gam/cmd/gmail/delegates.py @@ -4,10 +4,12 @@ Part of the _gmail_monolith sub-package.""" """GAM Gmail management: labels, messages, filters, forwarding, sendas, S/MIME, CSE, vacation.""" +import re from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.api import buildGAPIObject from gam.util.svcacct import buildGAPIServiceObject diff --git a/src/gam/cmd/gmail/filters.py b/src/gam/cmd/gmail/filters.py index ecc17b1f..3fa29a83 100644 --- a/src/gam/cmd/gmail/filters.py +++ b/src/gam/cmd/gmail/filters.py @@ -4,13 +4,16 @@ Part of the _gmail_monolith sub-package.""" """GAM Gmail management: labels, messages, filters, forwarding, sendas, S/MIME, CSE, vacation.""" +import re import json +import sys from gam.cmd.gmail.labels import _getLabelId, _getLabelName, _getLabelSet, _getUserGmailLabels, buildLabelPath from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIitems diff --git a/src/gam/cmd/gmail/forms.py b/src/gam/cmd/gmail/forms.py index d5c662d7..13504e55 100644 --- a/src/gam/cmd/gmail/forms.py +++ b/src/gam/cmd/gmail/forms.py @@ -4,10 +4,14 @@ Part of the _gmail_monolith sub-package.""" """GAM Gmail management: labels, messages, filters, forwarding, sendas, S/MIME, CSE, vacation.""" +import re import json from gamlib import api as API +from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM +from gamlib import msgs as Msg from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIpages from gam.util.args import ( diff --git a/src/gam/cmd/gmail/labels.py b/src/gam/cmd/gmail/labels.py index fc57de33..c607d6a1 100644 --- a/src/gam/cmd/gmail/labels.py +++ b/src/gam/cmd/gmail/labels.py @@ -9,6 +9,7 @@ import re from gam.util.csv_pf import RI_ENTITY, RI_J, RI_JCOUNT, RI_ITEM from gamlib import api as API +from gamlib import settings as GC from gamlib import gapi as GAPI from gamlib import state as GM from gamlib import msgs as Msg @@ -768,7 +769,7 @@ def _convertLabelNamesToIds(gmail, user, i, count, bodyLabels, labelNameMap, add # make sure to create parent labels for proper nesting parent_label = label[:label.rfind('/')] while True: - if (parent_label not in labelNameMap) and (parent_label.upper() not in labelNameMap): + if (not parent_label in labelNameMap) and (not parent_label.upper() in labelNameMap): result = callGAPI(gmail.users().labels(), 'create', userId='me', body={'name': parent_label}, fields='id') labelNameMap[parent_label] = labelNameMap[parent_label.upper()] = result['id'] diff --git a/src/gam/cmd/gmail/profile.py b/src/gam/cmd/gmail/profile.py index 06ce0896..c07cbb06 100644 --- a/src/gam/cmd/gmail/profile.py +++ b/src/gam/cmd/gmail/profile.py @@ -4,12 +4,17 @@ Part of the _gmail_monolith sub-package.""" """GAM Gmail management: labels, messages, filters, forwarding, sendas, S/MIME, CSE, vacation.""" +import re import json +import sys import uuid import base64 from gamlib import api as API +from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM +from gamlib import msgs as Msg from gam.util.api import buildGAPIObject from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIpages @@ -25,7 +30,7 @@ from gam.util.display import ( from gam.util.entity import getEntityArgument from gam.util.errors import unknownArgumentExit -from gam.var import Act, Cmd, Ent +from gam.var import Act, Cmd, Ent, Ind def watchGmail(users): maxMessages = 100 diff --git a/src/gam/cmd/gmail/settings.py b/src/gam/cmd/gmail/settings.py index c05cb2b7..16d7cfe6 100644 --- a/src/gam/cmd/gmail/settings.py +++ b/src/gam/cmd/gmail/settings.py @@ -4,12 +4,15 @@ Part of the _gmail_monolith sub-package.""" """GAM Gmail management: labels, messages, filters, forwarding, sendas, S/MIME, CSE, vacation.""" +import re from gam.cmd.gmail.messages import forwardMessagesThreads from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM +from gamlib import msgs as Msg from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIitems from gam.util.args import ( diff --git a/src/gam/cmd/gmail/signature.py b/src/gam/cmd/gmail/signature.py index c3dca7fa..a8e549c4 100644 --- a/src/gam/cmd/gmail/signature.py +++ b/src/gam/cmd/gmail/signature.py @@ -4,11 +4,15 @@ Part of the _gmail_monolith sub-package.""" """GAM Gmail management: labels, messages, filters, forwarding, sendas, S/MIME, CSE, vacation.""" +import re from gam.cmd.gmail.settings import _processSendAs, _processSignature, getSendAsAttributes from gamlib import api as API +from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM +from gamlib import msgs as Msg from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI from gam.util.args import ( diff --git a/src/gam/cmd/gmail/smime.py b/src/gam/cmd/gmail/smime.py index f308a0fd..60535fb8 100644 --- a/src/gam/cmd/gmail/smime.py +++ b/src/gam/cmd/gmail/smime.py @@ -4,6 +4,7 @@ Part of the _gmail_monolith sub-package.""" """GAM Gmail management: labels, messages, filters, forwarding, sendas, S/MIME, CSE, vacation.""" +import re from gam.util.args import formatLocalTimestamp import base64 @@ -11,6 +12,7 @@ import base64 from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIitems diff --git a/src/gam/cmd/groups/members.py b/src/gam/cmd/groups/members.py index aa1c51fd..c236f352 100644 --- a/src/gam/cmd/groups/members.py +++ b/src/gam/cmd/groups/members.py @@ -78,6 +78,7 @@ from gam.util.display import ( printGettingEntityItem, printGettingEntityItemForWhom, printKeyValueList, + printKeyValueListWithCount, printKeyValueWithCRsNLs, printLine, ) @@ -107,7 +108,7 @@ from gam.constants import ( ) from gam.util.domain_filters import ( getUserGroupDomainQueryFilters, initUserGroupDomainQueryFilters, - makeUserGroupDomainQueryFilters, + makeUserGroupDomainQueryFilters, _setUserGroupArgs, ) from gam.util.schema_utils import _initSchemaParms, _getSchemaNameList from gam.util.output import executeBatch, writeStderr, writeStdout @@ -1442,11 +1443,11 @@ def getGroupMembers(cd, groupEmail, memberRoles, membersList, membersSet, i, cou groupMemberList = [] for member in groupMembers: if member['type'] != Ent.TYPE_GROUP: - if (member['type'] in typesSet and + if ((member['type'] in typesSet and _checkMemberMatch(member, memberOptions) and _checkMemberRoleIsSuspendedIsArchived(member, validRoles, memberOptions[MEMBEROPTION_ISSUSPENDED], memberOptions[MEMBEROPTION_ISARCHIVED]) and (not checkShowCategory or _checkMemberCategory(member, memberDisplayOptions)) and - member['id'] not in membersSet): + member['id'] not in membersSet)): if memberOptions[MEMBEROPTION_GETDELIVERYSETTINGS]: _getMemberDeliverySettings(member) membersSet.add(member['id']) diff --git a/src/gam/cmd/licenses.py b/src/gam/cmd/licenses.py index c70c0edd..9e65c2a8 100644 --- a/src/gam/cmd/licenses.py +++ b/src/gam/cmd/licenses.py @@ -5,10 +5,11 @@ from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI from gamlib import state as GM +from gamlib import msgs as Msg from gamlib import skus as SKU -from gam.var import Cmd, Ent +from gam.var import Act, Cmd, Ent, Ind from gam.util.api import buildGAPIObject from gam.util.api_call import callGAPIpages from gam.util.args import getArgument, getGoogleProductList, getGoogleSKUList, getInteger diff --git a/src/gam/cmd/meet.py b/src/gam/cmd/meet.py index ad098327..4111f416 100644 --- a/src/gam/cmd/meet.py +++ b/src/gam/cmd/meet.py @@ -3,7 +3,10 @@ import json from gamlib import api as API +from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM +from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIpages diff --git a/src/gam/cmd/mobile.py b/src/gam/cmd/mobile.py index 0a6409f3..76ed449e 100644 --- a/src/gam/cmd/mobile.py +++ b/src/gam/cmd/mobile.py @@ -5,8 +5,9 @@ import json from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg -from gam.var import Cmd, Ent, Ind +from gam.var import Act, Cmd, Ent, Ind from gam.util.api import buildGAPIObject from gam.util.api_call import callGAPI, callGAPIpages, yieldGAPIpages from gam.util.args import ( diff --git a/src/gam/cmd/notes.py b/src/gam/cmd/notes.py index 1f9b459f..74585e07 100644 --- a/src/gam/cmd/notes.py +++ b/src/gam/cmd/notes.py @@ -9,6 +9,7 @@ import os from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.svcacct import buildGAPIServiceObject diff --git a/src/gam/cmd/oauth.py b/src/gam/cmd/oauth.py index 6a5d0d5c..2a58ae15 100644 --- a/src/gam/cmd/oauth.py +++ b/src/gam/cmd/oauth.py @@ -11,6 +11,7 @@ import os import re import socket import sys +import datetime import time import webbrowser import wsgiref.simple_server diff --git a/src/gam/cmd/people.py b/src/gam/cmd/people.py index e53271bd..884e5543 100644 --- a/src/gam/cmd/people.py +++ b/src/gam/cmd/people.py @@ -51,6 +51,7 @@ import google.auth.exceptions from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind diff --git a/src/gam/cmd/printers.py b/src/gam/cmd/printers.py index d1c2f7f3..2135d9b1 100644 --- a/src/gam/cmd/printers.py +++ b/src/gam/cmd/printers.py @@ -6,6 +6,7 @@ import json from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.access import entityUnknownWarning diff --git a/src/gam/cmd/project.py b/src/gam/cmd/project.py index f3600e89..68ee820b 100644 --- a/src/gam/cmd/project.py +++ b/src/gam/cmd/project.py @@ -5,6 +5,7 @@ key operations, and API enablement. """ import base64 +import datetime import json import os import re @@ -288,7 +289,7 @@ def _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo, except (IndexError, KeyError, SyntaxError, TypeError, ValueError) as e: sys.stderr.write(f'{str(e)}: {content}') return False - if 'error' not in content or 'error_description' not in content: + if not 'error' in content or not 'error_description' in content: sys.stderr.write(f'Unknown error: {content}\n') return False if content['error'] == 'invalid_grant': diff --git a/src/gam/cmd/reports.py b/src/gam/cmd/reports.py index 116b0b36..b4c418d2 100644 --- a/src/gam/cmd/reports.py +++ b/src/gam/cmd/reports.py @@ -2,13 +2,15 @@ import arrow +import datetime import re from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg -from gam.var import Cmd, Ent +from gam.var import Act, Cmd, Ent, Ind from gam.util.access import accessErrorExit, entityUnknownWarning from gam.util.api import _getAdminEmail, buildGAPIObject from gam.util.api_call import callGAPI, callGAPIpages diff --git a/src/gam/cmd/reseller.py b/src/gam/cmd/reseller.py index 836300c2..78e6f832 100644 --- a/src/gam/cmd/reseller.py +++ b/src/gam/cmd/reseller.py @@ -3,6 +3,7 @@ import json import sys +import re from gamlib import api as API from gamlib import settings as GC diff --git a/src/gam/cmd/schemas.py b/src/gam/cmd/schemas.py index 4d0472e4..139954c8 100644 --- a/src/gam/cmd/schemas.py +++ b/src/gam/cmd/schemas.py @@ -4,6 +4,7 @@ from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.access import checkEntityAFDNEorAccessErrorExit diff --git a/src/gam/cmd/send_email.py b/src/gam/cmd/send_email.py index e8a2c4b0..34f0ec11 100644 --- a/src/gam/cmd/send_email.py +++ b/src/gam/cmd/send_email.py @@ -2,17 +2,23 @@ import time +import re from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind -from gam.util.api import _getAdminEmail +from gam.util.access import entityUnknownWarning +from gam.util.api import _getAdminEmail, buildGAPIObject from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIpages from gam.util.args import ( + FALSE, SORF_MSG_FILE_ARGUMENTS, + TRUE, + TRUE_FALSE, UTF8, checkArgumentPresent, getArgument, @@ -21,10 +27,12 @@ from gam.util.args import ( getDateOrDeltaFromNow, getEmailAddress, getFilename, + getREPatternSubstitution, getString, getStringOrFile, getTimeOrDeltaFromNow, normalizeEmailAddressOrUID, + splitEmailAddress, ) from gam.util.display import ( entityActionFailedWarning, @@ -35,13 +43,15 @@ from gam.util.display import ( userGmailServiceNotEnabledWarning, ) from gam.util.email import send_email -from gam.util.entity import getEntityArgument, getEntityList +from gam.util.entity import getEntityArgument, getEntityList, getEntityToModify, getNormalizedEmailAddressEntity from gam.util.errors import ( + invalidArgumentExit, + invalidChoiceExit, missingArgumentExit, unknownArgumentExit, usageErrorExit, ) -from gam.util.output import setSysExitRC +from gam.util.output import ERROR, setSysExitRC from gam.util.tags import ( # noqa: F401 # re-export ADDRESS_FIELDS_PRINT_ORDER, CASE_MARKERS, diff --git a/src/gam/cmd/sites.py b/src/gam/cmd/sites.py index 696ff41c..a7044eba 100644 --- a/src/gam/cmd/sites.py +++ b/src/gam/cmd/sites.py @@ -1,10 +1,12 @@ """GAM site verification and web resource management.""" import json +import sys from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.api import buildGAPIObject, getHttpObj diff --git a/src/gam/cmd/sso.py b/src/gam/cmd/sso.py index bd44ed35..57978e92 100644 --- a/src/gam/cmd/sso.py +++ b/src/gam/cmd/sso.py @@ -6,6 +6,7 @@ import json from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.api import buildGAPIObject diff --git a/src/gam/cmd/tasks.py b/src/gam/cmd/tasks.py index decc53de..7450a4ef 100644 --- a/src/gam/cmd/tasks.py +++ b/src/gam/cmd/tasks.py @@ -1,10 +1,12 @@ """GAM Google Tasks and Tag Manager management.""" import json +import sys from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.svcacct import buildGAPIServiceObject diff --git a/src/gam/cmd/userop/licenses.py b/src/gam/cmd/userop/licenses.py index bba12c59..0626f233 100644 --- a/src/gam/cmd/userop/licenses.py +++ b/src/gam/cmd/userop/licenses.py @@ -4,6 +4,8 @@ Part of the _userop_tmp sub-package.""" """GAM user operations: Looker Studio, user groups, licenses, photos, profile, sheets, tokens, deprovision.""" +import re +import sys from gam.cmd.userop.usergroups import LICENSE_PREVIEW_TITLES @@ -12,6 +14,7 @@ from gam.cmd.userop.usergroups import LICENSE_PRODUCT_SKUIDS from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gamlib import skus as SKU from gam.util.access import entityUnknownWarning diff --git a/src/gam/cmd/userop/photos.py b/src/gam/cmd/userop/photos.py index 077e883f..298d35e7 100644 --- a/src/gam/cmd/userop/photos.py +++ b/src/gam/cmd/userop/photos.py @@ -16,6 +16,7 @@ import google.auth.exceptions from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.access import entityUnknownWarning from gam.util.api import buildGAPIObject, getHttpObj @@ -45,7 +46,7 @@ from gam.util.output import writeStdout from gam.util.tags import _substituteForUser from gam.cmd.drive.core import _validateUserGetFileIDs, getDriveFileEntity -from gam.var import Cmd, Ent +from gam.var import Act, Cmd, Ent, Ind from tempfile import TemporaryFile diff --git a/src/gam/cmd/userop/sheets.py b/src/gam/cmd/userop/sheets.py index 9aebe4b7..f5fc1d36 100644 --- a/src/gam/cmd/userop/sheets.py +++ b/src/gam/cmd/userop/sheets.py @@ -4,11 +4,13 @@ Part of the _userop_tmp sub-package.""" """GAM user operations: Looker Studio, user groups, licenses, photos, profile, sheets, tokens, deprovision.""" +import re import json from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.svcacct import buildGAPIServiceObject from gam.util.api_call import callGAPI, callGAPIitems diff --git a/src/gam/cmd/userop/tokens.py b/src/gam/cmd/userop/tokens.py index 14177897..401bf702 100644 --- a/src/gam/cmd/userop/tokens.py +++ b/src/gam/cmd/userop/tokens.py @@ -11,6 +11,7 @@ from gam.cmd.userop.sheets import commonClientIds from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.access import ClientAPIAccessDeniedExit, entityUnknownWarning from gam.util.api import _getAdminEmail, buildGAPIObject diff --git a/src/gam/cmd/users/display.py b/src/gam/cmd/users/display.py index 263b67e8..5a23d247 100644 --- a/src/gam/cmd/users/display.py +++ b/src/gam/cmd/users/display.py @@ -34,7 +34,7 @@ from gamlib import gapi as GAPI from gamlib import state as GM from gamlib import msgs as Msg -from gam.var import Cmd, Ent, Ind +from gam.var import Act, Cmd, Ent, Ind from gamlib import skus as SKU from gamlib import uprop as UProp diff --git a/src/gam/cmd/users/manage.py b/src/gam/cmd/users/manage.py index 474f3253..e22460c2 100644 --- a/src/gam/cmd/users/manage.py +++ b/src/gam/cmd/users/manage.py @@ -5,6 +5,7 @@ Part of the _users_tmp sub-package.""" """GAM user management.""" import re +import sys from gam.util.args import DEFAULT_CHOICE @@ -106,7 +107,7 @@ def hashPassword(password): Returns a tuple of (hashed_password, hash_function_name). The hash_function_name is always 'crypt' for Google's Directory API. """ - return (sha512_crypt.using(rounds=10000).hash(password), 'crypt') + return (sha512_crypt.hash(password, rounds=10000), 'crypt') def _getGroupOrgUnitMap(): @@ -138,7 +139,7 @@ def _getGroupOrgUnitMap(): closeFile(f) return groupOrgUnitMap -class PasswordOptions: +class PasswordOptions(): def __init__(self, updateCmd): self.password = '' self.notFoundPassword = '' diff --git a/src/gam/cmd/userservices.py b/src/gam/cmd/userservices.py index 5c93739f..d954dc28 100644 --- a/src/gam/cmd/userservices.py +++ b/src/gam/cmd/userservices.py @@ -1,6 +1,7 @@ """GAM user service management: ASPs, backup codes, user calendars.""" import json +import sys from gam.util.args import formatLocalTimestamp @@ -21,6 +22,7 @@ from gam.cmd.calendar import ( from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.var import Act, Cmd, Ent, Ind from gam.util.access import checkEntityAFDNEorAccessErrorExit, entityUnknownWarning @@ -84,6 +86,22 @@ from gam.util.display import ( userYouTubeServiceNotEnabledWarning, ) from gam.util.entity import ( + APPLICATION_VND_GOOGLE_APPS, + ME_IN_OWNERS, + ME_IN_OWNERS_AND, + MIMETYPE_GA_3P_SHORTCUT, + MIMETYPE_GA_DOCUMENT, + MIMETYPE_GA_FOLDER, + MIMETYPE_GA_FORM, + MIMETYPE_GA_PRESENTATION, + MIMETYPE_GA_SHORTCUT, + MIMETYPE_GA_SPREADSHEET, + NOT_ME_IN_OWNERS, + NOT_ME_IN_OWNERS_AND, + QUERY_SHORTCUTS_MAP, + SHAREDDRIVE_QUERY_SHORTCUTS_MAP, + _getEntityMimeType, + _getTargetEntityMimeType, checkUserSuspended, convertEntityToList, convertUIDtoEmailAddress, diff --git a/src/gam/cmd/vault/holds.py b/src/gam/cmd/vault/holds.py index 89c59a8d..f1aaf19b 100644 --- a/src/gam/cmd/vault/holds.py +++ b/src/gam/cmd/vault/holds.py @@ -4,6 +4,7 @@ Part of the _vault_tmp sub-package.""" """GAM Google Vault management.""" +import re import json from gam.cmd.vault.matters import _buildVaultQuery, _validateVaultQuery, convertHoldNameToID, convertMatterNameToID, convertQueryNameToID, formatVaultNameId, getMatterItem, warnMatterNotOpen @@ -18,7 +19,9 @@ from gam.cmd.vault.matters import ( import time from gamlib import api as API +from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.constants import NO_ENTITIES_FOUND_RC, PROJECTION_CHOICE_MAP diff --git a/src/gam/cmd/vault/matters.py b/src/gam/cmd/vault/matters.py index 95a18779..6b97cfbf 100644 --- a/src/gam/cmd/vault/matters.py +++ b/src/gam/cmd/vault/matters.py @@ -14,6 +14,7 @@ import time from gamlib import api as API from gamlib import settings as GC from gamlib import gapi as GAPI +from gamlib import state as GM from gamlib import msgs as Msg from gam.util.api import buildGAPIObject from gam.util.api_call import callGAPI, callGAPIpages @@ -527,7 +528,7 @@ def doCreateVaultExport(): body['exportOptions'][optionsField] = {'includeAccessInfo': includeAccessInfo} else: if exportFormat is not None: - if exportFormat not in VAULT_CORPUS_EXPORT_FORMATS[body['query']['corpus']]: + if not exportFormat in VAULT_CORPUS_EXPORT_FORMATS[body['query']['corpus']]: Cmd.SetLocation(formatLocation) invalidChoiceExit(exportFormat, VAULT_CORPUS_EXPORT_FORMATS[body['query']['corpus']], False) else: diff --git a/src/gam/util/access.py b/src/gam/util/access.py index a34cfa47..f2c9f661 100644 --- a/src/gam/util/access.py +++ b/src/gam/util/access.py @@ -4,6 +4,7 @@ Access-error diagnostics, API access denied handlers, and entity warning functions. """ +import sys from gamlib import action from gamlib import api as API @@ -14,11 +15,12 @@ from gamlib import state as GM from gamlib import indent from gamlib import msgs as Msg from gam.constants import API_ACCESS_DENIED_RC, INVALID_DOMAIN_RC -from util.api import _getAdminEmail, _getSvcAcctData, buildGAPIObject, APIAccessDeniedExit, ClientAPIAccessDeniedExit, SvcAcctAPIAccessDeniedExit, SvcAcctAPIDisabledExit # noqa: F401 +from util.api import _getAdminEmail, _getSvcAcctData, buildGAPIObject, APIAccessDeniedExit, ClientAPIAccessDeniedExit, SvcAcctAPIAccessDeniedExit, SvcAcctAPIDisabledExit from util.api_call import callGAPI from util.args import getEmailAddressDomain, getPhraseDNEorSNA from util.display import ENTITY_DOES_NOT_EXIST_RC, ENTITY_DUPLICATE_RC, entityActionFailedWarning, entityDoesNotExistWarning, entityServiceNotApplicableWarning -from util.output import currentCountNL, formatKeyValueList, setSysExitRC, systemErrorExit, writeStderr +from util.errors import OAUTH2SERVICE_JSON_REQUIRED_RC +from util.output import currentCountNL, formatKeyValueList, setSysExitRC, stderrErrorMsg, systemErrorExit, writeStderr diff --git a/src/gam/util/api.py b/src/gam/util/api.py index 577b62d6..838a5843 100644 --- a/src/gam/util/api.py +++ b/src/gam/util/api.py @@ -43,16 +43,18 @@ except ImportError: from gamlib import api as API from gamlib import settings as GC +from gamlib import gapi as GAPI +from gamlib import gdata as GDATA from gamlib import state as GM from gamlib import msgs as Msg from gamlib import yubikey from gam.var import Ent, Ind -from gam.constants import API_ACCESS_DENIED_RC, GOOGLE_API_ERROR_RC, NETWORK_ERROR_RC, NO_SCOPES_FOR_API_RC, REFRESH_EXPIRY, SOCKET_ERROR_RC, SYSTEM_ERROR_RC -from util.args import UTF8, YYYYMMDDTHHMMSSZ_FORMAT -from util.display import SERVICE_NOT_APPLICABLE_RC, entityActionFailedWarning, printBlankLine, printKeyValueList, userServiceNotEnabledWarning +from gam.constants import API_ACCESS_DENIED_RC, GOOGLE_API_ERROR_RC, HTTP_ERROR_RC, NETWORK_ERROR_RC, NO_SCOPES_FOR_API_RC, REFRESH_EXPIRY, SOCKET_ERROR_RC, SYSTEM_ERROR_RC +from util.args import UTF8, YYYYMMDDTHHMMSSZ_FORMAT, formatHTTPError +from util.display import FIRST_ITEM_MARKER, LAST_ITEM_MARKER, SERVICE_NOT_APPLICABLE_RC, TOTAL_ITEMS_MARKER, entityActionFailedWarning, printBlankLine, printKeyValueList, userServiceNotEnabledWarning from util.errors import INVALID_JSON_RC, OAUTH2SERVICE_JSON_REQUIRED_RC, OAUTH2_TXT_REQUIRED_RC, expiredRevokedOauth2TxtExit, invalidDiscoveryJsonExit, invalidOauth2TxtExit, invalidOauth2serviceJsonExit -from util.fileio import FILE_ERROR_RC, UNKNOWN, incrAPICallsRetryData, readFile, writeFile -from util.output import flushStderr, setSysExitRC, stderrErrorMsg, systemErrorExit, writeStderr, writeStdout +from util.fileio import FILE_ERROR_RC, UNKNOWN, checkAPICallsRate, incrAPICallsRetryData, readFile, writeFile +from util.output import ERROR_PREFIX, flushStderr, setSysExitRC, stderrErrorMsg, systemErrorExit, writeStderr, writeStdout HTML_TITLE_PATTERN = re.compile(r'.*