From 7d003d128fecc55a1a23957c358ec1797287d0c3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Sun, 17 Nov 2024 18:56:55 +0100
Subject: [PATCH 01/55] bug: Redirect URLs for Aliexpress are not working
---
handlers/aliexpress_api_handler.py | 71 ++++++++++++++++++++++++++----
1 file changed, 62 insertions(+), 9 deletions(-)
diff --git a/handlers/aliexpress_api_handler.py b/handlers/aliexpress_api_handler.py
index c649905..e156d14 100644
--- a/handlers/aliexpress_api_handler.py
+++ b/handlers/aliexpress_api_handler.py
@@ -4,7 +4,7 @@
import requests
import time
-from urllib.parse import urlparse, urlunparse
+from urllib.parse import urlparse, urlunparse,parse_qs
from handlers.base_handler import BaseHandler
from handlers.aliexpress_handler import ALIEXPRESS_PATTERN
@@ -100,10 +100,50 @@ async def _convert_to_aliexpress_affiliate(self, source_url):
return None
+ def _get_real_url(self, link: str) -> str:
+ """
+ Checks for a 'redirectUrl' parameter in the given link and extracts its value if present.
+ If no 'redirectUrl' is found, returns the original link.
+
+ Parameters:
+ - link: The original URL to analyze.
+
+ Returns:
+ - A string representing the resolved URL or the original link if no redirect exists.
+ """
+ parsed_url = urlparse(link)
+ query_params = parse_qs(parsed_url.query)
+
+ # Check if the 'redirectUrl' parameter exists in the query
+ if "redirectUrl" in query_params:
+ redirect_url = query_params["redirectUrl"][0] # Extract the first value
+ return requests.utils.unquote(redirect_url) # Decode the URL
+ return link # Return the original link if no redirectUrl exists
+
+ def _resolve_redirects(self, message_text: str) -> dict:
+ """
+ Resolves redirected URLs (e.g., redirectUrl) in the message text.
+
+ Parameters:
+ - message_text: The text of the message to process.
+
+ Returns:
+ - A dictionary mapping original URLs to resolved URLs.
+ """
+ urls_in_message = re.findall(r"https?://[^\s]+", message_text)
+
+ original_to_resolved = {}
+ for url in urls_in_message:
+ resolved_url = self._get_real_url(url) # Resolve redirectUrl if present
+ original_to_resolved[url] = resolved_url
+
+ return original_to_resolved
+
async def handle_links(self, context) -> bool:
"""Handles AliExpress links and converts them using the Aliexpress API."""
message, modified_text, self.selected_users = self._unpack_context(context)
+
# Retrieve the AliExpress configuration from self.selected_users
aliexpress_config = self.selected_users.get("aliexpress.com", {}).get(
"aliexpress", {}
@@ -120,10 +160,14 @@ async def handle_links(self, context) -> bool:
f"{message.message_id}: Handling AliExpress links in the message..."
)
- new_text = modified_text
+ # Map original links (with redirectUrl) to resolved links
+ original_to_resolved = self._resolve_redirects(modified_text)
- # Find AliExpress links in the message text
- aliexpress_links = re.findall(ALIEXPRESS_PATTERN, new_text)
+ # Extract resolved URLs that match the pattern
+ aliexpress_links = [
+ resolved for original, resolved in original_to_resolved.items()
+ if re.match(ALIEXPRESS_PATTERN, resolved)
+ ]
if not aliexpress_links:
self.logger.info(
@@ -135,11 +179,20 @@ async def handle_links(self, context) -> bool:
f"{message.message_id}: Found {len(aliexpress_links)} AliExpress links. Processing..."
)
- # Convert the links to affiliate links
- for link in aliexpress_links:
- affiliate_link = await self._convert_to_aliexpress_affiliate(link)
- if affiliate_link:
- new_text = new_text.replace(link, affiliate_link)
+ # Map original links to their affiliate counterparts
+ updated_links = {}
+
+ # Convert the resolved links to affiliate links
+ for original, resolved in original_to_resolved.items():
+ if resolved in aliexpress_links:
+ affiliate_link = await self._convert_to_aliexpress_affiliate(resolved)
+ if affiliate_link:
+ updated_links[original] = affiliate_link # Replace the original link
+
+ # Replace original links with their affiliate counterparts
+ new_text = modified_text
+ for original, affiliate in updated_links.items():
+ new_text = new_text.replace(original, affiliate)
# Add discount codes if they are configured
if discount_codes:
From 9d972493f5722cf436d2eb73eff6dbd5c9bb3c29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 14:48:52 +0100
Subject: [PATCH 02/55] pre-commit
---
handlers/.pre-commit-config.yaml | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 handlers/.pre-commit-config.yaml
diff --git a/handlers/.pre-commit-config.yaml b/handlers/.pre-commit-config.yaml
new file mode 100644
index 0000000..11fe74b
--- /dev/null
+++ b/handlers/.pre-commit-config.yaml
@@ -0,0 +1,28 @@
+minimum_pre_commit_version: "3.0.4"
+repos:
+ - repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.3.2
+ hooks:
+ - id: ruff
+ args:
+ - --fix
+ - id: ruff-format
+ - repo: "https://github.com/pre-commit/pre-commit-hooks"
+ rev: "v4.5.0"
+ hooks:
+ - id: end-of-file-fixer
+ - id: trailing-whitespace
+ - id: check-json
+ - id: check-toml
+ - id: check-yaml
+ - repo: https://github.com/pre-commit/mirrors-prettier
+ rev: v4.0.0-alpha.8
+ hooks:
+ - id: prettier
+ - repo: "https://github.com/pre-commit/mirrors-mypy"
+ rev: "v1.13.0"
+ hooks:
+ - id: "mypy"
+ name: "Check type hints (mypy)"
+ args: [--ignore-missing-imports]
+ verbose: true
From f6865bb86d60513e790596f3185e3cc42fb2edee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 14:50:27 +0100
Subject: [PATCH 03/55] pre-commit
---
{handlers => tests}/.pre-commit-config.yaml | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename {handlers => tests}/.pre-commit-config.yaml (100%)
diff --git a/handlers/.pre-commit-config.yaml b/tests/.pre-commit-config.yaml
similarity index 100%
rename from handlers/.pre-commit-config.yaml
rename to tests/.pre-commit-config.yaml
From 8bd7ef07fd8b2a87f8c4218c138b5f695cd2976d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 14:51:26 +0100
Subject: [PATCH 04/55] pre-commit
---
tests/.pre-commit-config.yaml => .pre-commit-config.yaml | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename tests/.pre-commit-config.yaml => .pre-commit-config.yaml (100%)
diff --git a/tests/.pre-commit-config.yaml b/.pre-commit-config.yaml
similarity index 100%
rename from tests/.pre-commit-config.yaml
rename to .pre-commit-config.yaml
From 63a9e1f38f07ae8d1a0fcbac53766fa3543dd23a Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 13:51:39 +0000
Subject: [PATCH 05/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
.dockerignore | 2 +-
.gitattributes | 2 +-
.gitignore | 2 +-
.vscode/settings.json | 20 +++------
botaffiumeiro.py | 6 ++-
data/config.yaml | 4 +-
ha-addon/CHANGELOG.md | 62 +++++++++++++++++-----------
ha-addon/README.md | 29 +++++++------
ha-addon/config.yaml | 1 -
ha-addon/json2yaml.py | 13 +++---
ha-addon/translations/en.yaml | 2 +-
ha-addon/translations/es.yaml | 1 -
handlers/aliexpress_api_handler.py | 13 ++++--
handlers/aliexpress_handler.py | 8 +++-
handlers/base_handler.py | 23 +++++------
tests/test_admitad_handler.py | 2 -
tests/test_aliexpress_api_handler.py | 1 -
tests/test_aliexpress_handler.py | 4 +-
tests/test_amazon_handler.py | 1 -
tests/test_awin_handler.py | 1 -
tests/test_base_handler.py | 5 +--
tests/test_botaffiumeiro.py | 42 ++++++++++---------
tests/test_config.py | 4 --
23 files changed, 131 insertions(+), 117 deletions(-)
diff --git a/.dockerignore b/.dockerignore
index e9e4f8f..e7238aa 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -2,4 +2,4 @@
.gitattributes
.gitignore
LICENSE
-README.md
\ No newline at end of file
+README.md
diff --git a/.gitattributes b/.gitattributes
index eba1110..dfe0770 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1,2 @@
# Auto detect text files and perform LF normalization
-* text=auto
\ No newline at end of file
+* text=auto
diff --git a/.gitignore b/.gitignore
index 5fd8f5f..38280d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,4 +14,4 @@ nosetests.xml
coverage.xml
# Environments
-.venv
\ No newline at end of file
+.venv
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 8609c0d..a37fb2c 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,15 +1,7 @@
{
- "python.analysis.typeCheckingMode": "off",
- "python.testing.pytestArgs": [
- "tests"
- ],
- "python.testing.unittestEnabled": true,
- "python.testing.pytestEnabled": false,
- "python.testing.unittestArgs": [
- "-v",
- "-s",
- "./tests",
- "-p",
- "test_*.py"
- ]
-}
\ No newline at end of file
+ "python.analysis.typeCheckingMode": "off",
+ "python.testing.pytestArgs": ["tests"],
+ "python.testing.unittestEnabled": true,
+ "python.testing.pytestEnabled": false,
+ "python.testing.unittestArgs": ["-v", "-s", "./tests", "-p", "test_*.py"]
+}
diff --git a/botaffiumeiro.py b/botaffiumeiro.py
index 341de47..302283b 100644
--- a/botaffiumeiro.py
+++ b/botaffiumeiro.py
@@ -48,12 +48,15 @@ def is_user_excluded(user: User) -> bool:
logger.debug(f"User {username} (ID: {user_id}) is excluded: {excluded}")
return excluded
+
def expand_shortened_url(url: str):
"""Expands shortened URLs by following redirects using a HEAD request."""
logger.info(f"Try expanding shortened URL: {url}")
# Strip trailing punctuation if present
stripped_url = url.rstrip(".,")
- punctuation = url[len(stripped_url):] # Store the punctuation for re-attachment if needed
+ punctuation = url[
+ len(stripped_url) :
+ ] # Store the punctuation for re-attachment if needed
try:
# Utilizamos HEAD para seguir las redirecciones sin descargar todo el contenido
response = requests.get(stripped_url, allow_redirects=True)
@@ -64,6 +67,7 @@ def expand_shortened_url(url: str):
logger.error(f"Error expanding shortened URL {url}: {e}")
return url
+
def extract_embedded_url(query_params):
"""
Extracts any valid URLs embedded in query parameters.
diff --git a/data/config.yaml b/data/config.yaml
index 6ed5f7c..e73a1ca 100644
--- a/data/config.yaml
+++ b/data/config.yaml
@@ -36,7 +36,7 @@ amazon:
awin:
publisher_id: "1639881"
advertisers:
-# aliexpress.com: "11640"
+ # aliexpress.com: "11640"
pccomponentes.com: "20982"
leroymerlin.es: "20598"
@@ -62,7 +62,7 @@ aliexpress:
app_secret: "" # Replace with your AliExpress API secret
tracking_id: "" # Replace with your AliExpress tracking ID
discount_codes: |
- 💥 AliExpress discount codes:
+ 💥 AliExpress discount codes:
💰2$ off for purchases over 20$: IFPTKOH
💰5$ off for purchases over 50$: IFPT35D
💰25$ off for purchases over 200$: IFPQDMH
diff --git a/ha-addon/CHANGELOG.md b/ha-addon/CHANGELOG.md
index 2ea8b4b..051f7b6 100644
--- a/ha-addon/CHANGELOG.md
+++ b/ha-addon/CHANGELOG.md
@@ -1,67 +1,81 @@
# 2.1.4.2
-* crashes because it is passigne creator percentage as an str not a number
+
+- crashes because it is passigne creator percentage as an str not a number
# 2.1.4.1
-* bug: Percentage donation to creators where not passing from addon configuration to Bottafiumeiro app.
+
+- bug: Percentage donation to creators where not passing from addon configuration to Bottafiumeiro app.
# 2.1.4.0
-* bug: If a short link has a . or , at the end won't expand and is not processed by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/69
-* feat: Expand always URLs, to avoid loosing some links by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/70
+
+- bug: If a short link has a . or , at the end won't expand and is not processed by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/69
+- feat: Expand always URLs, to avoid loosing some links by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/70
# 2.1.3.0
-* bug: Aliexpress codes showed two times by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/67
+
+- bug: Aliexpress codes showed two times by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/67
# 2.1.2.0
-* addon bug, not updating to the latest version
+
+- addon bug, not updating to the latest version
# 2.1.1.1
-* bug:rexexp error fixed, addon failed to work
+
+- bug:rexexp error fixed, addon failed to work
# 2.1.1.0
-* bug: amzn.eu not handled by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/62
+
+- bug: amzn.eu not handled by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/62
# 2.1.0
+
### NEW!
+
Tradedoubler affiliate platform support: This platform allows affiliations to stores like mediamarkt, philips-hue, balay, boshc, dyson, HP, Huawey, PCBOX, etc.
### Improvements and fixes
-* feat: Refactor pattern handlers by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/57
-* bug: Short urls are not working by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/59
-* Feat/tradedoubler by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/58
+
+- feat: Refactor pattern handlers by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/57
+- bug: Short urls are not working by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/59
+- Feat/tradedoubler by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/58
# 2.0.3
-* bug: long Aliexpress links fails when asking API for an affiliate link by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/53
-* feat: Show examples of HTML code in config.yaml by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/48
-* doc: Add video tutorial to documentation by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/50
+
+- bug: long Aliexpress links fails when asking API for an affiliate link by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/53
+- feat: Show examples of HTML code in config.yaml by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/48
+- doc: Add video tutorial to documentation by @hectorzin in https://github.com/hectorzin/botaffiumeiro/pull/50
**Full Changelog**: https://github.com/hectorzin/botaffiumeiro/compare/2.0.1...2.0.2
+
# 2.0.2
+
Bug/Amazon configuration error while sending from HA Addon to Botaffiumeiro
# 2.0.1
+
Bug/domain_added_two_times
# 2.0.0
## WARNING: BREAKING CHANGES
+
The way to configure Amazon links has changed.
This is because it has been unified with affiliate stores and now allows handling Amazon from different countries.
The new way to configure it is as follows:
amazon:
- amazon.es: botaffiumeiro_cofee-21
- amazon.com: hectorzindomo-20
- amazon.com.au: hectorzindomo-22
- amazon.co.uk: hectorzindomo-21
- amazon.fr: hectorzindo0d-21
- amazon.it: hectorzindo04-21
- amazon.de: hectorzindo0e-21
+amazon.es: botaffiumeiro_cofee-21
+amazon.com: hectorzindomo-20
+amazon.com.au: hectorzindomo-22
+amazon.co.uk: hectorzindomo-21
+amazon.fr: hectorzindo0d-21
+amazon.it: hectorzindo04-21
+amazon.de: hectorzindo0e-21
## New features
+
- allow use of HTML in predefined messages: We can now use bold, italic, etc styles in the predefined messages as shown in the following image:
-
+ 
- You can use custom commands so that your Telegram group users can request AliExpress discount codes: /discount /aliexpress, etc.
- Improved Logging levels
- We've replaced the classic "give a coffee" with a parameter that represents the approximate % (as it is random) of times the affiliate link will belong to the creators. This parameter is entirely optional and can be set between 0 and 100%; by default, it is set to 10%. Thanks!
-
-
diff --git a/ha-addon/README.md b/ha-addon/README.md
index 556f312..6f8caad 100644
--- a/ha-addon/README.md
+++ b/ha-addon/README.md
@@ -23,8 +23,8 @@ Below is a breakdown of all the available configuration fields, including exampl
- id: "Username1"
- id: "Username2"
```
-**NOTE**: If you want to leave the list empty you must write []
+ **NOTE**: If you want to leave the list empty you must write []
- **discount_keywords**: List of keywords that trigger the bot to display AliExpress discount codes when used in a message. You can define multiple keywords in a list format using the following structure:
@@ -46,12 +46,12 @@ Below is a breakdown of all the available configuration fields, including exampl
A list of domains and ids per domain:
- ```yaml
- - domain: amazon.es
- id: botaffiumeiro_cofee-21
- - domain: amazon.com
- id: hectorzindomo-20
- ```
+```yaml
+- domain: amazon.es
+ id: botaffiumeiro_cofee-21
+- domain: amazon.com
+ id: hectorzindomo-20
+```
### 4. Aliexpress settings
@@ -65,7 +65,8 @@ A list of domains and ids per domain:
- line: "💥 2$ off for purchases over 20$: 【CODE1】"
- line: "💰 5$ off for purchases over 50$: 【CODE2】"
```
-**NOTE**: If you want to leave the list empty you must write []
+
+ **NOTE**: If you want to leave the list empty you must write []
### 5. Awin Settings
@@ -78,7 +79,8 @@ A list of domains and ids per domain:
- domain: "store2.com"
id: "advertiser_id_2"
```
-**NOTE**: If you want to leave the list empty you must write []
+
+ **NOTE**: If you want to leave the list empty you must write []
### 6. Admitad Settings
@@ -91,7 +93,8 @@ A list of domains and ids per domain:
- domain: "store2.com"
id: "campaign_id_2"
```
-**NOTE**: If you want to leave the list empty you must write []
+
+ **NOTE**: If you want to leave the list empty you must write []
### 7. Tradedoubler Settings
@@ -104,7 +107,8 @@ A list of domains and ids per domain:
- domain: "store2.com"
id: "campaign_id_2"
```
-**NOTE**: If you want to leave the list empty you must write []
+
+ **NOTE**: If you want to leave the list empty you must write []
### 8. Support for creators
@@ -117,7 +121,8 @@ A list of domains and ids per domain:
You can define this percentage in the following format:
```yaml
- creator_affiliate_percentage: 10 # Example: 10%
+ creator_affiliate_percentage: 10 # Example: 10%
+ ```
### 9. LOG
diff --git a/ha-addon/config.yaml b/ha-addon/config.yaml
index 8d97e52..4fdaa46 100644
--- a/ha-addon/config.yaml
+++ b/ha-addon/config.yaml
@@ -49,4 +49,3 @@ schema:
id: str?
creator_affiliate_percentage: str?
log_level: list(DEBUG|INFO|WARN|ERROR|CRITICAL)
-
diff --git a/ha-addon/json2yaml.py b/ha-addon/json2yaml.py
index 215e8d0..3aebced 100644
--- a/ha-addon/json2yaml.py
+++ b/ha-addon/json2yaml.py
@@ -15,7 +15,9 @@
"bot_token": data.get("bot_token", ""),
"delete_messages": data.get("delete_messages", True),
"excluded_users": [user.get("id") for user in data.get("excluded_users", [])],
- "discount_keywords": [user.get("key") for user in data.get("discount_keywords", [])]
+ "discount_keywords": [
+ user.get("key") for user in data.get("discount_keywords", [])
+ ],
},
"messages": {
"affiliate_link_modified": data.get(
@@ -27,8 +29,7 @@
),
},
"amazon": {
- advertiser["domain"]: advertiser["id"]
- for advertiser in data.get("amazon", [])
+ advertiser["domain"]: advertiser["id"] for advertiser in data.get("amazon", [])
},
"awin": {
"publisher_id": data.get("awin_publisher_id", ""),
@@ -61,8 +62,10 @@
},
"log_level": data.get("log_level", "INFO"),
"affiliate_settings": {
- "creator_affiliate_percentage": int(data.get("creator_affiliate_percentage", 10)),
- }
+ "creator_affiliate_percentage": int(
+ data.get("creator_affiliate_percentage", 10)
+ ),
+ },
}
# Save the YAML file
diff --git a/ha-addon/translations/en.yaml b/ha-addon/translations/en.yaml
index e828150..5bb4e4f 100644
--- a/ha-addon/translations/en.yaml
+++ b/ha-addon/translations/en.yaml
@@ -52,7 +52,7 @@ configuration:
description: "List of Tradedoubler advertisers and their campaign IDs (format: - domain: DOMAIN and id: ID)."
creator_affiliate_percentage:
name: "Creator Affiliate Percentage"
- description: "Creators support 🙏. Defines the percentage of links that will be replaced with affiliate links belonging to the software creators when the user does not have a link for a specific domain. Thanks!"
+ description: "Creators support 🙏. Defines the percentage of links that will be replaced with affiliate links belonging to the software creators when the user does not have a link for a specific domain. Thanks!"
log_level:
name: "Log Level"
description: "Set the logging level for the bot (DEBUG, INFO, WARN, ERROR, CRITICAL)."
diff --git a/ha-addon/translations/es.yaml b/ha-addon/translations/es.yaml
index 729eede..111dfc0 100644
--- a/ha-addon/translations/es.yaml
+++ b/ha-addon/translations/es.yaml
@@ -56,4 +56,3 @@ configuration:
log_level:
name: "Nivel de Log"
description: "Configura el nivel de registro (DEBUG, INFO, WARN, ERROR, CRITICAL)."
-
diff --git a/handlers/aliexpress_api_handler.py b/handlers/aliexpress_api_handler.py
index e156d14..1e4ea16 100644
--- a/handlers/aliexpress_api_handler.py
+++ b/handlers/aliexpress_api_handler.py
@@ -4,7 +4,7 @@
import requests
import time
-from urllib.parse import urlparse, urlunparse,parse_qs
+from urllib.parse import urlparse, urlunparse, parse_qs
from handlers.base_handler import BaseHandler
from handlers.aliexpress_handler import ALIEXPRESS_PATTERN
@@ -37,7 +37,9 @@ async def _convert_to_aliexpress_affiliate(self, source_url):
"""Converts a regular AliExpress link into an affiliate link using the Aliexpress API."""
self.logger.info(f"Converting AliExpress link to affiliate link: {source_url}")
parsed_url = urlparse(source_url)
- source_url = urlunparse((parsed_url.scheme, parsed_url.netloc, parsed_url.path, '', '', ''))
+ source_url = urlunparse(
+ (parsed_url.scheme, parsed_url.netloc, parsed_url.path, "", "", "")
+ )
timestamp = str(int(time.time() * 1000)) # Current timestamp in milliseconds
# Get AliExpress-specific configuration from self.selected_users
@@ -165,7 +167,8 @@ async def handle_links(self, context) -> bool:
# Extract resolved URLs that match the pattern
aliexpress_links = [
- resolved for original, resolved in original_to_resolved.items()
+ resolved
+ for original, resolved in original_to_resolved.items()
if re.match(ALIEXPRESS_PATTERN, resolved)
]
@@ -187,7 +190,9 @@ async def handle_links(self, context) -> bool:
if resolved in aliexpress_links:
affiliate_link = await self._convert_to_aliexpress_affiliate(resolved)
if affiliate_link:
- updated_links[original] = affiliate_link # Replace the original link
+ updated_links[original] = (
+ affiliate_link # Replace the original link
+ )
# Replace original links with their affiliate counterparts
new_text = modified_text
diff --git a/handlers/aliexpress_handler.py b/handlers/aliexpress_handler.py
index 93ee1a8..cdbd324 100644
--- a/handlers/aliexpress_handler.py
+++ b/handlers/aliexpress_handler.py
@@ -20,10 +20,14 @@ async def show_discount_codes(self, context) -> None:
aliexpress_data = self.selected_users.get("aliexpress.com", {})
# Check if there are any discount codes available for AliExpress
- aliexpress_discount_codes = aliexpress_data.get("aliexpress", {}).get("discount_codes", None)
+ aliexpress_discount_codes = aliexpress_data.get("aliexpress", {}).get(
+ "discount_codes", None
+ )
if not aliexpress_discount_codes:
- self.logger.info(f"{message.message_id}: Discount codes are empty. Skipping reply.")
+ self.logger.info(
+ f"{message.message_id}: Discount codes are empty. Skipping reply."
+ )
return
# Send the discount codes as a response to the original message
diff --git a/handlers/base_handler.py b/handlers/base_handler.py
index 6e66d41..4e810fb 100644
--- a/handlers/base_handler.py
+++ b/handlers/base_handler.py
@@ -4,9 +4,8 @@
from urllib.parse import urlparse, parse_qs
from abc import ABC, abstractmethod
from telegram import Message
-from urllib.parse import urlparse, parse_qs, urlencode
+from urllib.parse import urlencode
from typing import Tuple
-from telegram import Message
from publicsuffix2 import get_sld
from config import config_data
@@ -17,13 +16,13 @@
class BaseHandler(ABC):
-
def __init__(self):
-
self.logger = logging.getLogger(__name__)
self.selected_users = {}
- def _unpack_context(self, context) -> Tuple[
+ def _unpack_context(
+ self, context
+ ) -> Tuple[
Message,
str,
]:
@@ -233,7 +232,7 @@ def _build_affiliate_url_pattern(self, advertiser_key):
return url_pattern_template.format(
domain_pattern,
)
-
+
def _extract_store_urls(self, message_text: str, url_pattern: str) -> list:
"""
Extracts store URLs directly from the message text or from URLs embedded in query parameters.
@@ -248,10 +247,12 @@ def _extract_store_urls(self, message_text: str, url_pattern: str) -> list:
extracted_urls = []
def _extract_and_append(original, extracted):
- """Helper function to parse and append URL and domain."""
- parsed_url = urlparse(extracted)
- domain = get_sld(parsed_url.netloc) # Use get_sld to extract domain (handles cases like .co.uk)
- extracted_urls.append((original, extracted, domain))
+ """Helper function to parse and append URL and domain."""
+ parsed_url = urlparse(extracted)
+ domain = get_sld(
+ parsed_url.netloc
+ ) # Use get_sld to extract domain (handles cases like .co.uk)
+ extracted_urls.append((original, extracted, domain))
# Find all URLs in the message text
urls_in_message = re.findall(r"https?://[^\s]+", message_text)
@@ -273,7 +274,6 @@ def _extract_and_append(original, extracted):
_extract_and_append(url, value)
return extracted_urls
-
async def _process_store_affiliate_links(
self,
@@ -287,7 +287,6 @@ async def _process_store_affiliate_links(
message, text, self.selected_users = self._unpack_context(context)
url_pattern = self._build_affiliate_url_pattern(affiliate_platform)
-
if not url_pattern:
self.logger.info(f"{message.message_id}: No affiliate list")
return False
diff --git a/tests/test_admitad_handler.py b/tests/test_admitad_handler.py
index ba89a22..ffaa867 100644
--- a/tests/test_admitad_handler.py
+++ b/tests/test_admitad_handler.py
@@ -11,8 +11,6 @@ def handle_links(self, _):
class TestHandleAdmitadLinks(unittest.IsolatedAsyncioTestCase):
-
-
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_admitad_aliexpress_link_admitad_config_empty_list(
self, mock_process
diff --git a/tests/test_aliexpress_api_handler.py b/tests/test_aliexpress_api_handler.py
index ba7fb28..8538b26 100644
--- a/tests/test_aliexpress_api_handler.py
+++ b/tests/test_aliexpress_api_handler.py
@@ -12,7 +12,6 @@ def handle_links(self, _):
class TestHandleAliExpressAPILinks(unittest.IsolatedAsyncioTestCase):
-
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_aliexpress_no_app_key(self, mock_process):
"""Test: No action is taken if AliExpress app_key is empty in selected_users."""
diff --git a/tests/test_aliexpress_handler.py b/tests/test_aliexpress_handler.py
index 8d84ba7..71f32b7 100644
--- a/tests/test_aliexpress_handler.py
+++ b/tests/test_aliexpress_handler.py
@@ -1,13 +1,11 @@
import unittest
-from unittest.mock import AsyncMock, patch
+from unittest.mock import AsyncMock
-from handlers.base_handler import BaseHandler
from handlers.aliexpress_handler import AliexpressHandler
class TestHandleAliExpressLinks(unittest.IsolatedAsyncioTestCase):
-
async def test_aliexpress_links_without_affiliate(self):
"""Test AliExpress links when they are not in the advertiser list and APP_KEY is empty."""
diff --git a/tests/test_amazon_handler.py b/tests/test_amazon_handler.py
index cf91ef3..604f894 100644
--- a/tests/test_amazon_handler.py
+++ b/tests/test_amazon_handler.py
@@ -13,7 +13,6 @@ def handle_links(self, _):
class TestHandleAmazonLinks(unittest.IsolatedAsyncioTestCase):
-
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_no_amazon_link(self, mock_process):
"""Test that no action is taken if there are no Amazon links in the message."""
diff --git a/tests/test_awin_handler.py b/tests/test_awin_handler.py
index 05ca8af..32982e6 100644
--- a/tests/test_awin_handler.py
+++ b/tests/test_awin_handler.py
@@ -4,7 +4,6 @@
class TestHandleAwinLinks(unittest.IsolatedAsyncioTestCase):
-
async def test_no_action_when_awin_publisher_id_is_none(self):
"""Test that no action is taken if AWIN_PUBLISHER_ID is None."""
diff --git a/tests/test_base_handler.py b/tests/test_base_handler.py
index 60beda4..214ed8b 100644
--- a/tests/test_base_handler.py
+++ b/tests/test_base_handler.py
@@ -1,6 +1,6 @@
import unittest
-from unittest.mock import AsyncMock, Mock, patch
+from unittest.mock import AsyncMock, patch
from urllib.parse import unquote
from handlers.base_handler import BaseHandler, PATTERN_AFFILIATE_URL_QUERY
from config import config_data
@@ -12,7 +12,6 @@ def handle_links(self):
class TestGenerateAffiliateUrl(unittest.TestCase):
-
def setUp(self):
"""Set up the TestHandler instance."""
self.handler = TestHandler()
@@ -203,7 +202,6 @@ def test_affiliate_link_with_url_param_replacement(self):
class TestProcessMessage(unittest.TestCase):
-
def setUp(self):
"""Set up the TestHandler instance."""
self.handler = TestHandler() # Pasar selected_users al crear la instancia
@@ -377,7 +375,6 @@ async def test_send_message_without_username(self):
class TestBuildAffiliateUrlPattern(unittest.TestCase):
-
def test_admitad_url_pattern(self):
"""
Test: Verify that admitad_url_pattern is correctly generated from multiple users' domains.
diff --git a/tests/test_botaffiumeiro.py b/tests/test_botaffiumeiro.py
index 468f413..7d8701e 100644
--- a/tests/test_botaffiumeiro.py
+++ b/tests/test_botaffiumeiro.py
@@ -176,7 +176,6 @@ def test_modify_link_without_user(
class TestExpandShortenedURL(unittest.TestCase):
-
@patch("requests.get")
def test_expand_amazon_short_url(self, mock_get):
"""
@@ -223,7 +222,6 @@ def test_expand_aliexpress_short_url(self, mock_get):
class TestExtractDomainsFromMessage(unittest.TestCase):
-
def test_direct_domain_extraction(self):
"""
Test: Extract domains directly from the message without embedded URLs.
@@ -506,7 +504,7 @@ def test_extract_domains_with_long_urls(self):
# Text with long URLs already expanded
message_text = (
"Check out this Amazon deal: https://www.amazon.com/dp/B08XYZ123 "
- "and this AliExpress: https://es.aliexpress.com/item/12345.html" ## We use a localized URL because expanding always, can change generic to local URL
+ "and this AliExpress: https://es.aliexpress.com/item/12345.html" ## We use a localized URL because expanding always, can change generic to local URL
)
# Call the function that processes the message
@@ -514,18 +512,19 @@ def test_extract_domains_with_long_urls(self):
# Verify that the correct domains were extracted
self.assertIn("amazon.com", domains) # Should find amazon.com
- self.assertIn("aliexpress.com", domains) # Should find aliexpress.com
+ self.assertIn("aliexpress.com", domains) # Should find aliexpress.com
# Verify that the full URLs are present in the modified message
self.assertIn("https://www.amazon.com/dp/B08XYZ123", modified_message)
- self.assertIn("aliexpress.com/item/12345.html", modified_message) # Should find aliexpress.com (not checking exact subdomain, as it may expand to different regions)
+ self.assertIn(
+ "aliexpress.com/item/12345.html", modified_message
+ ) # Should find aliexpress.com (not checking exact subdomain, as it may expand to different regions)
# Ensure there were no unnecessary modifications
self.assertEqual(message_text, modified_message)
class TestExtractEmbeddedUrl(unittest.TestCase):
-
def test_no_embedded_urls(self):
"""
Test: No embedded URLs in the query parameters.
@@ -593,7 +592,6 @@ def test_multiple_values_for_single_param(self):
class TestPrepareMessage(unittest.TestCase):
-
@patch("botaffiumeiro.extract_domains_from_message")
@patch("botaffiumeiro.select_user_for_domain")
def test_prepare_message_with_valid_domains(
@@ -701,10 +699,13 @@ def test_prepare_message_with_mixed_domains(
Test: Simulate a message where one domain has a user and another domain does not.
"""
# Mock the domains extracted from the message
- mock_extract_domains.return_value = {
- "amazon.com",
- "unknown.com",
- }, "Modified message with expanded URLs"
+ mock_extract_domains.return_value = (
+ {
+ "amazon.com",
+ "unknown.com",
+ },
+ "Modified message with expanded URLs",
+ )
# Define a function for side_effect to return users based on the domain
def select_user_side_effect(domain):
@@ -747,9 +748,10 @@ def test_prepare_message_with_only_unknown_domains(
Test: Simulate a message where all domains are unknown.
"""
# Mock the domains extracted from the message
- mock_extract_domains.return_value = {
- "unknown.com"
- }, "Modified message with expanded URLs"
+ mock_extract_domains.return_value = (
+ {"unknown.com"},
+ "Modified message with expanded URLs",
+ )
# Mock the user selection for the unknown domain
mock_select_user.return_value = None # No user for unknown.com
@@ -781,10 +783,13 @@ def test_prepare_message_with_expanded_urls(
Test: Ensure that prepare_message returns both the selected users and the modified message.
"""
# Mock the domains and the modified message returned by extract_domains_from_message
- mock_extract_domains.return_value = {
- "amazon.com",
- "aliexpress.com",
- }, "Modified message with expanded URLs"
+ mock_extract_domains.return_value = (
+ {
+ "amazon.com",
+ "aliexpress.com",
+ },
+ "Modified message with expanded URLs",
+ )
# Define a function for side_effect to return users based on the domain
def select_user_side_effect(domain):
@@ -839,7 +844,6 @@ def test_prepare_message_with_no_text(self, mock_select_user, mock_extract_domai
class TestSelectUserForDomain(unittest.TestCase):
-
@patch(
"botaffiumeiro.domain_percentage_table",
{
diff --git a/tests/test_config.py b/tests/test_config.py
index 2957bd2..06a85f7 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -4,7 +4,6 @@
class TestAddToDomainTable(unittest.TestCase):
-
@patch("config.domain_percentage_table", {})
def test_user_with_affiliate_id(self):
"""
@@ -102,7 +101,6 @@ def test_multiple_users_in_same_domain(self):
class TestAddAffiliateStoresDomains(unittest.TestCase):
-
@patch("config.domain_percentage_table", {})
def test_no_advertisers(self):
"""
@@ -235,7 +233,6 @@ def test_different_percentages(self):
class TestAddUserToDomainPercentageTable(unittest.TestCase):
-
@patch("config.domain_percentage_table", {})
def test_no_affiliate_ids(self):
"""
@@ -552,7 +549,6 @@ def test_multiple_users_with_aliexpress_on_different_platforms(self):
class TestAdjustDomainAffiliatePercentages(unittest.TestCase):
-
@patch("config.domain_percentage_table", {})
def test_only_user_in_domain(self):
"""
From c4ea2ef3bf4b133430f4a64d1d8107bda233ff96 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 15:00:27 +0100
Subject: [PATCH 06/55] pre-commit
---
handlers/aliexpress_handler.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/handlers/aliexpress_handler.py b/handlers/aliexpress_handler.py
index 93ee1a8..a7d44b3 100644
--- a/handlers/aliexpress_handler.py
+++ b/handlers/aliexpress_handler.py
@@ -39,7 +39,7 @@ async def handle_links(self, context) -> bool:
"""Handles both long and short AliExpress links in the message."""
message, modified_text, self.selected_users = self._unpack_context(context)
# Extraemos self.selected_users.get("aliexpress.com", {}) a una variable
- aliexpress_data = self.selected_users.get("aliexpress.com", {})
+ self.selected_users.get("aliexpress.com", {})
aliexpress_links = re.findall(ALIEXPRESS_PATTERN, modified_text)
From c4acbacfe98ec01f425e8fd9d11246404c1b51a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 15:21:07 +0100
Subject: [PATCH 07/55] pre-commit, no time to see how to install it local
---
.pre-commit-config.yaml | 4 ++-
tests/test_aliexpress_api_handler.py | 1 +
tests/test_aliexpress_handler.py | 1 +
tests/test_amazon_handler.py | 3 +++
tests/test_awin_handler.py | 8 ++++++
tests/test_botaffiumeiro.py | 39 +---------------------------
6 files changed, 17 insertions(+), 39 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 11fe74b..e04489f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -24,5 +24,7 @@ repos:
hooks:
- id: "mypy"
name: "Check type hints (mypy)"
- args: [--ignore-missing-imports]
+ args:
+ - --ignore-missing-imports
+ - --explicit-package-bases
verbose: true
diff --git a/tests/test_aliexpress_api_handler.py b/tests/test_aliexpress_api_handler.py
index 8538b26..d17632b 100644
--- a/tests/test_aliexpress_api_handler.py
+++ b/tests/test_aliexpress_api_handler.py
@@ -108,6 +108,7 @@ async def test_long_aliexpress_link(self, mock_process, mock_convert, mock_expan
)
mock_process.assert_called_with(mock_message, expected_message)
+ self.assertTrue(result)
if __name__ == "__main__":
diff --git a/tests/test_aliexpress_handler.py b/tests/test_aliexpress_handler.py
index 71f32b7..79a188a 100644
--- a/tests/test_aliexpress_handler.py
+++ b/tests/test_aliexpress_handler.py
@@ -39,6 +39,7 @@ async def test_aliexpress_links_without_affiliate(self):
"💥 AliExpress discount codes: 💰 5% off!",
reply_to_message_id=mock_message.message_id,
)
+ self.assertTrue(result)
async def test_no_discount_codes(self):
"""Test that no action is taken when ALIEXPRESS_DISCOUNT_CODES is empty."""
diff --git a/tests/test_amazon_handler.py b/tests/test_amazon_handler.py
index 604f894..6034b8c 100644
--- a/tests/test_amazon_handler.py
+++ b/tests/test_amazon_handler.py
@@ -97,6 +97,7 @@ async def test_long_amazon_link_without_affiliate(self, mock_process, mock_expan
mock_message,
"Here is a product: https://www.amazon.com/dp/B08N5WRWNW?tag=com_affiliate_id",
)
+ self.assertTrue(result)
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_amazon_link_with_affiliate(self, mock_process):
@@ -124,6 +125,7 @@ async def test_amazon_link_with_affiliate(self, mock_process):
mock_message,
"Here is a product: https://www.amazon.com/dp/B08N5WRWNW?tag=our_affiliate_id",
)
+ self.assertTrue(result)
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_explicit_amazon_link_conversion(self, mock_process):
@@ -151,6 +153,7 @@ async def test_explicit_amazon_link_conversion(self, mock_process):
re.match(expected_pattern, actual_call_args),
f"URL '{actual_call_args}' does not match the expected pattern",
)
+ self.assertTrue(result)
if __name__ == "__main__":
diff --git a/tests/test_awin_handler.py b/tests/test_awin_handler.py
index 32982e6..bf8bb4d 100644
--- a/tests/test_awin_handler.py
+++ b/tests/test_awin_handler.py
@@ -53,6 +53,7 @@ async def test_awin_aliexpress_link_awin_config_empty_list(self):
"selected_users": mock_selected_users,
}
result = await handler.handle_links(context)
+ self.assertFalse(result)
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_awin_link_in_list(self, mock_process):
@@ -87,6 +88,7 @@ async def test_awin_link_in_list(self, mock_process):
expected_message = "Check this out: https://www.awin1.com/cread.php?awinmid=20982&awinaffid=my_awin_id&ued=https://www.giftmio.com/some-product I hope you like it"
mock_process.assert_called_with(mock_message, expected_message)
+ self.assertTrue(result)
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_awin_affiliate_link_from_list(self, mock_process):
@@ -116,6 +118,7 @@ async def test_awin_affiliate_link_from_list(self, mock_process):
expected_message = "Here is a product: https://www.awin1.com/cread.php?awinmid=20982&awinaffid=my_awin_id&ued=https://www.giftmio.com/some-product I hope you like it"
mock_process.assert_called_with(mock_message, expected_message)
+ self.assertTrue(result)
async def test_awin_affiliate_link_not_in_list(self):
"""Test that an existing Awin affiliate link is NOT modified when the store is NOT in our list of Awin advertisers."""
@@ -142,6 +145,7 @@ async def test_awin_affiliate_link_not_in_list(self):
result = await handler.handle_links(context)
mock_message.chat.send_message.assert_not_called()
+ self.assertFalse(result)
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_awin_aliexpress_link_without_discount(self, mock_process):
@@ -175,6 +179,7 @@ async def test_awin_aliexpress_link_without_discount(self, mock_process):
expected_message = "Check this out: https://www.awin1.com/cread.php?awinmid=11640&awinaffid=my_awin_id&ued=https://www.aliexpress.com/item/1005002958205071.html I hope you like it"
mock_process.assert_called_with(mock_message, expected_message)
+ self.assertTrue(result)
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_awin_aliexpress_link_with_discount(self, mock_process):
@@ -211,6 +216,7 @@ async def test_awin_aliexpress_link_with_discount(self, mock_process):
)
mock_process.assert_called_with(mock_message, expected_message)
+ self.assertTrue(result)
async def test_awin_aliexpress_link_no_awin_config(self):
"""Test AliExpress link when AliExpress is NOT in the Awin list and discount codes should NOT be added."""
@@ -240,6 +246,7 @@ async def test_awin_aliexpress_link_no_awin_config(self):
result = await handler.handle_links(context)
mock_message.chat.send_message.assert_not_called()
+ self.assertFalse(result)
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_awin_no_aliexpress_from_link_with_discount(self, mock_process):
@@ -273,6 +280,7 @@ async def test_awin_no_aliexpress_from_link_with_discount(self, mock_process):
result = await handler.handle_links(context)
mock_process.assert_called_with(mock_message, expected_message)
+ self.assertTrue(result)
if __name__ == "__main__":
diff --git a/tests/test_botaffiumeiro.py b/tests/test_botaffiumeiro.py
index 7d8701e..a0f27a0 100644
--- a/tests/test_botaffiumeiro.py
+++ b/tests/test_botaffiumeiro.py
@@ -309,7 +309,7 @@ def test_amazon_shortened_url(self, mock_expand):
message_text = "Check out this product: https://amzn.to/abc123"
# Simulate the expansion of the shortened URL
- expand_shortened_url = Mock(return_value="https://www.amazon.com/dp/product123")
+ Mock(return_value="https://www.amazon.com/dp/product123")
domains, modified_message = extract_domains_from_message(message_text)
mock_expand.assert_called_once_with("https://amzn.to/abc123")
@@ -407,17 +407,6 @@ def test_amazon_full_url_uk(self):
) # The amazon.co.uk domain should be extracted
self.assertEqual(len(domains), 1) # Should only find one domain
- def test_no_matching_patterns(self):
- """
- Test: No matching domains or patterns in the message.
- """
- message_text = "There are no valid links in this message."
- domains, modified_message = extract_domains_from_message(message_text)
-
- self.assertEqual(
- domains, set()
- ) # Should return an empty set since no domains are matched
-
@patch("requests.get")
def test_expand_amazon_short_url_and_replace_in_message(self, mock_get):
"""
@@ -636,32 +625,6 @@ def select_user_side_effect(domain):
self.assertIn("aliexpress.com", context["selected_users"])
self.assertEqual(context["selected_users"]["aliexpress.com"]["user"], "user2")
- @patch("handlers.base_handler.BaseHandler._extract_domains_from_message")
- @patch("handlers.base_handler.BaseHandler._select_user_for_domain")
- def test_prepare_message_with_no_domains(
- self, mock_select_user, mock_extract_domains
- ):
- """
- Test: Handle a case where no valid domains are found in the message.
- """
- # Mock the domains extracted from the message (empty set and message unchanged)
- mock_extract_domains.return_value = (set(), "This message contains no links.")
-
- # Simulate a message object with text
- message = Mock()
- message.text = "This message contains no links."
-
- # Call the method
- modified_message = prepare_message(message)
-
- # No domains, so the selected_users should be empty
- self.assertEqual(self.handler.selected_users, {})
-
- # Ensure the _select_user_for_domain function was never called
- mock_select_user.assert_not_called()
-
- # Check that the message text was not changed
- self.assertEqual(modified_message, "This message contains no links.")
@patch("botaffiumeiro.extract_domains_from_message")
@patch("botaffiumeiro.select_user_for_domain")
From c91583aca92b7a7df5e60ef653cc2ef5a4c58c71 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 14:21:22 +0000
Subject: [PATCH 08/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
tests/test_botaffiumeiro.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/tests/test_botaffiumeiro.py b/tests/test_botaffiumeiro.py
index a0f27a0..42a0cb7 100644
--- a/tests/test_botaffiumeiro.py
+++ b/tests/test_botaffiumeiro.py
@@ -625,7 +625,6 @@ def select_user_side_effect(domain):
self.assertIn("aliexpress.com", context["selected_users"])
self.assertEqual(context["selected_users"]["aliexpress.com"]["user"], "user2")
-
@patch("botaffiumeiro.extract_domains_from_message")
@patch("botaffiumeiro.select_user_for_domain")
def test_prepare_message_with_no_domains(
From 912e0a10b4bb352d77f04c0a24ea6d51e921c3a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 15:55:31 +0100
Subject: [PATCH 09/55] precommit
---
handlers/base_handler.py | 57 +---------------------------------------
requirements.txt | 1 +
2 files changed, 2 insertions(+), 56 deletions(-)
diff --git a/handlers/base_handler.py b/handlers/base_handler.py
index 4e810fb..e37eea3 100644
--- a/handlers/base_handler.py
+++ b/handlers/base_handler.py
@@ -25,6 +25,7 @@ def _unpack_context(
) -> Tuple[
Message,
str,
+ dict,
]:
return (
context["message"],
@@ -32,62 +33,6 @@ def _unpack_context(
context["selected_users"],
)
- def _expand_shortened_url_from_list(self, url: str, domains: list[str]) -> str:
- """
- Expands shortened URLs by following redirects if the domain matches one of the given domains.
-
- Args:
- url (str): The shortened URL to expand.
- domains (list): A list of domains for which the URL should be expanded.
-
- Returns:
- str: The expanded URL if the domain matches, or the original URL otherwise.
- """
- parsed_url = urlparse(url)
-
- # Check if the domain is in the list of provided domains
- if any(domain in parsed_url.netloc for domain in domains):
- # Call the superclass method to expand the URL
- url = self._expand_shortened_url(url)
-
- return url
-
- def _expand_short_links_from_message(
- self, message_text: str, url_pattern: str, short_domains: list
- ) -> str:
- """
- Expands shortened URLs in a message using a specified pattern and list of short domains.
-
- Args:
- message_text (str): The text of the message to search for short links.
- url_pattern (str): The regular expression pattern to search for short links.
- short_domains (list): A list of domains to check for short links.
-
- Returns:
- str: The message text with expanded URLs.
- """
- new_text = message_text
- short_links = re.findall(url_pattern, message_text)
-
- if short_links:
- self.logger.info(f"Found {len(short_links)} short links. Processing...")
-
- for short_link in short_links:
- full_link = self._expand_shortened_url_from_list(
- short_link, short_domains
- )
- new_text = new_text.replace(short_link, full_link)
-
- return new_text
-
- def _expand_aliexpress_links_from_message(self, message_text: str) -> str:
- new_text = self._expand_short_links_from_message(
- message_text=message_text,
- url_pattern=self._domain_patterns["aliexpress_short_url_pattern"],
- short_domains=["s.click.aliexpress.com"],
- )
- return new_text
-
def _generate_affiliate_url(
self,
original_url: str,
diff --git a/requirements.txt b/requirements.txt
index 3574fc1..380100f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,3 +2,4 @@ python-telegram-bot~=21.6
requests~=2.31
PyYAML~=6.0
publicsuffix2~=2.20191221
+types-PyYAML~=6.0.12.20240917
From 9f7afeb61384709694f4b40094f11bf69d7157b1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 16:06:50 +0100
Subject: [PATCH 10/55] precommit
---
.pre-commit-config.yaml | 2 ++
handlers/base_handler.py | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index e04489f..8956672 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -25,6 +25,8 @@ repos:
- id: "mypy"
name: "Check type hints (mypy)"
args:
+ - --install-types
+ - --non-interactive
- --ignore-missing-imports
- --explicit-package-bases
verbose: true
diff --git a/handlers/base_handler.py b/handlers/base_handler.py
index e37eea3..ccb0242 100644
--- a/handlers/base_handler.py
+++ b/handlers/base_handler.py
@@ -39,7 +39,7 @@ def _generate_affiliate_url(
format_template: str,
affiliate_tag: str,
affiliate_id: str,
- advertiser_id: str = None,
+ advertiser_id: str = "",
) -> str:
"""
Converts a product URL into an affiliate link based on the provided format template.
@@ -69,7 +69,7 @@ def _generate_affiliate_url(
query_params[affiliate_tag] = [affiliate_id]
# Add or update advertiser ID if provided
- if advertiser_id:
+ if advertiser_id != "":
query_params["advertiser_id"] = [advertiser_id]
# Build the new query string
From eb42cfb6fb3da831a52803b09d01875f32b8beda Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 15:07:12 +0000
Subject: [PATCH 11/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
.pre-commit-config.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 8956672..d751e40 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -26,7 +26,7 @@ repos:
name: "Check type hints (mypy)"
args:
- --install-types
- - --non-interactive
+ - --non-interactive
- --ignore-missing-imports
- --explicit-package-bases
verbose: true
From fe4a00caa195b72e04d66fafaf0ed57367d8a630 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 16:20:22 +0100
Subject: [PATCH 12/55] precommit
---
.github/workflows/pre-commit.yml | 30 ++++++++++++++++++++++++++++
.github/workflows/setup_precommit.sh | 7 +++++++
2 files changed, 37 insertions(+)
create mode 100644 .github/workflows/pre-commit.yml
create mode 100644 .github/workflows/setup_precommit.sh
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
new file mode 100644
index 0000000..f9346a5
--- /dev/null
+++ b/.github/workflows/pre-commit.yml
@@ -0,0 +1,30 @@
+name: Run Pre-Commit Checks
+
+on:
+ push:
+ pull_request:
+
+jobs:
+ pre-commit:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.11"
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install pre-commit types-requests types-PyYAML
+ pre-commit install-hooks
+
+ - name: Set up Pre-Commit
+ run: bash setup_precommit.sh
+
+ - name: Run Pre-Commit
+ run: pre-commit run --all-files
diff --git a/.github/workflows/setup_precommit.sh b/.github/workflows/setup_precommit.sh
new file mode 100644
index 0000000..40da1b3
--- /dev/null
+++ b/.github/workflows/setup_precommit.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Instalar pre-commit y las dependencias necesarias
+pip install pre-commit types-requests types-PyYAML
+
+# Instalar hooks de pre-commit
+pre-commit install-hooks
From 4e7fb980cadbb84d8d7b45c61f77a4352fc41e67 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 15:22:21 +0000
Subject: [PATCH 13/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
.github/workflows/pre-commit.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index f9346a5..a60e7ad 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -25,6 +25,6 @@ jobs:
- name: Set up Pre-Commit
run: bash setup_precommit.sh
-
+
- name: Run Pre-Commit
run: pre-commit run --all-files
From 2716030346a17f29ac5c39393dee2954cc60d486 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 16:25:39 +0100
Subject: [PATCH 14/55] precommit
---
.github/workflows/pre-commit.yml | 3 ---
.github/workflows/setup_precommit.sh | 7 -------
2 files changed, 10 deletions(-)
delete mode 100644 .github/workflows/setup_precommit.sh
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index f9346a5..413ba41 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -23,8 +23,5 @@ jobs:
pip install pre-commit types-requests types-PyYAML
pre-commit install-hooks
- - name: Set up Pre-Commit
- run: bash setup_precommit.sh
-
- name: Run Pre-Commit
run: pre-commit run --all-files
diff --git a/.github/workflows/setup_precommit.sh b/.github/workflows/setup_precommit.sh
deleted file mode 100644
index 40da1b3..0000000
--- a/.github/workflows/setup_precommit.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-
-# Instalar pre-commit y las dependencias necesarias
-pip install pre-commit types-requests types-PyYAML
-
-# Instalar hooks de pre-commit
-pre-commit install-hooks
From 78c34b479b1b2be03b3fab318ac1fd2a3f9d10cd Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 15:30:00 +0000
Subject: [PATCH 15/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
.github/workflows/pre-commit.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index 3e51d29..413ba41 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -1,6 +1,5 @@
name: Run Pre-Commit Checks
-
on:
push:
pull_request:
From 6f370d7e3b9975002c99e022cb6e7a066582d4e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 16:56:40 +0100
Subject: [PATCH 16/55] pre-commit
---
.github/workflows/pre-commit.yml | 1 -
botaffiumeiro.py | 9 +++++----
config.py | 2 +-
handlers/aliexpress_api_handler.py | 4 ++--
handlers/patterns.py | 3 ++-
5 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index 3e51d29..78499e3 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -21,7 +21,6 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
- pip install pre-commit types-requests types-PyYAML
pre-commit install-hooks
- name: Run Pre-Commit
diff --git a/botaffiumeiro.py b/botaffiumeiro.py
index 302283b..ed0fc49 100644
--- a/botaffiumeiro.py
+++ b/botaffiumeiro.py
@@ -25,10 +25,6 @@
"aliexpress": ALIEXPRESS_PATTERN,
}
-logging.basicConfig(
- format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
- level=config_data["LOG_LEVEL"],
-)
logger = logging.getLogger(__name__)
logging.getLogger("httpx").setLevel(
logger.getEffectiveLevel() + 10
@@ -315,6 +311,11 @@ def register_discount_handlers(application):
def main() -> None:
"""Start the bot with python-telegram-bot"""
load_configuration()
+
+ logging.basicConfig(
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
+ level=config_data["LOG_LEVEL"],
+ )
logger.info("Configuring the bot")
# Program a job to reaload config every day
diff --git a/config.py b/config.py
index fd6c041..73e2294 100644
--- a/config.py
+++ b/config.py
@@ -13,7 +13,7 @@
logger = logging.getLogger(__name__)
domain_percentage_table = {}
-all_users_configurations = {}
+all_users_configurations: dict[str, dict] = {}
config_data = {
# Telegram
diff --git a/handlers/aliexpress_api_handler.py b/handlers/aliexpress_api_handler.py
index 1e4ea16..20b1872 100644
--- a/handlers/aliexpress_api_handler.py
+++ b/handlers/aliexpress_api_handler.py
@@ -4,7 +4,7 @@
import requests
import time
-from urllib.parse import urlparse, urlunparse, parse_qs
+from urllib.parse import urlparse, urlunparse, parse_qs, unquote
from handlers.base_handler import BaseHandler
from handlers.aliexpress_handler import ALIEXPRESS_PATTERN
@@ -119,7 +119,7 @@ def _get_real_url(self, link: str) -> str:
# Check if the 'redirectUrl' parameter exists in the query
if "redirectUrl" in query_params:
redirect_url = query_params["redirectUrl"][0] # Extract the first value
- return requests.utils.unquote(redirect_url) # Decode the URL
+ return unquote(redirect_url) # Decode the URL
return link # Return the original link if no redirectUrl exists
def _resolve_redirects(self, message_text: str) -> dict:
diff --git a/handlers/patterns.py b/handlers/patterns.py
index 6ed2ee0..d1e443f 100644
--- a/handlers/patterns.py
+++ b/handlers/patterns.py
@@ -1,6 +1,7 @@
from handlers.base_handler import PATTERN_URL_QUERY
+from typing import Dict, Optional
-PATTERNS = {
+PATTERNS: Dict[str, Dict[str, Optional[str]]] = {
"amazon": {
"pattern": (
r"(https?://(?:www\.)?(?:amazon\.[a-z]{2,3}(?:\.[a-z]{2})?|amzn\.to|amzn\.eu)"
From 85fa6a986119965c8141d38fe1a5b3bac08a1296 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 16:59:25 +0100
Subject: [PATCH 17/55] pc
---
.github/workflows/pre-commit.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index 2d2c9fd..7eb7c37 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -20,6 +20,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
+ python -m pip install pre-commit
pre-commit install-hooks
- name: Run Pre-Commit
From c226c003672f9bb0d73e229aefbbab0d37c6c39e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 17:12:39 +0100
Subject: [PATCH 18/55] pc
---
.github/workflows/pre-commit.yml | 1 +
config.py | 3 ++-
handlers/patterns.py | 11 +++++++++--
3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index 7eb7c37..071ad76 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -19,6 +19,7 @@ jobs:
- name: Install dependencies
run: |
+ python -m pip install types-PyYAML types-requests
python -m pip install --upgrade pip
python -m pip install pre-commit
pre-commit install-hooks
diff --git a/config.py b/config.py
index 73e2294..d7f77e2 100644
--- a/config.py
+++ b/config.py
@@ -3,6 +3,7 @@
import requests
from datetime import datetime, timedelta
+from typing import Dict, Any
# Rutas a los archivos de configuración
CONFIG_PATH = "data/config.yaml"
@@ -15,7 +16,7 @@
domain_percentage_table = {}
all_users_configurations: dict[str, dict] = {}
-config_data = {
+config_data: Dict[str, Any] = {
# Telegram
"BOT_TOKEN": "",
"DELETE_MESSAGES": "",
diff --git a/handlers/patterns.py b/handlers/patterns.py
index d1e443f..e144ff1 100644
--- a/handlers/patterns.py
+++ b/handlers/patterns.py
@@ -1,7 +1,14 @@
from handlers.base_handler import PATTERN_URL_QUERY
-from typing import Dict, Optional
+from typing import Dict
-PATTERNS: Dict[str, Dict[str, Optional[str]]] = {
+from typing import TypedDict
+
+class PatternConfig(TypedDict):
+ pattern: str
+ format_template: str
+ affiliate_tag: str
+
+PATTERNS: Dict[str, PatternConfig] = {
"amazon": {
"pattern": (
r"(https?://(?:www\.)?(?:amazon\.[a-z]{2,3}(?:\.[a-z]{2})?|amzn\.to|amzn\.eu)"
From c5ef0d13aa5bcfc549945a8e85d3de9f05631ddc Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 16:13:05 +0000
Subject: [PATCH 19/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
handlers/patterns.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/handlers/patterns.py b/handlers/patterns.py
index e144ff1..0be2cbd 100644
--- a/handlers/patterns.py
+++ b/handlers/patterns.py
@@ -3,11 +3,13 @@
from typing import TypedDict
+
class PatternConfig(TypedDict):
pattern: str
format_template: str
affiliate_tag: str
+
PATTERNS: Dict[str, PatternConfig] = {
"amazon": {
"pattern": (
From 66b896274812beb65a153992c03ea311a9b86bd1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 17:16:40 +0100
Subject: [PATCH 20/55] pc
---
handlers/patterns.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/handlers/patterns.py b/handlers/patterns.py
index e144ff1..a0ce7dc 100644
--- a/handlers/patterns.py
+++ b/handlers/patterns.py
@@ -1,12 +1,11 @@
from handlers.base_handler import PATTERN_URL_QUERY
-from typing import Dict
-from typing import TypedDict
+from typing import Dict, TypedDict, Optional
class PatternConfig(TypedDict):
pattern: str
format_template: str
- affiliate_tag: str
+ affiliate_tag: Optional[str] # Ahora permite valores `None`.
PATTERNS: Dict[str, PatternConfig] = {
"amazon": {
From 930012f7df74716b91e0096a028b5c45907263ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 17:22:34 +0100
Subject: [PATCH 21/55] pc
---
.pre-commit-config.yaml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index d751e40..3c7c728 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -25,7 +25,6 @@ repos:
- id: "mypy"
name: "Check type hints (mypy)"
args:
- - --install-types
- --non-interactive
- --ignore-missing-imports
- --explicit-package-bases
From 35db8a7f8da16d87089603689600f56b9d0974e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 17:24:20 +0100
Subject: [PATCH 22/55] pc
---
.pre-commit-config.yaml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 3c7c728..e04489f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -25,7 +25,6 @@ repos:
- id: "mypy"
name: "Check type hints (mypy)"
args:
- - --non-interactive
- --ignore-missing-imports
- --explicit-package-bases
verbose: true
From 117dcef548b44de7a7db5503f1ec82ef68deac1a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 17:31:54 +0100
Subject: [PATCH 23/55] pc
---
.github/workflows/pre-commit.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index 071ad76..7c472b6 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -22,6 +22,7 @@ jobs:
python -m pip install types-PyYAML types-requests
python -m pip install --upgrade pip
python -m pip install pre-commit
+ pip install types-requests
pre-commit install-hooks
- name: Run Pre-Commit
From 81ec9ce1ddad1cbc398795e136f76960cccca623 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 17:38:30 +0100
Subject: [PATCH 24/55] pc
---
.github/workflows/pre-commit.yml | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index 7c472b6..c53e196 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -19,10 +19,8 @@ jobs:
- name: Install dependencies
run: |
- python -m pip install types-PyYAML types-requests
python -m pip install --upgrade pip
- python -m pip install pre-commit
- pip install types-requests
+ python -m pip install types-PyYAML types-requests pre-commit
pre-commit install-hooks
- name: Run Pre-Commit
From 6c48235201d746b218fef722fa795c234209bd8a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 17:42:04 +0100
Subject: [PATCH 25/55] pc
---
pyproject.toml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 pyproject.toml
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..9655d58
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,5 @@
+[tool.mypy]
+install_types = true
+namespace_packages = true
+ignore_missing_imports = true
+explicit_package_bases = true
From 2bd000d34dde45504aa48550f38b2f4fbe718c80 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 17:46:54 +0100
Subject: [PATCH 26/55] pc
---
pyproject.toml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 9655d58..b9271ea 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,5 +1,5 @@
[tool.mypy]
-install_types = true
+install_types = false
namespace_packages = true
ignore_missing_imports = true
-explicit_package_bases = true
+explicit_package_bases = true
\ No newline at end of file
From 244eaa0febd2e3281ab5ad115f42b8151658fe04 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 16:47:07 +0000
Subject: [PATCH 27/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index b9271ea..551f5a7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -2,4 +2,4 @@
install_types = false
namespace_packages = true
ignore_missing_imports = true
-explicit_package_bases = true
\ No newline at end of file
+explicit_package_bases = true
From 4880a608d0eb2df60c27fd84db3540299a646e6a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 17:54:23 +0100
Subject: [PATCH 28/55] pc
---
.pre-commit-config.yaml | 4 +---
pyproject.toml | 5 -----
2 files changed, 1 insertion(+), 8 deletions(-)
delete mode 100644 pyproject.toml
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index e04489f..11fe74b 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -24,7 +24,5 @@ repos:
hooks:
- id: "mypy"
name: "Check type hints (mypy)"
- args:
- - --ignore-missing-imports
- - --explicit-package-bases
+ args: [--ignore-missing-imports]
verbose: true
diff --git a/pyproject.toml b/pyproject.toml
deleted file mode 100644
index b9271ea..0000000
--- a/pyproject.toml
+++ /dev/null
@@ -1,5 +0,0 @@
-[tool.mypy]
-install_types = false
-namespace_packages = true
-ignore_missing_imports = true
-explicit_package_bases = true
\ No newline at end of file
From 4d120570a092860c09ca4faa9dd38f51d11985b5 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 16:58:42 +0000
Subject: [PATCH 29/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
pyproject.toml | 1 -
1 file changed, 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index 636c1b5..551f5a7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -3,4 +3,3 @@ install_types = false
namespace_packages = true
ignore_missing_imports = true
explicit_package_bases = true
-
From c2d27051b80f281fbe1fb1531d89b3c67d4b9be5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 18:10:52 +0100
Subject: [PATCH 30/55] pc
---
pyproject.toml | 87 +++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 82 insertions(+), 5 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 636c1b5..4f176c4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,83 @@
-[tool.mypy]
-install_types = false
-namespace_packages = true
-ignore_missing_imports = true
-explicit_package_bases = true
+[tool.poetry]
+name = "botaffiumeiro"
+version = "1.0"
+description = "Telegram bot for modifying links with affiliate programs"
+authors = [
+ "Héctor Martínez",
+ "Daniel Martín"
+]
+license = "GPL3"
+readme = "README.md"
+repository = "https://github.com/hectorzin/botaffiumeiro"
+[tool.poetry.dependencies]
+python = ">=3.11,<3.14"
+
+[tool.poetry.group.dev.dependencies]
+pre-commit = "3.6.2"
+pre-commit-hooks = "4.5.0"
+pylint = "3.1.0"
+ruff = "0.3.4"
+mypy = "1.13.0"
+
+[build-system]
+requires = ["poetry-core"]
+build-backend = "poetry.core.masonry.api"
+
+[tool.ruff]
+src = ["botaffiumeiro"]
+
+[tool.ruff.lint]
+ignore = [
+ "ANN101", # Self... explanatory
+ "ANN401", # Opiniated warning on disallowing dynamically typed expressions
+ "D203", # Conflicts with other rules
+ "D213", # Conflicts with other rules
+ "TID252", # Relative imports
+ "RUF012", # Just broken
+
+ # Formatter conflicts
+ "COM812",
+ "COM819",
+ "D206",
+ "E501",
+ "ISC001",
+ "Q000",
+ "Q001",
+ "Q002",
+ "Q003",
+ "W191",
+]
+select = ["ALL"]
+
+[tool.ruff.lint.flake8-import-conventions.extend-aliases]
+"telegram.ext" = "tgext"
+"telegram" = "tg"
+"handlers" = "h"
+"config" = "cfg"
+
+[tool.ruff.lint.isort]
+force-sort-within-sections = true
+known-first-party = [
+ "botaffiumeiro",
+]
+combine-as-imports = true
+
+[tool.pylint."MESSAGES CONTROL"]
+# Reasons disabled:
+# format - handled by ruff
+# duplicate-code - unavoidable
+# used-before-assignment - false positives with TYPE_CHECKING structures
+disable = [
+ "abstract-method",
+ "duplicate-code",
+ "format",
+ "unexpected-keyword-arg",
+ "used-before-assignment",
+]
+
+[tool.isort]
+profile = "black"
+combine_as_imports = true
+known_first_party = ["botaffiumeiro"]
+force_sort_within_sections = true
From 092451c3e29d7853ae3b3d71521cefbd3b03a735 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 17:12:08 +0000
Subject: [PATCH 31/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
botaffiumeiro.py | 84 +++++++++---------
config.py | 53 ++++++-----
ha-addon/json2yaml.py | 3 +-
handlers/aliexpress_api_handler.py | 29 +++---
handlers/aliexpress_handler.py | 2 +-
handlers/base_handler.py | 44 +++++-----
handlers/pattern_handler.py | 1 -
handlers/patterns.py | 4 +-
tests/test_admitad_handler.py | 2 +-
tests/test_aliexpress_api_handler.py | 6 +-
tests/test_aliexpress_handler.py | 4 -
tests/test_amazon_handler.py | 3 +-
tests/test_awin_handler.py | 9 +-
tests/test_base_handler.py | 21 ++---
tests/test_botaffiumeiro.py | 126 ++++++++-------------------
tests/test_config.py | 90 +++++--------------
16 files changed, 184 insertions(+), 297 deletions(-)
diff --git a/botaffiumeiro.py b/botaffiumeiro.py
index ed0fc49..916aa7e 100644
--- a/botaffiumeiro.py
+++ b/botaffiumeiro.py
@@ -1,25 +1,24 @@
import logging
import random
import re
-import requests
import threading
-
-from publicsuffix2 import get_sld
-from telegram import Update, User
-from telegram.ext import Application, CommandHandler, Defaults, filters, MessageHandler
from typing import Tuple
from urllib.parse import parse_qs, urlparse
-from handlers.pattern_handler import PatternHandler
-from handlers.aliexpress_api_handler import AliexpressAPIHandler
-from handlers.aliexpress_handler import AliexpressHandler, ALIEXPRESS_PATTERN
-from handlers.patterns import PATTERNS
from config import (
+ all_users_configurations,
config_data,
domain_percentage_table,
- all_users_configurations,
load_configuration,
)
+from handlers.aliexpress_api_handler import AliexpressAPIHandler
+from handlers.aliexpress_handler import ALIEXPRESS_PATTERN, AliexpressHandler
+from handlers.pattern_handler import PatternHandler
+from handlers.patterns import PATTERNS
+from publicsuffix2 import get_sld
+import requests
+from telegram import Update, User
+from telegram.ext import Application, CommandHandler, Defaults, MessageHandler, filters
DOMAIN_PATTERNS = {
"aliexpress": ALIEXPRESS_PATTERN,
@@ -35,7 +34,6 @@
def is_user_excluded(user: User) -> bool:
"""Checks if the user is in the list of excluded users."""
-
user_id = user.id
username = user.username
logger.debug(f"Checking if user {username} (ID: {user_id}) is excluded.")
@@ -65,14 +63,16 @@ def expand_shortened_url(url: str):
def extract_embedded_url(query_params):
- """
- Extracts any valid URLs embedded in query parameters.
+ """Extracts any valid URLs embedded in query parameters.
- Parameters:
+ Parameters
+ ----------
- query_params: A dictionary of query parameters from a URL.
- Returns:
+ Returns
+ -------
- A set of embedded domains found in the query parameters.
+
"""
embedded_domains = set()
for key, values in query_params.items():
@@ -86,17 +86,19 @@ def extract_embedded_url(query_params):
def extract_domains_from_message(message_text: str) -> Tuple[set, str]:
- """
- Extracts domains from a message using domain patterns and searches for embedded URLs.
+ """Extracts domains from a message using domain patterns and searches for embedded URLs.
Additionally, expands short URLs and replaces them in the message text.
- Parameters:
+ Parameters
+ ----------
- message_text: The text of the message to search for domains.
- Returns:
+ Returns
+ -------
- A tuple containing:
- A set of domains found in the message.
- The modified message text with expanded URLs.
+
"""
domains = set()
@@ -135,14 +137,16 @@ def extract_domains_from_message(message_text: str) -> Tuple[set, str]:
def select_user_for_domain(domain):
- """
- Selects a user for the given domain based on percentages in domain_percentage_table.
+ """Selects a user for the given domain based on percentages in domain_percentage_table.
- Parameters:
+ Parameters
+ ----------
- domain: The domain to select the user for (e.g., "amazon")
- Returns:
+ Returns
+ -------
- The user_data for the selected user, or the first user's data if no random selection occurs.
+
"""
# Get the domain data from the table
domain_data = domain_percentage_table.get(domain, [])
@@ -168,14 +172,16 @@ def select_user_for_domain(domain):
def choose_users(domains) -> dict:
- """
- Handles the domains and selects users randomly based on domain configurations.
+ """Handles the domains and selects users randomly based on domain configurations.
- Parameters:
+ Parameters
+ ----------
- domains: List of domains extracted from the message.
- Returns:
+ Returns
+ -------
- A dictionary of selected users mapped by their respective domains.
+
"""
selected_users = {}
@@ -189,18 +195,20 @@ def choose_users(domains) -> dict:
def prepare_message(message, default_domains=None) -> dict:
- """
- Prepares the message by extracting domains, selecting users, and returning a processing context.
+ """Prepares the message by extracting domains, selecting users, and returning a processing context.
- Parameters:
+ Parameters
+ ----------
- message: The message object containing the text with links.
- default_domains: An optional list of domains to consider if the message is a command or lacks domains.
- Returns:
+ Returns
+ -------
- A dictionary (context) containing:
- The original message (or None if not provided).
- The modified message text with expanded URLs (or None if not applicable).
- A dictionary of selected users mapped to their respective domains (or empty if no users).
+
"""
if not message or not message.text:
return {
@@ -232,7 +240,6 @@ def prepare_message(message, default_domains=None) -> dict:
async def process_link_handlers(message) -> None:
"""Process all link handlers for Amazon, Awin, Admitad, and AliExpress."""
-
logger.info(f"Processing link handlers for message ID: {message.message_id}...")
context = prepare_message(message)
@@ -250,7 +257,6 @@ async def process_link_handlers(message) -> None:
async def modify_link(update: Update, context) -> None:
"""Modifies Amazon, AliExpress, Awin, and Admitad links in messages."""
-
logger.info(f"Received new update (ID: {update.update_id}).")
if not update.message or not update.message.text:
@@ -281,17 +287,13 @@ async def modify_link(update: Update, context) -> None:
def reload_config_periodically(interval):
- """
- Function to reload the configuration periodically every `interval` seconds.
- """
+ """Function to reload the configuration periodically every `interval` seconds."""
load_configuration()
threading.Timer(interval, reload_config_periodically, [interval]).start()
async def handle_discount_command(update: Update, context) -> None:
- """
- Maneja los comandos de descuento llamando a la función 'show_discount_codes' de AliexpressHandler.
- """
+ """Maneja los comandos de descuento llamando a la función 'show_discount_codes' de AliexpressHandler."""
logger.info(f"Processing discount command: {update.message.text}")
context = prepare_message(update.message, ["aliexpress.com"])
@@ -301,9 +303,7 @@ async def handle_discount_command(update: Update, context) -> None:
def register_discount_handlers(application):
- """
- Registra dinámicamente todos los comandos de descuento en el bot.
- """
+ """Registra dinámicamente todos los comandos de descuento en el bot."""
for keyword in config_data["DISCOUNT_KEYWORDS"]:
application.add_handler(CommandHandler(keyword, handle_discount_command))
diff --git a/config.py b/config.py
index d7f77e2..ea6522e 100644
--- a/config.py
+++ b/config.py
@@ -1,9 +1,9 @@
+from datetime import datetime, timedelta
import logging
-import yaml
-import requests
+from typing import Any, Dict
-from datetime import datetime, timedelta
-from typing import Dict, Any
+import requests
+import yaml
# Rutas a los archivos de configuración
CONFIG_PATH = "data/config.yaml"
@@ -36,8 +36,7 @@
def load_user_configuration(user, creator_percentage, user_data):
- """
- Load user-specific configuration for affiliate programs and settings
+ """Load user-specific configuration for affiliate programs and settings
without including global items like API tokens or messages.
"""
return {
@@ -70,15 +69,17 @@ def load_user_configuration(user, creator_percentage, user_data):
def load_user_configuration_from_url(user_id, percentage, url):
- """
- Load user-specific configuration from a URL.
+ """Load user-specific configuration from a URL.
- Parameters:
+ Parameters
+ ----------
- user_id: ID of the user.
- url: URL to fetch the user's configuration YAML file.
- Returns:
+ Returns
+ -------
- Dictionary containing user configuration data.
+
"""
try:
response = requests.get(url)
@@ -93,14 +94,15 @@ def load_user_configuration_from_url(user_id, percentage, url):
def add_to_domain_table(domain, user_id, affiliate_id, percentage):
- """
- Adds a user to the domain percentage table if they have an ID for the given domain.
+ """Adds a user to the domain percentage table if they have an ID for the given domain.
- Parameters:
+ Parameters
+ ----------
- domain: The domain name to add to the table (e.g., "amazon", "aliexpress").
- user_id: The ID of the user (e.g., "user", "HectorziN").
- affiliate_id: The affiliate ID for the given domain.
- percentage: The percentage of time this user should be selected for the domain.
+
"""
if affiliate_id:
if domain not in domain_percentage_table:
@@ -115,14 +117,15 @@ def add_to_domain_table(domain, user_id, affiliate_id, percentage):
def add_affiliate_stores_domains(user_id, advertisers, platform_key, percentage):
- """
- Processes multiple domains for networks like Awin or Admitad.
+ """Processes multiple domains for networks like Awin or Admitad.
- Parameters:
+ Parameters
+ ----------
- user_id: The ID of the user (e.g., "user", "HectorziN")
- advertisers: A dictionary of advertisers for the given platform (e.g., Awin or Admitad)
- platform_key: The key indicating the platform (e.g., "awin", "admitad")
- percentage: The percentage of time this user should be selected for these domains
+
"""
if not advertisers:
logger.info(f"No advertisers for {platform_key}. Skipping {user_id}.")
@@ -134,13 +137,14 @@ def add_affiliate_stores_domains(user_id, advertisers, platform_key, percentage)
def add_user_to_domain_percentage_table(user_id, user_data, percentage):
- """
- Adds a user to the domain percentage table based on their affiliate configurations.
+ """Adds a user to the domain percentage table based on their affiliate configurations.
- Parameters:
+ Parameters
+ ----------
- user_id: ID of the user (e.g., "user", "HectorziN")
- user_data: Configuration data of the user (structured as amazon, awin, admitad, aliexpress)
- percentage: Percentage of time this user should be selected for each domain
+
"""
logger.debug(f"Adding {user_id} with percentage {percentage}")
@@ -181,12 +185,13 @@ def add_user_to_domain_percentage_table(user_id, user_data, percentage):
def adjust_domain_affiliate_percentages(domain, creator_percentage):
- """
- Adjusts the percentages of users in a given domain within domain_percentage_table, ensuring they sum to 100%.
+ """Adjusts the percentages of users in a given domain within domain_percentage_table, ensuring they sum to 100%.
- Parameters:
+ Parameters
+ ----------
- domain: The domain (e.g., "amazon", "aliexpress") to adjust in domain_percentage_table.
- creator_percentage: The percentage of total influence given to creators by the user.
+
"""
logger.debug(f"Adjusting percentages for domain: {domain}")
domain_data = domain_percentage_table.get(domain, [])
@@ -255,10 +260,10 @@ def load_configuration():
logger.info("Loading configuration")
domain_percentage_table.clear()
all_users_configurations.clear()
- with open(CONFIG_PATH, "r", encoding="utf-8") as file:
+ with open(CONFIG_PATH, encoding="utf-8") as file:
config_file_data = yaml.safe_load(file)
- with open(CREATORS_CONFIG_PATH, "r", encoding="utf-8") as file:
+ with open(CREATORS_CONFIG_PATH, encoding="utf-8") as file:
creators_file_data = yaml.safe_load(file)
# Telegram settings
diff --git a/ha-addon/json2yaml.py b/ha-addon/json2yaml.py
index 3aebced..be9d909 100644
--- a/ha-addon/json2yaml.py
+++ b/ha-addon/json2yaml.py
@@ -1,4 +1,5 @@
import json
+
import yaml
# File paths
@@ -6,7 +7,7 @@
yaml_file = "/botaffiumeiro/data/config.yaml"
# Load the JSON file
-with open(json_file, "r") as f:
+with open(json_file) as f:
data = json.load(f)
# Convert JSON into the desired YAML structure
diff --git a/handlers/aliexpress_api_handler.py b/handlers/aliexpress_api_handler.py
index 20b1872..11ca20e 100644
--- a/handlers/aliexpress_api_handler.py
+++ b/handlers/aliexpress_api_handler.py
@@ -1,12 +1,12 @@
-import hmac
import hashlib
+import hmac
import re
-import requests
import time
+from urllib.parse import parse_qs, unquote, urlparse, urlunparse
-from urllib.parse import urlparse, urlunparse, parse_qs, unquote
-from handlers.base_handler import BaseHandler
from handlers.aliexpress_handler import ALIEXPRESS_PATTERN
+from handlers.base_handler import BaseHandler
+import requests
# API endpoint for generating affiliate links
ALIEXPRESS_API_URL = "https://api-sg.aliexpress.com/sync"
@@ -103,15 +103,17 @@ async def _convert_to_aliexpress_affiliate(self, source_url):
return None
def _get_real_url(self, link: str) -> str:
- """
- Checks for a 'redirectUrl' parameter in the given link and extracts its value if present.
+ """Checks for a 'redirectUrl' parameter in the given link and extracts its value if present.
If no 'redirectUrl' is found, returns the original link.
- Parameters:
+ Parameters
+ ----------
- link: The original URL to analyze.
- Returns:
+ Returns
+ -------
- A string representing the resolved URL or the original link if no redirect exists.
+
"""
parsed_url = urlparse(link)
query_params = parse_qs(parsed_url.query)
@@ -123,14 +125,16 @@ def _get_real_url(self, link: str) -> str:
return link # Return the original link if no redirectUrl exists
def _resolve_redirects(self, message_text: str) -> dict:
- """
- Resolves redirected URLs (e.g., redirectUrl) in the message text.
+ """Resolves redirected URLs (e.g., redirectUrl) in the message text.
- Parameters:
+ Parameters
+ ----------
- message_text: The text of the message to process.
- Returns:
+ Returns
+ -------
- A dictionary mapping original URLs to resolved URLs.
+
"""
urls_in_message = re.findall(r"https?://[^\s]+", message_text)
@@ -143,7 +147,6 @@ def _resolve_redirects(self, message_text: str) -> dict:
async def handle_links(self, context) -> bool:
"""Handles AliExpress links and converts them using the Aliexpress API."""
-
message, modified_text, self.selected_users = self._unpack_context(context)
# Retrieve the AliExpress configuration from self.selected_users
diff --git a/handlers/aliexpress_handler.py b/handlers/aliexpress_handler.py
index ce18661..d070323 100644
--- a/handlers/aliexpress_handler.py
+++ b/handlers/aliexpress_handler.py
@@ -1,6 +1,6 @@
import re
-from handlers.base_handler import BaseHandler, PATTERN_URL_QUERY
+from handlers.base_handler import PATTERN_URL_QUERY, BaseHandler
ALIEXPRESS_PATTERN = (
r"(https?://(?:[a-z]{2,3}\.)?aliexpress\.[a-z]{2,3}(?:\.[a-z]{2,3})?"
diff --git a/handlers/base_handler.py b/handlers/base_handler.py
index ccb0242..97fc57b 100644
--- a/handlers/base_handler.py
+++ b/handlers/base_handler.py
@@ -1,14 +1,12 @@
+from abc import ABC, abstractmethod
import logging
import re
-
-from urllib.parse import urlparse, parse_qs
-from abc import ABC, abstractmethod
-from telegram import Message
-from urllib.parse import urlencode
from typing import Tuple
-from publicsuffix2 import get_sld
+from urllib.parse import parse_qs, urlencode, urlparse
from config import config_data
+from publicsuffix2 import get_sld
+from telegram import Message
# Known short URL domains for expansion
PATTERN_URL_QUERY = r"?[^\s]+"
@@ -41,10 +39,10 @@ def _generate_affiliate_url(
affiliate_id: str,
advertiser_id: str = "",
) -> str:
- """
- Converts a product URL into an affiliate link based on the provided format template.
+ """Converts a product URL into an affiliate link based on the provided format template.
Args:
+ ----
original_url (str): The original product URL.
format_template (str): The template for the affiliate URL, e.g., '{domain}/{path_before_query}?{affiliate_tag}={affiliate_id}'.
affiliate_tag (str): The query parameter for the affiliate ID (e.g., 'tag', 'aff_id').
@@ -52,7 +50,9 @@ def _generate_affiliate_url(
advertiser_id (str): The advertiser ID for the platform (optional).
Returns:
+ -------
str: The URL with the affiliate tag and advertiser ID added according to the template.
+
"""
# Parse the original URL
parsed_url = urlparse(original_url)
@@ -102,12 +102,13 @@ def _generate_affiliate_url(
return affiliate_url
async def _process_message(self, message, new_text: str):
- """
- Send a polite affiliate message, either by deleting the original message or replying to it.
+ """Send a polite affiliate message, either by deleting the original message or replying to it.
Args:
+ ----
message (telegram.Message): The message to modify.
new_text (str): The modified text with affiliate links.
+
"""
# Get user information
user_first_name = message.from_user.first_name
@@ -139,14 +140,16 @@ async def _process_message(self, message, new_text: str):
)
def _build_affiliate_url_pattern(self, advertiser_key):
- """
- Builds a URL pattern for a given affiliate platform (e.g., Admitad, Awin) by gathering all the advertiser domains.
+ """Builds a URL pattern for a given affiliate platform (e.g., Admitad, Awin) by gathering all the advertiser domains.
- Parameters:
+ Parameters
+ ----------
- advertiser_key: The key in selected_users that holds advertisers (e.g., 'admitad', 'awin').
- Returns:
+ Returns
+ -------
- A regex pattern string that matches any of the advertiser domains.
+
"""
affiliate_domains = set()
@@ -159,7 +162,7 @@ def _build_affiliate_url_pattern(self, advertiser_key):
advertisers.update(advertisers_n)
# Add each domain, properly escaped for regex, to the affiliate_domains set
- for domain in advertisers.keys():
+ for domain in advertisers:
affiliate_domains.add(domain.replace(".", r"\."))
# If no domains were found, return None
@@ -179,15 +182,17 @@ def _build_affiliate_url_pattern(self, advertiser_key):
)
def _extract_store_urls(self, message_text: str, url_pattern: str) -> list:
- """
- Extracts store URLs directly from the message text or from URLs embedded in query parameters.
+ """Extracts store URLs directly from the message text or from URLs embedded in query parameters.
- Parameters:
+ Parameters
+ ----------
- message_text: The text of the message.
- url_pattern: The regex pattern to match store URLs.
- Returns:
+ Returns
+ -------
- A list of tuples (original_url, extracted_url, domain) matching the store pattern.
+
"""
extracted_urls = []
@@ -228,7 +233,6 @@ async def _process_store_affiliate_links(
affiliate_tag: str,
) -> bool:
"""Generic method to handle affiliate links for different platforms."""
-
message, text, self.selected_users = self._unpack_context(context)
url_pattern = self._build_affiliate_url_pattern(affiliate_platform)
diff --git a/handlers/pattern_handler.py b/handlers/pattern_handler.py
index 7015e2d..7a4cc75 100644
--- a/handlers/pattern_handler.py
+++ b/handlers/pattern_handler.py
@@ -17,7 +17,6 @@ async def process_affiliate_link(self, context, platform, data):
async def handle_links(self, context) -> bool:
"""Handles links based on the platform's patterns."""
-
processed = False
for platform, data in PATTERNS.items():
processed |= await self.process_affiliate_link(context, platform, data)
diff --git a/handlers/patterns.py b/handlers/patterns.py
index 8dbd99a..ab802f4 100644
--- a/handlers/patterns.py
+++ b/handlers/patterns.py
@@ -1,6 +1,6 @@
-from handlers.base_handler import PATTERN_URL_QUERY
+from typing import Dict, Optional, TypedDict
-from typing import Dict, TypedDict, Optional
+from handlers.base_handler import PATTERN_URL_QUERY
class PatternConfig(TypedDict):
diff --git a/tests/test_admitad_handler.py b/tests/test_admitad_handler.py
index ffaa867..a563aa1 100644
--- a/tests/test_admitad_handler.py
+++ b/tests/test_admitad_handler.py
@@ -1,6 +1,6 @@
import unittest
-
from unittest.mock import AsyncMock, patch
+
from handlers.base_handler import BaseHandler
from handlers.pattern_handler import PatternHandler
diff --git a/tests/test_aliexpress_api_handler.py b/tests/test_aliexpress_api_handler.py
index d17632b..9341148 100644
--- a/tests/test_aliexpress_api_handler.py
+++ b/tests/test_aliexpress_api_handler.py
@@ -1,9 +1,8 @@
import unittest
-
from unittest.mock import AsyncMock, patch
-from handlers.base_handler import BaseHandler
from handlers.aliexpress_api_handler import AliexpressAPIHandler
+from handlers.base_handler import BaseHandler
class TestHandler(BaseHandler):
@@ -15,7 +14,6 @@ class TestHandleAliExpressAPILinks(unittest.IsolatedAsyncioTestCase):
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_aliexpress_no_app_key(self, mock_process):
"""Test: No action is taken if AliExpress app_key is empty in selected_users."""
-
# Mock selected_users without AliExpress app_key
mock_selected_users = {"aliexpress": {"app_key": None}}
aliexpress_handler = AliexpressAPIHandler()
@@ -41,7 +39,6 @@ async def test_aliexpress_no_app_key(self, mock_process):
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_no_aliexpress_link(self, mock_process):
"""Test: No action is taken if there are no AliExpress links in the message."""
-
mock_selected_users = {"aliexpress": {"app_key": "some_app_key"}}
aliexpress_handler = AliexpressAPIHandler()
@@ -69,7 +66,6 @@ async def test_no_aliexpress_link(self, mock_process):
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_long_aliexpress_link(self, mock_process, mock_convert, mock_expand):
"""Test: Long AliExpress links."""
-
aliexpress_handler = AliexpressAPIHandler()
mock_selected_users = {
"aliexpress.com": {
diff --git a/tests/test_aliexpress_handler.py b/tests/test_aliexpress_handler.py
index 79a188a..2a4332f 100644
--- a/tests/test_aliexpress_handler.py
+++ b/tests/test_aliexpress_handler.py
@@ -1,5 +1,4 @@
import unittest
-
from unittest.mock import AsyncMock
from handlers.aliexpress_handler import AliexpressHandler
@@ -8,7 +7,6 @@
class TestHandleAliExpressLinks(unittest.IsolatedAsyncioTestCase):
async def test_aliexpress_links_without_affiliate(self):
"""Test AliExpress links when they are not in the advertiser list and APP_KEY is empty."""
-
mock_message = AsyncMock()
mock_message.text = (
"Check this out: https://www.aliexpress.com/item/1005002958205071.html"
@@ -43,7 +41,6 @@ async def test_aliexpress_links_without_affiliate(self):
async def test_no_discount_codes(self):
"""Test that no action is taken when ALIEXPRESS_DISCOUNT_CODES is empty."""
-
mock_message = AsyncMock()
mock_message.text = (
"Check this out: https://www.aliexpress.com/item/1005002958205071.html"
@@ -73,7 +70,6 @@ async def test_no_discount_codes(self):
async def test_no_aliexpress_links(self):
"""Test that no action is taken when no AliExpress links are present in the message."""
-
mock_message = AsyncMock()
mock_message.text = "This is a random message without AliExpress links."
mock_message.message_id = 4
diff --git a/tests/test_amazon_handler.py b/tests/test_amazon_handler.py
index 6034b8c..7a676c1 100644
--- a/tests/test_amazon_handler.py
+++ b/tests/test_amazon_handler.py
@@ -1,6 +1,5 @@
-import unittest
import re
-
+import unittest
from unittest.mock import AsyncMock, patch
from handlers.base_handler import BaseHandler
diff --git a/tests/test_awin_handler.py b/tests/test_awin_handler.py
index bf8bb4d..c47240d 100644
--- a/tests/test_awin_handler.py
+++ b/tests/test_awin_handler.py
@@ -1,12 +1,12 @@
import unittest
from unittest.mock import AsyncMock, patch
+
from handlers.pattern_handler import PatternHandler
class TestHandleAwinLinks(unittest.IsolatedAsyncioTestCase):
async def test_no_action_when_awin_publisher_id_is_none(self):
"""Test that no action is taken if AWIN_PUBLISHER_ID is None."""
-
mock_message = AsyncMock()
mock_message.text = "Check this out: https://www.pccomponentes.com/some-product I hope you like it"
mock_message.message_id = 1
@@ -58,7 +58,6 @@ async def test_awin_aliexpress_link_awin_config_empty_list(self):
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_awin_link_in_list(self, mock_process):
"""Test Awin links conversion when. New message must match the original reply structure."""
-
mock_message = AsyncMock()
mock_message.text = (
"Check this out: https://www.giftmio.com/some-product I hope you like it"
@@ -93,7 +92,6 @@ async def test_awin_link_in_list(self, mock_process):
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_awin_affiliate_link_from_list(self, mock_process):
"""Test if an existing Awin affiliate link is modified when the store is in our list of Awin advertisers."""
-
mock_message = AsyncMock()
mock_message.text = "Here is a product: https://www.awin1.com/cread.php?awinmid=other_id_not_mine&awinaffid=other_affiliate_id&ued=https://www.giftmio.com/some-product I hope you like it"
mock_message.message_id = 3
@@ -122,7 +120,6 @@ async def test_awin_affiliate_link_from_list(self, mock_process):
async def test_awin_affiliate_link_not_in_list(self):
"""Test that an existing Awin affiliate link is NOT modified when the store is NOT in our list of Awin advertisers."""
-
mock_message = AsyncMock()
mock_message.text = "Here is a product: https://www.awin1.com/cread.php?awinmid=other_id_not_mine&awinaffid=other_affiliate_id&ued=https://www.unknownstore.com/product I hope you like it"
mock_message.message_id = 4
@@ -150,7 +147,6 @@ async def test_awin_affiliate_link_not_in_list(self):
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_awin_aliexpress_link_without_discount(self, mock_process):
"""Test AliExpress link in Awin list, no discount code added."""
-
mock_message = AsyncMock()
mock_message.text = "Check this out: https://www.aliexpress.com/item/1005002958205071.html I hope you like it"
mock_message.message_id = 5
@@ -184,7 +180,6 @@ async def test_awin_aliexpress_link_without_discount(self, mock_process):
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_awin_aliexpress_link_with_discount(self, mock_process):
"""Test AliExpress link in Awin list, adding discount codes when applicable."""
-
mock_message = AsyncMock()
mock_message.text = "Here is a product: https://www.aliexpress.com/item/1005002958205071.html I hope you like it"
mock_message.message_id = 6
@@ -220,7 +215,6 @@ async def test_awin_aliexpress_link_with_discount(self, mock_process):
async def test_awin_aliexpress_link_no_awin_config(self):
"""Test AliExpress link when AliExpress is NOT in the Awin list and discount codes should NOT be added."""
-
mock_message = AsyncMock()
mock_message.text = "Here is a product: https://www.aliexpress.com/item/1005002958205071.html I hope you like it"
mock_message.message_id = 2
@@ -251,7 +245,6 @@ async def test_awin_aliexpress_link_no_awin_config(self):
@patch("handlers.base_handler.BaseHandler._process_message")
async def test_awin_no_aliexpress_from_link_with_discount(self, mock_process):
"""Test No AliExpress link in Awin list, the discount should not be applied."""
-
mock_message = AsyncMock()
mock_message.text = "Here is a product: https://www.pccomponentes.com/item/1005002958205071.html I hope you like it"
mock_message.message_id = 6
diff --git a/tests/test_base_handler.py b/tests/test_base_handler.py
index 214ed8b..5746166 100644
--- a/tests/test_base_handler.py
+++ b/tests/test_base_handler.py
@@ -1,9 +1,9 @@
import unittest
-
from unittest.mock import AsyncMock, patch
from urllib.parse import unquote
-from handlers.base_handler import BaseHandler, PATTERN_AFFILIATE_URL_QUERY
+
from config import config_data
+from handlers.base_handler import PATTERN_AFFILIATE_URL_QUERY, BaseHandler
class TestHandler(BaseHandler):
@@ -148,7 +148,6 @@ def test_affiliate_url_with_full_url(self):
def test_affiliate_and_advertiser_id_update(self):
"""Test that both affiliate_id and advertiser_id are updated correctly in the URL."""
-
original_url = "https://www.example.com/product?tag=old_affiliate_id&advertiser_id=old_advertiser_id"
format_template = "{domain}{path_before_query}?{affiliate_tag}={affiliate_id}&advertiser_id={advertiser_id}"
@@ -376,9 +375,7 @@ async def test_send_message_without_username(self):
class TestBuildAffiliateUrlPattern(unittest.TestCase):
def test_admitad_url_pattern(self):
- """
- Test: Verify that admitad_url_pattern is correctly generated from multiple users' domains.
- """
+ """Test: Verify that admitad_url_pattern is correctly generated from multiple users' domains."""
base_handler = TestHandler()
base_handler.selected_users = {
"example.com": {
@@ -412,9 +409,7 @@ def test_admitad_url_pattern(self):
)
def test_admitad_no_domains(self):
- """
- Test: Verify that None is returned when no Admitad advertisers exist across users.
- """
+ """Test: Verify that None is returned when no Admitad advertisers exist across users."""
base_handler = TestHandler()
# Generate Admitad URL pattern (should return None as no advertisers are set)
base_handler.selected_users = {
@@ -428,9 +423,7 @@ def test_admitad_no_domains(self):
self.assertIsNone(admitad_url_pattern)
def test_awin_url_pattern(self):
- """
- Test: Verify that awin_url_pattern is correctly generated from multiple users' domains.
- """
+ """Test: Verify that awin_url_pattern is correctly generated from multiple users' domains."""
# Generate Awin URL pattern
base_handler = TestHandler()
base_handler.selected_users = {
@@ -470,9 +463,7 @@ def test_awin_url_pattern(self):
)
def test_no_users_in_configuration(self):
- """
- Test: Verify that None is returned when there are no users in the configuration.
- """
+ """Test: Verify that None is returned when there are no users in the configuration."""
# Generate Admitad URL pattern with no users in the configuration
base_handler = TestHandler()
base_handler.selected_users = {
diff --git a/tests/test_botaffiumeiro.py b/tests/test_botaffiumeiro.py
index 42a0cb7..2175848 100644
--- a/tests/test_botaffiumeiro.py
+++ b/tests/test_botaffiumeiro.py
@@ -1,15 +1,15 @@
+from datetime import datetime
import unittest
+from unittest.mock import AsyncMock, Mock, patch
-from datetime import datetime
-from telegram import Update, User, Message, Chat
-from unittest.mock import Mock, AsyncMock, patch
+from telegram import Chat, Message, Update, User
from botaffiumeiro import (
- is_user_excluded,
- modify_link,
expand_shortened_url,
extract_domains_from_message,
extract_embedded_url,
+ is_user_excluded,
+ modify_link,
prepare_message,
select_user_for_domain,
)
@@ -178,9 +178,7 @@ def test_modify_link_without_user(
class TestExpandShortenedURL(unittest.TestCase):
@patch("requests.get")
def test_expand_amazon_short_url(self, mock_get):
- """
- Test: Expands a shortened Amazon URL (amzn.to).
- """
+ """Test: Expands a shortened Amazon URL (amzn.to)."""
mock_response = Mock()
mock_response.url = "https://www.amazon.com/dp/B08XYZ123"
mock_get.return_value = mock_response
@@ -192,9 +190,7 @@ def test_expand_amazon_short_url(self, mock_get):
@patch("requests.get")
def test_no_redirect_url(self, mock_get):
- """
- Test: URL does not redirect (original URL is returned).
- """
+ """Test: URL does not redirect (original URL is returned)."""
mock_response = Mock()
mock_response.url = "https://www.amazon.com/dp/B08XYZ123"
mock_get.return_value = mock_response
@@ -207,9 +203,7 @@ def test_no_redirect_url(self, mock_get):
@patch("requests.get")
def test_expand_aliexpress_short_url(self, mock_get):
- """
- Test: Expands a shortened AliExpress URL (s.click.aliexpress.com).
- """
+ """Test: Expands a shortened AliExpress URL (s.click.aliexpress.com)."""
mock_response = Mock()
mock_response.url = "https://www.aliexpress.com/item/12345.html"
mock_get.return_value = mock_response
@@ -223,9 +217,7 @@ def test_expand_aliexpress_short_url(self, mock_get):
class TestExtractDomainsFromMessage(unittest.TestCase):
def test_direct_domain_extraction(self):
- """
- Test: Extract domains directly from the message without embedded URLs.
- """
+ """Test: Extract domains directly from the message without embedded URLs."""
message_text = "Check out this link: https://www.amazon.com/someproduct and this: https://aliexpress.com/item/12345"
domains, modified_message = extract_domains_from_message(message_text)
@@ -234,9 +226,7 @@ def test_direct_domain_extraction(self):
self.assertEqual(len(domains), 2) # Should find 2 unique domains
def test_embedded_url_excludes_main_domain(self):
- """
- Test: If there are embedded URLs, the main domain should be excluded.
- """
+ """Test: If there are embedded URLs, the main domain should be excluded."""
message_text = (
"Visit https://awin1.com/cread.php?ulp=https://aliexpress.com/item/12345"
)
@@ -250,9 +240,7 @@ def test_embedded_url_excludes_main_domain(self):
@patch("botaffiumeiro.extract_embedded_url", return_value=set())
def test_no_embedded_urls(self, mock_extract_embedded_url):
- """
- Test: No embedded URLs, only direct domain extraction.
- """
+ """Test: No embedded URLs, only direct domain extraction."""
message_text = "Check out https://amazon.com/product123"
domains, modified_message = extract_domains_from_message(message_text)
@@ -260,9 +248,7 @@ def test_no_embedded_urls(self, mock_extract_embedded_url):
self.assertEqual(len(domains), 1) # Only one domain should be found
def test_multiple_direct_and_embedded_urls(self):
- """
- Test: Extract multiple direct and embedded URLs.
- """
+ """Test: Extract multiple direct and embedded URLs."""
message_text = (
"Check this product on Amazon: https://www.amazon.com/product?ref=123 "
"or visit https://aliexpress.com/item/456 "
@@ -277,9 +263,7 @@ def test_multiple_direct_and_embedded_urls(self):
self.assertEqual(len(domains), 2) # Should find 3 unique domains
def test_no_matching_patterns(self):
- """
- Test: No matching domains or patterns in the message.
- """
+ """Test: No matching domains or patterns in the message."""
message_text = "There are no valid links in this message."
domains, modified_message = extract_domains_from_message(message_text)
@@ -288,9 +272,7 @@ def test_no_matching_patterns(self):
) # Should return an empty set since no domains are matched
def test_invalid_urls(self):
- """
- Test: Handle invalid URLs that should not be extracted.
- """
+ """Test: Handle invalid URLs that should not be extracted."""
message_text = "Visit this: ftp://invalid-url.com and this invalid scheme: invalid://nope.com"
domains, modified_message = extract_domains_from_message(message_text)
@@ -303,9 +285,7 @@ def test_invalid_urls(self):
return_value="https://www.amazon.com/dp/product123",
)
def test_amazon_shortened_url(self, mock_expand):
- """
- Test: Handle shortened Amazon URL (amzn.to) and expand it.
- """
+ """Test: Handle shortened Amazon URL (amzn.to) and expand it."""
message_text = "Check out this product: https://amzn.to/abc123"
# Simulate the expansion of the shortened URL
@@ -330,9 +310,7 @@ def test_amazon_shortened_url(self, mock_expand):
return_value="https://www.aliexpress.com/item/1005001234567890.html",
)
def test_aliexpress_shortened_url(self, mock_expand):
- """
- Test: Handle shortened AliExpress URL (s.click.aliexpress.com) and expand it.
- """
+ """Test: Handle shortened AliExpress URL (s.click.aliexpress.com) and expand it."""
message_text = (
"Check out this deal: https://s.click.aliexpress.com/e/buyproduct"
)
@@ -357,9 +335,7 @@ def test_aliexpress_shortened_url(self, mock_expand):
@patch("botaffiumeiro.expand_shortened_url")
def test_mixed_full_and_shortened_urls(self, mock_expand):
- """
- Test: Handle a mixture of full and shortened URLs for both platforms.
- """
+ """Test: Handle a mixture of full and shortened URLs for both platforms."""
message_text = (
"Check out this Amazon deal: https://www.amazon.com/dp/product123 "
"or the shortened version: https://amzn.to/abc123 "
@@ -396,9 +372,7 @@ def test_mixed_full_and_shortened_urls(self, mock_expand):
)
def test_amazon_full_url_uk(self):
- """
- Test: Handle full Amazon URL with amazon.co.uk.
- """
+ """Test: Handle full Amazon URL with amazon.co.uk."""
message_text = "Check out this product on Amazon UK: https://www.amazon.co.uk/dp/product123"
domains, modified_message = extract_domains_from_message(message_text)
@@ -409,9 +383,7 @@ def test_amazon_full_url_uk(self):
@patch("requests.get")
def test_expand_amazon_short_url_and_replace_in_message(self, mock_get):
- """
- Test: Expands a shortened Amazon URL and replaces it in the message.
- """
+ """Test: Expands a shortened Amazon URL and replaces it in the message."""
mock_response = Mock()
mock_response.url = "https://www.amazon.com/dp/B08XYZ123"
mock_get.return_value = mock_response
@@ -428,9 +400,7 @@ def test_expand_amazon_short_url_and_replace_in_message(self, mock_get):
@patch("requests.get")
def test_expand_multiple_short_urls_and_replace_in_message(self, mock_get):
- """
- Test: Expands multiple shortened URLs and replaces them in the message.
- """
+ """Test: Expands multiple shortened URLs and replaces them in the message."""
mock_response_amazon = Mock()
mock_response_amazon.url = "https://www.amazon.com/dp/B08XYZ123"
mock_response_aliexpress = Mock()
@@ -450,9 +420,7 @@ def test_expand_multiple_short_urls_and_replace_in_message(self, mock_get):
@patch("requests.get")
def test_extract_domains_with_short_urls(self, mock_get):
- """
- Test: Extract domains after expanding shortened URLs.
- """
+ """Test: Extract domains after expanding shortened URLs."""
# Simula las respuestas de las cabeceras para las URLs cortas
mock_response_amazon = Mock()
mock_response_amazon.url = (
@@ -487,9 +455,7 @@ def test_extract_domains_with_short_urls(self, mock_get):
)
def test_extract_domains_with_long_urls(self):
- """
- Test: Extract domains from long Amazon and AliExpress URLs.
- """
+ """Test: Extract domains from long Amazon and AliExpress URLs."""
# Text with long URLs already expanded
message_text = (
"Check out this Amazon deal: https://www.amazon.com/dp/B08XYZ123 "
@@ -515,25 +481,19 @@ def test_extract_domains_with_long_urls(self):
class TestExtractEmbeddedUrl(unittest.TestCase):
def test_no_embedded_urls(self):
- """
- Test: No embedded URLs in the query parameters.
- """
+ """Test: No embedded URLs in the query parameters."""
query_params = {"param1": ["value1"], "param2": ["value2"]}
result = extract_embedded_url(query_params)
self.assertEqual(result, set()) # Should return an empty set
def test_single_embedded_url(self):
- """
- Test: A single embedded URL inside the query parameters.
- """
+ """Test: A single embedded URL inside the query parameters."""
query_params = {"param1": ["https://example.com/path?query=123"]}
result = extract_embedded_url(query_params)
self.assertIn("example.com", result) # Should contain the domain 'example.com'
def test_multiple_embedded_urls(self):
- """
- Test: Multiple embedded URLs in different query parameters.
- """
+ """Test: Multiple embedded URLs in different query parameters."""
query_params = {
"param1": ["https://example.com/path"],
"param2": ["https://another.com/resource"],
@@ -544,9 +504,7 @@ def test_multiple_embedded_urls(self):
self.assertEqual(len(result), 2) # There should be two unique domains
def test_invalid_urls(self):
- """
- Test: Invalid URLs in the query parameters should not be considered.
- """
+ """Test: Invalid URLs in the query parameters should not be considered."""
query_params = {
"param1": ["ftp://invalid.com/file"], # Not http/https
"param2": ["invalid://notvalid"],
@@ -555,9 +513,7 @@ def test_invalid_urls(self):
self.assertEqual(result, set()) # Should return an empty set
def test_mixed_valid_and_invalid_urls(self):
- """
- Test: A mix of valid and invalid URLs in the query parameters.
- """
+ """Test: A mix of valid and invalid URLs in the query parameters."""
query_params = {
"param1": ["https://valid.com/resource"],
"param2": ["ftp://invalid.com/file"], # Invalid scheme
@@ -568,9 +524,7 @@ def test_mixed_valid_and_invalid_urls(self):
self.assertEqual(len(result), 1) # There should be only one valid domain
def test_multiple_values_for_single_param(self):
- """
- Test: A single query parameter with multiple values (some valid URLs).
- """
+ """Test: A single query parameter with multiple values (some valid URLs)."""
query_params = {
"param1": ["https://valid.com/resource", "https://another.com/path"]
}
@@ -586,9 +540,7 @@ class TestPrepareMessage(unittest.TestCase):
def test_prepare_message_with_valid_domains(
self, mock_select_user, mock_extract_domains
):
- """
- Test: Simulate a message with valid domains and ensure users are selected correctly.
- """
+ """Test: Simulate a message with valid domains and ensure users are selected correctly."""
# Mock the domains extracted from the message
mock_extract_domains.return_value = (
{"amazon.com", "aliexpress.com"},
@@ -630,9 +582,7 @@ def select_user_side_effect(domain):
def test_prepare_message_with_no_domains(
self, mock_select_user, mock_extract_domains
):
- """
- Test: Handle a case where no valid domains are found in the message.
- """
+ """Test: Handle a case where no valid domains are found in the message."""
# Mock the domains extracted from the message (empty set and message unchanged)
mock_extract_domains.return_value = (set(), "This message contains no links.")
@@ -657,9 +607,7 @@ def test_prepare_message_with_no_domains(
def test_prepare_message_with_mixed_domains(
self, mock_select_user, mock_extract_domains
):
- """
- Test: Simulate a message where one domain has a user and another domain does not.
- """
+ """Test: Simulate a message where one domain has a user and another domain does not."""
# Mock the domains extracted from the message
mock_extract_domains.return_value = (
{
@@ -706,9 +654,7 @@ def select_user_side_effect(domain):
def test_prepare_message_with_only_unknown_domains(
self, mock_select_user, mock_extract_domains
):
- """
- Test: Simulate a message where all domains are unknown.
- """
+ """Test: Simulate a message where all domains are unknown."""
# Mock the domains extracted from the message
mock_extract_domains.return_value = (
{"unknown.com"},
@@ -741,9 +687,7 @@ def test_prepare_message_with_only_unknown_domains(
def test_prepare_message_with_expanded_urls(
self, mock_select_user, mock_extract_domains
):
- """
- Test: Ensure that prepare_message returns both the selected users and the modified message.
- """
+ """Test: Ensure that prepare_message returns both the selected users and the modified message."""
# Mock the domains and the modified message returned by extract_domains_from_message
mock_extract_domains.return_value = (
{
@@ -790,9 +734,7 @@ def select_user_side_effect(domain):
@patch("botaffiumeiro.extract_domains_from_message")
@patch("botaffiumeiro.select_user_for_domain")
def test_prepare_message_with_no_text(self, mock_select_user, mock_extract_domains):
- """
- Test: Ensure that prepare_message returns an empty dictionary and None for the modified message when there is no text.
- """
+ """Test: Ensure that prepare_message returns an empty dictionary and None for the modified message when there is no text."""
# Simulate an empty message
message = Mock()
message.text = None
diff --git a/tests/test_config.py b/tests/test_config.py
index 06a85f7..7ca35f5 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -1,14 +1,13 @@
import unittest
-import config
from unittest.mock import patch
+import config
+
class TestAddToDomainTable(unittest.TestCase):
@patch("config.domain_percentage_table", {})
def test_user_with_affiliate_id(self):
- """
- Test: Add a user with an affiliate ID.
- """
+ """Test: Add a user with an affiliate ID."""
user_id = "main"
affiliate_id = "amazon_affiliate_id"
config.add_to_domain_table("amazon", user_id, affiliate_id, 90)
@@ -19,9 +18,7 @@ def test_user_with_affiliate_id(self):
@patch("config.domain_percentage_table", {})
def test_user_without_affiliate_id(self):
- """
- Test: Do not add a user if they don't have an affiliate ID.
- """
+ """Test: Do not add a user if they don't have an affiliate ID."""
user_id = "main"
affiliate_id = None
config.add_to_domain_table("amazon", user_id, affiliate_id, 90)
@@ -30,9 +27,7 @@ def test_user_without_affiliate_id(self):
@patch("config.domain_percentage_table", {})
def test_new_domain_creation(self):
- """
- Test: Create a new domain in the table if it doesn't exist.
- """
+ """Test: Create a new domain in the table if it doesn't exist."""
user_id = "main"
affiliate_id = "user-affiliate-id"
config.add_to_domain_table("amazon", user_id, affiliate_id, 90)
@@ -43,9 +38,7 @@ def test_new_domain_creation(self):
@patch("config.domain_percentage_table", {})
def test_existing_domain_append(self):
- """
- Test: Add a user to an existing domain without duplicating the domain.
- """
+ """Test: Add a user to an existing domain without duplicating the domain."""
# First user
user_id_1 = "user1"
affiliate_id_1 = "user1-affiliate-id"
@@ -72,9 +65,7 @@ def test_existing_domain_append(self):
@patch("config.domain_percentage_table", {})
def test_multiple_users_in_same_domain(self):
- """
- Test: Add multiple users to the same domain.
- """
+ """Test: Add multiple users to the same domain."""
# User 1
user_id_1 = "user1"
affiliate_id_1 = "user1-affiliate-id"
@@ -103,9 +94,7 @@ def test_multiple_users_in_same_domain(self):
class TestAddAffiliateStoresDomains(unittest.TestCase):
@patch("config.domain_percentage_table", {})
def test_no_advertisers(self):
- """
- Test: No advertisers for the store key. The table should remain empty.
- """
+ """Test: No advertisers for the store key. The table should remain empty."""
user_id = "main"
user_data = {"awin_advertisers": {}} # No advertisers
config.add_affiliate_stores_domains(user_id, user_data, "awin_advertisers", 50)
@@ -115,9 +104,7 @@ def test_no_advertisers(self):
@patch("config.domain_percentage_table", {})
def test_single_advertiser(self):
- """
- Test: Add a single advertiser to the domain_percentage_table.
- """
+ """Test: Add a single advertiser to the domain_percentage_table."""
user_id = "main"
advertisers = {
"example.com": "affiliate-id",
@@ -135,9 +122,7 @@ def test_single_advertiser(self):
@patch("config.domain_percentage_table", {})
def test_multiple_advertisers(self):
- """
- Test: Add multiple advertisers to the domain_percentage_table.
- """
+ """Test: Add multiple advertisers to the domain_percentage_table."""
user_id = "main"
advertisers = {
"example1.com": "affiliate-id1",
@@ -166,9 +151,7 @@ def test_multiple_advertisers(self):
@patch("config.domain_percentage_table", {})
def test_existing_domain_append(self):
- """
- Test: Append a new user to an existing domain without overwriting.
- """
+ """Test: Append a new user to an existing domain without overwriting."""
# Pre-populate the table with one user for "example.com"
config.domain_percentage_table = {
"example.com": [{"user": "existing_user", "percentage": 60}]
@@ -199,9 +182,7 @@ def test_existing_domain_append(self):
@patch("config.domain_percentage_table", {})
def test_different_percentages(self):
- """
- Test: Add different users with different percentages for the same advertiser.
- """
+ """Test: Add different users with different percentages for the same advertiser."""
# First user with 70% for "example.com"
user_id_1 = "user1"
adversiters_1 = {"example.com": "affiliate-id1"}
@@ -235,9 +216,7 @@ def test_different_percentages(self):
class TestAddUserToDomainPercentageTable(unittest.TestCase):
@patch("config.domain_percentage_table", {})
def test_no_affiliate_ids(self):
- """
- Test: No affiliate IDs provided for the user. The table should remain empty.
- """
+ """Test: No affiliate IDs provided for the user. The table should remain empty."""
user_id = "user"
user_data = {
"amazon": {"advertisers": {}},
@@ -252,9 +231,7 @@ def test_no_affiliate_ids(self):
@patch("config.domain_percentage_table", {})
def test_amazon_affiliate_id(self):
- """
- Test: The user has an Amazon affiliate ID. The table should be updated with Amazon.
- """
+ """Test: The user has an Amazon affiliate ID. The table should be updated with Amazon."""
user_id = "main"
user_data = {
"amazon": {"advertisers": {"amazon.es": "amazon-affiliate-id"}},
@@ -273,9 +250,7 @@ def test_amazon_affiliate_id(self):
@patch("config.domain_percentage_table", {})
def test_multiple_affiliate_ids(self):
- """
- Test: The user has IDs for Amazon, AliExpress, and advertisers in Awin and Admitad.
- """
+ """Test: The user has IDs for Amazon, AliExpress, and advertisers in Awin and Admitad."""
user_id = "main"
user_data = {
"amazon": {"advertisers": {"amazon.es": "amazon-affiliate-id"}},
@@ -321,9 +296,7 @@ def test_multiple_affiliate_ids(self):
@patch("config.domain_percentage_table", {})
def test_multiple_users_same_domains(self):
- """
- Test: Multiple users with affiliate data for the same domains.
- """
+ """Test: Multiple users with affiliate data for the same domains."""
# First user with Amazon and AliExpress
user_id_1 = "user1"
user_data_1 = {
@@ -384,9 +357,7 @@ def test_multiple_users_same_domains(self):
@patch("config.domain_percentage_table", {})
def test_multiple_users_with_shared_and_unique_domains(self):
- """
- Test: Multiple users where some domains overlap and others are unique.
- """
+ """Test: Multiple users where some domains overlap and others are unique."""
# First user with Amazon and an Awin advertiser
user_id_1 = "user1"
user_data_1 = {
@@ -483,9 +454,7 @@ def test_multiple_users_with_shared_and_unique_domains(self):
@patch("config.domain_percentage_table", {})
def test_multiple_users_with_aliexpress_on_different_platforms(self):
- """
- Test: Multiple users with AliExpress affiliate IDs from different platforms (API, Awin, Admitad).
- """
+ """Test: Multiple users with AliExpress affiliate IDs from different platforms (API, Awin, Admitad)."""
# First user has AliExpress via API
user_id_1 = "user1"
user_data_1 = {
@@ -551,9 +520,7 @@ def test_multiple_users_with_aliexpress_on_different_platforms(self):
class TestAdjustDomainAffiliatePercentages(unittest.TestCase):
@patch("config.domain_percentage_table", {})
def test_only_user_in_domain(self):
- """
- Test: Only the main user is in the domain. The user should get 100% of the percentage.
- """
+ """Test: Only the main user is in the domain. The user should get 100% of the percentage."""
creator_percentage = 0
user_percentage = 100 - creator_percentage
config.domain_percentage_table = {
@@ -575,9 +542,7 @@ def test_only_user_in_domain(self):
@patch("config.domain_percentage_table", {})
def test_user_and_single_creator(self):
- """
- Test: One user and one creator. Percentages should adjust based on creator_percentage.
- """
+ """Test: One user and one creator. Percentages should adjust based on creator_percentage."""
creator_percentage = 30
user_percentage = 100 - creator_percentage
config.domain_percentage_table = {
@@ -612,9 +577,7 @@ def test_user_and_single_creator(self):
@patch("config.domain_percentage_table", {})
def test_user_and_multiple_creators(self):
- """
- Test: One user and multiple creators. Percentages should adjust according to creator_percentage.
- """
+ """Test: One user and multiple creators. Percentages should adjust according to creator_percentage."""
creator_percentage = 30
config.domain_percentage_table = {
@@ -660,9 +623,7 @@ def test_user_and_multiple_creators(self):
@patch("config.domain_percentage_table", {})
def test_only_creators_in_domain(self):
- """
- Test: No main user, only creators. The creators should be adjusted to sum to 100%.
- """
+ """Test: No main user, only creators. The creators should be adjusted to sum to 100%."""
creator_percentage = 10
config.domain_percentage_table = {
"amazon": [
@@ -697,9 +658,7 @@ def test_only_creators_in_domain(self):
@patch("config.domain_percentage_table", {})
def test_user_with_zero_creator_percentage(self):
- """
- Test: User with 0% creator influence. The user should get 100%.
- """
+ """Test: User with 0% creator influence. The user should get 100%."""
creator_percentage = 0
config.domain_percentage_table = {
"amazon": [
@@ -735,8 +694,7 @@ def test_user_with_zero_creator_percentage(self):
@patch("config.domain_percentage_table", {})
def test_main_user_only(self):
- """
- Test: The main user is the only one in the logisplan.com domain.
+ """Test: The main user is the only one in the logisplan.com domain.
The user should get 100% of the percentage.
"""
creator_percentage = 10 # Percentage intended for creators, not applicable here
From b1308ad4dc1ad73ffd10ecf7e74d4bcf0374f781 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 18:22:30 +0100
Subject: [PATCH 32/55] quitar precommit por ahora
---
.pre-commit-config.yaml => .pre-commit-config-no.yaml | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename .pre-commit-config.yaml => .pre-commit-config-no.yaml (100%)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config-no.yaml
similarity index 100%
rename from .pre-commit-config.yaml
rename to .pre-commit-config-no.yaml
From 9a33cf3e8dfe6e06e01c626b2bf9ea8727cfadb2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 18:23:31 +0100
Subject: [PATCH 33/55] no pc
---
pyproject.toml => pyproject-no.toml | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename pyproject.toml => pyproject-no.toml (100%)
diff --git a/pyproject.toml b/pyproject-no.toml
similarity index 100%
rename from pyproject.toml
rename to pyproject-no.toml
From 007d475017ab6a563aafbebe44094c0cf56659d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 18:24:38 +0100
Subject: [PATCH 34/55] pcno
---
pyproject-no.toml | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyproject-no.toml b/pyproject-no.toml
index b42461f..1ca16a1 100644
--- a/pyproject-no.toml
+++ b/pyproject-no.toml
@@ -1,4 +1,5 @@
+
[tool.poetry]
name = "botaffiumeiro"
version = "1.0"
From 27dcb773c8ac9e281f2a154ab0365f4abb3ec5a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:19:34 +0100
Subject: [PATCH 35/55] pc
---
.pre-commit-config-no.yaml => .pre-commit-config.yaml | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename .pre-commit-config-no.yaml => .pre-commit-config.yaml (100%)
diff --git a/.pre-commit-config-no.yaml b/.pre-commit-config.yaml
similarity index 100%
rename from .pre-commit-config-no.yaml
rename to .pre-commit-config.yaml
From fd4dee95fa1eec31d8eb51d8846a50a1c0339cd8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:26:05 +0100
Subject: [PATCH 36/55] pc
---
.pre-commit-config.yaml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 11fe74b..a7ea992 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -24,5 +24,7 @@ repos:
hooks:
- id: "mypy"
name: "Check type hints (mypy)"
- args: [--ignore-missing-imports]
+ args:
+ --ignore-missing-imports
+ --explicit-package-bases
verbose: true
From 2bf2179c470278260d3787b2728ba8c1dc3b09aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:29:29 +0100
Subject: [PATCH 37/55] pc
---
.pre-commit-config.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index a7ea992..ca159e5 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -25,6 +25,6 @@ repos:
- id: "mypy"
name: "Check type hints (mypy)"
args:
- --ignore-missing-imports
- --explicit-package-bases
+ - "--explicit-package-bases"
+ - "ignore-missing-imports"
verbose: true
From bfacbcac4d8a990a163a2cd6b5a08cd4a3aed560 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 21:29:43 +0000
Subject: [PATCH 38/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
.pre-commit-config.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ca159e5..2bf60db 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -24,7 +24,7 @@ repos:
hooks:
- id: "mypy"
name: "Check type hints (mypy)"
- args:
+ args:
- "--explicit-package-bases"
- "ignore-missing-imports"
verbose: true
From db3a195db70614bf6c686e613b0d6705b87b134d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:31:05 +0100
Subject: [PATCH 39/55] pc
---
.pre-commit-config.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ca159e5..70b6f83 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -26,5 +26,5 @@ repos:
name: "Check type hints (mypy)"
args:
- "--explicit-package-bases"
- - "ignore-missing-imports"
+ - "--ignore-missing-imports"
verbose: true
From 4ccf7b3e9c53967117f7349278a58438df8fab27 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:47:47 +0100
Subject: [PATCH 40/55] pc
---
.github/workflows/pre-commit.yml | 2 +-
.pre-commit-config.yaml | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index c53e196..a633bc5 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -20,7 +20,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
- python -m pip install types-PyYAML types-requests pre-commit
+ python -m pip install pre-commit types-PyYAML types-requests
pre-commit install-hooks
- name: Run Pre-Commit
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index d9e53c3..96b5534 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -26,5 +26,7 @@ repos:
name: "Check type hints (mypy)"
args:
- "--explicit-package-bases"
+ - "--install-types"
+ - "--non-interactive"
- "--ignore-missing-imports"
verbose: true
From 8a6221163ff6671068b59030ba3fc734ab72906f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:57:13 +0100
Subject: [PATCH 41/55] pc
---
.pre-commit-config.yaml | 1 +
pyproject.toml | 6 ++++++
2 files changed, 7 insertions(+)
create mode 100644 pyproject.toml
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 96b5534..43d6e7d 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -25,6 +25,7 @@ repos:
- id: "mypy"
name: "Check type hints (mypy)"
args:
+ - "--config-file=pyproject.toml"
- "--explicit-package-bases"
- "--install-types"
- "--non-interactive"
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..ec9786a
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,6 @@
+[tool.mypy]
+[mypy-requests.*]
+ignore_missing_imports = true
+
+[mypy-yaml.*]
+ignore_missing_imports = true
\ No newline at end of file
From f7a2f7030f09e9529eb151f085dcc5ffd397cad8 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 21:57:50 +0000
Subject: [PATCH 42/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
.pre-commit-config.yaml | 2 +-
pyproject.toml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 43d6e7d..6dcdd76 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -25,7 +25,7 @@ repos:
- id: "mypy"
name: "Check type hints (mypy)"
args:
- - "--config-file=pyproject.toml"
+ - "--config-file=pyproject.toml"
- "--explicit-package-bases"
- "--install-types"
- "--non-interactive"
diff --git a/pyproject.toml b/pyproject.toml
index ec9786a..5aca8be 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -3,4 +3,4 @@
ignore_missing_imports = true
[mypy-yaml.*]
-ignore_missing_imports = true
\ No newline at end of file
+ignore_missing_imports = true
From 80f74020a971a27b6cab38be2eef5aa8d1f0ae17 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:58:55 +0100
Subject: [PATCH 43/55] pc
---
.pre-commit-config.yaml | 4 ----
1 file changed, 4 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 43d6e7d..befd2ae 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -26,8 +26,4 @@ repos:
name: "Check type hints (mypy)"
args:
- "--config-file=pyproject.toml"
- - "--explicit-package-bases"
- - "--install-types"
- - "--non-interactive"
- - "--ignore-missing-imports"
verbose: true
From 337e9e98493c5736b524150fe94c78e30c510d65 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:00:06 +0000
Subject: [PATCH 44/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
.pre-commit-config.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index befd2ae..da5302c 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -25,5 +25,5 @@ repos:
- id: "mypy"
name: "Check type hints (mypy)"
args:
- - "--config-file=pyproject.toml"
+ - "--config-file=pyproject.toml"
verbose: true
From f42bacd72c6399948dac4fdde729ec0404ead7d4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 23:01:19 +0100
Subject: [PATCH 45/55] pc
---
.pre-commit-config.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index befd2ae..e0b585d 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -26,4 +26,6 @@ repos:
name: "Check type hints (mypy)"
args:
- "--config-file=pyproject.toml"
+ - "--explicit-package-bases"
+ - "--ignore-missing-imports"
verbose: true
From 4b1b9cd398afc8355f1633814aafb459fb1be18a Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:02:27 +0000
Subject: [PATCH 46/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
.pre-commit-config.yaml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index c4b2d8a..f471919 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -25,8 +25,7 @@ repos:
- id: "mypy"
name: "Check type hints (mypy)"
args:
- - "--config-file=pyproject.toml"
+ - "--config-file=pyproject.toml"
- "--explicit-package-bases"
- "--ignore-missing-imports"
verbose: true
-
From 13ea2109477adf0310a0ad64a79cf2b559d83584 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 23:04:45 +0100
Subject: [PATCH 47/55] pc
---
pyproject.toml | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 5aca8be..777c786 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,8 @@
[tool.mypy]
-[mypy-requests.*]
ignore_missing_imports = true
-[mypy-yaml.*]
+[tool.mypy-requests]
+ignore_missing_imports = true
+
+[tool.mypy-yaml]
ignore_missing_imports = true
From 05cda760945874127292f60b4085369d65498d1a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 23:07:36 +0100
Subject: [PATCH 48/55] pc
---
pyproject.toml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/pyproject.toml b/pyproject.toml
index 777c786..c60566b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,3 +6,12 @@ ignore_missing_imports = true
[tool.mypy-yaml]
ignore_missing_imports = true
+
+[mypy]
+ignore_missing_imports = True
+
+[mypy-requests]
+ignore_missing_imports = True
+
+[mypy-yaml]
+ignore_missing_imports = True
From be680e2054028a2c099358424d371f92dbc98f62 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 23:13:19 +0100
Subject: [PATCH 49/55] pc
---
pyproject.toml | 18 +++---------------
1 file changed, 3 insertions(+), 15 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index c60566b..2514bbf 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,17 +1,5 @@
[tool.mypy]
ignore_missing_imports = true
-
-[tool.mypy-requests]
-ignore_missing_imports = true
-
-[tool.mypy-yaml]
-ignore_missing_imports = true
-
-[mypy]
-ignore_missing_imports = True
-
-[mypy-requests]
-ignore_missing_imports = True
-
-[mypy-yaml]
-ignore_missing_imports = True
+namespace_packages = true
+explicit_package_bases = true
+install_types = true
\ No newline at end of file
From 9fd6abbb3c42211c945a74dca006f4847e558f6f Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:13:35 +0000
Subject: [PATCH 50/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index 2514bbf..22cf206 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -2,4 +2,4 @@
ignore_missing_imports = true
namespace_packages = true
explicit_package_bases = true
-install_types = true
\ No newline at end of file
+install_types = true
From bf690c75442534542f0715aa7a2a03e9d93d3f5e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 23:16:41 +0100
Subject: [PATCH 51/55] pc
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index 2514bbf..c28dda4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -2,4 +2,4 @@
ignore_missing_imports = true
namespace_packages = true
explicit_package_bases = true
-install_types = true
\ No newline at end of file
+install_types = false
From 9afdba1562fcd7a9009a481e9885b1c4cfce52f9 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:17:40 +0000
Subject: [PATCH 52/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
pyproject.toml | 1 -
1 file changed, 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index 9b2e5e6..c28dda4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -3,4 +3,3 @@ ignore_missing_imports = true
namespace_packages = true
explicit_package_bases = true
install_types = false
-
From 640a918e21055e91c3c439464b91268bc0e7f9b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 23:23:03 +0100
Subject: [PATCH 53/55] pc
---
botaffiumeiro.py | 2 +-
config.py | 4 ++--
handlers/aliexpress_api_handler.py | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/botaffiumeiro.py b/botaffiumeiro.py
index 916aa7e..787c32d 100644
--- a/botaffiumeiro.py
+++ b/botaffiumeiro.py
@@ -16,7 +16,7 @@
from handlers.pattern_handler import PatternHandler
from handlers.patterns import PATTERNS
from publicsuffix2 import get_sld
-import requests
+import requests # type: ignore
from telegram import Update, User
from telegram.ext import Application, CommandHandler, Defaults, MessageHandler, filters
diff --git a/config.py b/config.py
index ea6522e..ccc0a2a 100644
--- a/config.py
+++ b/config.py
@@ -2,8 +2,8 @@
import logging
from typing import Any, Dict
-import requests
-import yaml
+import requests # type: ignore
+import yaml # type: ignore
# Rutas a los archivos de configuración
CONFIG_PATH = "data/config.yaml"
diff --git a/handlers/aliexpress_api_handler.py b/handlers/aliexpress_api_handler.py
index 11ca20e..0d8a192 100644
--- a/handlers/aliexpress_api_handler.py
+++ b/handlers/aliexpress_api_handler.py
@@ -6,7 +6,7 @@
from handlers.aliexpress_handler import ALIEXPRESS_PATTERN
from handlers.base_handler import BaseHandler
-import requests
+import requests # type: ignore
# API endpoint for generating affiliate links
ALIEXPRESS_API_URL = "https://api-sg.aliexpress.com/sync"
From 75c31952631abec90e2ad73f042f237daac79d60 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:23:31 +0000
Subject: [PATCH 54/55] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
config.py | 4 ++--
handlers/aliexpress_api_handler.py | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/config.py b/config.py
index ccc0a2a..b8d60d8 100644
--- a/config.py
+++ b/config.py
@@ -2,8 +2,8 @@
import logging
from typing import Any, Dict
-import requests # type: ignore
-import yaml # type: ignore
+import requests # type: ignore
+import yaml # type: ignore
# Rutas a los archivos de configuración
CONFIG_PATH = "data/config.yaml"
diff --git a/handlers/aliexpress_api_handler.py b/handlers/aliexpress_api_handler.py
index 0d8a192..973af00 100644
--- a/handlers/aliexpress_api_handler.py
+++ b/handlers/aliexpress_api_handler.py
@@ -6,7 +6,7 @@
from handlers.aliexpress_handler import ALIEXPRESS_PATTERN
from handlers.base_handler import BaseHandler
-import requests # type: ignore
+import requests # type: ignore
# API endpoint for generating affiliate links
ALIEXPRESS_API_URL = "https://api-sg.aliexpress.com/sync"
From e35b5b7f0f20998bbaf092c386fb002b9f3c802d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A9ctor=20Mart=C3=ADnez?=
<103188721+hectorzin@users.noreply.github.com>
Date: Mon, 18 Nov 2024 23:26:27 +0100
Subject: [PATCH 55/55] pc
---
ha-addon/json2yaml.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ha-addon/json2yaml.py b/ha-addon/json2yaml.py
index be9d909..b7d3569 100644
--- a/ha-addon/json2yaml.py
+++ b/ha-addon/json2yaml.py
@@ -1,6 +1,6 @@
import json
-import yaml
+import yaml # type: ignore
# File paths
json_file = "/data/options.json"