generated from cds-snc/project-template
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor/google workspace service (#388)
* feat: add google meet integration * fix: remove typo * fix: delete file due to conflict with separate dev branch * fix: fmt * feat: setup standalone google_service function * feat: add debug config file * fix: use json format for service account credentials * tmp: setup test command using new service * fix: devcontainer customization errors * test: updated devcontainer * fix: lint & fmt
- Loading branch information
Showing
12 changed files
with
301 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"version": "0.2.0", | ||
"configurations": [ | ||
{ | ||
"name": "Python: Module", | ||
"type": "python", | ||
"request": "launch", | ||
"module": "uvicorn", | ||
"args": [ | ||
"main:server_app", | ||
"--reload" | ||
], | ||
"env": { | ||
"LOGLEVEL": "DEBUG", | ||
"PREFIX": "dev-" | ||
}, | ||
"console": "integratedTerminal", | ||
"cwd": "${workspaceFolder}/app" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,3 @@ | ||
{ | ||
"python.linting.pylintEnabled": false, | ||
"python.linting.flake8Enabled": true, | ||
"python.linting.enabled": true | ||
"python.pylintPath": "/usr/local/py-utils/bin/pylint", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
"""Testing new google service (will be removed)""" | ||
import os | ||
|
||
from integrations.google_workspace.google_service import get_google_service | ||
from dotenv import load_dotenv | ||
|
||
load_dotenv() | ||
|
||
SRE_DRIVE_ID = os.environ.get("SRE_DRIVE_ID") | ||
SRE_INCIDENT_FOLDER = os.environ.get("SRE_INCIDENT_FOLDER") | ||
|
||
|
||
def open_modal(client, body): | ||
folders = list_folders() | ||
folder_names = [i["name"] for i in folders] | ||
blocks = [ | ||
{"type": "section", "text": {"type": "mrkdwn", "text": f"*{name}*"}} | ||
for name in folder_names | ||
] | ||
view = { | ||
"type": "modal", | ||
"title": {"type": "plain_text", "text": "Folder List"}, | ||
"blocks": blocks, | ||
} | ||
client.views_open(trigger_id=body["trigger_id"], view=view) | ||
|
||
|
||
def google_service_command(client, body): | ||
open_modal(client, body) | ||
|
||
|
||
def list_folders(): | ||
service = get_google_service("drive", "v3") | ||
results = ( | ||
service.files() | ||
.list( | ||
pageSize=25, | ||
supportsAllDrives=True, | ||
includeItemsFromAllDrives=True, | ||
corpora="drive", | ||
q="parents in '{}' and mimeType = 'application/vnd.google-apps.folder' and trashed=false and not name contains '{}'".format( | ||
SRE_INCIDENT_FOLDER, "Templates" | ||
), | ||
driveId=SRE_DRIVE_ID, | ||
fields="nextPageToken, files(id, name)", | ||
) | ||
.execute() | ||
) | ||
return results.get("files", []) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
"""Google Meet integration.""" | ||
import re | ||
from datetime import datetime | ||
|
||
|
||
def create_google_meet(title=None): | ||
""" | ||
Starts a Google Meet session. | ||
Args: | ||
title (str, optional): The title of the session. | ||
Returns: | ||
str: The URL of the Google Meet session. | ||
""" | ||
# if title is None, set it to the current date | ||
if title is None: | ||
title = f"Meeting-Rencontre-{datetime.now().strftime('%Y-%m-%d')}" | ||
|
||
# replace spaces with dashes | ||
title = title.replace(" ", "-") | ||
# remove any special characters | ||
title = re.sub("[^0-9a-zA-Z]+", "-", title) | ||
title = title.strip("-") | ||
|
||
meeting_link = f"https://g.co/meet/{title}" | ||
if len(meeting_link) > 78: | ||
meeting_link = meeting_link[:78] | ||
|
||
return meeting_link |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
"""Google Service Module.""" | ||
import os | ||
import logging | ||
import json | ||
|
||
from json import JSONDecodeError | ||
from dotenv import load_dotenv | ||
from google.oauth2 import service_account | ||
from googleapiclient.discovery import build | ||
|
||
load_dotenv() | ||
|
||
|
||
def get_google_service(service, version): | ||
""" | ||
Get an authenticated Google service. | ||
Args: | ||
service (str): The Google service to get. | ||
version (str): The version of the service to get. | ||
Returns: | ||
The authenticated Google service resource. | ||
""" | ||
|
||
creds_json = os.environ.get("GCP_SRE_SERVICE_ACCOUNT_KEY_FILE", False) | ||
|
||
if creds_json is False: | ||
raise ValueError("Credentials JSON not set") | ||
|
||
try: | ||
creds_info = json.loads(creds_json) | ||
creds = service_account.Credentials.from_service_account_info(creds_info) | ||
except JSONDecodeError as json_decode_exception: | ||
logging.error("Error while loading credentials JSON: %s", json_decode_exception) | ||
raise JSONDecodeError( | ||
msg="Invalid credentials JSON", doc="Credentials JSON", pos=0 | ||
) from json_decode_exception | ||
return build(service, version, credentials=creds, cache_discovery=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
73 changes: 73 additions & 0 deletions
73
app/tests/integrations/google_workspace/test_google_meet.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
"""Test google_meet.py functions.""" | ||
from unittest.mock import patch | ||
from integrations.google_workspace import google_meet | ||
|
||
|
||
def test_create_google_meet_with_valid_title(): | ||
"""Test create_google_meet with a title.""" | ||
title = "TestTitle" | ||
expected = "https://g.co/meet/TestTitle" | ||
assert google_meet.create_google_meet(title) == expected | ||
|
||
|
||
@patch("integrations.google_workspace.google_meet.datetime") | ||
def test_create_google_meet_without_title(date_time_mock): | ||
"""Test create_google_meet without a title.""" | ||
date_time_mock.now.return_value.strftime.return_value = "2021-06-01" | ||
expected = "https://g.co/meet/Meeting-Rencontre-2021-06-01" | ||
assert google_meet.create_google_meet() == expected | ||
|
||
|
||
def test_create_google_meet_with_title_too_long(): | ||
"""Test create_google_meet with a title that is too long.""" | ||
title = ( | ||
"Testing-title-that-is-much-too-long-for-google-meet-and" | ||
"-it-should-be-truncated" | ||
) | ||
expected = ( | ||
"https://g.co/meet/Testing-title-that-is-much-too-long-for-google-meet-and-it-s" | ||
) | ||
assert google_meet.create_google_meet(title) == expected | ||
|
||
|
||
def test_create_google_meet_with_title_with_spaces(): | ||
"""Test create_google_meet with a title that has spaces.""" | ||
title = "Testing title with spaces" | ||
expected = "https://g.co/meet/Testing-title-with-spaces" | ||
assert google_meet.create_google_meet(title) == expected | ||
|
||
|
||
def test_create_google_meet_with_title_too_long_and_spaces(): | ||
"""Test create_google_meet with a title that is too long and has spaces.""" | ||
title = ( | ||
"Testing title that is much too long for google" | ||
" meet and it should be truncated" | ||
) | ||
expected = ( | ||
"https://g.co/meet/Testing-title-that-is-much-too-" | ||
"long-for-google-meet-and-it-s" | ||
) | ||
assert google_meet.create_google_meet(title) == expected | ||
assert len(google_meet.create_google_meet(title)) == 78 | ||
|
||
|
||
def test_create_google_meet_with_title_special_characters(): | ||
"""Test create_google_meet with a title that has special characters.""" | ||
title = "Testing title with special @!@#$!@# characters !@#$%^&*()" | ||
expected = "https://g.co/meet/Testing-title-with-special-characters" | ||
assert google_meet.create_google_meet(title) == expected | ||
|
||
|
||
def test_create_google_meet_with_title_too_long_and_special_characters(): | ||
"""Test create_google_meet with a title that is too long | ||
and has special characters.""" | ||
title = ( | ||
"Testing title that is much too long for google" | ||
" meet and it should be truncated !@#$%^&*()" | ||
) | ||
expected = ( | ||
"https://g.co/meet/Testing-title-that-is-much-too-" | ||
"long-for-google-meet-and-it-s" | ||
) | ||
assert google_meet.create_google_meet(title) == expected | ||
assert len(google_meet.create_google_meet(title)) == 78 |
52 changes: 52 additions & 0 deletions
52
app/tests/integrations/google_workspace/test_google_service.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import json | ||
import pytest | ||
from unittest.mock import patch, MagicMock | ||
from integrations.google_workspace.google_service import get_google_service | ||
from json import JSONDecodeError | ||
|
||
|
||
@patch("integrations.google_workspace.google_service.build") | ||
@patch( | ||
"integrations.google_workspace.google_service.service_account.Credentials.from_service_account_info" | ||
) | ||
def test_get_google_service_returns_build_object(credentials_mock, build_mock): | ||
""" | ||
Test case to verify that the function returns a build object. | ||
""" | ||
credentials_mock.return_value = MagicMock() | ||
with patch.dict( | ||
"os.environ", | ||
{"GCP_SRE_SERVICE_ACCOUNT_KEY_FILE": json.dumps({"type": "service_account"})}, | ||
): | ||
get_google_service("drive", "v3") | ||
build_mock.assert_called_once_with( | ||
"drive", "v3", credentials=credentials_mock.return_value, cache_discovery=False | ||
) | ||
|
||
|
||
def test_get_google_service_raises_exception_if_credentials_json_not_set(): | ||
""" | ||
Test case to verify that the function raises an exception if: | ||
- GCP_SRE_SERVICE_ACCOUNT_KEY_FILE is not set. | ||
""" | ||
with patch.dict("os.environ", clear=True): | ||
with pytest.raises(ValueError) as e: | ||
get_google_service("drive", "v3") | ||
assert "Credentials JSON not set" in str(e.value) | ||
|
||
|
||
@patch("integrations.google_workspace.google_service.build") | ||
@patch( | ||
"integrations.google_workspace.google_service.service_account.Credentials.from_service_account_info" | ||
) | ||
def test_get_google_service_raises_exception_if_credentials_json_is_invalid( | ||
credentials_mock, build_mock | ||
): | ||
""" | ||
Test case to verify that the function raises an exception if: | ||
- GCP_SRE_SERVICE_ACCOUNT_KEY_FILE is invalid. | ||
""" | ||
with patch.dict("os.environ", {"GCP_SRE_SERVICE_ACCOUNT_KEY_FILE": "invalid"}): | ||
with pytest.raises(JSONDecodeError) as e: | ||
get_google_service("drive", "v3") | ||
assert "Invalid credentials JSON" in str(e.value) |