Compare commits
	
		
			1 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 9830c5cc3a | 
@@ -1,3 +1,6 @@
 | 
			
		||||
APP_LIFECYCLE="dev"
 | 
			
		||||
SENTRY_ENABLED="False"
 | 
			
		||||
SENTRY_DSN=""
 | 
			
		||||
ADMIN_EMAIL=""
 | 
			
		||||
ADMIN_FIRST_NAME=""
 | 
			
		||||
BOT_NAME=""
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -13,7 +13,7 @@ jobs:
 | 
			
		||||
      - uses: actions/checkout@v4
 | 
			
		||||
      - name: Bump version and push tag
 | 
			
		||||
        id: tag_version
 | 
			
		||||
        uses: mathieudutour/github-tag-action@v6.1
 | 
			
		||||
        uses: mathieudutour/github-tag-action@v6.2
 | 
			
		||||
        with:
 | 
			
		||||
          github_token: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
          default_bump: minor
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
import sentry_sdk
 | 
			
		||||
 | 
			
		||||
from webex_bot.models.command import Command
 | 
			
		||||
from webex_bot.models.response import Response, response_from_adaptive_card
 | 
			
		||||
@@ -113,7 +114,8 @@ class SubmitTaskCommand(Command):
 | 
			
		||||
                Submit(title="Cancel", data={"command_keyword": "exit"}),
 | 
			
		||||
            ],
 | 
			
		||||
        )
 | 
			
		||||
        return response_from_adaptive_card(card)
 | 
			
		||||
        with sentry_sdk.start_transaction(name="submit_task_command"):
 | 
			
		||||
            return response_from_adaptive_card(card)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SubmitTaskCallback(Command):
 | 
			
		||||
@@ -147,7 +149,8 @@ class SubmitTaskCallback(Command):
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def execute(self, message, attachment_actions, activity) -> str:
 | 
			
		||||
        return self.msg
 | 
			
		||||
        with sentry_sdk.start_transaction(name="submit_task_callback"):
 | 
			
		||||
            return self.msg
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MyTasksCallback(Command):
 | 
			
		||||
@@ -158,11 +161,13 @@ class MyTasksCallback(Command):
 | 
			
		||||
        self.msg: str = ""
 | 
			
		||||
 | 
			
		||||
    def pre_execute(self, message, attachment_actions, activity) -> str:
 | 
			
		||||
        return "Getting your tasks..."
 | 
			
		||||
        with sentry_sdk.start_transaction(name="my_tasks_preexec"):
 | 
			
		||||
            return "Getting your tasks..."
 | 
			
		||||
 | 
			
		||||
    def execute(self, message, attachment_actions, activity) -> str | None:
 | 
			
		||||
        sender: str = attachment_actions.inputs.get("sender")
 | 
			
		||||
        result: bool = get_tasks(requestor=sender)
 | 
			
		||||
        if not result:
 | 
			
		||||
            return "Failed to get tasks. Please try again."
 | 
			
		||||
        return
 | 
			
		||||
        with sentry_sdk.start_transaction(name="my_tasks_exec"):
 | 
			
		||||
            if not result:
 | 
			
		||||
                return "Failed to get tasks. Please try again."
 | 
			
		||||
            return
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								app/main.py
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								app/main.py
									
									
									
									
									
								
							@@ -1,5 +1,8 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import sentry_sdk
 | 
			
		||||
from sentry_sdk.integrations.stdlib import StdlibIntegration
 | 
			
		||||
 | 
			
		||||
from webex_bot.webex_bot import WebexBot
 | 
			
		||||
 | 
			
		||||
from app.commands.exit import ExitCommand
 | 
			
		||||
@@ -7,8 +10,18 @@ from app.commands.submit_task import SubmitTaskCommand
 | 
			
		||||
