From 9197698858c271bc602380a7b5b383df5ad6c267 Mon Sep 17 00:00:00 2001 From: reza omidian Date: Sat, 18 May 2024 21:29:55 +0330 Subject: [PATCH 1/6] add support for telegram log system --- brightIDfaucet/settings.py | 6 ++++++ brightIDfaucet/telegram.py | 44 ++++++++++++++++++++++++++++++++++++++ sample.env | 2 ++ 3 files changed, 52 insertions(+) create mode 100644 brightIDfaucet/telegram.py diff --git a/brightIDfaucet/settings.py b/brightIDfaucet/settings.py index ef81eba7..d7c856e7 100644 --- a/brightIDfaucet/settings.py +++ b/brightIDfaucet/settings.py @@ -71,6 +71,8 @@ def str2bool(v): MEMCACHED_USERNAME = os.environ.get("MEMCACHEDCLOUD_USERNAME") MEMCACHED_PASSWORD = os.environ.get("MEMCACHEDCLOUD_PASSWORD") DEPLOYMENT_ENV = os.environ.get("DEPLOYMENT_ENV") +TELEGRAM_CHANNEL_ID = os.environ.get("TELEGRAM_CHANNEL_ID") +TELEGRAM_API_TOKEN = os.environ.get("TELEGRAM_API_TOKEN") assert DEPLOYMENT_ENV in ["dev", "main"] @@ -138,6 +140,10 @@ def before_send(event, hint): "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", + # 'telegram.LogMiddleware' + "telegram.LogMiddleware" + + ] ROOT_URLCONF = "brightIDfaucet.urls" diff --git a/brightIDfaucet/telegram.py b/brightIDfaucet/telegram.py new file mode 100644 index 00000000..6ac5455d --- /dev/null +++ b/brightIDfaucet/telegram.py @@ -0,0 +1,44 @@ +import requests +import time +from collections import defaultdict +from django.utils.deprecation import MiddlewareMixin +from django.conf import settings + +API_TOKEN = settings.TELEGRAM_API_TOKEN +CHANNEL_ID = settings.TELEGRAM_CHANNEL_ID + + +BASE_URL = f"https://api.telegram.org/bot{API_TOKEN}" + + +def send_telegram_log(text): + url = f"{BASE_URL}/sendMessage" + payload = { + "chat_id": CHANNEL_ID, + "text": text, + "parse_mode": "MarkdownV2", + "disable_web_page_preview": True, + } + response = requests.post(url, data=payload) + return response.json() + + + +log_cache = defaultdict(int) +MIN_INTERVAL = 3600 + + +class LogMiddleware(MiddlewareMixin): + def log_message(self, message): + log_hash = hash(message) + current_time = time.time() + + # Check if the log has been sent before or if it has been more than 1 hour + if current_time - log_cache[log_hash] > MIN_INTERVAL: + self.send_to_telegram(message) + log_cache[log_hash] = current_time + + def send_to_telegram(self, message): + send_telegram_log(message) + + diff --git a/sample.env b/sample.env index 825c75b7..48278e71 100644 --- a/sample.env +++ b/sample.env @@ -7,3 +7,5 @@ BRIGHT_PRIVATE_KEY="" DEBUG="True" SENTRY_DSN="DEBUG-DSN" DEPLOYMENT_ENV="env" +TELEGRAM_API_TOKEN="" +TELEGRAM_CHANNEL_ID="" From ed6f38cb27ab6b71ce08ee638ca4fbd5512a8325 Mon Sep 17 00:00:00 2001 From: reza omidian Date: Mon, 20 May 2024 09:59:09 +0330 Subject: [PATCH 2/6] tests --- brightIDfaucet/settings.py | 3 +- {brightIDfaucet => core}/telegram.py | 0 core/tests.py | 75 ++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) rename {brightIDfaucet => core}/telegram.py (100%) diff --git a/brightIDfaucet/settings.py b/brightIDfaucet/settings.py index d7c856e7..e77a28f4 100644 --- a/brightIDfaucet/settings.py +++ b/brightIDfaucet/settings.py @@ -140,8 +140,7 @@ def before_send(event, hint): "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", - # 'telegram.LogMiddleware' - "telegram.LogMiddleware" + "core.telegram.LogMiddleware" ] diff --git a/brightIDfaucet/telegram.py b/core/telegram.py similarity index 100% rename from brightIDfaucet/telegram.py rename to core/telegram.py diff --git a/core/tests.py b/core/tests.py index 03e58931..8feeabca 100644 --- a/core/tests.py +++ b/core/tests.py @@ -6,6 +6,10 @@ from authentication.models import GitcoinPassportConnection, UserProfile, Wallet from core.models import Chain, NetworkTypes, WalletAccount +from django.test import TestCase, RequestFactory +from unittest.mock import patch +from core.telegram import LogMiddleware + from .constraints import ( Attest, BeAttestedBy, @@ -363,3 +367,74 @@ def test_gitcoin_passport_connection_constraint_fail(self): constraint = HasGitcoinPassportProfile(self.not_connected_user_profile) self.assertEqual(constraint.is_observed(), False) + + + + + +class LogMiddlewareTests(TestCase): + def setUp(self): + self.factory = RequestFactory() + self.middleware = LogMiddleware() + + @patch("your_project_name.telegram.send_telegram_log") + def test_log_message_sent_to_telegram(self, mock_send_telegram_log): + # Mock the current time + with patch("time.time", return_value=1000000): + request = self.factory.get("/") + response = self.factory.get_response("/") + + # Simulate processing a request + self.middleware.process_request(request) + self.middleware.log_message("Test log message") + + # Ensure the send_telegram_log function was called + mock_send_telegram_log.assert_called_once_with("Test log message") + + @patch("your_project_name.telegram.send_telegram_log") + def test_log_message_not_sent_within_one_hour(self, mock_send_telegram_log): + # Mock the current time + with patch("time.time", side_effect=[1000000, 1000000 + 3599]): + request = self.factory.get("/") + response = self.factory.get_response("/") + + # Simulate processing a request and logging a message + self.middleware.process_request(request) + self.middleware.log_message("Test log message") + + # Simulate another request within one hour + self.middleware.process_request(request) + self.middleware.log_message("Test log message") + + # Ensure the send_telegram_log function was called only once + mock_send_telegram_log.assert_called_once_with("Test log message") + + @patch("your_project_name.telegram.send_telegram_log") + def test_log_message_sent_after_one_hour(self, mock_send_telegram_log): + # Mock the current time + with patch("time.time", side_effect=[1000000, 1000000 + 3601]): + request = self.factory.get("/") + response = self.factory.get_response("/") + + # Simulate processing a request and logging a message + self.middleware.process_request(request) + self.middleware.log_message("Test log message") + + # Simulate another request after more than one hour + self.middleware.process_request(request) + self.middleware.log_message("Test log message") + + # Ensure the send_telegram_log function was called twice + self.assertEqual(mock_send_telegram_log.call_count, 2) + + @patch("your_project_name.telegram.send_telegram_log") + def test_middleware_handles_requests(self, mock_send_telegram_log): + request = self.factory.get("/") + response = self.factory.get_response("/") + + # Simulate processing a request + self.middleware.process_request(request) + + # Ensure that no log message was sent + mock_send_telegram_log.assert_not_called() + From c22dcf5db7200cb54e58e3e8146ff2ec6680a253 Mon Sep 17 00:00:00 2001 From: reza omidian Date: Mon, 20 May 2024 11:14:59 +0330 Subject: [PATCH 3/6] Update tests.py --- core/tests.py | 51 +++++++-------------------------------------------- 1 file changed, 7 insertions(+), 44 deletions(-) diff --git a/core/tests.py b/core/tests.py index 8feeabca..36995f0e 100644 --- a/core/tests.py +++ b/core/tests.py @@ -375,66 +375,29 @@ def test_gitcoin_passport_connection_constraint_fail(self): class LogMiddlewareTests(TestCase): def setUp(self): self.factory = RequestFactory() - self.middleware = LogMiddleware() + self.middleware = LogMiddleware(get_response=lambda request: None) - @patch("your_project_name.telegram.send_telegram_log") + @patch("core.telegram.send_telegram_log") def test_log_message_sent_to_telegram(self, mock_send_telegram_log): - # Mock the current time with patch("time.time", return_value=1000000): - request = self.factory.get("/") - response = self.factory.get_response("/") - - # Simulate processing a request - self.middleware.process_request(request) self.middleware.log_message("Test log message") - - # Ensure the send_telegram_log function was called mock_send_telegram_log.assert_called_once_with("Test log message") - @patch("your_project_name.telegram.send_telegram_log") + @patch("core.telegram.send_telegram_log") def test_log_message_not_sent_within_one_hour(self, mock_send_telegram_log): - # Mock the current time with patch("time.time", side_effect=[1000000, 1000000 + 3599]): - request = self.factory.get("/") - response = self.factory.get_response("/") - - # Simulate processing a request and logging a message - self.middleware.process_request(request) self.middleware.log_message("Test log message") - - # Simulate another request within one hour - self.middleware.process_request(request) self.middleware.log_message("Test log message") - - # Ensure the send_telegram_log function was called only once mock_send_telegram_log.assert_called_once_with("Test log message") - @patch("your_project_name.telegram.send_telegram_log") + @patch("core.telegram.send_telegram_log") def test_log_message_sent_after_one_hour(self, mock_send_telegram_log): - # Mock the current time with patch("time.time", side_effect=[1000000, 1000000 + 3601]): - request = self.factory.get("/") - response = self.factory.get_response("/") - - # Simulate processing a request and logging a message - self.middleware.process_request(request) self.middleware.log_message("Test log message") - - # Simulate another request after more than one hour - self.middleware.process_request(request) self.middleware.log_message("Test log message") - - # Ensure the send_telegram_log function was called twice self.assertEqual(mock_send_telegram_log.call_count, 2) - @patch("your_project_name.telegram.send_telegram_log") - def test_middleware_handles_requests(self, mock_send_telegram_log): + @patch("core.telegram.send_telegram_log") + def test_middleware_initialization(self, mock_send_telegram_log): request = self.factory.get("/") - response = self.factory.get_response("/") - - # Simulate processing a request - self.middleware.process_request(request) - - # Ensure that no log message was sent - mock_send_telegram_log.assert_not_called() - + mock_send_telegram_log.assert_not_called() \ No newline at end of file From 3cfca22c6bb10710f904e372e835b5b424554001 Mon Sep 17 00:00:00 2001 From: reza omidian Date: Mon, 20 May 2024 13:19:17 +0330 Subject: [PATCH 4/6] tests --- core/telegram.py | 16 ++++++++++------ core/tests.py | 47 +++++++++++++++++++---------------------------- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/core/telegram.py b/core/telegram.py index 6ac5455d..00e0d4e7 100644 --- a/core/telegram.py +++ b/core/telegram.py @@ -19,13 +19,15 @@ def send_telegram_log(text): "parse_mode": "MarkdownV2", "disable_web_page_preview": True, } - response = requests.post(url, data=payload) - return response.json() - + try: + response = requests.post(url, data=payload) + return {"ok":True} + except Exception as e: + return {"ok": False} log_cache = defaultdict(int) -MIN_INTERVAL = 3600 +MIN_INTERVAL = 10 class LogMiddleware(MiddlewareMixin): @@ -35,10 +37,12 @@ def log_message(self, message): # Check if the log has been sent before or if it has been more than 1 hour if current_time - log_cache[log_hash] > MIN_INTERVAL: - self.send_to_telegram(message) log_cache[log_hash] = current_time + return self.send_to_telegram(message) + + return {"ok": False} def send_to_telegram(self, message): - send_telegram_log(message) + return send_telegram_log(message) diff --git a/core/tests.py b/core/tests.py index 36995f0e..d84a3873 100644 --- a/core/tests.py +++ b/core/tests.py @@ -1,3 +1,4 @@ +import time from unittest.mock import PropertyMock, patch from django.contrib.auth.models import User @@ -6,8 +7,7 @@ from authentication.models import GitcoinPassportConnection, UserProfile, Wallet from core.models import Chain, NetworkTypes, WalletAccount -from django.test import TestCase, RequestFactory -from unittest.mock import patch +from django.test import TestCase from core.telegram import LogMiddleware from .constraints import ( @@ -374,30 +374,21 @@ def test_gitcoin_passport_connection_constraint_fail(self): class LogMiddlewareTests(TestCase): def setUp(self): - self.factory = RequestFactory() self.middleware = LogMiddleware(get_response=lambda request: None) - - @patch("core.telegram.send_telegram_log") - def test_log_message_sent_to_telegram(self, mock_send_telegram_log): - with patch("time.time", return_value=1000000): - self.middleware.log_message("Test log message") - mock_send_telegram_log.assert_called_once_with("Test log message") - - @patch("core.telegram.send_telegram_log") - def test_log_message_not_sent_within_one_hour(self, mock_send_telegram_log): - with patch("time.time", side_effect=[1000000, 1000000 + 3599]): - self.middleware.log_message("Test log message") - self.middleware.log_message("Test log message") - mock_send_telegram_log.assert_called_once_with("Test log message") - - @patch("core.telegram.send_telegram_log") - def test_log_message_sent_after_one_hour(self, mock_send_telegram_log): - with patch("time.time", side_effect=[1000000, 1000000 + 3601]): - self.middleware.log_message("Test log message") - self.middleware.log_message("Test log message") - self.assertEqual(mock_send_telegram_log.call_count, 2) - - @patch("core.telegram.send_telegram_log") - def test_middleware_initialization(self, mock_send_telegram_log): - request = self.factory.get("/") - mock_send_telegram_log.assert_not_called() \ No newline at end of file + + + def test_log_message_sent_to_telegram(self): + + res = self.middleware.log_message("Test log message") + self.assertEqual(res['ok'], True) + res = self.middleware.log_message("Test log message") + self.assertEqual(res['ok'], False) + # delay 11 seconds + time.sleep(11) + res = self.middleware.log_message("Test log message") + self.assertEqual(res['ok'], True) + res = self.middleware.log_message("Test log message") + self.assertEqual(res['ok'], False) + res = self.middleware.log_message("Test log message2") + self.assertEqual(res['ok'], True) + From 7f695040d9a187ac709c9e8437baabd75f33d369 Mon Sep 17 00:00:00 2001 From: reza omidian Date: Mon, 20 May 2024 13:24:26 +0330 Subject: [PATCH 5/6] interval from settings --- brightIDfaucet/settings.py | 3 +++ core/telegram.py | 3 ++- core/tests.py | 7 +++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/brightIDfaucet/settings.py b/brightIDfaucet/settings.py index e77a28f4..999fda7a 100644 --- a/brightIDfaucet/settings.py +++ b/brightIDfaucet/settings.py @@ -74,6 +74,7 @@ def str2bool(v): TELEGRAM_CHANNEL_ID = os.environ.get("TELEGRAM_CHANNEL_ID") TELEGRAM_API_TOKEN = os.environ.get("TELEGRAM_API_TOKEN") + assert DEPLOYMENT_ENV in ["dev", "main"] @@ -264,3 +265,5 @@ def before_send(event, hint): ), } CELERY_BROKER_URL = REDIS_URL + +TELEGRAM_MIN_LOG_INTERVAL = 10 # seconds \ No newline at end of file diff --git a/core/telegram.py b/core/telegram.py index 00e0d4e7..805dcc62 100644 --- a/core/telegram.py +++ b/core/telegram.py @@ -6,6 +6,7 @@ API_TOKEN = settings.TELEGRAM_API_TOKEN CHANNEL_ID = settings.TELEGRAM_CHANNEL_ID +MIN_INTERVAL = settings.TELEGRAM_MIN_LOG_INTERVAL BASE_URL = f"https://api.telegram.org/bot{API_TOKEN}" @@ -27,7 +28,7 @@ def send_telegram_log(text): log_cache = defaultdict(int) -MIN_INTERVAL = 10 + class LogMiddleware(MiddlewareMixin): diff --git a/core/tests.py b/core/tests.py index d84a3873..4539e04c 100644 --- a/core/tests.py +++ b/core/tests.py @@ -9,6 +9,9 @@ from django.test import TestCase from core.telegram import LogMiddleware +from django.conf import settings + +TELEGRAM_MIN_LOG_INTERVAL = settings.TELEGRAM_MIN_LOG_INTERVAL from .constraints import ( Attest, @@ -383,8 +386,8 @@ def test_log_message_sent_to_telegram(self): self.assertEqual(res['ok'], True) res = self.middleware.log_message("Test log message") self.assertEqual(res['ok'], False) - # delay 11 seconds - time.sleep(11) + # delay + time.sleep(TELEGRAM_MIN_LOG_INTERVAL) res = self.middleware.log_message("Test log message") self.assertEqual(res['ok'], True) res = self.middleware.log_message("Test log message") From b7b4824030dd73280f3d284796843d401ba75f86 Mon Sep 17 00:00:00 2001 From: reza omidian Date: Mon, 20 May 2024 13:42:49 +0330 Subject: [PATCH 6/6] Update telegram.py --- core/telegram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/telegram.py b/core/telegram.py index 805dcc62..b3147f84 100644 --- a/core/telegram.py +++ b/core/telegram.py @@ -36,7 +36,7 @@ def log_message(self, message): log_hash = hash(message) current_time = time.time() - # Check if the log has been sent before or if it has been more than 1 hour + # Check if the log has been sent before if current_time - log_cache[log_hash] > MIN_INTERVAL: log_cache[log_hash] = current_time return self.send_to_telegram(message)