fix(config): return None if env var is empty or non-existent #315

Merged
luketainton merged 4 commits from 278-bug-handle-empty-or-undefined-environment-variables-for-approved-usersroomsdomains into main 2024-11-21 23:26:07 +01:00
7 changed files with 70 additions and 41 deletions
Showing only changes of commit 8105fd0d72 - Show all commits

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 """Exit command."""
import logging import logging
@ -8,7 +8,10 @@ log: logging.Logger = logging.getLogger(__name__)
class ExitCommand(Command): class ExitCommand(Command):
"""Exit command class."""
def __init__(self) -> None: def __init__(self) -> None:
"""Exit command class."""
super().__init__( super().__init__(
command_keyword="exit", command_keyword="exit",
help_message="Exit", help_message="Exit",
@ -17,10 +20,10 @@ class ExitCommand(Command):
self.sender: str = "" self.sender: str = ""
def pre_execute(self, message, attachment_actions, activity) -> None: def pre_execute(self, message, attachment_actions, activity) -> None:
pass """Pre-execute method."""
def execute(self, message, attachment_actions, activity) -> None: def execute(self, message, attachment_actions, activity) -> None:
pass """Execute method."""
def post_execute(self, message, attachment_actions, activity) -> None: def post_execute(self, message, attachment_actions, activity) -> None:
pass """Post-execute method."""

View File

@ -1,20 +1,12 @@
#!/usr/bin/env python3 """Submit task command."""
import logging import logging
import sentry_sdk
import sentry_sdk
from webex_bot.models.command import Command from webex_bot.models.command import Command
from webex_bot.models.response import Response, response_from_adaptive_card from webex_bot.models.response import Response, response_from_adaptive_card
from webexteamssdk.models.cards import ( from webexteamssdk.models.cards import (AdaptiveCard, Column, ColumnSet, Date,
AdaptiveCard, FontSize, FontWeight, Text, TextBlock)
Column,
ColumnSet,
Date,
FontSize,
FontWeight,
Text,
TextBlock,
)
from webexteamssdk.models.cards.actions import Submit from webexteamssdk.models.cards.actions import Submit
from app.utils.config import config from app.utils.config import config
@ -24,7 +16,10 @@ log: logging.Logger = logging.getLogger(__name__)
class SubmitTaskCommand(Command): class SubmitTaskCommand(Command):
"""Submit task command."""
def __init__(self) -> None: def __init__(self) -> None:
"""Submit task command."""
super().__init__( super().__init__(
command_keyword="submit_feedback_dstgmyn", command_keyword="submit_feedback_dstgmyn",
help_message="Submit Task", help_message="Submit Task",
@ -34,9 +29,11 @@ class SubmitTaskCommand(Command):
self.sender: str = "" self.sender: str = ""
def pre_execute(self, message, attachment_actions, activity) -> None: def pre_execute(self, message, attachment_actions, activity) -> None:
"""Pre-execute method."""
self.sender = activity.get("actor").get("id") self.sender = activity.get("actor").get("id")
def execute(self, message, attachment_actions, activity) -> Response: def execute(self, message, attachment_actions, activity) -> Response:
"""Execute method."""
card_body: list = [ card_body: list = [
ColumnSet( ColumnSet(
columns=[ columns=[
@ -48,7 +45,8 @@ class SubmitTaskCommand(Command):
size=FontSize.MEDIUM, size=FontSize.MEDIUM,
), ),
TextBlock( TextBlock(
f"Add a task to {config.admin_first_name}'s To Do list. All fields are required. Please don't use special characters.", f"Add a task to {config.admin_first_name}'s To Do list. "
+ "All fields are required. Please don't use special characters.",
wrap=True, wrap=True,
isSubtle=True, isSubtle=True,
), ),
@ -62,7 +60,9 @@ class SubmitTaskCommand(Command):
Column( Column(
width=2, width=2,
items=[ items=[
Text(id="issue_title", placeholder="Summary", maxLength=100), Text(
id="issue_title", placeholder="Summary", maxLength=100
),
Text( Text(
id="issue_description", id="issue_description",
placeholder="Description", placeholder="Description",
@ -85,7 +85,8 @@ class SubmitTaskCommand(Command):
items=[ items=[
Text( Text(
id="issue_requester", id="issue_requester",
placeholder="Requester Email (leave blank to submit for yourself)", placeholder="Requester Email "
+ "(leave blank to submit for yourself)",
maxLength=100, maxLength=100,
), ),
], ],
@ -119,19 +120,26 @@ class SubmitTaskCommand(Command):
class SubmitTaskCallback(Command): class SubmitTaskCallback(Command):
"""Submit task callback."""
def __init__(self) -> None: def __init__(self) -> None:
"""Submit task callback."""
super().__init__( super().__init__(
card_callback_keyword="submit_task_callback_rbamzfyx", delete_previous_message=True card_callback_keyword="submit_task_callback_rbamzfyx",
delete_previous_message=True,
) )
self.msg: str = "" self.msg: str = ""
def pre_execute(self, message, attachment_actions, activity) -> None: def pre_execute(self, message, attachment_actions, activity) -> None:
"""Pre-execute method."""
issue_title: str = attachment_actions.inputs.get("issue_title") issue_title: str = attachment_actions.inputs.get("issue_title")
issue_description: str = attachment_actions.inputs.get("issue_description") issue_description: str = attachment_actions.inputs.get("issue_description")
completion_date: str = attachment_actions.inputs.get("completion_date") completion_date: str = attachment_actions.inputs.get("completion_date")
sender: str = attachment_actions.inputs.get("sender") sender: str = attachment_actions.inputs.get("sender")
issue_requester: str = attachment_actions.inputs.get("issue_requester") or sender issue_requester: str = (
attachment_actions.inputs.get("issue_requester") or sender
)
if not issue_title or not issue_description or not completion_date: if not issue_title or not issue_description or not completion_date:
self.msg = "Please complete all fields." self.msg = "Please complete all fields."
@ -145,29 +153,38 @@ class SubmitTaskCallback(Command):
) )
self.msg = ( self.msg = (
"Submitting your task..." if result else "Failed to submit task. Please try again." "Submitting your task..."
if result
else "Failed to submit task. Please try again."
) )
def execute(self, message, attachment_actions, activity) -> str: def execute(self, message, attachment_actions, activity) -> str:
"""Execute method."""
with sentry_sdk.start_transaction(name="submit_task_callback"): with sentry_sdk.start_transaction(name="submit_task_callback"):
return self.msg return self.msg
class MyTasksCallback(Command): class MyTasksCallback(Command):
"""My tasks callback."""
def __init__(self) -> None: def __init__(self) -> None:
"""My tasks callback."""
super().__init__( super().__init__(
card_callback_keyword="my_tasks_callback_rbamzfyx", delete_previous_message=True card_callback_keyword="my_tasks_callback_rbamzfyx",
delete_previous_message=True,
) )
self.msg: str = "" self.msg: str = ""
def pre_execute(self, message, attachment_actions, activity) -> str: def pre_execute(self, message, attachment_actions, activity) -> str:
"""Pre-execute method."""
with sentry_sdk.start_transaction(name="my_tasks_preexec"): with sentry_sdk.start_transaction(name="my_tasks_preexec"):
return "Getting your tasks..." return "Getting your tasks..."
def execute(self, message, attachment_actions, activity) -> str | None: def execute(self, message, attachment_actions, activity) -> str | None:
"""Execute method."""
sender: str = attachment_actions.inputs.get("sender") sender: str = attachment_actions.inputs.get("sender")
result: bool = get_tasks(requestor=sender) result: bool = get_tasks(requestor=sender)
with sentry_sdk.start_transaction(name="my_tasks_exec"): with sentry_sdk.start_transaction(name="my_tasks_exec"):
if not result: if not result:
return "Failed to get tasks. Please try again." return "Failed to get tasks. Please try again."
return return None

View File

@ -1,4 +1,6 @@
#!/usr/bin/env python3 """Main module."""
import sys
import sentry_sdk import sentry_sdk
from sentry_sdk.integrations.stdlib import StdlibIntegration from sentry_sdk.integrations.stdlib import StdlibIntegration
@ -43,4 +45,4 @@ if __name__ == "__main__":
bot.run() bot.run()
except KeyboardInterrupt: except KeyboardInterrupt:
print("Shutting down bot...") print("Shutting down bot...")
exit() sys.exit(0)

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 """Provides functions for converting timestamps to dates."""
from datetime import datetime from datetime import datetime
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo

View File

@ -1,3 +1,5 @@
"""N8N utils module."""
import requests import requests
import sentry_sdk import sentry_sdk

View File

@ -6,7 +6,7 @@
import os import os
vars: dict = { config_vars: dict = {
"APP_VERSION": "dev", "APP_VERSION": "dev",
"BOT_NAME": "TestBot", "BOT_NAME": "TestBot",
"WEBEX_API_KEY": "testing", "WEBEX_API_KEY": "testing",
@ -21,26 +21,29 @@ vars: dict = {
} }
for var, value in vars.items(): for config_var, value in config_vars.items():
os.environ[var] = value os.environ[config_var] = value
# needs to be imported AFTER environment variables are set # needs to be imported AFTER environment variables are set
from app.utils.config import config # pragma: no cover from app.utils.config import config # pragma: no cover
def test_config() -> None: def test_config() -> None:
assert config.admin_emails == vars["ADMIN_EMAIL"].split(",") """Test config module."""
assert config.admin_first_name == vars["ADMIN_FIRST_NAME"] assert config.admin_emails == config_vars["ADMIN_EMAIL"].split(",")
assert config.approved_domains == vars["APPROVED_DOMAINS"].split(",") assert config.admin_first_name == config_vars["ADMIN_FIRST_NAME"]
assert config.approved_rooms == vars["APPROVED_ROOMS"].split(",") assert config.approved_domains == config_vars["APPROVED_DOMAINS"].split(",")
assert config.approved_users == vars["APPROVED_USERS"].split(",") assert config.approved_rooms == config_vars["APPROVED_ROOMS"].split(",")
assert config.bot_name == vars["BOT_NAME"] assert config.approved_users == config_vars["APPROVED_USERS"].split(",")
assert config.n8n_webhook_url == vars["N8N_WEBHOOK_URL"] assert config.bot_name == config_vars["BOT_NAME"]
assert config.sentry_enabled == bool(vars["SENTRY_ENABLED"].upper() == "TRUE") assert config.n8n_webhook_url == config_vars["N8N_WEBHOOK_URL"]
assert config.version == vars["APP_VERSION"] assert config.sentry_enabled == bool(
assert config.webex_token == vars["WEBEX_API_KEY"] config_vars["SENTRY_ENABLED"].upper() == "TRUE"
)
assert config.version == config_vars["APP_VERSION"]
assert config.webex_token == config_vars["WEBEX_API_KEY"]
if config.sentry_enabled: if config.sentry_enabled:
assert config.sentry_dsn == vars["SENTRY_DSN"] assert config.sentry_dsn == config_vars["SENTRY_DSN"]
else: else:
assert config.sentry_dsn == "" assert config.sentry_dsn == ""

View File

@ -8,12 +8,14 @@ from app.utils.datetime import timestamp_to_date # pragma: no cover
def test_correct() -> None: def test_correct() -> None:
"""Test timestamp_to_date() with a correct timestamp."""
timestamp: int = 1680722218 timestamp: int = 1680722218
result: str = timestamp_to_date(timestamp) result: str = timestamp_to_date(timestamp)
assert result == "2023-04-05" assert result == "2023-04-05"
def test_invalid() -> None: def test_invalid() -> None:
"""Test timestamp_to_date() with an invalid timestamp."""
timestamp: str = "hello" timestamp: str = "hello"
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
timestamp_to_date(timestamp) timestamp_to_date(timestamp)