Mr-Help commited on
Commit
bdbb117
ยท
verified ยท
1 Parent(s): c53df32

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +38 -130
main.py CHANGED
@@ -1,73 +1,36 @@
1
  # app.py
2
  import os
 
3
  import json
4
  import requests
5
- from fastapi import FastAPI, Request, HTTPException
6
- from starlette.concurrency import run_in_threadpool
7
- from playwright.sync_api import sync_playwright
8
 
9
- # ------------ ุฅุนุฏุงุฏุงุช ุซุงุจุชุฉ/ุจูŠุฆุฉ ------------
10
- ODOO_BASE = os.getenv("ODOO_BASE", "https://odoo.binrushd.care")
11
- ODOO_API = f"{ODOO_BASE}/api/crm.lead"
12
- AUTH_URL = f"{ODOO_BASE}/api/auth/token"
13
- SESSION_AUTH_URL = f"{ODOO_BASE}/web/session/authenticate"
14
-
15
- CF_ID = os.getenv("CF_ACCESS_CLIENT_ID", "0491b36d7dcabce5b04f1a53f347bb4e.access")
16
- CF_SECRET = os.getenv("CF_ACCESS_CLIENT_SECRET", "22152cb41b62393e159daaff7dce433006c3744c5850e6adc15fa3544bb5eb09")
17
 
 
 
 
18
  LOGIN = os.getenv("ODOO_LOGIN", "binrushd.automation@gmail.com")
19
  PASSWORD = os.getenv("ODOO_PASSWORD", "BR2025")
20
  DB_NAME = os.getenv("ODOO_DB", "BR_EMR_16.0_202401")
21
 
