AI Update: تست اف تی پی نتیجه رو درست نمیگه
This commit is contained in:
@@ -360,6 +360,13 @@ class SessionManager:
|
|||||||
"created_at": p_obj.created_at,
|
"created_at": p_obj.created_at,
|
||||||
"description": p_obj.description,
|
"description": p_obj.description,
|
||||||
"conversation_titles": p_obj.conversation_titles,
|
"conversation_titles": p_obj.conversation_titles,
|
||||||
|
"active_branch": p_obj.active_branch,
|
||||||
|
"ftp_host": p_obj.ftp_host,
|
||||||
|
"ftp_port": p_obj.ftp_port,
|
||||||
|
"ftp_user": p_obj.ftp_user,
|
||||||
|
"ftp_password": p_obj.ftp_password,
|
||||||
|
"ftp_path": p_obj.ftp_path,
|
||||||
|
"ftp_tls": p_obj.ftp_tls,
|
||||||
}
|
}
|
||||||
curr = self.get_current_project(sess.chat_id)
|
curr = self.get_current_project(sess.chat_id)
|
||||||
data[str(k)] = {
|
data[str(k)] = {
|
||||||
|
|||||||
+17
-2
@@ -4832,9 +4832,24 @@ async def callback_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||||||
path=curr_proj.ftp_path or "/",
|
path=curr_proj.ftp_path or "/",
|
||||||
tls=curr_proj.ftp_tls,
|
tls=curr_proj.ftp_tls,
|
||||||
)
|
)
|
||||||
|
icon = "✅" if test_ok else "❌"
|
||||||
|
res_card = (
|
||||||
|
f"{icon} <b>نتیجه تست اتصال FTP:</b>\n\n"
|
||||||
|
f"• 🌐 <b>هاست:</b> <code>{escape_html(curr_proj.ftp_host)}:{curr_proj.ftp_port}</code>\n"
|
||||||
|
f"• 👤 <b>نام کاربری:</b> <code>{escape_html(curr_proj.ftp_user or '(بدون نام کاربری)')}</code>\n"
|
||||||
|
f"• 📂 <b>مسیر:</b> <code>{escape_html(curr_proj.ftp_path or '/')}</code>\n"
|
||||||
|
f"• 🔒 <b>پروتکل:</b> {'FTPS/TLS امن 🔒' if curr_proj.ftp_tls else 'FTP معمولی'}\n\n"
|
||||||
|
f"📋 <b>گزارش ارتباط:</b>\n{test_msg}"
|
||||||
|
) if is_fa else (
|
||||||
|
f"{icon} <b>FTP Connection Test Result:</b>\n\n"
|
||||||
|
f"• 🌐 <b>Host:</b> <code>{escape_html(curr_proj.ftp_host)}:{curr_proj.ftp_port}</code>\n"
|
||||||
|
f"• 👤 <b>User:</b> <code>{escape_html(curr_proj.ftp_user or '(none)')}</code>\n"
|
||||||
|
f"• 📂 <b>Path:</b> <code>{escape_html(curr_proj.ftp_path or '/')}</code>\n"
|
||||||
|
f"• 🔒 <b>Protocol:</b> {'Secure FTPS/TLS 🔒' if curr_proj.ftp_tls else 'Standard FTP'}\n\n"
|
||||||
|
f"📋 <b>Status:</b>\n{test_msg}"
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
alert_text = ("✅ اتصال FTP برقرار است" if test_ok else "❌ خطا در اتصال FTP") + f"\n{test_msg}"
|
await query.message.reply_html(res_card, disable_web_page_preview=True)
|
||||||
await query.answer(alert_text[:200], show_alert=True)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -116,17 +116,27 @@ class FTPManager:
|
|||||||
timeout: int = 15,
|
timeout: int = 15,
|
||||||
) -> ftplib.FTP:
|
) -> ftplib.FTP:
|
||||||
"""Helper to create and authenticate an FTP or FTPS client."""
|
"""Helper to create and authenticate an FTP or FTPS client."""
|
||||||
|
clean_host = host.strip()
|
||||||
|
clean_user = user.strip() if user else ""
|
||||||
|
clean_pass = password.strip() if password else ""
|
||||||
|
|
||||||
if tls:
|
if tls:
|
||||||
ftp = ftplib.FTP_TLS(timeout=timeout)
|
ftp = ftplib.FTP_TLS(timeout=timeout)
|
||||||
else:
|
else:
|
||||||
ftp = ftplib.FTP(timeout=timeout)
|
ftp = ftplib.FTP(timeout=timeout)
|
||||||
|
|
||||||
ftp.connect(host=host, port=port, timeout=timeout)
|
ftp.encoding = "utf-8"
|
||||||
ftp.login(user=user or "anonymous", passwd=password or "")
|
ftp.connect(host=clean_host, port=int(port), timeout=timeout)
|
||||||
|
|
||||||
if tls and isinstance(ftp, ftplib.FTP_TLS):
|
if tls and isinstance(ftp, ftplib.FTP_TLS):
|
||||||
|
ftp.auth()
|
||||||
|
ftp.login(user=clean_user or "anonymous", passwd=clean_pass)
|
||||||
ftp.prot_p() # Secure data connection
|
ftp.prot_p() # Secure data connection
|
||||||
|
else:
|
||||||
|
ftp.login(user=clean_user or "anonymous", passwd=clean_pass)
|
||||||
|
|
||||||
|
# Force passive mode (standard for firewalls / NAT)
|
||||||
|
ftp.set_pasv(True)
|
||||||
return ftp
|
return ftp
|
||||||
|
|
||||||
async def test_connection(
|
async def test_connection(
|
||||||
@@ -137,39 +147,72 @@ class FTPManager:
|
|||||||
password: str = "",
|
password: str = "",
|
||||||
path: str = "/",
|
path: str = "/",
|
||||||
tls: bool = False,
|
tls: bool = False,
|
||||||
timeout: int = 10,
|
timeout: int = 12,
|
||||||
) -> Tuple[bool, str]:
|
) -> Tuple[bool, str]:
|
||||||
"""Tests FTP credentials and verifies access to the target remote directory."""
|
"""Tests FTP credentials and verifies access to the target remote directory."""
|
||||||
if not host or not host.strip():
|
if not host or not host.strip():
|
||||||
return False, "آدرس هاست (Host) FTP مشخص نشده است."
|
return False, "آدرس هاست (Host) FTP مشخص نشده است."
|
||||||
|
|
||||||
def _test():
|
def _test():
|
||||||
|
ftp = None
|
||||||
try:
|
try:
|
||||||
ftp = self._create_ftp_client(host.strip(), int(port), user.strip(), password, tls, timeout)
|
ftp = self._create_ftp_client(host.strip(), int(port), user.strip(), password, tls, timeout)
|
||||||
|
|
||||||
|
# Check root PWD
|
||||||
|
init_pwd = ftp.pwd()
|
||||||
|
|
||||||
# Test CWD to target path if specified
|
# Test CWD to target path if specified
|
||||||
target_path = path.strip() if path else "/"
|
target_path = path.strip() if path else "/"
|
||||||
if target_path and target_path != "/":
|
if target_path and target_path != "/":
|
||||||
try:
|
try:
|
||||||
ftp.cwd(target_path)
|
ftp.cwd(target_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pwd = ftp.pwd()
|
curr_pwd = ftp.pwd() if ftp else "/"
|
||||||
|
try:
|
||||||
ftp.quit()
|
ftp.quit()
|
||||||
return False, f"اتصال به FTP برقرار شد، اما مسیر ریموت «{target_path}» یافت نشد (مسیر فعلی: {pwd}): {e}"
|
except Exception:
|
||||||
|
pass
|
||||||
|
return False, f"اتصال به سرور برقرار شد، اما مسیر ریموت «{target_path}» یافت نشد (مسیر فعلی: {curr_pwd}): {e}"
|
||||||
|
|
||||||
pwd = ftp.pwd()
|
final_pwd = ftp.pwd()
|
||||||
|
|
||||||
|
# Test directory listing
|
||||||
|
item_count = 0
|
||||||
try:
|
try:
|
||||||
listing = ftp.nlst()
|
listing = ftp.nlst()
|
||||||
count = len(listing)
|
item_count = len(listing)
|
||||||
except Exception:
|
except Exception:
|
||||||
count = 0
|
try:
|
||||||
|
lines = []
|
||||||
|
ftp.dir(lines.append)
|
||||||
|
item_count = len(lines)
|
||||||
|
except Exception:
|
||||||
|
item_count = 0
|
||||||
|
|
||||||
|
try:
|
||||||
ftp.quit()
|
ftp.quit()
|
||||||
return True, f"اتصال با موفقیت برقرار شد. مسیر فعلی: <code>{pwd}</code> (تعداد آیتمها: {count})"
|
except Exception:
|
||||||
except (socket.gaierror, socket.timeout) as e:
|
pass
|
||||||
return False, f"خطای شبکه / نامعتبر بودن آدرس سرور ({host}:{port}): {e}"
|
|
||||||
|
tls_label = " (FTPS/TLS امن)" if tls else " (FTP معمولی)"
|
||||||
|
return True, f"اتصال با موفقیت برقرار شد{tls_label} | مسیر: <code>{final_pwd}</code> | تعداد فایلها و پوشهها: {item_count}"
|
||||||
|
|
||||||
|
except socket.gaierror as e:
|
||||||
|
return False, f"نام دامنه/هاست سرور یافت نشد ({host}): {e}"
|
||||||
|
except (socket.timeout, TimeoutError) as e:
|
||||||
|
return False, f"مهلت زمانی اتصال به سرور به پایان رسید (Timeout روی پورت {port}): {e}"
|
||||||
|
except ConnectionRefusedError as e:
|
||||||
|
return False, f"اتصال توسط سرور رد شد (پورت {port} بسته است یا FTP روی آن فعال نیست): {e}"
|
||||||
except ftplib.error_perm as e:
|
except ftplib.error_perm as e:
|
||||||
return False, f"خطای احراز هویت / دسترسی FTP: {e}"
|
return False, f"خطای نام کاربری یا رمز عبور (دسترسی نامعتبر): {e}"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return False, f"خطا در برقراری ارتباط با FTP: {e}"
|
return False, f"خطا در برقراری ارتباط با FTP: {e}"
|
||||||
|
finally:
|
||||||
|
if ftp:
|
||||||
|
try:
|
||||||
|
ftp.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
return await asyncio.to_thread(_test)
|
return await asyncio.to_thread(_test)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user