-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi_client.py
More file actions
95 lines (81 loc) · 3.82 KB
/
api_client.py
File metadata and controls
95 lines (81 loc) · 3.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import os
import requests
import logging
logger = logging.getLogger(__name__)
class APIClient:
def __init__(self):
self.base_url = os.getenv("BACKEND_URL")
self.secret = os.getenv("BOT_SERVICE_SECRET")
if not self.base_url or not self.secret:
raise ValueError("BACKEND_URL and BOT_SERVICE_SECRET must be set in .env")
def _get_headers(self, telegram_id):
return {
"X-Bot-Secret": self.secret,
"X-Telegram-User-ID": str(telegram_id),
"Content-Type": "application/json"
}
def _handle_response(self, response):
try:
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
logger.error(f"API Error: {e.response.status_code} - {e.response.text}")
if e.response.status_code == 404:
return {"error": "User not linked or resource not found."}
if e.response.status_code == 401 or e.response.status_code == 403:
return {"error": "Unauthorized. Please start the bot again or check linkage."}
return {"error": f"Backend error: {e.response.text}"}
except Exception as e:
logger.error(f"Request failed: {e}")
return {"error": "Failed to connect to backend."}
def get_groups(self, telegram_id):
url = f"{self.base_url}/api/bot/groups"
response = requests.get(url, headers=self._get_headers(telegram_id))
return self._handle_response(response)
def get_friends(self, telegram_id):
url = f"{self.base_url}/api/bot/friends"
response = requests.get(url, headers=self._get_headers(telegram_id))
return self._handle_response(response)
def get_stats(self, telegram_id):
url = f"{self.base_url}/api/bot/stats"
response = requests.get(url, headers=self._get_headers(telegram_id))
return self._handle_response(response)
def get_dues(self, telegram_id, filter_by=None):
url = f"{self.base_url}/api/bot/dues"
params = {}
if filter_by:
params['filter'] = filter_by
response = requests.get(url, headers=self._get_headers(telegram_id), params=params)
return self._handle_response(response)
def post_personal_expense(self, telegram_id, text):
url = f"{self.base_url}/api/bot/expense/personal"
data = {"text": text}
response = requests.post(url, json=data, headers=self._get_headers(telegram_id))
return self._handle_response(response)
def post_group_expense(self, telegram_id, group_name, amount, description):
url = f"{self.base_url}/api/bot/expense/group"
data = {
"group_name": group_name,
"amount": amount,
"description": description
}
response = requests.post(url, json=data, headers=self._get_headers(telegram_id))
return self._handle_response(response)
def post_receipt(self, telegram_id, image_file, group_id=None):
url = f"{self.base_url}/api/bot/receipt"
headers = self._get_headers(telegram_id)
# requests will set content-type for multipart automatically, so we remove json content type
del headers["Content-Type"]
files = {'file': image_file}
data = {}
if group_id:
data['group_id'] = group_id
response = requests.post(url, files=files, data=data, headers=headers)
return self._handle_response(response)
def check_linkage(self, telegram_id):
"""Simple ping to check if user exists/linked"""
# We can use get_stats or a dedicated ping endpoint. Using groups for now as it's lightweight.
res = self.get_groups(telegram_id)
if "error" in res and "User not linked" in res["error"]:
return False
return True