Compare commits

..

3 Commits

Author SHA1 Message Date
Elisiário Couto
02c4f5c6ef chore(ci): Bump version to 2025.9.14 2025-09-18 11:49:36 +01:00
Elisiário Couto
30d7c2ed4e chore(ci): Prevent double GitHub Actions runs on new releases. 2025-09-18 11:21:04 +01:00
Elisiário Couto
61442a598f fix(config): Remove aliases for configuration keys that were disabling telegram notifications in some cases. 2025-09-18 11:09:43 +01:00
12 changed files with 81 additions and 60 deletions

View File

@@ -10,6 +10,7 @@ jobs:
test-python: test-python:
name: Test Python name: Test Python
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, 'chore(ci): Bump version to')"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -32,6 +33,7 @@ jobs:
test-frontend: test-frontend:
name: Test Frontend name: Test Frontend
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, 'chore(ci): Bump version to')"
defaults: defaults:
run: run:
working-directory: ./frontend working-directory: ./frontend

View File

@@ -1,4 +1,30 @@
## 2025.9.14 (2025/09/18)
### Bug Fixes
- **config:** Remove aliases for configuration keys that were disabling telegram notifications in some cases. ([61442a59](https://github.com/elisiariocouto/leggen/commit/61442a598fa7f38c568e3df7e1d924ed85df7491))
### Miscellaneous Tasks
- **ci:** Prevent double GitHub Actions runs on new releases. ([30d7c2ed](https://github.com/elisiariocouto/leggen/commit/30d7c2ed4e9aff144837a1f0ed67a8ded0b5d72a))
## 2025.9.14 (2025/09/18)
### Bug Fixes
- **config:** Remove aliases for configuration keys that were disabling telegram notifications in some cases. ([61442a59](https://github.com/elisiariocouto/leggen/commit/61442a598fa7f38c568e3df7e1d924ed85df7491))
### Miscellaneous Tasks
- **ci:** Prevent double GitHub Actions runs on new releases. ([30d7c2ed](https://github.com/elisiariocouto/leggen/commit/30d7c2ed4e9aff144837a1f0ed67a8ded0b5d72a))
## 2025.9.13 (2025/09/17) ## 2025.9.13 (2025/09/17)
### Bug Fixes ### Bug Fixes

View File

@@ -146,8 +146,8 @@ enabled = true
# Optional: Transaction filters for notifications # Optional: Transaction filters for notifications
[filters] [filters]
case-insensitive = ["salary", "utility"] case_insensitive = ["salary", "utility"]
case-sensitive = ["SpecificStore"] case_sensitive = ["SpecificStore"]
``` ```
## 📖 Usage ## 📖 Usage

View File

@@ -20,11 +20,11 @@ enabled = true
# Optional: Telegram notifications # Optional: Telegram notifications
[notifications.telegram] [notifications.telegram]
api-key = "your-bot-token" token = "your-bot-token"
chat-id = 12345 chat_id = 12345
enabled = true enabled = true
# Optional: Transaction filters for notifications # Optional: Transaction filters for notifications
[filters] [filters]
case-insensitive = ["salary", "utility"] case_insensitive = ["salary", "utility"]
case-sensitive = ["SpecificStore"] case_sensitive = ["SpecificStore"]

View File

@@ -37,15 +37,15 @@ async def get_notification_settings() -> APIResponse:
if discord_config.get("webhook") if discord_config.get("webhook")
else None, else None,
telegram=TelegramConfig( telegram=TelegramConfig(
token="***" if telegram_config.get("api-key") else "", token="***" if telegram_config.get("token") else "",
chat_id=telegram_config.get("chat-id", 0), chat_id=telegram_config.get("chat_id", 0),
enabled=telegram_config.get("enabled", True), enabled=telegram_config.get("enabled", True),
) )
if telegram_config.get("api-key") if telegram_config.get("token")
else None, else None,
filters=NotificationFilters( filters=NotificationFilters(
case_insensitive=filters_config.get("case-insensitive", []), case_insensitive=filters_config.get("case_insensitive", []),
case_sensitive=filters_config.get("case-sensitive"), case_sensitive=filters_config.get("case_sensitive"),
), ),
) )
@@ -77,17 +77,17 @@ async def update_notification_settings(settings: NotificationSettings) -> APIRes
if settings.telegram: if settings.telegram:
notifications_config["telegram"] = { notifications_config["telegram"] = {
"api-key": settings.telegram.token, "token": settings.telegram.token,
"chat-id": settings.telegram.chat_id, "chat_id": settings.telegram.chat_id,
"enabled": settings.telegram.enabled, "enabled": settings.telegram.enabled,
} }
# Update filters config # Update filters config
filters_config: Dict[str, Any] = {} filters_config: Dict[str, Any] = {}
if settings.filters.case_insensitive: if settings.filters.case_insensitive:
filters_config["case-insensitive"] = settings.filters.case_insensitive filters_config["case_insensitive"] = settings.filters.case_insensitive
if settings.filters.case_sensitive: if settings.filters.case_sensitive:
filters_config["case-sensitive"] = settings.filters.case_sensitive filters_config["case_sensitive"] = settings.filters.case_sensitive
# Save to config # Save to config
if notifications_config: if notifications_config:
@@ -153,12 +153,12 @@ async def get_notification_services() -> APIResponse:
"telegram": { "telegram": {
"name": "Telegram", "name": "Telegram",
"enabled": bool( "enabled": bool(
notifications_config.get("telegram", {}).get("api-key") notifications_config.get("telegram", {}).get("token")
and notifications_config.get("telegram", {}).get("chat-id") and notifications_config.get("telegram", {}).get("chat_id")
), ),
"configured": bool( "configured": bool(
notifications_config.get("telegram", {}).get("api-key") notifications_config.get("telegram", {}).get("token")
and notifications_config.get("telegram", {}).get("chat-id") and notifications_config.get("telegram", {}).get("chat_id")
), ),
"active": notifications_config.get("telegram", {}).get("enabled", True), "active": notifications_config.get("telegram", {}).get("enabled", True),
}, },

View File

@@ -22,8 +22,8 @@ class DiscordNotificationConfig(BaseModel):
class TelegramNotificationConfig(BaseModel): class TelegramNotificationConfig(BaseModel):
token: str = Field(..., alias="api-key", description="Telegram bot token") token: str = Field(..., description="Telegram bot token")
chat_id: int = Field(..., alias="chat-id", description="Telegram chat ID") chat_id: int = Field(..., description="Telegram chat ID")
enabled: bool = Field(default=True, description="Enable Telegram notifications") enabled: bool = Field(default=True, description="Enable Telegram notifications")
@@ -33,12 +33,8 @@ class NotificationConfig(BaseModel):
class FilterConfig(BaseModel): class FilterConfig(BaseModel):
case_insensitive: Optional[List[str]] = Field( case_insensitive: Optional[List[str]] = Field(default_factory=list)
default_factory=list, alias="case-insensitive" case_sensitive: Optional[List[str]] = Field(default_factory=list)
)
case_sensitive: Optional[List[str]] = Field(
default_factory=list, alias="case-sensitive"
)
class SyncScheduleConfig(BaseModel): class SyncScheduleConfig(BaseModel):
@@ -60,6 +56,3 @@ class Config(BaseModel):
notifications: Optional[NotificationConfig] = None notifications: Optional[NotificationConfig] = None
filters: Optional[FilterConfig] = None filters: Optional[FilterConfig] = None
scheduler: SchedulerConfig = Field(default_factory=SchedulerConfig) scheduler: SchedulerConfig = Field(default_factory=SchedulerConfig)
class Config:
validate_by_name = True

View File

@@ -29,8 +29,8 @@ def escape_markdown(text: str) -> str:
def send_expire_notification(ctx: click.Context, notification: dict): def send_expire_notification(ctx: click.Context, notification: dict):
token = ctx.obj["notifications"]["telegram"]["api-key"] token = ctx.obj["notifications"]["telegram"]["token"]
chat_id = ctx.obj["notifications"]["telegram"]["chat-id"] chat_id = ctx.obj["notifications"]["telegram"]["chat_id"]
bot_url = f"https://api.telegram.org/bot{token}/sendMessage" bot_url = f"https://api.telegram.org/bot{token}/sendMessage"
info("Sending expiration notification to Telegram") info("Sending expiration notification to Telegram")
message = "*💲 [Leggen](https://github.com/elisiariocouto/leggen)*\n" message = "*💲 [Leggen](https://github.com/elisiariocouto/leggen)*\n"
@@ -54,8 +54,8 @@ def send_expire_notification(ctx: click.Context, notification: dict):
def send_transaction_message(ctx: click.Context, transactions: list): def send_transaction_message(ctx: click.Context, transactions: list):
token = ctx.obj["notifications"]["telegram"]["api-key"] token = ctx.obj["notifications"]["telegram"]["token"]
chat_id = ctx.obj["notifications"]["telegram"]["chat-id"] chat_id = ctx.obj["notifications"]["telegram"]["chat_id"]
bot_url = f"https://api.telegram.org/bot{token}/sendMessage" bot_url = f"https://api.telegram.org/bot{token}/sendMessage"
info(f"Got {len(transactions)} new transactions, sending message to Telegram") info(f"Got {len(transactions)} new transactions, sending message to Telegram")
message = "*💲 [Leggen](https://github.com/elisiariocouto/leggen)*\n" message = "*💲 [Leggen](https://github.com/elisiariocouto/leggen)*\n"

View File

@@ -63,8 +63,8 @@ class NotificationService:
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
"""Filter transactions based on notification criteria""" """Filter transactions based on notification criteria"""
matching = [] matching = []
filters_case_insensitive = self.filters_config.get("case-insensitive", []) filters_case_insensitive = self.filters_config.get("case_insensitive", [])
filters_case_sensitive = self.filters_config.get("case-sensitive", []) filters_case_sensitive = self.filters_config.get("case_sensitive", [])
for transaction in transactions: for transaction in transactions:
description = transaction.get("description", "") description = transaction.get("description", "")
@@ -159,8 +159,8 @@ class NotificationService:
ctx.obj = { ctx.obj = {
"notifications": { "notifications": {
"telegram": { "telegram": {
"api-key": telegram_config.get("token"), "token": telegram_config.get("token"),
"chat-id": telegram_config.get("chat_id"), "chat_id": telegram_config.get("chat_id"),
} }
} }
} }
@@ -219,8 +219,8 @@ class NotificationService:
ctx.obj = { ctx.obj = {
"notifications": { "notifications": {
"telegram": { "telegram": {
"api-key": telegram_config.get("token"), "token": telegram_config.get("token"),
"chat-id": telegram_config.get("chat_id"), "chat_id": telegram_config.get("chat_id"),
} }
} }
} }
@@ -277,8 +277,8 @@ class NotificationService:
ctx.obj = { ctx.obj = {
"notifications": { "notifications": {
"telegram": { "telegram": {
"api-key": telegram_config.get("token"), "token": telegram_config.get("token"),
"chat-id": telegram_config.get("chat_id"), "chat_id": telegram_config.get("chat_id"),
} }
} }
} }

View File

@@ -29,7 +29,7 @@ def send_notification(ctx: click.Context, transactions: list):
warning("No filters are enabled, skipping notifications") warning("No filters are enabled, skipping notifications")
return return
filters_case_insensitive = ctx.obj.get("filters", {}).get("case-insensitive", {}) filters_case_insensitive = ctx.obj.get("filters", {}).get("case_insensitive", {})
# Add transaction to the list of transactions to be sent as a notification # Add transaction to the list of transactions to be sent as a notification
notification_transactions = [] notification_transactions = []

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "leggen" name = "leggen"
version = "2025.9.13" version = "2025.9.14"
description = "An Open Banking CLI" description = "An Open Banking CLI"
authors = [{ name = "Elisiário Couto", email = "elisiario@couto.io" }] authors = [{ name = "Elisiário Couto", email = "elisiario@couto.io" }]
requires-python = "~=3.13.0" requires-python = "~=3.13.0"

View File

@@ -216,8 +216,8 @@ class TestConfig:
"""Test filters configuration access.""" """Test filters configuration access."""
custom_config = { custom_config = {
"filters": { "filters": {
"case-insensitive": ["salary", "utility"], "case_insensitive": ["salary", "utility"],
"case-sensitive": ["SpecificStore"], "case_sensitive": ["SpecificStore"],
} }
} }
@@ -225,6 +225,6 @@ class TestConfig:
config._config = custom_config config._config = custom_config
filters = config.filters_config filters = config.filters_config
assert "salary" in filters["case-insensitive"] assert "salary" in filters["case_insensitive"]
assert "utility" in filters["case-insensitive"] assert "utility" in filters["case_insensitive"]
assert "SpecificStore" in filters["case-sensitive"] assert "SpecificStore" in filters["case_sensitive"]

2
uv.lock generated
View File

@@ -220,7 +220,7 @@ wheels = [
[[package]] [[package]]
name = "leggen" name = "leggen"
version = "2025.9.13" version = "2025.9.14"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "apscheduler" }, { name = "apscheduler" },