diff --git a/app/controller/command/commands/team.py b/app/controller/command/commands/team.py index 6def3a2e..eb131a17 100644 --- a/app/controller/command/commands/team.py +++ b/app/controller/command/commands/team.py @@ -9,6 +9,7 @@ from interface.github import GithubAPIException, GithubInterface from interface.slack import SlackAPIError from interface.gcp import GCPInterface +from interface.gcp_utils import sync_team_email_perms from config import Config from app.model import Team, User from utils.slack_parse import check_permissions @@ -682,39 +683,4 @@ def refresh_all_drive_permissions(self): all_teams: List[Team] = self.facade.query(Team) for t in all_teams: - self.refresh_drive_permissions(t) - - def refresh_drive_permissions(self, t: Team): - """ - Refresh Google Drive permissions for provided team. If no GCP client - is provided, this function is a no-op. - """ - - if self.gcp is None: - logging.debug("GCP not enabled, skipping drive permissions") - return - - if len(t.folder) == 0: - return - - # Generate who to share with - emails: List[str] = [] - for github_id in t.members: - users = self.facade. \ - query(User, [('github_user_id', github_id)]) - if len(users) != 1: - logging.warn(f"None/multiple users for GitHub ID {github_id}") - - # For now, naiively iterate over all users, due to - # https://github.com/ubclaunchpad/rocket2/issues/493 - for user in users: - if len(user.email) > 0: - emails.append(user.email) - - # Sync permissions - if len(emails) > 0: - logging.info("Synchronizing permissions for " - + f"{t.github_team_name}'s folder ({t.folder}) " - + f"to {emails}") - self.gcp.set_drive_permissions( - t.github_team_name, t.folder, emails) + sync_team_email_perms(self.gcp, self.facade, t) diff --git a/app/controller/command/commands/user.py b/app/controller/command/commands/user.py index 19294503..3d298517 100644 --- a/app/controller/command/commands/user.py +++ b/app/controller/command/commands/user.py @@ -7,8 +7,10 @@ from app.controller.command.commands.base import Command from db.facade import DBFacade from interface.github import GithubAPIException, GithubInterface +from interface.gcp import GCPInterface +from interface.gcp_utils import sync_user_email_perms from app.model import User, Permissions -from typing import Dict, cast +from typing import Dict, cast, Optional from utils.slack_parse import escape_email @@ -24,7 +26,8 @@ class UserCommand(Command): def __init__(self, db_facade: DBFacade, - github_interface: GithubInterface): + github_interface: GithubInterface, + gcp: Optional[GCPInterface]): """Initialize user command.""" logging.info("Initializing UserCommand instance") self.parser = ArgumentParser(prog="/rocket") @@ -33,6 +36,7 @@ def __init__(self, self.help = self.get_help() self.facade = db_facade self.github = github_interface + self.gcp = gcp def init_subparsers(self) -> _SubParsersAction: """Initialize subparsers for user command.""" @@ -220,6 +224,8 @@ def edit_helper(self, " level.") self.facade.store(edited_user) + sync_user_email_perms(self.gcp, self.facade, edited_user) + ret = {'attachments': [edited_user.get_attachment()]} if msg != "": # mypy doesn't like the fact that there could be different types diff --git a/app/controller/command/parser.py b/app/controller/command/parser.py index 927a7a4c..561a3732 100644 --- a/app/controller/command/parser.py +++ b/app/controller/command/parser.py @@ -33,7 +33,9 @@ def __init__(self, self.__bot = bot self.__github = gh_interface self.__gcp = gcp - self.commands["user"] = UserCommand(self.__facade, self.__github) + self.commands["user"] = UserCommand(self.__facade, + self.__github, + self.__gcp) self.commands["team"] = TeamCommand(config, self.__facade, self.__github, self.__bot, diff --git a/interface/gcp_utils.py b/interface/gcp_utils.py new file mode 100644 index 00000000..18fb586b --- /dev/null +++ b/interface/gcp_utils.py @@ -0,0 +1,64 @@ +"""Utilities for common-used interactions with Google API.""" +import logging +from typing import List, Optional +from interface.gcp import GCPInterface +from db import DBFacade +from app.model import User, Team + + +def sync_user_email_perms(gcp: Optional[GCPInterface], + db: DBFacade, + user: User): + """ + Refresh Google Drive permissions for a provided user. If no GCP client is + provided, this function is a no-op. + + Finds folders for user by checking all teams the user is a part of, and + calling ``sync_team_email_perms()``. + """ + if gcp is None: + logging.debug('GCP not enabled, skipping drive permissions') + return + + if len(user.email) == 0 or len(user.github_id) == 0: + return + + teams_user_is_in = db.query(Team, [('members', user.github_id)]) + for team in teams_user_is_in: + sync_team_email_perms(gcp, db, team) + + +def sync_team_email_perms(gcp: Optional[GCPInterface], + db: DBFacade, + team: Team): + """ + Refresh Google Drive permissions for provided team. If no GCP client + is provided, this function is a no-op. + """ + if gcp is None: + logging.debug("GCP not enabled, skipping drive permissions") + return + + if len(team.folder) == 0: + return + + # Generate who to share with + emails: List[str] = [] + for github_id in team.members: + users = db.query(User, [('github_user_id', github_id)]) + if len(users) != 1: + logging.warn(f"None/multiple users for GitHub ID {github_id}") + + # For now, naiively iterate over all users, due to + # https://github.com/ubclaunchpad/rocket2/issues/493 + for user in users: + if len(user.email) > 0: + emails.append(user.email) + + # Sync permissions + if len(emails) > 0: + logging.info("Synchronizing permissions for " + + f"{team.github_team_name}'s folder ({team.folder}) " + + f"to {emails}") + gcp.set_drive_permissions( + team.github_team_name, team.folder, emails) diff --git a/tests/app/controller/command/commands/user_test.py b/tests/app/controller/command/commands/user_test.py index d8f4c679..72747854 100644 --- a/tests/app/controller/command/commands/user_test.py +++ b/tests/app/controller/command/commands/user_test.py @@ -17,7 +17,7 @@ def setUp(self): self.db = MemoryDB(users=[self.u0, self.u1, self.admin]) self.mock_github = mock.MagicMock(GithubInterface) - self.testcommand = UserCommand(self.db, self.mock_github) + self.testcommand = UserCommand(self.db, self.mock_github, None) self.maxDiff = None def test_get_help(self): diff --git a/tests/utils/slack_parse_test.py b/tests/utils/slack_parse_test.py index 768034ab..d13d91fc 100644 --- a/tests/utils/slack_parse_test.py +++ b/tests/utils/slack_parse_test.py @@ -106,3 +106,7 @@ def test_escape_email(self): email = "" ret = util.escape_email(email) self.assertEqual(ret, "email@a.com") + + def test_escape_normal_email(self): + email = 'robert@bobheadxi.dev' + self.assertEqual(util.escape_email(email), email) diff --git a/utils/slack_parse.py b/utils/slack_parse.py index 06d1e82a..b5133d54 100644 --- a/utils/slack_parse.py +++ b/utils/slack_parse.py @@ -99,7 +99,12 @@ def escape_email(email: str) -> str: email@a.com + Does nothing if the email is not escaped. + :param email: email to convert :return: unescaped email """ - return email.split('|')[0][8:] + if email.startswith('<'): + return email.split('|')[0][8:] + else: + return email