from app.utils.config import config
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if config.sentry_enabled:
 | 
			
		||||
    apm = sentry_sdk.init(
 | 
			
		||||
        dsn=config.sentry_dsn,
 | 
			
		||||
        enable_tracing=True,
 | 
			
		||||
        environment=config.environment,
 | 
			
		||||
        integrations=[StdlibIntegration()],
 | 
			
		||||
        spotlight=True
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_bot() -> WebexBot:
 | 
			
		||||
    # Create a Bot Object
 | 
			
		||||
    """Create and return a Webex Bot object."""
 | 
			
		||||
    webex_bot: WebexBot = WebexBot(
 | 
			
		||||
        bot_name=config.bot_name,
 | 
			
		||||
        teams_bot_token=config.webex_token,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,34 +1,65 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
"""Configuration module."""
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Config:
 | 
			
		||||
    """Configuration module."""
 | 
			
		||||
    def __init__(self) -> None:
 | 
			
		||||
        """Configuration module."""
 | 
			
		||||
        self.__environment: str = os.environ.get("APP_LIFECYCLE", "DEV").upper()
 | 
			
		||||
        self.__bot_name: str = os.environ["BOT_NAME"]
 | 
			
		||||
        self.__webex_token: str = os.environ["WEBEX_API_KEY"]
 | 
			
		||||
        self.__admin_first_name: str = os.environ["ADMIN_FIRST_NAME"]
 | 
			
		||||
        self.__admin_emails: list = os.environ["ADMIN_EMAIL"].split(",")
 | 
			
		||||
        self.__n8n_webhook_url: str = os.environ["N8N_WEBHOOK_URL"]
 | 
			
		||||
        self.__sentry_dsn: str = os.environ.get("SENTRY_DSN", "")
 | 
			
		||||
        self.__sentry_enabled: bool = bool(
 | 
			
		||||
            os.environ.get("SENTRY_ENABLED", "False").upper() == "TRUE"
 | 
			
		||||
            and self.__sentry_dsn != ""
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def environment(self) -> str:
 | 
			
		||||
        """Returns the current app lifecycle."""
 | 
			
		||||
        return self.__environment
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def sentry_enabled(self) -> bool:
 | 
			
		||||
        """Returns True if Sentry SDK is enabled, else False."""
 | 
			
		||||
        return self.__sentry_enabled
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def sentry_dsn(self) -> str:
 | 
			
		||||
        """Returns the Sentry DSN value if Sentry SDK is enabled AND
 | 
			
		||||
        Sentry DSN is set, else blank string."""
 | 
			
		||||
        if not self.__sentry_enabled:
 | 
			
		||||
            return ""
 | 
			
		||||
        return self.__sentry_dsn
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def bot_name(self) -> str:
 | 
			
		||||
        """Returns the bot name."""
 | 
			
		||||
        return self.__bot_name
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def webex_token(self) -> str:
 | 
			
		||||
        """Returns the Webex API key."""
 | 
			
		||||
        return self.__webex_token
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def admin_first_name(self) -> str:
 | 
			
		||||
        """Returns the first name of the bot admin."""
 | 
			
		||||
        return self.__admin_first_name
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def admin_emails(self) -> list:
 | 
			
		||||
        """Returns a list of admin email addresses."""
 | 
			
		||||
        return self.__admin_emails
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def n8n_webhook_url(self) -> str:
 | 
			
		||||
        """Returns the n8n webhook URL."""
 | 
			
		||||
        return self.__n8n_webhook_url
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,18 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
from zoneinfo import ZoneInfo
 | 
			
		||||
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def timestamp_to_date(timestamp: int) -> str:
 | 
			
		||||
    return datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d")
 | 
			
		||||
    """Convert timestamp to date.
 | 
			
		||||
    
 | 
			
		||||
    Args:
 | 
			
		||||
        timestamp (int): Timestamp to convert.
 | 
			
		||||
    
 | 
			
		||||
    Returns:
 | 
			
		||||
        str: Date in the format YYYY-MM-DD.
 | 
			
		||||
    """
 | 
			
		||||
    return datetime.fromtimestamp(timestamp=timestamp, tz=ZoneInfo("UTC")).strftime("%Y-%m-%d")
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,18 @@
 | 
			
		||||
import requests
 | 
			
		||||
import sentry_sdk
 | 
			
		||||
 | 
			
		||||
from app.utils.config import config
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def __n8n_post(data: dict) -> bool:
 | 
			
		||||
    """Post data to N8N webhook URL.
 | 
			
		||||
    
 | 
			
		||||
    Args:
 | 
			
		||||
        data (dict): Data to post to webhook URL.
 | 
			
		||||
    
 | 
			
		||||
    Returns:
 | 
			
		||||
        bool: True if successful, else False.
 | 
			
		||||
    """
 | 
			
		||||
    headers: dict = {"Content-Type": "application/json"}
 | 
			
		||||
    resp: requests.Response = requests.post(
 | 
			
		||||
        url=config.n8n_webhook_url,
 | 
			
		||||
@@ -16,22 +25,45 @@ def __n8n_post(data: dict) -> bool:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def submit_task(summary, description, completion_date, requestor) -> bool:
 | 
			
		||||
    data: dict = {
 | 
			
		||||
        "requestor": requestor,
 | 
			
		||||
        "title": summary,
 | 
			
		||||
        "description": description,
 | 
			
		||||
        "completiondate": completion_date,
 | 
			
		||||
    }
 | 
			
		||||
    return __n8n_post(data=data)
 | 
			
		||||
    """Submit task to N8N webhook URL.
 | 
			
		||||
    
 | 
			
		||||
    Args:
 | 
			
		||||
        summary (str): Summary of task.
 | 
			
		||||
        description (str): Description of task.
 | 
			
		||||
        completion_date (str): Completion date of task.
 | 
			
		||||
        requestor (str): Requestor of task.
 | 
			
		||||
    
 | 
			
		||||
    Returns:
 | 
			
		||||
        bool: True if successful, else False.
 | 
			
		||||
    """
 | 
			
		||||
    with sentry_sdk.start_transaction(name="submit_task"):
 | 
			
		||||
        data: dict = {
 | 
			
		||||
            "requestor": requestor,
 | 
			
		||||
            "title": summary,
 | 
			
		||||
            "description": description,
 | 
			
		||||
            "completiondate": completion_date,
 | 
			
		||||
        }
 | 
			
		||||
        _data = __n8n_post(data=data)
 | 
			
		||||
    return _data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_tasks(requestor) -> bool:
 | 
			
		||||
    headers: dict = {"Content-Type": "application/json"}
 | 
			
		||||
    resp: requests.Response = requests.get(
 | 
			
		||||
        url=config.n8n_webhook_url,
 | 
			
		||||
        headers=headers,
 | 
			
		||||
        timeout=10,
 | 
			
		||||
        verify=False,
 | 
			
		||||
        params={"requestor": requestor},
 | 
			
		||||
    )
 | 
			
		||||
    return bool(resp.status_code == 200)
 | 
			
		||||
    """Get tasks from N8N webhook URL.
 | 
			
		||||
    
 | 
			
		||||
    Args:
 | 
			
		||||
        requestor (str): Requestor of tasks.
 | 
			
		||||
    
 | 
			
		||||
    Returns:
 | 
			
		||||
        bool: True if successful, else False.
 | 
			
		||||
    """
 | 
			
		||||
    with sentry_sdk.start_transaction(name="get_tasks"):
 | 
			
		||||
        headers: dict = {"Content-Type": "application/json"}
 | 
			
		||||
        resp: requests.Response = requests.get(
 | 
			
		||||
            url=config.n8n_webhook_url,
 | 
			
		||||
            headers=headers,
 | 
			
		||||
            timeout=10,
 | 
			
		||||
            verify=False,
 | 
			
		||||
            params={"requestor": requestor},
 | 
			
		||||
        )
 | 
			
		||||
        _data = bool(resp.status_code == 200)
 | 
			
		||||
    return _data
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
appdirs==1.4.4
 | 
			
		||||
astroid==3.1.0
 | 
			
		||||
attrs==23.2.0
 | 
			
		||||
autopep8==2.0.4
 | 
			
		||||
autopep8==2.1.0
 | 
			
		||||
backoff==2.2.1
 | 
			
		||||
certifi==2024.2.2
 | 
			
		||||
cfgv==3.4.0
 | 
			
		||||
@@ -10,35 +10,36 @@ click==8.1.7
 | 
			
		||||
coloredlogs==15.0.1
 | 
			
		||||
dill==0.3.8
 | 
			
		||||
distlib==0.3.8
 | 
			
		||||
filelock==3.13.1
 | 
			
		||||
filelock==3.13.4
 | 
			
		||||
future==1.0.0
 | 
			
		||||
humanfriendly==10.0
 | 
			
		||||
identify==2.5.35
 | 
			
		||||
idna==3.6
 | 
			
		||||
idna==3.7
 | 
			
		||||
iniconfig==2.0.0
 | 
			
		||||
lazy-object-proxy==1.10.0
 | 
			
		||||
mccabe==0.7.0
 | 
			
		||||
mypy-extensions==1.0.0
 | 
			
		||||
nodeenv==1.8.0
 | 
			
		||||
packaging==23.2
 | 
			
		||||
packaging==24.0
 | 
			
		||||
pathspec==0.12.1
 | 
			
		||||
platformdirs==4.2.0
 | 
			
		||||
pluggy==1.4.0
 | 
			
		||||
py==1.11.0
 | 
			
		||||
pycodestyle==2.11.1
 | 
			
		||||
PyJWT==2.8.0
 | 
			
		||||
pyparsing==3.1.1
 | 
			
		||||
pyparsing==3.1.2
 | 
			
		||||
python-dateutil==2.9.0.post0
 | 
			
		||||
python-dotenv==1.0.1
 | 
			
		||||
PyYAML==6.0.1
 | 
			
		||||
requests==2.31.0
 | 
			
		||||
requests-toolbelt==1.0.0
 | 
			
		||||
sentry-sdk==1.45.0
 | 
			
		||||
six==1.16.0
 | 
			
		||||
toml==0.10.2
 | 
			
		||||
tomli==2.0.1
 | 
			
		||||
tomlkit==0.12.4
 | 
			
		||||
urllib3==2.2.1
 | 
			
		||||
virtualenv==20.25.1
 | 
			
		||||
virtualenv==20.25.3
 | 
			
		||||
webex-bot==0.4.1
 | 
			
		||||
webexteamssdk==1.6.1
 | 
			
		||||
websockets==10.2
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								test.sh
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								test.sh
									
									
									
									
									
								
							@@ -1,3 +1,3 @@
 | 
			
		||||
export $(cat .env | xargs)
 | 
			
		||||
python -B -m app.main
 | 
			
		||||
unset BOT_NAME WEBEX_API_KEY ADMIN_FIRST_NAME ADMIN_EMAIL N8N_WEBHOOK_URL
 | 
			
		||||
unset APP_LIFECYCLE SENTRY_ENABLED SENTRY_DSN BOT_NAME WEBEX_API_KEY ADMIN_FIRST_NAME ADMIN_EMAIL N8N_WEBHOOK_URL
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										0
									
								
								tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -11,6 +11,8 @@ vars: dict = {
 | 
			
		||||
    "ADMIN_FIRST_NAME": "Test",
 | 
			
		||||
    "ADMIN_EMAIL": "test@test.com",
 | 
			
		||||
    "N8N_WEBHOOK_URL": "https://n8n.test.com/webhook/abcdefg",
 | 
			
		||||
    "SENTRY_ENABLED": "false",
 | 
			
		||||
    "SENTRY_DSN": "http://localhost"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user