googleapis / google-api-python-client

🐍 The official Python client library for Google's discovery based APIs.
https://googleapis.github.io/google-api-python-client/docs/
Apache License 2.0
7.69k stars 2.4k forks source link

Service Account cannot edit slide with labels #2410

Closed humanendpoint closed 2 months ago

humanendpoint commented 4 months ago

Thanks for stopping by to let us know something could be better!

PLEASE READ: If you have a support contract with Google, please create an issue in the support console instead of filing on GitHub. This will ensure a timely response.

Please run down the following list and make sure you've tried the usual "quick fixes":

If you are still having issues, please be sure to include as much information as possible:

Environment details

Steps to reproduce

  1. Assign SA (Google Service Account) to template slides
  2. Assign SA as editor to template slides
  3. Setup Google Workspace labels: all new files are labeled as Data Classification = Internal. We have a DLP rule that will deny sharing files outside of $company if they are labeled as Internal
  4. Use below python script as a Google Cloud Function (with relevant Google APIs enabled) to try to copy, edit and share the copied slide file, setting the org as editor.

Code example

def add_label_to_file(file_id, credentials, label_id):
    """
    Add a label to the file (fields will be empty initially).
    """
    drive_service = build("drive", "v3", credentials=credentials)
    add_label_request_body = {
        "labelModifications": [
            {
                "labelId": label_id,
                "kind": "drive#labelModification"
            }
        ],
        "kind": "drive#modifyLabelsRequest"
    }

    response = drive_service.files().modifyLabels(
        fileId=file_id,
        body=add_label_request_body
    ).execute()

    print(f"Label added response: {response}")
    return response

def set_label_field(file_id, credentials, label_id, field_id, field_value):
    """
    Set a field value on the label of the file.
    """
    drive_service = build("drive", "v3", credentials=credentials)
    field_modification = {
        "fieldId": field_id,
        "setSelectionValues": [field_value],
        "kind": "drive#labelFieldModification"
    }

    modify_labels_request_body = {
        "labelModifications": [
            {
                "labelId": label_id,
                "fieldModifications": [field_modification],
                "kind": "drive#labelModification"
            }
        ],
        "kind": "drive#modifyLabelsRequest"
    }

    response = drive_service.files().modifyLabels(
        fileId=file_id,
        body=modify_labels_request_body
    ).execute()

    print(f"Label field set response: {response}")
    return response

def modify_labels(file_id, credentials):
    """
    Add and set labels of the copied file.
    """
    label_id = "<LABEL-ID>"
    field_id = "<FIELD-ID>"
    field_value = "<FIELD-VALUE>"

    add_label_to_file(file_id, credentials, label_id)
    set_label_field(file_id, credentials, label_id, field_id, field_value)

def set_sharing_options(presentation_id, credentials):
    """
    set the permissions to everyone at the org can edit
    """
    drive_service = build("drive", "v3", credentials=credentials)
    # the permission set we want
    permission = {
        "type": "domain", 
        "role": "writer", 
        "domain": "company",
    }

    drive_service.permissions().create(
        sendNotificationEmail=False,
        fileId=presentation_id, 
        body=permission, 
        fields="id", 
        supportsAllDrives=True
    ).execute()

def edit_placeholders(presentation_id, date, credentials):
    """
    edit the date in the copied slide 
    """
    slides_service = build("slides", "v1", credentials=credentials)
    # request to replace placeholders with the formatted date
    requests = [
        {
            "replaceAllText": {
                "containsText": {"text": "{{date}}"},
                "replaceText": date,
            }
        }
    ]

    slides_service.presentations().batchUpdate(
        presentationId=presentation_id, body={"requests": requests}
    ).execute()

def copy_presentation(presentation_id, copy_title):
    """
    The key to it all, the function that copies.
    """
    credentials_data = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS")
    credentials = get_service_account_credentials(credentials_data)
    try:
        # initialize the drive service
        drive_service = build("drive", "v3", credentials=credentials)
        body = {"name": copy_title}
        # copy the template slides
        drive_response = (
            drive_service.files().copy(
                fileId=presentation_id, 
                body=body, 
                supportsAllDrives=True, 
                includeLabels="<LABEL-ID>",
            ).execute()
        )
        presentation_copy_id = drive_response.get("id")

        formatted_date = f"{datetime.now().strftime('%b %d, %Y')}"
        # edits
        modify_labels(presentation_copy_id, credentials)
        set_sharing_options(presentation_copy_id, credentials)
        edit_placeholders(presentation_copy_id, formatted_date, credentials)

Stack trace

An error occurred: <HttpError 403 when requesting https://slides.googleapis.com/v1/presentations/<PRESENTATION-ID>:batchUpdate?alt=json returned "The caller does not have permission". Details: "The caller does not have permission">

While the caller (SA) clearly has permission to edit both the template and copied slide.

Seemingly after adding labels to our workspace, the service account is unable to adjust the copied slides. We also had issues to copy and share the slides, except when editing the template to be available to the world. This worked fine before adding labels to the mix. Any ideas why this happens and how to solve?

Thanks

humanendpoint commented 4 months ago

anyone that could take a look?

ohmayr commented 3 months ago

Hi @humanendpoint, thanks for reaching out! This seems to be an issue with the underlying API and not the Python client. Please report this issue directly with the API team by clicking on Send Feedback on the following link: https://developers.google.com/drive/api/reference/rest/v3.

Feel free to reach out to us if you have any questions or concerns related to the Python client.

ohmayr commented 2 months ago

Closing this issue as per previous comment.