2

I am trying to create a call that gets all the group Gmail emails so that I can update those that aren't there and delete those that shouldn't be. I am currently trying the below code and I'm getting a scope error.

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/admin.directory.group.members', 'https://www.googleapis.com/auth/admin.directory.group']

def main():
    """Shows basic usage of the Admin SDK Directory API.
    Prints the emails and names of the first 10 users in the domain.
    """
    creds = None
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
# time.
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
           creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
            'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
    # Save the credentials for the next run
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    service = build('admin', 'directory_v1', credentials=creds)

 # Call the Admin SDK Directory API
    print('Getting the members of Hospitality Team')
    response_group = service.groups().list(customer='my_customer').execute()
    for group in response_group['groups']:
       print(group['email'])
Andrew P
  • 21
  • 2
  • Where did you get this code from? You are trying to authenticate via `build` and then trying to do your request via `requests`. You should use your built `service` in order to call the API. Please start by taking a look at the [python quickstart](https://developers.google.com/admin-sdk/directory/v1/quickstart/python), and then modify the request part to call [members.list](https://developers.google.com/admin-sdk/directory/reference/rest/v1/members/list) instead. – Iamblichus May 21 '21 at 08:32
  • I'd like to provide an answer explaining this in more detail but first I'd like to clarify what exact `updates` you want to do (it's not clear how you get information on `those that aren't there` and `those that shouldn't be`). – Iamblichus May 21 '21 at 08:32
  • @lamblichus Thank you! I pulled this code from another stack overflow thread. I basically have another API that's hitting another site then brining back a list of emails. I'm taking that list of emails that are in that other API result --> matching that list to my google member group --> Deleting any emails that aren't in the original API result --> add any that aren't there. Basically the list of emails from the other website is what should be the source of truth, driving the members of the group. I update my code above after your response and I'm now getting insufficient permissions on scp. – Andrew P May 23 '21 at 20:19
  • Just to note, that I have ensured I have all the appropriate scopes within my token auth file as well as the appropriate scopes added within GCP directly. – Andrew P May 23 '21 at 21:00

1 Answers1

0

Solution:

You could do the following:

  • List all your groups via Groups: list.
  • For each group, check whether it has members.
  • If the group has members, retrieve its members via Members: list.
  • For each desired member coming from the other API, check if it already exists in the group. If it doesn't exist, add it to your group via Members: insert.
  • For each current member in the group, check if it's one of the desired members. If it's not, delete it via Members: delete.
  • If the group does not have members, add all desired members to the group via Members: insert.

Code snippet:

def updateGroupMembers(service):
    ideal_member_emails = ["member_1@example.com", "member_2@example.com", "member_3@example.com"]
    response_group = service.groups().list(customer='my_customer').execute()
    for group in response_group['groups']:
        group_email = group['email']
        response_members = service.members().list(groupKey=group_email).execute()
        if "members" in response_members:
            current_member_emails = list(map((lambda member : member["email"]), response_members["members"]))
            for ideal_member_email in ideal_member_emails:
                if ideal_member_email not in current_member_emails:
                    payload = {
                        "email": ideal_member_email
                    }
                    service.members().insert(groupKey=group_email, body=payload).execute()
            for current_member_email in current_member_emails:
                if current_member_email not in ideal_member_emails:
                    service.members().delete(groupKey=group_email, memberKey=current_member_email).execute()
        else:
            for ideal_member_email in ideal_member_emails:
                payload = {
                    "email": ideal_member_email
                }
                service.members().insert(groupKey=group_email, body=payload).execute()

Notes:

  • The scopes you are providing should be enough for these calls. If you edited those scopes after last authenticating, remove the old token.json and authenticate again.
  • Make sure the authenticated user has edit access to these groups.
  • Here I'm assuming the desired list of members is the same for all groups. I'm also assuming you have a list of these emails (currently ideal_member_emails). If that's not the case, please edit the provided script according to your preferences.
  • If your list of groups and members is large enough, you should iteratively fetch the different page results for your list requests. See this related answer (regarding Users: list, but the process is identical) for more information on how to do this.

Reference:

Iamblichus
  • 18,540
  • 2
  • 11
  • 27
  • I don't have a 15+ rep or I'd upvote this solution. This was just what I was looking for!!! I really appreciate the API documentation -- I was able to find a few things I was missing along the way, like the entity ID, etc. I really appreciate the time that this took! – Andrew P May 24 '21 at 18:41