Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions Packs/GoogleDrive/Integrations/GoogleDrive/GoogleDrive.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@
"FILE_MODIFY_LABEL": "drive/v3/files/{}/modifyLabels",
"FILE_GET_LABELS": "drive/v3/files/{}/listLabels",
"FILE_GET_PARENTS": "drive/v2/files/{}/parents",
"FILE_MOVE": "drive/v3/files/{}",
"FILE_CREATE": "drive/v3/files",
}

OUTPUT_PREFIX: dict[str, str] = {
Expand Down Expand Up @@ -1937,6 +1939,102 @@ def fetch_incidents(
return incidents, {"last_fetch": last_fetch}


@logger
def file_move_command(client: "GSuiteClient", args: dict[str, str]) -> CommandResults:
"""
google-drive-file-move
Move a file to a different folder by modifying its parent folder references.

:param client: Client object.
:param args: Command arguments.

:return: Command Result.
"""
file_id = args.get("file_id", "")
add_parent_id = args.get("add_parent_id", "")
remove_parent_id = args.get("remove_parent_id", "")

# user_id can be overridden in the args
user_id = args.get("user_id") or client.user_id
client.set_authorized_http(scopes=COMMAND_SCOPES["FILES"], subject=user_id)

url_suffix = URL_SUFFIX["FILE_MOVE"].format(file_id)
params = {
"addParents": add_parent_id,
"removeParents": remove_parent_id,
"fields": args.get("fields", "*"),
"supportsAllDrives": True,
}
response = client.http_request(url_suffix=url_suffix, method="PATCH", params=params)

readable_output = tableToMarkdown(
f'File "{file_id}" moved successfully.',
response,
headers=["id", "name", "mimeType", "parents"],
headerTransform=pascalToSpace,
)

return CommandResults(
outputs_prefix="GoogleDrive.File",
outputs_key_field="id",
outputs=response,
readable_output=readable_output,
raw_response=response,
)


@logger
def file_create_command(client: "GSuiteClient", args: dict[str, str]) -> CommandResults:
"""
google-drive-file-create
Create a metadata-only file or folder (no content upload).

:param client: Client object.
:param args: Command arguments.

:return: Command Result.
"""
name = args.get("name", "")
mime_type = args.get("mime_type", "application/vnd.google-apps.folder")
parent_id = args.get("parent_id", "")
description = args.get("description", "")

# user_id can be overridden in the args
user_id = args.get("user_id") or client.user_id
client.set_authorized_http(scopes=COMMAND_SCOPES["FILES"], subject=user_id)

url_suffix = URL_SUFFIX["FILE_CREATE"]
params = {
"fields": args.get("fields", "*"),
"supportsAllDrives": True,
}
body: dict[str, Any] = {
"name": name,
"mimeType": mime_type,
}
if parent_id:
body["parents"] = [parent_id]
if description:
body["description"] = description

response = client.http_request(url_suffix=url_suffix, method="POST", params=params, body=body)

readable_output = tableToMarkdown(
f'Created "{name}" successfully.',
response,
headers=["id", "name", "mimeType", "parents"],
headerTransform=pascalToSpace,
)

return CommandResults(
outputs_prefix="GoogleDrive.File",
outputs_key_field="id",
outputs=response,
readable_output=readable_output,
raw_response=response,
)


def main() -> None: # pragma: no cover
"""
PARSE AND VALIDATE INTEGRATION PARAMS
Expand Down Expand Up @@ -1966,6 +2064,8 @@ def main() -> None: # pragma: no cover
"google-drive-get-labels": get_labels_command,
"google-drive-get-file-labels": get_file_labels_command,
"google-drive-file-get-parents": file_get_parents,
"google-drive-file-move": file_move_command,
"google-drive-file-create": file_create_command,
}
command = demisto.command()

Expand Down
65 changes: 65 additions & 0 deletions Packs/GoogleDrive/Integrations/GoogleDrive/GoogleDrive.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3113,6 +3113,71 @@ script:
- contextPath: GoogleDrive.File.Parents
description: The IDs of the parent folders which contain the file.
type: String
- name: google-drive-file-move
description: Moves a file from one folder to another by modifying its parent folder references. Used for quarantine workflows.
arguments:
- name: file_id
required: true
description: The ID of the file to move.
- name: add_parent_id
required: true
description: The ID of the destination folder to move the file into.
- name: remove_parent_id
required: true
description: The ID of the current parent folder to remove the file from.
- name: user_id
required: false
description: The user's email address. The command will be executed on behalf of this user (requires domain-wide delegation). If not provided, the default user configured in the integration instance will be used.
- name: fields
required: false
description: 'A comma-separated list of fields to include in the response. Default is "*" which returns all fields. Example: "id, name, mimeType, parents".'
defaultValue: "*"
outputs:
- contextPath: GoogleDrive.File.id
description: The file ID.
type: String
- contextPath: GoogleDrive.File.name
description: The name of the file.
type: String
- contextPath: GoogleDrive.File.mimeType
description: The MIME type of the file.
type: String
- contextPath: GoogleDrive.File.parents
description: The list of parent folder IDs.
type: Unknown
- name: google-drive-file-create
description: Creates a new metadata-only file or folder without uploading content. Use for creating quarantine folders or tombstone placeholder files.
arguments:
- name: name
required: true
description: The name of the file or folder to create.
- name: mime_type
description: 'The MIME type of the file. Use "application/vnd.google-apps.folder" to create a folder. Default is "application/vnd.google-apps.folder".'
defaultValue: application/vnd.google-apps.folder
- name: user_id
required: false
description: The user's email address. The command will be executed on behalf of this user (requires domain-wide delegation). If not provided, the default user configured in the integration instance will be used.
- name: parent_id
description: The ID of the parent folder. If not specified, the file will be created in the user's root folder.
- name: description
description: A short description of the file or folder.
- name: fields
required: false
description: 'A comma-separated list of fields to include in the response. Default is "*" which returns all fields. Example: "id, name, mimeType, parents".'
defaultValue: "*"
outputs:
- contextPath: GoogleDrive.File.id
description: The ID of the created file or folder.
type: String
- contextPath: GoogleDrive.File.name
description: The name of the created file or folder.
type: String
- contextPath: GoogleDrive.File.mimeType
description: The MIME type of the created file or folder.
type: String
- contextPath: GoogleDrive.File.parents
description: The list of parent folder IDs.
type: Unknown
dockerimage: demisto/googleapi-python3:1.0.0.115338
isfetch: true
runonce: false
Expand Down
106 changes: 106 additions & 0 deletions Packs/GoogleDrive/Integrations/GoogleDrive/GoogleDrive_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1073,3 +1073,109 @@ def test_drive_get_file_parents_success(self, mocker_http_request, gsuite_client

assert len(result.outputs.get("GoogleDrive.File.Parents", [])) == 1 # type: ignore
assert result.raw_response == mock_response

@patch(MOCKER_HTTP_METHOD)
def test_file_move_command_success(self, mocker_http_request, gsuite_client):
"""
Scenario: For google-drive-file-move command successful run.

Given:
- Command args.

When:
- Calling google-drive-file-move command with the parameters provided.

Then:
- Ensure command's outputs and readable_output should be as expected.
"""
from GoogleDrive import file_move_command

with open("test_data/file_move_response.json", encoding="utf-8") as data:
mock_response = json.load(data)
mocker_http_request.return_value = mock_response

args = {
"file_id": "1234567890abcdef",
"add_parent_id": "quarantine_folder_id_123",
"remove_parent_id": "original_folder_id_789",
"user_id": "admin@example.com",
}
result: CommandResults = file_move_command(gsuite_client, args)

assert result.outputs_prefix == "GoogleDrive.File"
assert result.outputs_key_field == "id"
assert result.outputs["id"] == "1234567890abcdef"
assert result.outputs["parents"] == ["quarantine_folder_id_123"]
assert "moved successfully" in result.readable_output

@patch(MOCKER_HTTP_METHOD)
def test_file_create_command_success(self, mocker_http_request, gsuite_client):
"""
Scenario: For google-drive-file-create command successful run for folder creation.

Given:
- Command args.

When:
- Calling google-drive-file-create command with the parameters provided.

Then:
- Ensure command's outputs and readable_output should be as expected.
"""
from GoogleDrive import file_create_command

with open("test_data/file_create_response.json", encoding="utf-8") as data:
mock_response = json.load(data)
mocker_http_request.return_value = mock_response

args = {
"name": "Quarantine Folder",
"mime_type": "application/vnd.google-apps.folder",
"user_id": "admin@example.com",
"parent_id": "root",
}
result: CommandResults = file_create_command(gsuite_client, args)

assert result.outputs_prefix == "GoogleDrive.File"
assert result.outputs_key_field == "id"
assert result.outputs["id"] == "new_folder_id_456"
assert result.outputs["mimeType"] == "application/vnd.google-apps.folder"
assert "Created" in result.readable_output

@patch(MOCKER_HTTP_METHOD)
def test_file_create_tombstone_command_success(self, mocker_http_request, gsuite_client):
"""
Scenario: For google-drive-file-create command successful run for tombstone placeholder creation.

Given:
- Command args for creating a tombstone placeholder file.

When:
- Calling google-drive-file-create command with the parameters provided.

Then:
- Ensure command's outputs should be as expected.
"""
from GoogleDrive import file_create_command

mock_response = {
"kind": "drive#file",
"id": "tombstone_id_789",
"name": "This file has been quarantined",
"mimeType": "application/vnd.google-apps.document",
"parents": ["original_folder_id"],
"description": "This file was quarantined by security policy. Contact admin for details.",
}
mocker_http_request.return_value = mock_response

args = {
"name": "This file has been quarantined",
"mime_type": "application/vnd.google-apps.document",
"user_id": "admin@example.com",
"parent_id": "original_folder_id",
"description": "This file was quarantined by security policy. Contact admin for details.",
}
result: CommandResults = file_create_command(gsuite_client, args)

assert result.outputs["id"] == "tombstone_id_789"
assert result.outputs["mimeType"] == "application/vnd.google-apps.document"
63 changes: 63 additions & 0 deletions Packs/GoogleDrive/Integrations/GoogleDrive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1380,3 +1380,66 @@ Get parents of a Google Drive file.
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| GoogleDrive.File.Parents | String | The IDs of the parent folders which contain the file. |

### google-drive-file-move

***
Moves a file from one folder to another by modifying its parent folder references. Used for quarantine workflows.

#### Base Command

`google-drive-file-move`

#### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| file_id | The ID of the file to move. | Required |
| add_parent_id | The ID of the destination folder to move the file into. | Required |
| remove_parent_id | The ID of the current parent folder to remove the file from. | Required |
| user_id | The user's email address. The command will be executed on behalf of this user (requires domain-wide delegation). | Required |

#### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| GoogleDrive.File.id | String | The file ID. |
| GoogleDrive.File.name | String | The name of the file. |
| GoogleDrive.File.mimeType | String | The MIME type of the file. |
| GoogleDrive.File.parents | Unknown | The list of parent folder IDs. |

#### Command example

```!google-drive-file-move file_id="1234567890abcdef" add_parent_id="quarantine_folder_id" remove_parent_id="original_folder_id" user_id="admin@example.com"```

### google-drive-file-create

***
Creates a new metadata-only file or folder without uploading content. Use for creating quarantine folders or tombstone placeholder files.

#### Base Command

`google-drive-file-create`

#### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| name | The name of the file or folder to create. | Required |
| mime_type | The MIME type of the file. Use "application/vnd.google-apps.folder" to create a folder. Default is "application/vnd.google-apps.folder". | Optional |
| user_id | The user's email address. The command will be executed on behalf of this user (requires domain-wide delegation). | Required |
| parent_id | The ID of the parent folder. If not specified, the file will be created in the user's root folder. | Optional |
| description | A short description of the file or folder. | Optional |

#### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| GoogleDrive.File.id | String | The ID of the created file or folder. |
| GoogleDrive.File.name | String | The name of the created file or folder. |
| GoogleDrive.File.mimeType | String | The MIME type of the created file or folder. |
| GoogleDrive.File.parents | Unknown | The list of parent folder IDs. |

#### Command example

```!google-drive-file-create name="Quarantine Folder" mime_type="application/vnd.google-apps.folder" user_id="admin@example.com" parent_id="root"```
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
!google-drive-file-copy file_id="1O8Gx7DslVpbd-HN7lp4MIN1DDakpw-bHVHCwir2wUlo" copy_title="New Copy"
!google-drive-file-copy file_id="1O8Gx7DslVpbd-HN7lp4MIN1DDakpw-bHVHCwir2wUlo" copy_title="New Copy"
!google-drive-file-move file_id="1234567890abcdef" add_parent_id="quarantine_folder_id" remove_parent_id="original_folder_id" user_id="admin@example.com"
!google-drive-file-create name="Quarantine Folder" mime_type="application/vnd.google-apps.folder" user_id="admin@example.com" parent_id="root"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"kind": "drive#file",
"id": "new_folder_id_456",
"name": "Quarantine Folder",
"mimeType": "application/vnd.google-apps.folder",
"parents": ["root"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"kind": "drive#file",
"id": "1234567890abcdef",
"name": "quarantined_document.docx",
"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"parents": ["quarantine_folder_id_123"]
}
Loading
Loading