fix another lazy import phase 1 introduced which confused PyInstaller

This commit is contained in:
Jay Lee
2026-07-03 15:48:45 -04:00
parent e6ba984c13
commit d992288d67
22 changed files with 1286 additions and 1149 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -52,7 +52,8 @@ from gam.util.entity import (
from gam.util.errors import entityActionFailedExit, unknownArgumentExit
from gam.util.orgunits import getOrgUnitItem
from gam.util.output import setSysExitRC
from gam.constants import ENTITY_IS_NOT_AN_ALIAS_RC, NO_ENTITIES_FOUND_RC
from gam.constants import ALIAS_TARGET_TYPES, ENTITY_IS_NOT_AN_ALIAS_RC, INFO_GROUP_OPTIONS, INFO_USER_OPTIONS, NO_ENTITIES_FOUND_RC
from gam.util.domain_filters import groupFilters
Act = glaction.GamAction()
Ent = glentity.GamEntity()
@@ -62,7 +63,6 @@ Cmd = glclargs.GamCLArgs()
def doCreateUpdateAliases():
from gam.cmd.ciuserinvitations import _getIsInvitableUser
from gam.cmd.orgunits import ALIAS_TARGET_TYPES
def verifyAliasTargetExists():
if targetType != 'group':
try:
@@ -205,7 +205,6 @@ def doCreateUpdateAliases():
# gam delete aliases|nicknames [user|group|target] <EmailAddressEntity>
def doDeleteAliases():
from gam.cmd.orgunits import ALIAS_TARGET_TYPES
cd = buildGAPIObject(API.DIRECTORY)
targetType = getChoice(ALIAS_TARGET_TYPES, defaultChoice='target')
entityList = getEntityList(Cmd.OB_EMAIL_ADDRESS_ENTITY)
@@ -370,8 +369,6 @@ def deleteUsersAliases(users):
def infoAliases(entityList):
from gam.cmd.groups.members import INFO_GROUP_OPTIONS
from gam.cmd.users.manage import INFO_USER_OPTIONS
def _showAliasInfo(uid, email, aliasEmail, entityType, aliasEntityType, i, count):
if email.lower() != aliasEmail:
printEntity([aliasEntityType, aliasEmail], i, count)
@@ -428,44 +425,7 @@ def infoAliases(entityList):
def doInfoAliases():
infoAliases(getEntityList(Cmd.OB_EMAIL_ADDRESS_ENTITY))
def initUserGroupDomainQueryFilters():
if not GC.Values[GC.PRINT_AGU_DOMAINS]:
return {'list': [{'customer': GC.Values[GC.CUSTOMER_ID]}], 'queries': [None]}
return {'list': [{'domain': domain.lower()} for domain in GC.Values[GC.PRINT_AGU_DOMAINS].replace(',', ' ').split()], 'queries': [None]}
def getUserGroupDomainQueryFilters(myarg, kwargsDict):
if myarg in {'domain', 'domains'}:
kwargsDict['list'] = [{'domain': domain.lower()} for domain in getEntityList(Cmd.OB_DOMAIN_NAME_ENTITY)]
elif myarg in {'query', 'queries'}:
kwargsDict['queries'] = getQueries(myarg)
else:
return False
return True
def makeUserGroupDomainQueryFilters(kwargsDict, isSuspended, isArchived, isDisabled):
def addToQuery(query, keyword, value):
pquery = query
if not pquery:
pquery = ''
else:
pquery += ' '
pquery += f'{keyword}={value}'
kwargsQueries.append((kwargs, pquery))
kwargsQueries = []
for kwargs in kwargsDict['list']:
for query in kwargsDict['queries']:
if isDisabled is not None:
addToQuery(query, 'isArchived', isDisabled)
addToQuery(query, 'isSuspended', isDisabled)
elif isSuspended is not None or isArchived is not None:
if isArchived is not None:
addToQuery(query, 'isArchived', isArchived)
if isSuspended is not None:
addToQuery(query, 'isSuspended', isSuspended)
else:
kwargsQueries.append((kwargs, query))
return kwargsQueries
from gam.util.domain_filters import initUserGroupDomainQueryFilters, getUserGroupDomainQueryFilters, makeUserGroupDomainQueryFilters # noqa: F401 - re-exported
def userFilters(kwargs, query, orgUnitPath):
queryTitle = ''
@@ -498,7 +458,6 @@ def userFilters(kwargs, query, orgUnitPath):
# [suppressnoaliasrows]
# (addcsvdata <FieldName> <String>)*
def doPrintAliases():
from gam.cmd.groups.members import groupFilters
def writeAliases(target, targetEmail, targetType):
if not oneRowPerTarget:
for alias in target.get('aliases', []):

View File

@@ -80,12 +80,11 @@ Ent = glentity.GamEntity()
Ind = glindent.GamIndent()
Cmd = glclargs.GamCLArgs()
from gam.constants import DFA_URL
from gam.util.orgunits import _getOrgunitsOrgUnitIdPath # noqa: F401 - re-exported
def _getOrgunitsOrgUnitIdPath(cd, orgUnit):
if orgUnit.startswith('orgunits/'):
orgUnit = f'id:{orgUnit[9:]}'
orgUnitPath, orgUnitId = getOrgUnitId(cd, orgUnit)
return (orgUnitPath, f'orgunits/{orgUnitId[3:]}')
def _getChromePolicySchemaName():
name = getString(Cmd.OB_SCHEMA_NAME)
@@ -1021,7 +1020,7 @@ CHROME_IMAGE_SCHEMAS_MAP = {
# gam create chromepolicyimage <ChromePolicyImageSchemaName> <FileName>
def doCreateChromePolicyImage():
from gam.cmd.drive.core import DFA_URL, getMediaBody
from gam.cmd.drive.core import getMediaBody
cp = buildGAPIObject(API.CHROMEPOLICY)
parent = _getCustomersCustomerIdWithC()
schema = getChoice(CHROME_IMAGE_SCHEMAS_MAP, mapChoice=True)

View File

@@ -103,6 +103,7 @@ from gam.util.errors import (
usageErrorExit,
)
from gam.util.fileio import UNKNOWN
from gam.util.orgunits import _getOrgunitsOrgUnitIdPath
from gam.util.output import systemErrorExit, writeStdout
CIGROUP_DISCUSSION_FORUM_LABEL = 'cloudidentity.googleapis.com/groups.discussion_forum'
@@ -432,7 +433,6 @@ def _checkPoliciesWithDASA():
# json <JSONData>
# [(ou|orgunit <OrgUnitItem>)|(group <GroupItem>)|(query <String>)]
def doCreateUpdateCIPolicy():
from gam.cmd.chromepolicies import _getOrgunitsOrgUnitIdPath
_checkPoliciesWithDASA()
ci = buildGAPIObject(API.CLOUDIDENTITY_POLICY)
cd = buildGAPIObject(API.DIRECTORY)

View File

@@ -93,6 +93,8 @@ from gam.cmd.drive.activity import ( # noqa: F401
showSharedDriveThemes,
)
from gam.cmd.drive.filepaths import ( # noqa: F401
addFilePathsToInfo,
addFilePathsToRow,
DRIVEFILE_BASIC_PERMISSION_FIELDS,
DRIVEFILE_ORDERBY_CHOICE_MAP,
DRIVEFILE_PERMISSIONS_FOR_VIEW_CHOICES,
@@ -168,8 +170,6 @@ from gam.cmd.drive.filetree import ( # noqa: F401
_validateACLOwnerType,
_validatePermissionAttributes,
_validatePermissionOwnerType,
addFilePathsToInfo,
addFilePathsToRow,
buildFileTree,
extendFileTree,
extendFileTreeParents,

View File

@@ -615,7 +615,7 @@ DFA_MODIFIED_TIME = 'modifiedTime'
DFA_PRESERVE_FILE_TIMES = 'preserveFileTimes'
DFA_IGNORE_DEFAULT_VISIBILITY = 'ignoreDefaultVisibility'
DFA_KEEP_REVISION_FOREVER = 'keepRevisionForever'
DFA_URL = 'url'
from gam.constants import DFA_URL # noqa: F401 - re-exported
DFA_LOCALFILEPATH = 'localFilepath'
DFA_LOCALFILENAME = 'localFilename'
DFA_LOCALMIMETYPE = 'localMimeType'

View File

@@ -60,6 +60,8 @@ SHARED_DRIVES = 'SharedDrives'
from gam.cmd.drive.filepaths import (
addFilePathsToInfo,
addFilePathsToRow,
DRIVEFILE_BASIC_PERMISSION_FIELDS, DRIVEFILE_ORDERBY_CHOICE_MAP,
DRIVE_FIELDS_CHOICE_MAP, DRIVE_LIST_FIELDS, DRIVE_SUBFIELDS_CHOICE_MAP,
DRIVE_TIME_OBJECTS, DriveFileFields, FILEPATH_FIELDS_TITLES,
@@ -95,8 +97,6 @@ from gam.cmd.drive.filetree import (
OWNED_BY_ME_FIELDS_TITLES,
SIZE_FIELD_CHOICE_MAP,
_getGettingEntity,
addFilePathsToInfo,
addFilePathsToRow,
extendFileTree,
extendFileTreeParents,
initFileTree,

View File

@@ -8,7 +8,7 @@ import re
import json
from gam.cmd.drive.core import _getSharedDriveNameFromId, _validateUserGetFileIDs, getDriveFileEntity
from gam.cmd.drive.filetree import addFilePathsToInfo, extendFileTree, extendFileTreeParents, initFileTree
from gam.cmd.drive.filetree import extendFileTree, extendFileTreeParents, initFileTree
from gam.cmd.drive.labels import normalizeDriveLabelID
from gam.util.csv_pf import DEFAULT_SKIP_OBJECTS
@@ -62,6 +62,9 @@ from gam.cmd.drive.core import DRIVE_LABEL_CHOICE_MAP # cross-module ref
from gam.util.api import callGAPI, callGAPIitems, callGAPIpages
from gam.util.args import (
OrderBy,
StartEndTime,
checkArgumentPresent,
escapeCRsNLs,
getArgument,
getBoolean,
getCharacter,
@@ -178,6 +181,34 @@ def getFilePaths(drive, fileTree, initialResult, filePathInfo, addParentsToTree=
maxDepth = 0
return (_getEntityMimeType(initialResult), filePaths, maxDepth)
def addFilePathsToRow(drive, fileTree, fileEntryInfo, filePathInfo, csvPF, row,
fullpath=False, showDepth=False, folderPathOnly=False, parentPathOnly=False):
_, paths, maxDepth = getFilePaths(drive, fileTree, fileEntryInfo, filePathInfo,
fullpath=fullpath, showDepth=showDepth, folderPathOnly=folderPathOnly, parentPathOnly=parentPathOnly)
kcount = len(paths)
if showDepth:
row['depth'] = maxDepth
row['paths'] = kcount
k = 0
for path in sorted(paths):
key = f'path{GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER]}{k}'
csvPF.AddTitles(key)
if GC.Values[GC.CSV_OUTPUT_CONVERT_CR_NL] and (path.find('\n') >= 0 or path.find('\r') >= 0):
row[key] = escapeCRsNLs(path)
else:
row[key] = path
k += 1
def addFilePathsToInfo(drive, fileTree, fileEntryInfo, filePathInfo, addParentsToTree=False, folderPathOnly=False, parentPathOnly=False):
_, paths, _ = getFilePaths(drive, fileTree, fileEntryInfo, filePathInfo, addParentsToTree=addParentsToTree,
showDepth=False, folderPathOnly=folderPathOnly, parentPathOnly=parentPathOnly)
fileEntryInfo['paths'] = []
for path in sorted(paths):
if GC.Values[GC.CSV_OUTPUT_CONVERT_CR_NL] and (path.find('\n') >= 0 or path.find('\r') >= 0):
fileEntryInfo['paths'].append(escapeCRsNLs(path))
else:
fileEntryInfo['paths'].append(path)
DRIVEFILE_ORDERBY_CHOICE_MAP = {
'createddate': 'createdTime',
'createdtime': 'createdTime',

View File

@@ -223,35 +223,6 @@ def buildFileTree(feed, drive):
fileTree[parentId]['children'].append(fileId)
return fileTree
def addFilePathsToRow(drive, fileTree, fileEntryInfo, filePathInfo, csvPF, row,
fullpath=False, showDepth=False, folderPathOnly=False, parentPathOnly=False):
from gam.cmd.drive.filepaths import getFilePaths # lazy import to avoid circular dependency
_, paths, maxDepth = getFilePaths(drive, fileTree, fileEntryInfo, filePathInfo,
fullpath=fullpath, showDepth=showDepth, folderPathOnly=folderPathOnly, parentPathOnly=parentPathOnly)
kcount = len(paths)
if showDepth:
row['depth'] = maxDepth
row['paths'] = kcount
k = 0
for path in sorted(paths):
key = f'path{GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER]}{k}'
csvPF.AddTitles(key)
if GC.Values[GC.CSV_OUTPUT_CONVERT_CR_NL] and (path.find('\n') >= 0 or path.find('\r') >= 0):
row[key] = escapeCRsNLs(path)
else:
row[key] = path
k += 1
def addFilePathsToInfo(drive, fileTree, fileEntryInfo, filePathInfo, addParentsToTree=False, folderPathOnly=False, parentPathOnly=False):
from gam.cmd.drive.filepaths import getFilePaths # lazy import to avoid circular dependency
_, paths, _ = getFilePaths(drive, fileTree, fileEntryInfo, filePathInfo, addParentsToTree=addParentsToTree,
showDepth=False, folderPathOnly=folderPathOnly, parentPathOnly=parentPathOnly)
fileEntryInfo['paths'] = []
for path in sorted(paths):
if GC.Values[GC.CSV_OUTPUT_CONVERT_CR_NL] and (path.find('\n') >= 0 or path.find('\r') >= 0):
fileEntryInfo['paths'].append(escapeCRsNLs(path))
else:
fileEntryInfo['paths'].append(path)
def _validateACLOwnerType(location, body):
if body.get('role', '') == 'owner' and body['type'] != 'user':

View File

@@ -75,8 +75,8 @@ from gam.util.entity import (
)
from gam.util.errors import invalidChoiceExit, unknownArgumentExit
from gam.util.output import writeStderr
from gam.cmd.mobile import GROUP_ALIAS_ATTRIBUTES, GROUP_ASSIST_CONTENT_ATTRIBUTES, GROUP_BASIC_ATTRIBUTES, GROUP_DEPRECATED_ATTRIBUTES, GROUP_DISCOVER_ATTRIBUTES, GROUP_MERGED_ATTRIBUTES, GROUP_MODERATE_CONTENT_ATTRIBUTES, GROUP_MODERATE_MEMBERS_ATTRIBUTES, GROUP_SETTINGS_ATTRIBUTES
from gam.cmd.mobile import GROUP_FIELDS_WITH_CRS_NLS
from gam.constants import GROUP_ALIAS_ATTRIBUTES, GROUP_ASSIST_CONTENT_ATTRIBUTES, GROUP_BASIC_ATTRIBUTES, GROUP_DEPRECATED_ATTRIBUTES, GROUP_DISCOVER_ATTRIBUTES, GROUP_MERGED_ATTRIBUTES, GROUP_MODERATE_CONTENT_ATTRIBUTES, GROUP_MODERATE_MEMBERS_ATTRIBUTES, GROUP_SETTINGS_ATTRIBUTES
from gam.constants import GROUP_FIELDS_WITH_CRS_NLS
from gam.cmd.ciuserinvitations import _getIsInvitableUser
Act = glaction.GamAction()

View File

@@ -113,6 +113,18 @@ from gam.util.entity import (
)
from gam.util.errors import entityActionFailedExit, invalidChoiceExit, unknownArgumentExit
from gam.util.fileio import UNKNOWN
from gam.constants import (
GROUP_ASSIST_CONTENT_ATTRIBUTES, GROUP_ATTRIBUTES_SET, GROUP_DEPRECATED_ATTRIBUTES,
GROUP_DISCOVER_ATTRIBUTES, GROUP_FIELDS_WITH_CRS_NLS, GROUP_MERGED_ATTRIBUTES_PRINT_ORDER,
GROUP_MERGED_TO_COMPONENT_MAP, GROUP_MODERATE_CONTENT_ATTRIBUTES,
GROUP_MODERATE_MEMBERS_ATTRIBUTES, GROUP_SETTINGS_ATTRIBUTES,
INFO_USER_OPTIONS, USER_FIELDS_CHOICE_MAP, USER_SKIP_OBJECTS, USER_TIME_OBJECTS,
)
from gam.util.domain_filters import (
getUserGroupDomainQueryFilters, initUserGroupDomainQueryFilters,
makeUserGroupDomainQueryFilters, _setUserGroupArgs,
)
from gam.util.schema_utils import _initSchemaParms, _getSchemaNameList
from gam.util.output import executeBatch, writeStderr, writeStdout
@@ -249,7 +261,7 @@ GROUP_FIELDS_CHOICE_MAP = {
'name': 'name',
}
GROUP_INFO_PRINT_ORDER = ['id', 'name', 'description', 'directMembersCount', 'adminCreated']
INFO_GROUP_OPTIONS = {'nousers', 'groups'}
from gam.constants import INFO_GROUP_OPTIONS # noqa: F401 - re-exported
CIGROUP_FIELDS_CHOICE_MAP = {
'additionalgroupkeys': 'additionalGroupKeys',
@@ -309,8 +321,6 @@ def _showCIGroup(group, groupEmail, i=0, count=0):
Ind.Decrement()
def infoGroups(entityList):
from gam.cmd.mobile import GROUP_ATTRIBUTES_SET, GROUP_DEPRECATED_ATTRIBUTES, GROUP_FIELDS_WITH_CRS_NLS, GROUP_MERGED_ATTRIBUTES_PRINT_ORDER, GROUP_MERGED_TO_COMPONENT_MAP, GROUP_SETTINGS_ATTRIBUTES
from gam.cmd.users.manage import INFO_USER_OPTIONS
def initGroupFieldsLists():
if not groupFieldsLists['cd']:
groupFieldsLists['cd'] = ['email']
@@ -586,18 +596,9 @@ def infoGroups(entityList):
def doInfoGroups():
infoGroups(getEntityList(Cmd.OB_GROUP_ENTITY))
def groupFilters(kwargs, query):
queryTitle = ''
if kwargs.get('domain'):
queryTitle += f'domain={kwargs["domain"]}, '
if query is not None:
queryTitle += f'query="{query}", '
if queryTitle:
return query, queryTitle[:-2]
return query, queryTitle
from gam.util.domain_filters import groupFilters # noqa: F401 - re-exported
def getGroupFilters(myarg, kwargsDict, showOwnedBy):
from gam.cmd.aliases import getUserGroupDomainQueryFilters
if getUserGroupDomainQueryFilters(myarg, kwargsDict):
pass
elif myarg in {'member', 'showownedby'}:
@@ -810,8 +811,6 @@ def addMemberInfoToRow(row, groupMembers, typesSet, memberOptions, memberDisplay
# [formatjson [quotechar <Character>]]
# [showitemcountonly]
def doPrintGroups():
from gam.cmd.aliases import initUserGroupDomainQueryFilters, makeUserGroupDomainQueryFilters
from gam.cmd.mobile import GROUP_ASSIST_CONTENT_ATTRIBUTES, GROUP_ATTRIBUTES_SET, GROUP_DEPRECATED_ATTRIBUTES, GROUP_DISCOVER_ATTRIBUTES, GROUP_FIELDS_WITH_CRS_NLS, GROUP_MERGED_ATTRIBUTES_PRINT_ORDER, GROUP_MERGED_TO_COMPONENT_MAP, GROUP_MODERATE_CONTENT_ATTRIBUTES, GROUP_MODERATE_MEMBERS_ATTRIBUTES, GROUP_SETTINGS_ATTRIBUTES
def _printGroupRow(groupEntity, groupSettings, groupMembers):
nonlocal itemCount
row = {}
@@ -1378,7 +1377,6 @@ def doInfoGroupMembers():
infoGroupMembers(getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS)[1], False)
def getGroupMembersEntityList(cd, entityList, matchPatterns, fieldsList, kwargsDict):
from gam.cmd.aliases import makeUserGroupDomainQueryFilters
if entityList is None:
updateFieldsForGroupMatchPatterns(matchPatterns, fieldsList)
entityList = []
@@ -1565,8 +1563,6 @@ GROUPMEMBERS_SORT_FIELDS = ['type', 'role', 'id', 'status', 'email']
# (addcsvdata <FieldName> <String>)* [includecsvdatainjson [<Boolean>]]
# [formatjson [quotechar <Character>]]
def doPrintGroupMembers():
from gam.cmd.aliases import initUserGroupDomainQueryFilters
from gam.cmd.users.manage import USER_FIELDS_CHOICE_MAP, USER_SKIP_OBJECTS, USER_TIME_OBJECTS, _getSchemaNameList, _initSchemaParms
def getNameFromPeople(memberId):
try:
info = callGAPI(people.people(), 'get',
@@ -1898,7 +1894,6 @@ def doPrintGroupMembers():
# [memberemaildisplaypattern|memberemailskippattern <REMatchPattern>]
# [includederivedmembership]
def doShowGroupMembers():
from gam.cmd.aliases import initUserGroupDomainQueryFilters
def _roleOrder(key):
return {Ent.ROLE_OWNER: 0, Ent.ROLE_MANAGER: 1, Ent.ROLE_MEMBER: 2}.get(key, 3)
@@ -2001,58 +1996,7 @@ def doShowGroupMembers():
if checkGroupMatchPatterns(groupEmail, group, matchPatterns):
_showGroup(groupEmail, 0)
def getGroupParents(cd, groupParents, groupEmail, groupName, kwargs):
from gam.cmd.userop.usergroups import _setUserGroupArgs
groupParents[groupEmail] = {'name': groupName, 'parents': []}
_setUserGroupArgs(groupEmail, kwargs)
try:
entityList = callGAPIpages(cd.groups(), 'list', 'groups',
throwReasons=GAPI.GROUP_LIST_USERKEY_THROW_REASONS,
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
orderBy='email', fields='nextPageToken,groups(email,name)', **kwargs)
for parentGroup in entityList:
groupParents[groupEmail]['parents'].append(parentGroup['email'])
if parentGroup['email'] not in groupParents:
getGroupParents(cd, groupParents, parentGroup['email'], parentGroup['name'], kwargs)
except (GAPI.invalidMember, GAPI.invalidInput):
badRequestWarning(Ent.GROUP, Ent.MEMBER, groupEmail)
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
accessErrorExit(cd)
def showGroupParents(groupParents, groupEmail, role, i, count):
kvList = [groupEmail, f'{groupParents[groupEmail]["name"]}']
if role:
kvList.extend([Ent.Singular(Ent.ROLE), role])
printKeyValueListWithCount(kvList, i, count)
Ind.Increment()
for parentEmail in groupParents[groupEmail]['parents']:
showGroupParents(groupParents, parentEmail, None, 0, 0)
Ind.Decrement()
def addJsonGroupParents(groupParents, userGroup, groupEmail):
userGroup.setdefault('parents', [])
for parentEmail in groupParents[groupEmail]['parents']:
userGroup['parents'].append({'email': parentEmail, 'name': groupParents[parentEmail]['name'], 'parents': []})
addJsonGroupParents(groupParents, userGroup['parents'][-1], parentEmail)
def printGroupParents(groupParents, groupEmail, row, csvPF, delimiter, showParentsAsList):
if groupParents[groupEmail]['parents']:
for parentEmail in groupParents[groupEmail]['parents']:
row['parents'].append({'email': parentEmail, 'name': groupParents[parentEmail]['name']})
printGroupParents(groupParents, parentEmail, row, csvPF, delimiter, showParentsAsList)
del row['parents'][-1]
else:
if not showParentsAsList:
csvPF.WriteRowTitles(flattenJSON(row))
else:
crow = row.copy()
if 'Role' in row:
crow['Role'] = row['Role']
parents = crow.pop('parents')
crow['ParentsCount'] = len(parents)
crow['Parents'] = delimiter.join([parent['email'] for parent in parents])
crow['ParentsName'] = delimiter.join([parent['name'] for parent in parents])
csvPF.WriteRow(flattenJSON(crow))
from gam.util.group_parents import getGroupParents, showGroupParents, addJsonGroupParents, printGroupParents # noqa: F401 - re-exported
# gam print grouptree <GroupEntity> [todrive <ToDriveAttribute>*]
# [showparentsaslist [<Boolean>]] [delimiter <Character>]

View File

@@ -443,151 +443,13 @@ def doPrintMobileDevices():
return
csvPF.writeCSVfile('Mobile')
GROUP_DISCOVER_CHOICES = {
'allmemberscandiscover': 'ALL_MEMBERS_CAN_DISCOVER',
'allindomaincandiscover': 'ALL_IN_DOMAIN_CAN_DISCOVER',
'anyonecandiscover': 'ANYONE_CAN_DISCOVER',
}
GROUP_ASSIST_CONTENT_CHOICES = {
'allmembers': 'ALL_MEMBERS',
'ownersandmanagers': 'OWNERS_AND_MANAGERS',
'managersonly': 'MANAGERS_ONLY',
'ownersonly': 'OWNERS_ONLY',
'none': 'NONE',
}
GROUP_MODERATE_CONTENT_CHOICES = {
'allmembers': 'ALL_MEMBERS',
'ownersandmanagers': 'OWNERS_AND_MANAGERS',
'ownersonly': 'OWNERS_ONLY',
'none': 'NONE',
}
GROUP_MODERATE_MEMBERS_CHOICES = {
'allmembers': 'ALL_MEMBERS',
'ownersandmanagers': 'OWNERS_AND_MANAGERS',
'ownersonly': 'OWNERS_ONLY',
'none': 'NONE',
}
GROUP_DEPRECATED_ATTRIBUTES = {
'allowgooglecommunication': ['allowGoogleCommunication', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'favoriterepliesontop': ['favoriteRepliesOnTop', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'maxmessagebytes': ['maxMessageBytes', {GC.VAR_TYPE: GC.TYPE_INTEGER, GC.VAR_LIMITS: (1024, 1048576)}],
'messagedisplayfont': ['messageDisplayFont', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'defaultfont': 'DEFAULT_FONT', 'fixedwidthfont': 'FIXED_WIDTH_FONT'}}],
'whocanaddreferences': ['whoCanAddReferences', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmarkfavoritereplyonowntopic': ['whoCanMarkFavoriteReplyOnOwnTopic', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
}
GROUP_DISCOVER_ATTRIBUTES = {
'showingroupdirectory': ['showInGroupDirectory', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
}
GROUP_ASSIST_CONTENT_ATTRIBUTES = {
'whocanassigntopics': ['whoCanAssignTopics', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanenterfreeformtags': ['whoCanEnterFreeFormTags', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanhideabuse': ['whoCanHideAbuse', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmaketopicssticky': ['whoCanMakeTopicsSticky', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmarkduplicate': ['whoCanMarkDuplicate', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmarkfavoritereplyonanytopic': ['whoCanMarkFavoriteReplyOnAnyTopic', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmarknoresponseneeded': ['whoCanMarkNoResponseNeeded', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmodifytagsandcategories': ['whoCanModifyTagsAndCategories', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocantaketopics': ['whoCanTakeTopics', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanunassigntopic': ['whoCanUnassignTopic', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanunmarkfavoritereplyonanytopic': ['whoCanUnmarkFavoriteReplyOnAnyTopic', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
}
GROUP_MODERATE_CONTENT_ATTRIBUTES = {
'whocanapprovemessages': ['whoCanApproveMessages', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocandeleteanypost': ['whoCanDeleteAnyPost', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocandeletetopics': ['whoCanDeleteTopics', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocanlocktopics': ['whoCanLockTopics', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocanmovetopicsin': ['whoCanMoveTopicsIn', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocanmovetopicsout': ['whoCanMoveTopicsOut', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocanpostannouncements': ['whoCanPostAnnouncements', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
}
GROUP_MODERATE_MEMBERS_ATTRIBUTES = {
'whocanadd': ['whoCanAdd', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'allmanagerscanadd': 'ALL_MANAGERS_CAN_ADD', 'allownerscanadd': 'ALL_OWNERS_CAN_ADD',
'allmemberscanadd': 'ALL_MEMBERS_CAN_ADD', 'nonecanadd': 'NONE_CAN_ADD'}}],
'whocanapprovemembers': ['whoCanApproveMembers', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'allownerscanapprove': 'ALL_OWNERS_CAN_APPROVE', 'allmanagerscanapprove': 'ALL_MANAGERS_CAN_APPROVE',
'allmemberscanapprove': 'ALL_MEMBERS_CAN_APPROVE', 'nonecanapprove': 'NONE_CAN_APPROVE'}}],
'whocanbanusers': ['whoCanBanUsers', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_MEMBERS_CHOICES}],
'whocaninvite': ['whoCanInvite', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'allmemberscaninvite': 'ALL_MEMBERS_CAN_INVITE', 'allmanagerscaninvite': 'ALL_MANAGERS_CAN_INVITE',
'allownerscaninvite': 'ALL_OWNERS_CAN_INVITE', 'nonecaninvite': 'NONE_CAN_INVITE'}}],
'whocanmodifymembers': ['whoCanModifyMembers', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_MEMBERS_CHOICES}],
}
GROUP_BASIC_ATTRIBUTES = {
'description': ['description', {GC.VAR_TYPE: GC.TYPE_STRING}],
'name': ['name', {GC.VAR_TYPE: GC.TYPE_STRING}],
'displayname': ['name', {GC.VAR_TYPE: GC.TYPE_STRING}],
}
GROUP_SETTINGS_ATTRIBUTES = {
'allowexternalmembers': ['allowExternalMembers', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'allowwebposting': ['allowWebPosting', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'archiveonly': ['archiveOnly', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'customfootertext': ['customFooterText', {GC.VAR_TYPE: GC.TYPE_STRING}],
'customreplyto': ['customReplyTo', {GC.VAR_TYPE: GC.TYPE_EMAIL_OPTIONAL}],
'customrolesenabledforsettingstobemerged': ['customRolesEnabledForSettingsToBeMerged', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'defaultmessagedenynotificationtext': ['defaultMessageDenyNotificationText', {GC.VAR_TYPE: GC.TYPE_STRING}],
'defaultsender': ['defaultSender', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'self': 'DEFAULT_SELF', 'defaultself': 'DEFAULT_SELF', 'group': 'GROUP'}}],
'enablecollaborativeinbox': ['enableCollaborativeInbox', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'includecustomfooter': ['includeCustomFooter', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'includeinglobaladdresslist': ['includeInGlobalAddressList', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'isarchived': ['isArchived', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'memberscanpostasthegroup': ['membersCanPostAsTheGroup', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'messagemoderationlevel': ['messageModerationLevel', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'moderateallmessages': 'MODERATE_ALL_MESSAGES', 'moderatenonmembers': 'MODERATE_NON_MEMBERS',
'moderatenewmembers': 'MODERATE_NEW_MEMBERS', 'moderatenone': 'MODERATE_NONE'}}],
'primarylanguage': ['primaryLanguage', {GC.VAR_TYPE: GC.TYPE_LANGUAGE}],
'replyto': ['replyTo', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'replytocustom': 'REPLY_TO_CUSTOM', 'replytosender': 'REPLY_TO_SENDER', 'replytolist': 'REPLY_TO_LIST',
'replytoowner': 'REPLY_TO_OWNER', 'replytoignore': 'REPLY_TO_IGNORE', 'replytomanagers': 'REPLY_TO_MANAGERS'}}],
'sendmessagedenynotification': ['sendMessageDenyNotification', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'spammoderationlevel': ['spamModerationLevel', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'allow': 'ALLOW', 'moderate': 'MODERATE', 'silentlymoderate': 'SILENTLY_MODERATE', 'reject': 'REJECT'}}],
'whocanaddexternalmembers': ['whoCanAddExternalMembers', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'onlyadminscanaddexternalmembers': 'ONLY_ADMINS_CAN_ADD_EXTERNAL_MEMBERS',
'enduserscanaddexternalmembers': 'END_USERS_CAN_ADD_EXTERNAL_MEMBERS'}}],
'whocancontactowner': ['whoCanContactOwner', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'anyonecancontact': 'ANYONE_CAN_CONTACT', 'allindomaincancontact': 'ALL_IN_DOMAIN_CAN_CONTACT',
'allmemberscancontact': 'ALL_MEMBERS_CAN_CONTACT', 'allmanagerscancontact': 'ALL_MANAGERS_CAN_CONTACT',
'allownerscancontact': 'ALL_OWNERS_CAN_CONTACT'}}],
'whocanjoin': ['whoCanJoin', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'anyonecanjoin': 'ANYONE_CAN_JOIN', 'allindomaincanjoin': 'ALL_IN_DOMAIN_CAN_JOIN',
'invitedcanjoin': 'INVITED_CAN_JOIN', 'canrequesttojoin': 'CAN_REQUEST_TO_JOIN'}}],
'whocanleavegroup': ['whoCanLeaveGroup', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'allmanagerscanleave': 'ALL_MANAGERS_CAN_LEAVE', 'allownerscanleave': 'ALL_OWNERS_CAN_LEAVE',
'allmemberscanleave': 'ALL_MEMBERS_CAN_LEAVE', 'nonecanleave': 'NONE_CAN_LEAVE'}}],
'whocanpostmessage': ['whoCanPostMessage', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'nonecanpost': 'NONE_CAN_POST', 'allmanagerscanpost': 'ALL_MANAGERS_CAN_POST',
'allmemberscanpost': 'ALL_MEMBERS_CAN_POST', 'allownerscanpost': 'ALL_OWNERS_CAN_POST',
'allindomaincanpost': 'ALL_IN_DOMAIN_CAN_POST', 'anyonecanpost': 'ANYONE_CAN_POST'}}],
'whocanviewgroup': ['whoCanViewGroup', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'anyonecanview': 'ANYONE_CAN_VIEW', 'allindomaincanview': 'ALL_IN_DOMAIN_CAN_VIEW',
'allmemberscanview': 'ALL_MEMBERS_CAN_VIEW', 'allmanagerscanview': 'ALL_MANAGERS_CAN_VIEW',
'allownerscanview': 'ALL_OWNERS_CAN_VIEW'}}],
'whocanviewmembership': ['whoCanViewMembership', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'allindomaincanview': 'ALL_IN_DOMAIN_CAN_VIEW', 'allmemberscanview': 'ALL_MEMBERS_CAN_VIEW',
'allmanagerscanview': 'ALL_MANAGERS_CAN_VIEW', 'allownerscanview': 'ALL_OWNERS_CAN_VIEW'}}],
}
GROUP_ALIAS_ATTRIBUTES = {
'collaborative': ['enableCollaborativeInbox', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'gal': ['includeInGlobalAddressList', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
}
GROUP_MERGED_ATTRIBUTES = {
'whocandiscovergroup': ['whoCanDiscoverGroup', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_DISCOVER_CHOICES}],
'whocanassistcontent': ['whoCanAssistContent', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmoderatecontent': ['whoCanModerateContent', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocanmoderatemembers': ['whoCanModerateMembers', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_MEMBERS_CHOICES}],
}
GROUP_MERGED_ATTRIBUTES_PRINT_ORDER = ['whoCanDiscoverGroup', 'whoCanAssistContent', 'whoCanModerateContent', 'whoCanModerateMembers']
GROUP_MERGED_TO_COMPONENT_MAP = {
'whoCanDiscoverGroup': GROUP_DISCOVER_ATTRIBUTES,
'whoCanAssistContent': GROUP_ASSIST_CONTENT_ATTRIBUTES,
'whoCanModerateContent': GROUP_MODERATE_CONTENT_ATTRIBUTES,
'whoCanModerateMembers': GROUP_MODERATE_MEMBERS_ATTRIBUTES,
}
GROUP_ATTRIBUTES_SET = set(list(GROUP_BASIC_ATTRIBUTES)+list(GROUP_SETTINGS_ATTRIBUTES)+list(GROUP_ALIAS_ATTRIBUTES)+
list(GROUP_ASSIST_CONTENT_ATTRIBUTES)+list(GROUP_MODERATE_CONTENT_ATTRIBUTES)+list(GROUP_MODERATE_MEMBERS_ATTRIBUTES)+
list(GROUP_MERGED_ATTRIBUTES)+list(GROUP_DEPRECATED_ATTRIBUTES))
GROUP_FIELDS_WITH_CRS_NLS = {'customFooterText', 'defaultMessageDenyNotificationText', 'description'}
from gam.constants import ( # noqa: F401 - re-exported for backward compatibility
GROUP_DISCOVER_CHOICES, GROUP_ASSIST_CONTENT_CHOICES, GROUP_MODERATE_CONTENT_CHOICES,
GROUP_MODERATE_MEMBERS_CHOICES, GROUP_DEPRECATED_ATTRIBUTES, GROUP_DISCOVER_ATTRIBUTES,
GROUP_ASSIST_CONTENT_ATTRIBUTES, GROUP_MODERATE_CONTENT_ATTRIBUTES,
GROUP_MODERATE_MEMBERS_ATTRIBUTES, GROUP_BASIC_ATTRIBUTES, GROUP_SETTINGS_ATTRIBUTES,
GROUP_ALIAS_ATTRIBUTES, GROUP_MERGED_ATTRIBUTES, GROUP_MERGED_ATTRIBUTES_PRINT_ORDER,
GROUP_MERGED_TO_COMPONENT_MAP, GROUP_ATTRIBUTES_SET, GROUP_FIELDS_WITH_CRS_NLS,
)

View File

@@ -1151,7 +1151,7 @@ def doCheckOrgUnit():
if not empty and GM.Globals[GM.SYSEXITRC] == 0:
setSysExitRC(ORGUNIT_NOT_EMPTY_RC)
ALIAS_TARGET_TYPES = ['user', 'group', 'target']
from gam.constants import ALIAS_TARGET_TYPES # noqa: F401 - re-exported
# gam create aliases|nicknames <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress>
# [verifynotinvitable]

View File

@@ -64,6 +64,8 @@ from gam.util.output import setSysExitRC
from gam.constants import CHECK_USER_GROUPS_ERROR_RC
from gam.cmd.drive.looker import _getLookerStudioAssets, _showLookerStudioPermissions, _validateUserGetLookerStudioAssetIds, getLookerStudioAssetSelectionParameters, initLookerStudioAssetSelectionParameters
from gam.util.group_parents import addJsonGroupParents, getGroupParents, printGroupParents, showGroupParents
Act = glaction.GamAction()
Ent = glentity.GamEntity()
Ind = glindent.GamIndent()
@@ -332,15 +334,7 @@ def _getUserGroupOptionalDomainCustomerId():
return {'customer': getString(Cmd.OB_CUSTOMER_ID)}
return {}
def _setUserGroupArgs(user, kwargs):
if 'customer' in kwargs:
if "'" not in user:
kwargs['query'] = f'memberKey={user}'
else:
quser = user.replace("'", "\\'")
kwargs['query'] = f'memberKey={quser}'
else:
kwargs['userKey'] = user
from gam.util.domain_filters import _setUserGroupArgs # noqa: F401 - re-exported
def checkUserGroupMatchPattern(groupEmail, matchPattern):
if not matchPattern['not']:
@@ -876,7 +870,6 @@ def printShowUserGroups(users):
# [roles <GroupRoleList>]
# [formatjson]
def printShowGroupTree(users):
from gam.cmd.groups.members import addJsonGroupParents, getGroupParents, printGroupParents, showGroupParents
cd = buildGAPIObject(API.DIRECTORY)
kwargs = {'customer': GC.Values[GC.CUSTOMER_ID]}
csvPF = CSVPrintFile(['User', 'Group', 'Name']) if Act.csvFormat() else None
@@ -1033,6 +1026,6 @@ def printUserGroupsList(users):
csvPF.writeCSVfile('User GroupsList')
# License command utilities
LICENSE_PRODUCT_SKUIDS = 'productSkuIds'
from gam.constants import LICENSE_PRODUCT_SKUIDS # noqa: F401 - re-exported
LICENSE_PREVIEW_TITLES = ['user', 'productId', 'skuId', 'action', 'message']

View File

@@ -7,7 +7,8 @@ Part of the _users_tmp sub-package."""
import re
import json
from gam.cmd.users.manage import _filterSchemaFields, _filterUserMultiAttributes, _formatLanguagesList, _getSchemaNameList, _getUserMultiAttributeFilters, _initSchemaParms, getUserLicenses
from gam.cmd.users.manage import _filterSchemaFields, _filterUserMultiAttributes, _formatLanguagesList, _getUserMultiAttributeFilters, getUserLicenses
from gam.util.schema_utils import _getSchemaNameList, _initSchemaParms
from gam.util.csv_pf import RI_JCOUNT, RI_ITEM
@@ -129,9 +130,10 @@ from gam.util.errors import entityActionFailedExit
from gam.util.fileio import UNKNOWN
from gam.util.orgunits import getOrgUnitItem
from gam.util.output import ERROR, executeBatch, writeStdout
from gam.cmd.groups.members import addJsonGroupParents, getGroupParents, showGroupParents
from gam.util.group_parents import addJsonGroupParents, getGroupParents, showGroupParents
from gam.cmd.resources import _getBuildingNameById
from gam.cmd.aliases import getUserGroupDomainQueryFilters, initUserGroupDomainQueryFilters, makeUserGroupDomainQueryFilters, userFilters
from gam.util.domain_filters import getUserGroupDomainQueryFilters, initUserGroupDomainQueryFilters, makeUserGroupDomainQueryFilters
from gam.cmd.aliases import userFilters
from gam.cmd.licenses import doPrintLicenses
def infoUsers(entityList):

View File

@@ -89,6 +89,7 @@ from gam.util.gdoc import openCSVFileReader
from gam.util.orgunits import getOrgUnitItem
from gam.util.output import readStdin, setSysExitRC, systemErrorExit, writeStderr
from gam.constants import MULTIPLE_DELETED_USERS_FOUND_RC, NO_ENTITIES_FOUND_RC, PASSWORD_SAFE_CHARS, USER_SUSPENDED_RC
from gam.constants import LICENSE_PRODUCT_SKUIDS
from gam.util.tags import (
_getTagReplacement,
_initTagReplacements,
@@ -422,7 +423,6 @@ def getNotifyArguments(myarg, notify, userNotification):
def getUserAttributes(cd, updateCmd, noUid=False):
from gam.cmd.resources import _getBuildingByNameOrId
from gam.cmd.userop.usergroups import LICENSE_PRODUCT_SKUIDS
def getKeywordAttribute(keywords, attrdict, **opts):
if Cmd.ArgumentsRemaining():
keyword = Cmd.Current().strip().lower()
@@ -961,7 +961,6 @@ def createUserAddAliases(cd, user, aliasList, i, count):
# [addnumericsuffixonduplicate <Number>]
def doCreateUser():
from gam.cmd.ciuserinvitations import _getIsInvitableUser
from gam.cmd.userop.usergroups import LICENSE_PRODUCT_SKUIDS
cd = buildGAPIObject(API.DIRECTORY)
body, notify, tagReplacements, addGroups, addAliases, PwdOpts, \
_, _, _, \
@@ -1659,89 +1658,7 @@ USER_SSH_PROPERTY_PRINT_ORDER = [
'fingerprint',
]
USER_FIELDS_CHOICE_MAP = {
'address': 'addresses',
'addresses': 'addresses',
'admin': ['isAdmin', 'isDelegatedAdmin'],
'agreed2terms': 'agreedToTerms',
'agreedtoterms': 'agreedToTerms',
'aliases': ['aliases', 'nonEditableAliases'],
'archived': ['archived', 'archivalTime'],
'changepassword': 'changePasswordAtNextLogin',
'changepasswordatnextlogin': 'changePasswordAtNextLogin',
'creationtime': 'creationTime',
'customerid': 'customerId',
'deletiontime': 'deletionTime',
'displayname': 'name.displayName',
'email': 'emails',
'emails': 'emails',
'employeeid': 'externalIds',
'externalid': 'externalIds',
'externalids': 'externalIds',
'familyname': 'name.familyName',
'firstname': 'name.givenName',
'fullname': 'name.fullName',
'gal': 'includeInGlobalAddressList',
'gender': ['gender.type', 'gender.customGender', 'gender.addressMeAs'],
'givenname': 'name.givenName',
'guestaccountinfo': ['guestAccountInfo.primaryGuestEmail'],
'id': 'id',
'im': 'ims',
'ims': 'ims',
'includeinglobaladdresslist': 'includeInGlobalAddressList',
'ipwhitelisted': 'ipWhitelisted',
'isadmin': ['isAdmin', 'isDelegatedAdmin'],
'isdelegatedadmin': ['isAdmin', 'isDelegatedAdmin'],
'isenforcedin2sv': 'isEnforcedIn2Sv',
'isenrolledin2sv': 'isEnrolledIn2Sv',
'isguestuser': 'isGuestUser',
'is2svenforced': 'isEnforcedIn2Sv',
'is2svenrolled': 'isEnrolledIn2Sv',
'ismailboxsetup': 'isMailboxSetup',
'keyword': 'keywords',
'keywords': 'keywords',
'language': 'languages',
'languages': 'languages',
'lastlogintime': 'lastLoginTime',
'lastname': 'name.familyName',
'location': 'locations',
'locations': 'locations',
'manager': 'relations',
'name': ['name.givenName', 'name.familyName', 'name.fullName', 'name.displayName'],
'nicknames': ['aliases', 'nonEditableAliases'],
'noneditablealiases': ['aliases', 'nonEditableAliases'],
'note': 'notes',
'notes': 'notes',
'org': 'orgUnitPath',
'organization': 'organizations',
'organizations': 'organizations',
'organisation': 'organizations',
'organisations': 'organizations',
'orgunit': 'orgUnitPath',
'orgunitpath': 'orgUnitPath',
'otheremail': 'emails',
'otheremails': 'emails',
'ou': 'orgUnitPath',
'phone': 'phones',
'phones': 'phones',
'photo': 'thumbnailPhotoUrl',
'photourl': 'thumbnailPhotoUrl',
'posix': 'posixAccounts',
'posixaccounts': 'posixAccounts',
'primaryemail': 'primaryEmail',
'recoveryemail': 'recoveryEmail',
'recoveryphone': 'recoveryPhone',
'relation': 'relations',
'relations': 'relations',
'ssh': 'sshPublicKeys',
'sshkeys': 'sshPublicKeys',
'sshpublickeys': 'sshPublicKeys',
'suspended': ['suspended', 'suspensionReason', 'suspensionTime'],
'thumbnailphotourl': 'thumbnailPhotoUrl',
'username': 'primaryEmail',
'website': 'websites',
'websites': 'websites',
}
from gam.constants import USER_FIELDS_CHOICE_MAP # noqa: F401 - re-exported
USER_MULTI_ATTR_FILTER_CHOICE_MAP = {
'address': 'addresses',
@@ -1770,9 +1687,7 @@ USER_MULTI_ATTR_FILTER_CHOICE_MAP = {
'websites': 'websites',
}
INFO_USER_OPTIONS = {'noaliases', 'nobuildingnames', 'nogroups', 'nolicenses', 'nolicences', 'noschemas', 'schemas', 'userview'}
USER_SKIP_OBJECTS = {'thumbnailPhotoEtag'}
USER_TIME_OBJECTS = {'creationTime', 'deletionTime', 'lastLoginTime', 'suspensionTime', 'archivalTime', 'disabledTime'}
from gam.constants import INFO_USER_OPTIONS, USER_SKIP_OBJECTS, USER_TIME_OBJECTS # noqa: F401 - re-exported
def _getUserMultiAttributeFilters(myarg, userMultiAttributeFilters):
up = getChoice(USER_MULTI_ATTR_FILTER_CHOICE_MAP, mapChoice=True)
@@ -1810,27 +1725,7 @@ def _formatLanguagesList(propertyValue, delimiter):
languages.append(lang)
return delimiter.join(languages)
def _initSchemaParms(projection):
return {'projection': projection, 'customFieldMask': None, 'selectedSchemaFields': {}}
def _getSchemaNameList(schemaParms):
customFieldMask = getString(Cmd.OB_SCHEMA_NAME_LIST).replace(' ', ',')
if customFieldMask.lower() == 'all':
schemaParms['projection'] = 'full'
schemaParms['customFieldMask'] = None
schemaParms['selectedSchemaFields'] = {}
else:
schemaParms['projection'] = 'custom'
customFieldMaskList = []
for schemaField in customFieldMask.split(','):
if schemaField.find('.') == -1:
customFieldMaskList.append(schemaField)
else:
schemaName, fieldName = schemaField.split('.', 1)
customFieldMaskList.append(schemaName)
schemaParms['selectedSchemaFields'] .setdefault(schemaName, set())
schemaParms['selectedSchemaFields'][schemaName].add(fieldName)
schemaParms['customFieldMask'] = ','.join(customFieldMaskList)
from gam.util.schema_utils import _initSchemaParms, _getSchemaNameList # noqa: F401 - re-exported
def _filterSchemaFields(userEntity, schemaParms):
schemas = userEntity.pop('customSchemas', None)

View File

@@ -7,6 +7,8 @@ shared across cmd/ modules.
import re
import string
from gamlib import glcfg as GC
# Time formats
IS08601_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S%:z'
RFC2822_TIME_FORMAT = '%a, %d %b %Y %H:%M:%S %z'
@@ -160,3 +162,254 @@ BUILDING_ADDRESS_FIELD_MAP = {
'sublocality': 'sublocality',
'zipcode': 'postalCode',
}
# Alias target types (moved from cmd/orgunits.py)
ALIAS_TARGET_TYPES = ['user', 'group', 'target']
# Info/display option sets (moved from cmd/groups/members.py, cmd/users/manage.py)
INFO_GROUP_OPTIONS = {'nousers', 'groups'}
INFO_USER_OPTIONS = {'noaliases', 'nobuildingnames', 'nogroups', 'nolicenses', 'nolicences', 'noschemas', 'schemas', 'userview'}
USER_SKIP_OBJECTS = {'thumbnailPhotoEtag'}
USER_TIME_OBJECTS = {'creationTime', 'deletionTime', 'lastLoginTime', 'suspensionTime', 'archivalTime', 'disabledTime'}
# License constants (moved from cmd/userop/usergroups.py)
LICENSE_PRODUCT_SKUIDS = 'productSkuIds'
# Drive file attribute keys (moved from cmd/drive/core.py)
DFA_URL = 'url'
# User fields choice map (moved from cmd/users/manage.py)
USER_FIELDS_CHOICE_MAP = {
'address': 'addresses',
'addresses': 'addresses',
'admin': ['isAdmin', 'isDelegatedAdmin'],
'agreed2terms': 'agreedToTerms',
'agreedtoterms': 'agreedToTerms',
'aliases': ['aliases', 'nonEditableAliases'],
'archived': ['archived', 'archivalTime'],
'changepassword': 'changePasswordAtNextLogin',
'changepasswordatnextlogin': 'changePasswordAtNextLogin',
'creationtime': 'creationTime',
'customerid': 'customerId',
'deletiontime': 'deletionTime',
'displayname': 'name.displayName',
'email': 'emails',
'emails': 'emails',
'employeeid': 'externalIds',
'externalid': 'externalIds',
'externalids': 'externalIds',
'familyname': 'name.familyName',
'firstname': 'name.givenName',
'fullname': 'name.fullName',
'gal': 'includeInGlobalAddressList',
'gender': ['gender.type', 'gender.customGender', 'gender.addressMeAs'],
'givenname': 'name.givenName',
'guestaccountinfo': ['guestAccountInfo.primaryGuestEmail'],
'id': 'id',
'im': 'ims',
'ims': 'ims',
'includeinglobaladdresslist': 'includeInGlobalAddressList',
'ipwhitelisted': 'ipWhitelisted',
'isadmin': ['isAdmin', 'isDelegatedAdmin'],
'isdelegatedadmin': ['isAdmin', 'isDelegatedAdmin'],
'isenforcedin2sv': 'isEnforcedIn2Sv',
'isenrolledin2sv': 'isEnrolledIn2Sv',
'isguestuser': 'isGuestUser',
'is2svenforced': 'isEnforcedIn2Sv',
'is2svenrolled': 'isEnrolledIn2Sv',
'ismailboxsetup': 'isMailboxSetup',
'keyword': 'keywords',
'keywords': 'keywords',
'language': 'languages',
'languages': 'languages',
'lastlogintime': 'lastLoginTime',
'lastname': 'name.familyName',
'location': 'locations',
'locations': 'locations',
'manager': 'relations',
'name': ['name.givenName', 'name.familyName', 'name.fullName', 'name.displayName'],
'nicknames': ['aliases', 'nonEditableAliases'],
'noneditablealiases': ['aliases', 'nonEditableAliases'],
'note': 'notes',
'notes': 'notes',
'org': 'orgUnitPath',
'organization': 'organizations',
'organizations': 'organizations',
'organisation': 'organizations',
'organisations': 'organizations',
'orgunit': 'orgUnitPath',
'orgunitpath': 'orgUnitPath',
'otheremail': 'emails',
'otheremails': 'emails',
'ou': 'orgUnitPath',
'phone': 'phones',
'phones': 'phones',
'photo': 'thumbnailPhotoUrl',
'photourl': 'thumbnailPhotoUrl',
'posix': 'posixAccounts',
'posixaccounts': 'posixAccounts',
'primaryemail': 'primaryEmail',
'recoveryemail': 'recoveryEmail',
'recoveryphone': 'recoveryPhone',
'relation': 'relations',
'relations': 'relations',
'ssh': 'sshPublicKeys',
'sshkeys': 'sshPublicKeys',
'sshpublickeys': 'sshPublicKeys',
'suspended': ['suspended', 'suspensionReason', 'suspensionTime'],
'thumbnailphotourl': 'thumbnailPhotoUrl',
'username': 'primaryEmail',
'website': 'websites',
'websites': 'websites',
}
# Group settings choice maps (moved from cmd/mobile.py)
GROUP_DISCOVER_CHOICES = {
'allmemberscandiscover': 'ALL_MEMBERS_CAN_DISCOVER',
'allindomaincandiscover': 'ALL_IN_DOMAIN_CAN_DISCOVER',
'anyonecandiscover': 'ANYONE_CAN_DISCOVER',
}
GROUP_ASSIST_CONTENT_CHOICES = {
'allmembers': 'ALL_MEMBERS',
'ownersandmanagers': 'OWNERS_AND_MANAGERS',
'managersonly': 'MANAGERS_ONLY',
'ownersonly': 'OWNERS_ONLY',
'none': 'NONE',
}
GROUP_MODERATE_CONTENT_CHOICES = {
'allmembers': 'ALL_MEMBERS',
'ownersandmanagers': 'OWNERS_AND_MANAGERS',
'ownersonly': 'OWNERS_ONLY',
'none': 'NONE',
}
GROUP_MODERATE_MEMBERS_CHOICES = {
'allmembers': 'ALL_MEMBERS',
'ownersandmanagers': 'OWNERS_AND_MANAGERS',
'ownersonly': 'OWNERS_ONLY',
'none': 'NONE',
}
# Group settings attribute maps (moved from cmd/mobile.py)
GROUP_DEPRECATED_ATTRIBUTES = {
'allowgooglecommunication': ['allowGoogleCommunication', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'favoriterepliesontop': ['favoriteRepliesOnTop', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'maxmessagebytes': ['maxMessageBytes', {GC.VAR_TYPE: GC.TYPE_INTEGER, GC.VAR_LIMITS: (1024, 1048576)}],
'messagedisplayfont': ['messageDisplayFont', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'defaultfont': 'DEFAULT_FONT', 'fixedwidthfont': 'FIXED_WIDTH_FONT'}}],
'whocanaddreferences': ['whoCanAddReferences', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmarkfavoritereplyonowntopic': ['whoCanMarkFavoriteReplyOnOwnTopic', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
}
GROUP_DISCOVER_ATTRIBUTES = {
'showingroupdirectory': ['showInGroupDirectory', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
}
GROUP_ASSIST_CONTENT_ATTRIBUTES = {
'whocanassigntopics': ['whoCanAssignTopics', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanenterfreeformtags': ['whoCanEnterFreeFormTags', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanhideabuse': ['whoCanHideAbuse', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmaketopicssticky': ['whoCanMakeTopicsSticky', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmarkduplicate': ['whoCanMarkDuplicate', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmarkfavoritereplyonanytopic': ['whoCanMarkFavoriteReplyOnAnyTopic', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmarknoresponseneeded': ['whoCanMarkNoResponseNeeded', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmodifytagsandcategories': ['whoCanModifyTagsAndCategories', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocantaketopics': ['whoCanTakeTopics', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanunassigntopic': ['whoCanUnassignTopic', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanunmarkfavoritereplyonanytopic': ['whoCanUnmarkFavoriteReplyOnAnyTopic', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
}
GROUP_MODERATE_CONTENT_ATTRIBUTES = {
'whocanapprovemessages': ['whoCanApproveMessages', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocandeleteanypost': ['whoCanDeleteAnyPost', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocandeletetopics': ['whoCanDeleteTopics', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocanlocktopics': ['whoCanLockTopics', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocanmovetopicsin': ['whoCanMoveTopicsIn', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocanmovetopicsout': ['whoCanMoveTopicsOut', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocanpostannouncements': ['whoCanPostAnnouncements', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
}
GROUP_MODERATE_MEMBERS_ATTRIBUTES = {
'whocanadd': ['whoCanAdd', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'allmanagerscanadd': 'ALL_MANAGERS_CAN_ADD', 'allownerscanadd': 'ALL_OWNERS_CAN_ADD',
'allmemberscanadd': 'ALL_MEMBERS_CAN_ADD', 'nonecanadd': 'NONE_CAN_ADD'}}],
'whocanapprovemembers': ['whoCanApproveMembers', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'allownerscanapprove': 'ALL_OWNERS_CAN_APPROVE', 'allmanagerscanapprove': 'ALL_MANAGERS_CAN_APPROVE',
'allmemberscanapprove': 'ALL_MEMBERS_CAN_APPROVE', 'nonecanapprove': 'NONE_CAN_APPROVE'}}],
'whocanbanusers': ['whoCanBanUsers', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_MEMBERS_CHOICES}],
'whocaninvite': ['whoCanInvite', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'allmemberscaninvite': 'ALL_MEMBERS_CAN_INVITE', 'allmanagerscaninvite': 'ALL_MANAGERS_CAN_INVITE',
'allownerscaninvite': 'ALL_OWNERS_CAN_INVITE', 'nonecaninvite': 'NONE_CAN_INVITE'}}],
'whocanmodifymembers': ['whoCanModifyMembers', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_MEMBERS_CHOICES}],
}
GROUP_BASIC_ATTRIBUTES = {
'description': ['description', {GC.VAR_TYPE: GC.TYPE_STRING}],
'name': ['name', {GC.VAR_TYPE: GC.TYPE_STRING}],
'displayname': ['name', {GC.VAR_TYPE: GC.TYPE_STRING}],
}
GROUP_SETTINGS_ATTRIBUTES = {
'allowexternalmembers': ['allowExternalMembers', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'allowwebposting': ['allowWebPosting', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'archiveonly': ['archiveOnly', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'customfootertext': ['customFooterText', {GC.VAR_TYPE: GC.TYPE_STRING}],
'customreplyto': ['customReplyTo', {GC.VAR_TYPE: GC.TYPE_EMAIL_OPTIONAL}],
'customrolesenabledforsettingstobemerged': ['customRolesEnabledForSettingsToBeMerged', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'defaultmessagedenynotificationtext': ['defaultMessageDenyNotificationText', {GC.VAR_TYPE: GC.TYPE_STRING}],
'defaultsender': ['defaultSender', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'self': 'DEFAULT_SELF', 'defaultself': 'DEFAULT_SELF', 'group': 'GROUP'}}],
'enablecollaborativeinbox': ['enableCollaborativeInbox', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'includecustomfooter': ['includeCustomFooter', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'includeinglobaladdresslist': ['includeInGlobalAddressList', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'isarchived': ['isArchived', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'memberscanpostasthegroup': ['membersCanPostAsTheGroup', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'messagemoderationlevel': ['messageModerationLevel', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'moderateallmessages': 'MODERATE_ALL_MESSAGES', 'moderatenonmembers': 'MODERATE_NON_MEMBERS',
'moderatenewmembers': 'MODERATE_NEW_MEMBERS', 'moderatenone': 'MODERATE_NONE'}}],
'primarylanguage': ['primaryLanguage', {GC.VAR_TYPE: GC.TYPE_LANGUAGE}],
'replyto': ['replyTo', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'replytocustom': 'REPLY_TO_CUSTOM', 'replytosender': 'REPLY_TO_SENDER', 'replytolist': 'REPLY_TO_LIST',
'replytoowner': 'REPLY_TO_OWNER', 'replytoignore': 'REPLY_TO_IGNORE', 'replytomanagers': 'REPLY_TO_MANAGERS'}}],
'sendmessagedenynotification': ['sendMessageDenyNotification', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'spammoderationlevel': ['spamModerationLevel', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'allow': 'ALLOW', 'moderate': 'MODERATE', 'silentlymoderate': 'SILENTLY_MODERATE', 'reject': 'REJECT'}}],
'whocanaddexternalmembers': ['whoCanAddExternalMembers', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'onlyadminscanaddexternalmembers': 'ONLY_ADMINS_CAN_ADD_EXTERNAL_MEMBERS',
'enduserscanaddexternalmembers': 'END_USERS_CAN_ADD_EXTERNAL_MEMBERS'}}],
'whocancontactowner': ['whoCanContactOwner', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'anyonecancontact': 'ANYONE_CAN_CONTACT', 'allindomaincancontact': 'ALL_IN_DOMAIN_CAN_CONTACT',
'allmemberscancontact': 'ALL_MEMBERS_CAN_CONTACT', 'allmanagerscancontact': 'ALL_MANAGERS_CAN_CONTACT',
'allownerscancontact': 'ALL_OWNERS_CAN_CONTACT'}}],
'whocanjoin': ['whoCanJoin', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'anyonecanjoin': 'ANYONE_CAN_JOIN', 'allindomaincanjoin': 'ALL_IN_DOMAIN_CAN_JOIN',
'invitedcanjoin': 'INVITED_CAN_JOIN', 'canrequesttojoin': 'CAN_REQUEST_TO_JOIN'}}],
'whocanleavegroup': ['whoCanLeaveGroup', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'allmanagerscanleave': 'ALL_MANAGERS_CAN_LEAVE', 'allownerscanleave': 'ALL_OWNERS_CAN_LEAVE',
'allmemberscanleave': 'ALL_MEMBERS_CAN_LEAVE', 'nonecanleave': 'NONE_CAN_LEAVE'}}],
'whocanpostmessage': ['whoCanPostMessage', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'nonecanpost': 'NONE_CAN_POST', 'allmanagerscanpost': 'ALL_MANAGERS_CAN_POST',
'allmemberscanpost': 'ALL_MEMBERS_CAN_POST', 'allownerscanpost': 'ALL_OWNERS_CAN_POST',
'allindomaincanpost': 'ALL_IN_DOMAIN_CAN_POST', 'anyonecanpost': 'ANYONE_CAN_POST'}}],
'whocanviewgroup': ['whoCanViewGroup', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'anyonecanview': 'ANYONE_CAN_VIEW', 'allindomaincanview': 'ALL_IN_DOMAIN_CAN_VIEW',
'allmemberscanview': 'ALL_MEMBERS_CAN_VIEW', 'allmanagerscanview': 'ALL_MANAGERS_CAN_VIEW',
'allownerscanview': 'ALL_OWNERS_CAN_VIEW'}}],
'whocanviewmembership': ['whoCanViewMembership', {GC.VAR_TYPE: GC.TYPE_CHOICE,
'choices': {'allindomaincanview': 'ALL_IN_DOMAIN_CAN_VIEW', 'allmemberscanview': 'ALL_MEMBERS_CAN_VIEW',
'allmanagerscanview': 'ALL_MANAGERS_CAN_VIEW', 'allownerscanview': 'ALL_OWNERS_CAN_VIEW'}}],
}
GROUP_ALIAS_ATTRIBUTES = {
'collaborative': ['enableCollaborativeInbox', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
'gal': ['includeInGlobalAddressList', {GC.VAR_TYPE: GC.TYPE_BOOLEAN}],
}
GROUP_MERGED_ATTRIBUTES = {
'whocandiscovergroup': ['whoCanDiscoverGroup', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_DISCOVER_CHOICES}],
'whocanassistcontent': ['whoCanAssistContent', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_ASSIST_CONTENT_CHOICES}],
'whocanmoderatecontent': ['whoCanModerateContent', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_CONTENT_CHOICES}],
'whocanmoderatemembers': ['whoCanModerateMembers', {GC.VAR_TYPE: GC.TYPE_CHOICE, 'choices': GROUP_MODERATE_MEMBERS_CHOICES}],
}
GROUP_MERGED_ATTRIBUTES_PRINT_ORDER = ['whoCanDiscoverGroup', 'whoCanAssistContent', 'whoCanModerateContent', 'whoCanModerateMembers']
GROUP_MERGED_TO_COMPONENT_MAP = {
'whoCanDiscoverGroup': GROUP_DISCOVER_ATTRIBUTES,
'whoCanAssistContent': GROUP_ASSIST_CONTENT_ATTRIBUTES,
'whoCanModerateContent': GROUP_MODERATE_CONTENT_ATTRIBUTES,
'whoCanModerateMembers': GROUP_MODERATE_MEMBERS_ATTRIBUTES,
}
GROUP_ATTRIBUTES_SET = set(list(GROUP_BASIC_ATTRIBUTES)+list(GROUP_SETTINGS_ATTRIBUTES)+list(GROUP_ALIAS_ATTRIBUTES)+
list(GROUP_ASSIST_CONTENT_ATTRIBUTES)+list(GROUP_MODERATE_CONTENT_ATTRIBUTES)+list(GROUP_MODERATE_MEMBERS_ATTRIBUTES)+
list(GROUP_MERGED_ATTRIBUTES)+list(GROUP_DEPRECATED_ATTRIBUTES))
GROUP_FIELDS_WITH_CRS_NLS = {'customFooterText', 'defaultMessageDenyNotificationText', 'description'}

View File

@@ -0,0 +1,71 @@
"""Domain/query filter utilities shared between aliases, groups, and users.
Moved here to break circular dependencies between cmd/ modules.
"""
from gamlib import glcfg as GC
from gamlib import glclargs
from gam.util.entity import getEntityList, getQueries
Cmd = glclargs.GamCLArgs()
def initUserGroupDomainQueryFilters():
if not GC.Values[GC.PRINT_AGU_DOMAINS]:
return {'list': [{'customer': GC.Values[GC.CUSTOMER_ID]}], 'queries': [None]}
return {'list': [{'domain': domain.lower()} for domain in GC.Values[GC.PRINT_AGU_DOMAINS].replace(',', ' ').split()], 'queries': [None]}
def getUserGroupDomainQueryFilters(myarg, kwargsDict):
if myarg in {'domain', 'domains'}:
kwargsDict['list'] = [{'domain': domain.lower()} for domain in getEntityList(Cmd.OB_DOMAIN_NAME_ENTITY)]
elif myarg in {'query', 'queries'}:
kwargsDict['queries'] = getQueries(myarg)
else:
return False
return True
def makeUserGroupDomainQueryFilters(kwargsDict, isSuspended, isArchived, isDisabled):
def addToQuery(query, keyword, value):
pquery = query
if not pquery:
pquery = ''
else:
pquery += ' '
pquery += f'{keyword}={value}'
kwargsQueries.append((kwargs, pquery))
kwargsQueries = []
for kwargs in kwargsDict['list']:
for query in kwargsDict['queries']:
if isDisabled is not None:
addToQuery(query, 'isArchived', isDisabled)
addToQuery(query, 'isSuspended', isDisabled)
elif isSuspended is not None or isArchived is not None:
if isArchived is not None:
addToQuery(query, 'isArchived', isArchived)
if isSuspended is not None:
addToQuery(query, 'isSuspended', isSuspended)
else:
kwargsQueries.append((kwargs, query))
return kwargsQueries
def groupFilters(kwargs, query):
queryTitle = ''
if kwargs.get('domain'):
queryTitle += f'domain={kwargs["domain"]}, '
if query is not None:
queryTitle += f'query="{query}", '
if queryTitle:
return query, queryTitle[:-2]
return query, queryTitle
def _setUserGroupArgs(user, kwargs):
if 'customer' in kwargs:
if "'" not in user:
kwargs['query'] = f'memberKey={user}'
else:
quser = user.replace("'", "\\\\'")
kwargs['query'] = f'memberKey={quser}'
else:
kwargs['userKey'] = user

View File

@@ -0,0 +1,70 @@
"""Group parent hierarchy utilities shared between groups/members and userop/usergroups.
Moved here to break circular dependencies between cmd/ modules.
"""
from gamlib import glentity
from gamlib import glgapi as GAPI
from gamlib import glindent
from gam.util.access import accessErrorExit
from gam.util.api import callGAPIpages
from gam.util.csv_pf import flattenJSON
from gam.util.display import badRequestWarning, printKeyValueListWithCount
from gam.util.domain_filters import _setUserGroupArgs
Ent = glentity.GamEntity()
Ind = glindent.GamIndent()
def getGroupParents(cd, groupParents, groupEmail, groupName, kwargs):
groupParents[groupEmail] = {'name': groupName, 'parents': []}
_setUserGroupArgs(groupEmail, kwargs)
try:
entityList = callGAPIpages(cd.groups(), 'list', 'groups',
throwReasons=GAPI.GROUP_LIST_USERKEY_THROW_REASONS,
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
orderBy='email', fields='nextPageToken,groups(email,name)', **kwargs)
for parentGroup in entityList:
groupParents[groupEmail]['parents'].append(parentGroup['email'])
if parentGroup['email'] not in groupParents:
getGroupParents(cd, groupParents, parentGroup['email'], parentGroup['name'], kwargs)
except (GAPI.invalidMember, GAPI.invalidInput):
badRequestWarning(Ent.GROUP, Ent.MEMBER, groupEmail)
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
accessErrorExit(cd)
def showGroupParents(groupParents, groupEmail, role, i, count):
kvList = [groupEmail, f'{groupParents[groupEmail]["name"]}']
if role:
kvList.extend([Ent.Singular(Ent.ROLE), role])
printKeyValueListWithCount(kvList, i, count)
Ind.Increment()
for parentEmail in groupParents[groupEmail]['parents']:
showGroupParents(groupParents, parentEmail, None, 0, 0)
Ind.Decrement()
def addJsonGroupParents(groupParents, userGroup, groupEmail):
userGroup.setdefault('parents', [])
for parentEmail in groupParents[groupEmail]['parents']:
userGroup['parents'].append({'email': parentEmail, 'name': groupParents[parentEmail]['name'], 'parents': []})
addJsonGroupParents(groupParents, userGroup['parents'][-1], parentEmail)
def printGroupParents(groupParents, groupEmail, row, csvPF, delimiter, showParentsAsList):
if groupParents[groupEmail]['parents']:
for parentEmail in groupParents[groupEmail]['parents']:
row['parents'].append({'email': parentEmail, 'name': groupParents[parentEmail]['name']})
printGroupParents(groupParents, parentEmail, row, csvPF, delimiter, showParentsAsList)
del row['parents'][-1]
else:
if not showParentsAsList:
csvPF.WriteRowTitles(flattenJSON(row))
else:
crow = row.copy()
if 'Role' in row:
crow['Role'] = row['Role']
parents = crow.pop('parents')
crow['ParentsCount'] = len(parents)
crow['Parents'] = delimiter.join([parent['email'] for parent in parents])
crow['ParentsName'] = delimiter.join([parent['name'] for parent in parents])
csvPF.WriteRow(flattenJSON(crow))

View File

@@ -130,3 +130,9 @@ def getAllParentOrgUnitsForUser(cd, user):
except (GAPI.badRequest, GAPI.invalidCustomerId, GAPI.loginRequired):
_getMain().accessErrorExit(cd)
return orgUnits
def _getOrgunitsOrgUnitIdPath(cd, orgUnit):
if orgUnit.startswith('orgunits/'):
orgUnit = f'id:{orgUnit[9:]}'
orgUnitPath, orgUnitId = getOrgUnitId(cd, orgUnit)
return (orgUnitPath, f'orgunits/{orgUnitId[3:]}')

View File

@@ -0,0 +1,32 @@
"""Schema parameter utilities shared between user management and groups.
Moved here to break circular dependencies between cmd/ modules.
"""
from gamlib import glclargs
from gam.util.args import getString
Cmd = glclargs.GamCLArgs()
def _initSchemaParms(projection):
return {'projection': projection, 'customFieldMask': None, 'selectedSchemaFields': {}}
def _getSchemaNameList(schemaParms):
customFieldMask = getString(Cmd.OB_SCHEMA_NAME_LIST).replace(' ', ',')
if customFieldMask.lower() == 'all':
schemaParms['projection'] = 'full'
schemaParms['customFieldMask'] = None
schemaParms['selectedSchemaFields'] = {}
else:
schemaParms['projection'] = 'custom'
customFieldMaskList = []
for schemaField in customFieldMask.split(','):
if schemaField.find('.') == -1:
customFieldMaskList.append(schemaField)
else:
schemaName, fieldName = schemaField.split('.', 1)
customFieldMaskList.append(schemaName)
schemaParms['selectedSchemaFields'] .setdefault(schemaName, set())
schemaParms['selectedSchemaFields'][schemaName].add(fieldName)
schemaParms['customFieldMask'] = ','.join(customFieldMaskList)