mirror of
https://github.com/nikdoof/smsbot.git
synced 2025-12-28 13:09:03 +00:00
Compare commits
18 Commits
b4e833f440
...
0.2.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
d00a4048cd
|
|||
|
bb5472f092
|
|||
|
6ce86042fb
|
|||
|
0a2970c38f
|
|||
|
126713c84a
|
|||
|
bace0200ab
|
|||
|
e98b8e6b8c
|
|||
| 876b0363c0 | |||
|
d0c18a1d00
|
|||
|
b056d6328d
|
|||
|
40a263686d
|
|||
|
5f1e5508f0
|
|||
|
|
6f36caf6e1 | ||
|
40e23c32a8
|
|||
|
51f4a62738
|
|||
|
b0afb9b15d
|
|||
|
1e28526be7
|
|||
|
594f4ba8ef
|
20
.devcontainer/devcontainer.json
Normal file
20
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
|
// README at: https://github.com/devcontainers/templates/tree/main/src/python
|
||||||
|
{
|
||||||
|
"name": "Development",
|
||||||
|
"image": "mcr.microsoft.com/devcontainers/python:1-3.13-bookworm",
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/eitsupi/devcontainer-features/go-task:1": {},
|
||||||
|
"ghcr.io/jsburckhardt/devcontainer-features/uv:1": {}
|
||||||
|
},
|
||||||
|
"forwardPorts": [
|
||||||
|
5000
|
||||||
|
],
|
||||||
|
"portsAttributes": {
|
||||||
|
"5000": {
|
||||||
|
"label": "Application",
|
||||||
|
"protocol": "http",
|
||||||
|
"public": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
.github/workflows/build-container.yaml
vendored
7
.github/workflows/build-container.yaml
vendored
@@ -22,11 +22,18 @@ jobs:
|
|||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
- name: Set build args
|
||||||
|
run: |
|
||||||
|
echo "PYTHON_VERSION=$(cat .python-version)" >> $GITHUB_ENV
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
id: docker_build
|
id: docker_build
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
build-args: |
|
||||||
|
PYTHON_VERSION=${{ env.PYTHON_VERSION }}
|
||||||
tags: |
|
tags: |
|
||||||
ghcr.io/${{ github.repository }}:${{ github.ref_name }}
|
ghcr.io/${{ github.repository }}:${{ github.ref_name }}
|
||||||
ghcr.io/${{ github.repository }}:latest
|
ghcr.io/${{ github.repository }}:latest
|
||||||
|
|||||||
2
.github/workflows/lint.yaml
vendored
2
.github/workflows/lint.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
python-version: ["3.13"]
|
python-version: ["3.13"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- name: Install Task
|
- name: Install Task
|
||||||
uses: arduino/setup-task@v2
|
uses: arduino/setup-task@v2
|
||||||
with:
|
with:
|
||||||
|
|||||||
4
.github/workflows/release.yaml
vendored
4
.github/workflows/release.yaml
vendored
@@ -10,12 +10,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
|
||||||
python-version: "3.9"
|
|
||||||
|
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@v6
|
uses: astral-sh/setup-uv@v6
|
||||||
|
|||||||
10
Dockerfile
10
Dockerfile
@@ -1,4 +1,6 @@
|
|||||||
FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS builder
|
ARG PYTHON_VERSION="3.13"
|
||||||
|
|
||||||
|
FROM ghcr.io/astral-sh/uv:python${PYTHON_VERSION}-bookworm-slim AS builder
|
||||||
ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
|
ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
|
||||||
ENV UV_PYTHON_DOWNLOADS=0
|
ENV UV_PYTHON_DOWNLOADS=0
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@@ -11,8 +13,10 @@ RUN --mount=type=cache,target=/root/.cache/uv \
|
|||||||
uv sync --locked --no-dev
|
uv sync --locked --no-dev
|
||||||
|
|
||||||
|
|
||||||
FROM python:3.13-slim-bookworm
|
FROM python:${PYTHON_VERSION}-slim-bookworm
|
||||||
COPY --from=builder --chown=app:app /app /app
|
COPY --from=builder --chown=app:app /app /app
|
||||||
|
COPY ./docs/examples/config-basic.ini /app/config.ini
|
||||||
ENV PATH="/app/.venv/bin:$PATH"
|
ENV PATH="/app/.venv/bin:$PATH"
|
||||||
EXPOSE 80/tcp
|
EXPOSE 5000/tcp
|
||||||
|
WORKDIR /app
|
||||||
CMD ["smsbot"]
|
CMD ["smsbot"]
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
version: 3
|
version: 3
|
||||||
tasks:
|
tasks:
|
||||||
|
default:
|
||||||
|
deps:
|
||||||
|
- python:tests
|
||||||
|
- python:lint
|
||||||
|
|
||||||
python:tests:
|
python:tests:
|
||||||
desc: Run Python tests
|
desc: Run Python tests
|
||||||
cmds:
|
cmds:
|
||||||
@@ -14,7 +19,7 @@ tasks:
|
|||||||
docker:build:
|
docker:build:
|
||||||
desc: Build the container using Docker
|
desc: Build the container using Docker
|
||||||
cmds:
|
cmds:
|
||||||
- docker build . -t smsbot:latest
|
- docker build . --build-arg PYTHON_VERSION=$(cat .python-version) -t smsbot:latest
|
||||||
|
|
||||||
smsbot:run:
|
smsbot:run:
|
||||||
desc: Run the SMSBot
|
desc: Run the SMSBot
|
||||||
|
|||||||
5
docs/examples/README.md
Normal file
5
docs/examples/README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Example deployments
|
||||||
|
|
||||||
|
Examples of how to deploy SMSBot.
|
||||||
|
|
||||||
|
* [Flux HelmRelease](flux-helmrelease.yaml) - An example Flux `HelmRelease` using a common chart for basic deployment.
|
||||||
2
docs/examples/config-basic.ini
Normal file
2
docs/examples/config-basic.ini
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[logging]
|
||||||
|
level = INFO
|
||||||
@@ -13,3 +13,4 @@ bot_token = BOT_TOKEN
|
|||||||
[twilio]
|
[twilio]
|
||||||
account_sid = TWILIO_ACCOUNT_SID
|
account_sid = TWILIO_ACCOUNT_SID
|
||||||
auth_token = TWILIO_AUTH_TOKEN
|
auth_token = TWILIO_AUTH_TOKEN
|
||||||
|
from_number = +12345678901
|
||||||
55
docs/examples/flux-helmrelease.yaml
Normal file
55
docs/examples/flux-helmrelease.yaml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
# yaml-language-server: $schema=https://nikdoof.github.io/flux-gitops/schemas/source.toolkit.fluxcd.io/helmrepository_v1.json
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1
|
||||||
|
kind: HelmRepository
|
||||||
|
metadata:
|
||||||
|
name: nikdoof
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
interval: 4h
|
||||||
|
url: https://nikdoof.github.io/helm-charts/
|
||||||
|
---
|
||||||
|
# yaml-language-server: $schema=https://nikdoof.github.io/flux-gitops/schemas/helm.toolkit.fluxcd.io/helmrelease_v2.json
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
name: smsbot
|
||||||
|
spec:
|
||||||
|
interval: 12h
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: common-chart
|
||||||
|
version: 1.2.3
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: nikdoof
|
||||||
|
namespace: flux-system
|
||||||
|
interval: 12h
|
||||||
|
values:
|
||||||
|
global:
|
||||||
|
nameOverride: smsbot
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/nikdoof/smsbot
|
||||||
|
tag: 0.2.0
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
controller:
|
||||||
|
strategy: Recreate
|
||||||
|
annotations:
|
||||||
|
secret.reloader.stakater.com/reload: "smsbot-secrets"
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: smsbot-secrets
|
||||||
|
service:
|
||||||
|
main:
|
||||||
|
ports:
|
||||||
|
http:
|
||||||
|
port: 5000
|
||||||
|
ingress:
|
||||||
|
main:
|
||||||
|
enabled: true
|
||||||
|
hosts:
|
||||||
|
- host: smsbot-webhooks.example.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "smsbot"
|
name = "smsbot"
|
||||||
version = "0.1.1"
|
version = "0.2.2"
|
||||||
description = "A simple Telegram bot to receive SMS messages."
|
description = "A simple Telegram bot to receive SMS messages."
|
||||||
authors = [{ name = "Andrew Williams", email = "andy@tensixtyone.com" }]
|
authors = [{ name = "Andrew Williams", email = "andy@tensixtyone.com" }]
|
||||||
license = { text = "MIT" }
|
license = { text = "MIT" }
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from signal import SIGINT, SIGTERM
|
from signal import SIGINT, SIGTERM
|
||||||
|
from twilio.rest import Client
|
||||||
|
|
||||||
import uvicorn
|
import uvicorn
|
||||||
from asgiref.wsgi import WsgiToAsgi
|
from asgiref.wsgi import WsgiToAsgi
|
||||||
@@ -14,6 +15,10 @@ from smsbot.utils import get_smsbot_version
|
|||||||
from smsbot.webhook import TwilioWebhookHandler
|
from smsbot.webhook import TwilioWebhookHandler
|
||||||
|
|
||||||
|
|
||||||
|
# Prefix of the environment variables to override config values
|
||||||
|
ENVIRONMENT_PREFIX = "SMSBOT_"
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser("smsbot")
|
parser = argparse.ArgumentParser("smsbot")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@@ -43,22 +48,46 @@ def main():
|
|||||||
|
|
||||||
# Override with environment variables, named SMSBOT_<SECTION>_<VALUE>
|
# Override with environment variables, named SMSBOT_<SECTION>_<VALUE>
|
||||||
for key, value in os.environ.items():
|
for key, value in os.environ.items():
|
||||||
if key.startswith("SMSBOT_"):
|
if key.startswith(ENVIRONMENT_PREFIX):
|
||||||
logging.debug("Overriding config %s with value %s", key, value)
|
section, option = key[7:].lower().split("_", 1)
|
||||||
section, option = key[7:].split("_", 1)
|
logging.debug("Overriding config %s/%s = %s", section, option, value)
|
||||||
|
if not config.has_section(section):
|
||||||
|
config.add_section(section)
|
||||||
config[section][option] = value
|
config[section][option] = value
|
||||||
|
|
||||||
# Validate configuration
|
# Validate configuration
|
||||||
if not config.has_section("telegram") or not config.get("telegram", "bot_token"):
|
if not config.has_section("telegram") or not config.get("telegram", "bot_token"):
|
||||||
logging.error("Telegram bot token is required, define a token either in the config file or as an environment variable.")
|
logging.error(
|
||||||
|
"Telegram bot token is required, define a token either in the config file or as an environment variable."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
if config.has_section("twilio") and not (config.get("twilio", "account_sid") and config.get("twilio", "auth_token") and config.get("twilio", "from_number")):
|
||||||
|
logging.error(
|
||||||
|
"Twilio account SID, auth token, and from number are required for outbound SMS functionality, define them in the config file or as environment variables."
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Now the config is loaded, set the logger level
|
# Now the config is loaded, set the logger level
|
||||||
level = getattr(logging, config.get("logging", "level", fallback="INFO").upper(), logging.INFO)
|
level = getattr(logging, config.get("logging", "level", fallback="INFO").upper(), logging.INFO)
|
||||||
logging.getLogger().setLevel(level)
|
logging.getLogger().setLevel(level)
|
||||||
|
|
||||||
|
# Configure Twilio client if we have credentials
|
||||||
|
if config.has_section("twilio") and config.get("twilio", "account_sid") and config.get("twilio", "auth_token"):
|
||||||
|
twilio_client = Client(
|
||||||
|
config.get("twilio", "account_sid"),
|
||||||
|
config.get("twilio", "auth_token"),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
twilio_client = None
|
||||||
|
logging.warning("No Twilio credentials found, outbound SMS functionality will be disabled.")
|
||||||
|
|
||||||
# Start bot
|
# Start bot
|
||||||
telegram_bot = TelegramSmsBot(token=config.get("telegram", "bot_token"))
|
telegram_bot = TelegramSmsBot(
|
||||||
|
token=config.get("telegram", "bot_token"),
|
||||||
|
twilio_client=twilio_client,
|
||||||
|
twilio_from_number=config.get("twilio", "from_number", fallback=None),
|
||||||
|
)
|
||||||
|
|
||||||
# Set the owner ID if configured
|
# Set the owner ID if configured
|
||||||
if config.has_option("telegram", "owner_id"):
|
if config.has_option("telegram", "owner_id"):
|
||||||
@@ -76,7 +105,7 @@ def main():
|
|||||||
account_sid=config.get("twilio", "account_sid", fallback=None),
|
account_sid=config.get("twilio", "account_sid", fallback=None),
|
||||||
auth_token=config.get("twilio", "auth_token", fallback=None),
|
auth_token=config.get("twilio", "auth_token", fallback=None),
|
||||||
)
|
)
|
||||||
webhooks.set_bot(telegram_bot)
|
webhooks.set_telegram_application(telegram_bot)
|
||||||
|
|
||||||
# Build a uvicorn ASGI server
|
# Build a uvicorn ASGI server
|
||||||
flask_app = uvicorn.Server(
|
flask_app = uvicorn.Server(
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from telegram.ext import (
|
|||||||
ContextTypes,
|
ContextTypes,
|
||||||
TypeHandler,
|
TypeHandler,
|
||||||
)
|
)
|
||||||
|
from twilio.rest import Client
|
||||||
|
|
||||||
from smsbot.utils import get_smsbot_version
|
from smsbot.utils import get_smsbot_version
|
||||||
|
|
||||||
@@ -17,11 +18,20 @@ COMMAND_COUNT = Counter("telegram_command_count", "Total number of commands proc
|
|||||||
|
|
||||||
|
|
||||||
class TelegramSmsBot:
|
class TelegramSmsBot:
|
||||||
def __init__(self, token: str, owners: list[int] = [], subscribers: list[int] = []):
|
def __init__(
|
||||||
|
self,
|
||||||
|
token: str,
|
||||||
|
twilio_client: Client | None = None,
|
||||||
|
twilio_from_number: str | None = None,
|
||||||
|
owners: list[int] = [],
|
||||||
|
subscribers: list[int] = [],
|
||||||
|
):
|
||||||
self.logger = logging.getLogger(self.__class__.__name__)
|
self.logger = logging.getLogger(self.__class__.__name__)
|
||||||
self.app = Application.builder().token(token).build()
|
self.app = Application.builder().token(token).build()
|
||||||
self.owners = owners
|
self.owners = owners
|
||||||
self.subscribers = subscribers
|
self.subscribers = subscribers
|
||||||
|
self.twilio_client = twilio_client
|
||||||
|
self.twilio_from_number = twilio_from_number
|
||||||
|
|
||||||
self.init_handlers()
|
self.init_handlers()
|
||||||
|
|
||||||
@@ -30,6 +40,7 @@ class TelegramSmsBot:
|
|||||||
self.app.add_handler(CommandHandler(["help", "start"], self.handler_help))
|
self.app.add_handler(CommandHandler(["help", "start"], self.handler_help))
|
||||||
self.app.add_handler(CommandHandler("subscribe", self.handler_subscribe))
|
self.app.add_handler(CommandHandler("subscribe", self.handler_subscribe))
|
||||||
self.app.add_handler(CommandHandler("unsubscribe", self.handler_unsubscribe))
|
self.app.add_handler(CommandHandler("unsubscribe", self.handler_unsubscribe))
|
||||||
|
self.app.add_handler(CommandHandler("sms", self.handler_sms))
|
||||||
|
|
||||||
async def callback(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
async def callback(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
"""Handle the update"""
|
"""Handle the update"""
|
||||||
@@ -97,3 +108,22 @@ class TelegramSmsBot:
|
|||||||
await update.message.reply_markdown("You have successfully unsubscribed from updates.")
|
await update.message.reply_markdown("You have successfully unsubscribed from updates.")
|
||||||
else:
|
else:
|
||||||
self.logger.info(f"User {user_id} is not subscribed.")
|
self.logger.info(f"User {user_id} is not subscribed.")
|
||||||
|
|
||||||
|
@REQUEST_TIME.time()
|
||||||
|
async def handler_sms(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""Handle sending SMS requests"""
|
||||||
|
if update.effective_user and update.message:
|
||||||
|
user_id = update.effective_user.id
|
||||||
|
if self.twilio_client and self.twilio_from_number:
|
||||||
|
to = context.args[0] if context.args else "No recipient provided"
|
||||||
|
message = context.args[1] if context.args else "No message provided"
|
||||||
|
self.logger.info(f"Sending SMS from user {user_id} -> {to}: {message}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.twilio_client.messages.create(body=message, to=to, from_=self.twilio_from_number)
|
||||||
|
except Exception:
|
||||||
|
self.logger.exception("Failed to send SMS due to exception")
|
||||||
|
await update.message.reply_markdown("Failed to send SMS")
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
await update.message.reply_markdown("Twilio client is not configured, cannot send SMS.")
|
||||||
|
|||||||
5
smsbot/utils/__init__.py
Normal file
5
smsbot/utils/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from importlib.metadata import version
|
||||||
|
|
||||||
|
|
||||||
|
def get_smsbot_version() -> str:
|
||||||
|
return version("smsbot")
|
||||||
@@ -1,10 +1,3 @@
|
|||||||
from importlib.metadata import version
|
|
||||||
|
|
||||||
|
|
||||||
def get_smsbot_version() -> str:
|
|
||||||
return version("smsbot")
|
|
||||||
|
|
||||||
|
|
||||||
class TwilioWebhookPayload:
|
class TwilioWebhookPayload:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse(data: dict[str, str]) -> "TwilioCall | TwilioMessage | None":
|
def parse(data: dict[str, str]) -> "TwilioCall | TwilioMessage | None":
|
||||||
@@ -6,7 +6,8 @@ from prometheus_client import Counter, Summary, make_wsgi_app
|
|||||||
from twilio.request_validator import RequestValidator
|
from twilio.request_validator import RequestValidator
|
||||||
from werkzeug.middleware.dispatcher import DispatcherMiddleware
|
from werkzeug.middleware.dispatcher import DispatcherMiddleware
|
||||||
|
|
||||||
from smsbot.utils import TwilioWebhookPayload, get_smsbot_version
|
from smsbot.utils import get_smsbot_version
|
||||||
|
from smsbot.utils.twilio import TwilioWebhookPayload
|
||||||
|
|
||||||
REQUEST_TIME = Summary("webhook_request_processing_seconds", "Time spent processing request")
|
REQUEST_TIME = Summary("webhook_request_processing_seconds", "Time spent processing request")
|
||||||
MESSAGE_COUNT = Counter("webhook_message_count", "Total number of messages processed")
|
MESSAGE_COUNT = Counter("webhook_message_count", "Total number of messages processed")
|
||||||
@@ -68,8 +69,9 @@ class TwilioWebhookHandler(object):
|
|||||||
|
|
||||||
return decorated_function
|
return decorated_function
|
||||||
|
|
||||||
def set_bot(self, bot):
|
def set_telegram_application(self, app):
|
||||||
self.bot = bot
|
"""Set the Telegram application instance to use for any webhook calls"""
|
||||||
|
self.telegram_app = app
|
||||||
|
|
||||||
async def index(self) -> str:
|
async def index(self) -> str:
|
||||||
return f'smsbot v{get_smsbot_version()} - <a href="https://github.com/nikdoof/smsbot">GitHub</a>'
|
return f'smsbot v{get_smsbot_version()} - <a href="https://github.com/nikdoof/smsbot">GitHub</a>'
|
||||||
@@ -78,8 +80,8 @@ class TwilioWebhookHandler(object):
|
|||||||
"""Return basic health information"""
|
"""Return basic health information"""
|
||||||
return {
|
return {
|
||||||
"version": get_smsbot_version(),
|
"version": get_smsbot_version(),
|
||||||
"owners": self.bot.owners,
|
"owners": self.telegram_app.owners,
|
||||||
"subscribers": len(self.bot.subscribers),
|
"subscribers": len(self.telegram_app.subscribers),
|
||||||
}
|
}
|
||||||
|
|
||||||
@time(REQUEST_TIME)
|
@time(REQUEST_TIME)
|
||||||
@@ -88,7 +90,7 @@ class TwilioWebhookHandler(object):
|
|||||||
current_app.logger.info("Received SMS from {From}: {Body}".format(**request.values.to_dict()))
|
current_app.logger.info("Received SMS from {From}: {Body}".format(**request.values.to_dict()))
|
||||||
hook_data = TwilioWebhookPayload.parse(request.values.to_dict())
|
hook_data = TwilioWebhookPayload.parse(request.values.to_dict())
|
||||||
if hook_data:
|
if hook_data:
|
||||||
await self.bot.send_subscribers(hook_data.to_markdownv2())
|
await self.telegram_app.send_subscribers(hook_data.to_markdownv2())
|
||||||
|
|
||||||
# Return a blank response
|
# Return a blank response
|
||||||
MESSAGE_COUNT.inc()
|
MESSAGE_COUNT.inc()
|
||||||
@@ -100,7 +102,7 @@ class TwilioWebhookHandler(object):
|
|||||||
current_app.logger.info("Received Call from {From}".format(**request.values.to_dict()))
|
current_app.logger.info("Received Call from {From}".format(**request.values.to_dict()))
|
||||||
hook_data = TwilioWebhookPayload.parse(request.values.to_dict())
|
hook_data = TwilioWebhookPayload.parse(request.values.to_dict())
|
||||||
if hook_data:
|
if hook_data:
|
||||||
await self.bot.send_subscribers(hook_data.to_markdownv2())
|
await self.telegram_app.send_subscribers(hook_data.to_markdownv2())
|
||||||
|
|
||||||
# Always reject calls
|
# Always reject calls
|
||||||
CALL_COUNT.inc()
|
CALL_COUNT.inc()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from smsbot.utils import TwilioMessage
|
from smsbot.utils.twilio import TwilioMessage
|
||||||
|
|
||||||
|
|
||||||
def test_twiliomessage_normal():
|
def test_twiliomessage_normal():
|
||||||
|
|||||||
2
uv.lock
generated
2
uv.lock
generated
@@ -592,7 +592,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smsbot"
|
name = "smsbot"
|
||||||
version = "0.1.1"
|
version = "0.2.2"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "flask", extra = ["async"] },
|
{ name = "flask", extra = ["async"] },
|
||||||
|
|||||||
Reference in New Issue
Block a user