22
- USER_AGENT = os.getenv("USER_AGENT",
23
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
24
- "(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
25
-
26
- REQUEST_TIMEOUT = int(os.getenv("REQUEST_TIMEOUT", "15"))
27
-
28
- app = FastAPI(title="HF Proxy -> Odoo (with Cloudflare cookie bootstrap)")
29
-
30
- # ---------- Utilities ----------
31
 
32
- def _mask(s: str, keep: int = 6) -> str:
33
- """ุฃุธู‡ุฑ ุฃูˆู„/ุขุฎุฑ ุฃุญุฑู ู‚ู„ูŠู„ุฉ ู„ู„ู‘ูˆุฌ ูู‚ุท"""
34
- if not s: return ""
35
- if len(s) <= keep*2: return s
36
- return f"{s[:keep]}โ€ฆ{s[-keep:]}"
37
-
38
- def _get_cloudflare_cookie_header_sync(base_url: str, wait_ms: int = 2000) -> str:
39
- """
40
- ูŠูุชุญ ุงู„ุตูุญุฉ ุงู„ุฑุฆูŠุณูŠุฉ ุจุงู„ุฏูˆู…ูŠู†ุŒ ูŠู†ูุฐ JS (Cloudflare challenge) ูˆูŠุฌู…ุน ุงู„ูƒูˆูƒูŠุฒ ูƒู€ Cookie header.
41
- """
42
- with sync_playwright() as p:
43
- browser = p.chromium.launch(headless=True)
44
- context = browser.new_context(user_agent=USER_AGENT, locale="en-US")
45
- page = context.new_page()
46
- page.goto(base_url, timeout=30000)
47
- page.wait_for_timeout(wait_ms)
48
- cookies = context.cookies()
49
- browser.close()
50
- if not cookies:
51
- return ""
52
- return "; ".join(f"{c['name']}={c['value']}" for c in cookies)
53
-
54
- def _get_token_and_session() -> tuple[str, str]:
55
- """
56
- ูŠุณุชุฎุฑุฌ access_token + session_id ููŠ ูƒู„ ู…ุฑุฉ:
57
- 1) GET /api/auth/token ู…ุน CF-Access + (login/password/db) ูƒู‡ูŠุฏุฑุฒ
58
- 2) ู„ูˆ session_id ุบูŠุฑ ู…ูˆุฌูˆุฏ: POST /web/session/authenticate (JSON-RPC)
59
- """
60
  s = requests.Session()
61
  s.headers.update({
62
  "Accept": "*/*",
63
  "Content-Type": "application/json",
64
- "Accept-Encoding": "gzip, deflate", # ุจุฏูˆู† br
 
65
  "Connection": "keep-alive",
66
  "CF-Access-Client-Id": CF_ID,
67
  "CF-Access-Client-Secret": CF_SECRET,
68
  })
69
 
70
- # (1) token
71
  auth_headers = {
72
  "CF-Access-Client-Id": CF_ID,
73
  "CF-Access-Client-Secret": CF_SECRET,
@@ -77,14 +40,17 @@ def _get_token_and_session() -> tuple[str, str]:
77
  }
78
  r = s.get(AUTH_URL, headers=auth_headers, timeout=(5, 30))
79
  r.raise_for_status()
 
 
 
 
 
80
 
81
- # Cloudflare ุบุงู„ุจู‹ุง ูŠุฑุฌู‘ุน JSONุ› requests ูŠููƒ gzip ุชู„ู‚ุงุฆูŠู‹ุง
82
- data = r.json()
83
  token = data.get("access_token") or (data.get("data") or {}).get("access_token")
84
  if not token:
85
  raise RuntimeError(f"No access_token in response: {data}")
86
 
87
- # (2) session_id
88
  session_id = s.cookies.get("session_id") or r.cookies.get("session_id")
89
  if not session_id:
90
  payload = {
@@ -97,88 +63,30 @@ def _get_token_and_session() -> tuple[str, str]:
97
  if not session_id:
98
  raise RuntimeError("Could not obtain session_id cookie.")
99
 
100
- # ุงุทุจุน ู„ู„ู‘ูˆุฌ (ู…ุฎูู‘ุถ)
101
- print(f"[AUTH] token={_mask(token)} session_id={_mask(session_id)}")
102
- return token, session_id
103
-
104
- # ---------- Endpoints ----------
105
-
106
- @app.get("/health")
107
- def health():
108
- return {"ok": True, "note": "ready to bootstrap cookies and forward requests"}
109
-
110
- @app.get("/ping")
111
- def ping():
112
- return {"pong": True}
113
 
114
- @app.post("/forward")
115
- async def forward_lead(request: Request):
116
- """
117
- - ูŠุณุชู‚ุจู„ JSON payload
118
- - ูŠุณุชุฎุฑุฌ access_token + session_id ููŠ ู†ูุณ ุงู„ู„ุญุธุฉ ูˆูŠุทุจุนู‡ู…ุง ููŠ ุงู„ู„ูˆุฌ
119
- - ูŠุฃุฎุฐ ูƒูˆูƒูŠุฒ Cloudflare ุจู€ Playwright
120
- - ูŠุฑุณู„ ุงู„ุทู„ุจ ุฅู„ู‰ Odoo ู…ุน ูƒู„ ุงู„ู‡ูŠุฏุฑุฒ/ุงู„ูƒูˆูƒูŠุฒ ุงู„ู…ุทู„ูˆุจุฉ
121
- """
122
- # 0) payload
123
- try:
124
- payload = await request.json()
125
- except Exception:
126
- body_text = await request.body()
127
- try:
128
- payload = json.loads(body_text.decode("utf-8") or "{}")
129
- except Exception:
130
- payload = {}
131
- # Debug (ุงุฎุชูŠุงุฑูŠ)
132
- print(f"[FORWARD] incoming payload keys={list(payload.keys())}")
133
 
134
- # 1) token + session_id
 
135
  try:
136
- access_token, session_id = await run_in_threadpool(_get_token_and_session)
 
137
  except Exception as e:
138
- raise HTTPException(status_code=502, detail=f"Auth failure: {str(e)}")
 
139
 
140
- # 2) Cloudflare cookies via Playwright
 
 
141
  try:
142
- cookie_header = await run_in_threadpool(_get_cloudflare_cookie_header_sync, ODOO_BASE, 2000)
 
143
  except Exception as e:
144
- cookie_header = ""
145
- print("Playwright error (continue without cookies):", str(e))
146
 
147
- # 3) headers
148
- headers = {
149
- "Accept": "application/json",
150
- "Content-Type": "application/json",
151
- "User-Agent": USER_AGENT,
152
- "Accept-Encoding": "gzip, deflate",
153
- "Connection": "keep-alive",
154
- "CF-Access-Client-Id": CF_ID,
155
- "CF-Access-Client-Secret": CF_SECRET,
156
- "access-token": access_token,
157
- }
158
- cookie_list = []
159
- if cookie_header:
160
- cookie_list.append(cookie_header)
161
- if session_id:
162
- cookie_list.append(f"session_id={session_id}")
163
- if cookie_list:
164
- headers["Cookie"] = "; ".join(cookie_list)
165
-
166
- # 4) POST -> Odoo
167
- try:
168
- resp = requests.post(ODOO_API, headers=headers, json=payload,
169
- timeout=REQUEST_TIMEOUT, allow_redirects=False)
170
- except requests.RequestException as e:
171
- raise HTTPException(status_code=502, detail=f"Error connecting to Odoo: {str(e)}")
172
-
173
- status = resp.status_code
174
- ctype = resp.headers.get("Content-Type", "")
175
- # ุงุทุจุน ู…ู„ุฎุต
176
- print(f"[FORWARD] Odoo status={status} content-type={ctype}")
177
-
178
- if "application/json" in ctype:
179
- try:
180
- return resp.json()
181
- except Exception:
182
- return {"status": status, "body": resp.text}
183
- else:
184
- return {"status": status, "body": resp.text}
 
1
  # app.py
2
  import os
3
+ import sys
4
  import json
5
  import requests
6
+ from fastapi import FastAPI, HTTPException, Request
 
 
7
 
8
+ BASE = os.getenv("ODOO_BASE", "https://odoo.binrushd.care")
9
+ AUTH_URL = f"{BASE}/api/auth/token"
10
+ SESSION_AUTH_URL = f"{BASE}/web/session/authenticate"
 
 
 
 
 
11
 
12
+ # ู†ูุณ ู…ุชุบูŠุฑุงุชูƒ ุจุงู„ุถุจุท (ุชู‚ุฏุฑ ุชุบูŠู‘ุฑู‡ุง ู…ู† env)
13
+ CF_ID = os.getenv("CF_ACCESS_CLIENT_ID", "0491b36d7dcabce5b04f1a53f347bb4e.access")
14
+ CF_SECRET = os.getenv("CF_ACCESS_CLIENT_SECRET", "22152cb41b62393e159daaff7dce433006c3744c5850e6adc15fa3544bb5eb09")
15
  LOGIN = os.getenv("ODOO_LOGIN", "binrushd.automation@gmail.com")
16
  PASSWORD = os.getenv("ODOO_PASSWORD", "BR2025")
17
  DB_NAME = os.getenv("ODOO_DB", "BR_EMR_16.0_202401")
18
 
19
+ app = FastAPI(title="Run get_token_and_session on request")
 
 
 
 
 
 
 
 
20
 
21
+ def get_token_and_session():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  s = requests.Session()
23
  s.headers.update({
24
  "Accept": "*/*",
25
  "Content-Type": "application/json",
26
+ # ู…ู‡ู…: ุจุฏูˆู† br ู„ุชูุงุฏูŠ brotli
27
+ "Accept-Encoding": "gzip, deflate",
28
  "Connection": "keep-alive",
29
  "CF-Access-Client-Id": CF_ID,
30
  "CF-Access-Client-Secret": CF_SECRET,
31
  })
32
 
33
+ # (1) ุงู„ุญุตูˆู„ ุนู„ู‰ access_token (ุงู„ู‡ูŠุฏุฑุฒ ุฒูŠ ู…ุง ููŠ ุณูƒุฑูŠุจุชูƒ)
34
  auth_headers = {
35
  "CF-Access-Client-Id": CF_ID,
36
  "CF-Access-Client-Secret": CF_SECRET,
 
40
  }
41
  r = s.get(AUTH_URL, headers=auth_headers, timeout=(5, 30))
42
  r.raise_for_status()
43
+ try:
44
+ data = r.json()
45
+ except ValueError:
46
+ # ุงุทุจุน ุฃูˆู„ ุฌุฒุก ู…ู† ุงู„ุจูˆุฏูŠ ู„ู„ุชุดุฎูŠุต
47
+ raise RuntimeError(f"Non-JSON from auth endpoint: {r.text[:300]}")
48
 
 
 
49
  token = data.get("access_token") or (data.get("data") or {}).get("access_token")
50
  if not token:
51
  raise RuntimeError(f"No access_token in response: {data}")
52
 
53
+ # (2) session_id ู…ู† ุงู„ูƒูˆูƒูŠุฒุŒ ุฃูˆ ู†ุนู…ู„ authenticate
54
  session_id = s.cookies.get("session_id") or r.cookies.get("session_id")
55
  if not session_id:
56
  payload = {
 
63
  if not session_id:
64
  raise RuntimeError("Could not obtain session_id cookie.")
65
 
66
+ # ุง๏ฟฝ๏ฟฝุจุงุนู‡ูู… ููŠ ุงู„ู„ูˆุฌ
67
+ print("ACCESS_TOKEN:", token)
68
+ print("SESSION_ID:", session_id)
 
 
 
 
 
 
 
 
 
 
69
 
70
+ return token, session_id
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
+ @app.get("/run")
73
+ def run_get_token_and_session_get():
74
  try:
75
+ token, session_id = get_token_and_session()
76
+ return {"ok": True, "access_token": token, "session_id": session_id}
77
  except Exception as e:
78
+ # ุฑุฌู‘ุน 502 ุนุดุงู† ุชุจุงู† ู…ุดูƒู„ุฉ ุฎุงุฑุฌูŠุฉ ุจูˆุถูˆุญ
79
+ raise HTTPException(status_code=502, detail=str(e))
80
 
81
+ @app.post("/run")
82
+ async def run_get_token_and_session_post(_req: Request):
83
+ # ู†ูุณ ุงู„ุณู„ูˆูƒ ู„ู„ู€ POST
84
  try:
85
+ token, session_id = get_token_and_session()
86
+ return {"ok": True, "access_token": token, "session_id": session_id}
87
  except Exception as e:
88
+ raise HTTPException(status_code=502, detail=str(e))
 
89
 
90
+ @app.get("/ping")
91
+ def ping():
92
+ return {"pong": True}