147 lines
4.0 KiB
Python
147 lines
4.0 KiB
Python
import re
|
||
from random import randint
|
||
from typing import Any, Dict, Optional
|
||
import urllib
|
||
import poplib
|
||
from appPublic.log import debug
|
||
from appPublic.dictObject import DictObject
|
||
from appPublic.timeUtils import curDateString, timestampstr
|
||
from email.parser import Parser
|
||
from email.header import decode_header
|
||
from email.utils import parseaddr
|
||
from ..core import Gateway
|
||
|
||
|
||
def guess_charset(msg):
|
||
charset = msg.get_charset()
|
||
if charset is None:
|
||
content_type = msg.get('Content-Type', '').lower()
|
||
pos = content_type.find('charset=')
|
||
if pos >= 0:
|
||
charset = content_type[pos + 8:].strip()
|
||
return charset
|
||
|
||
class EmailClient:
|
||
def __init__(self, pop3_server, emailaddress, password):
|
||
self.client = poplib.POP3(pop3_server)
|
||
self.client.user(emailaddress)
|
||
self.client.pass_(password)
|
||
|
||
def stat(self):
|
||
return self.client.stat()
|
||
|
||
def mail_list(self):
|
||
resp, mails, octets = self.client.list()
|
||
|
||
def get_mail(self, index):
|
||
resp, lines, octets = self.client.retr(index)
|
||
debug(f'{resp=}, {octets=}')
|
||
msg_content = b'\r\n'.join(lines).decode('utf-8')
|
||
msg = Parser().parsestr(msg_content)
|
||
mail = {
|
||
"mailfrom": msg.get('From'),
|
||
"mailto": msg.get('To'),
|
||
"subject": msg.get('Subject'),
|
||
"body": self.get_body(msg)
|
||
}
|
||
return DictObject(**mail)
|
||
|
||
def get_body(self, msg):
|
||
if msg.is_multipart():
|
||
parts = msg.get_payload()
|
||
content = ''
|
||
for part in parts:
|
||
content += self.get_body(part)
|
||
return content
|
||
else:
|
||
content_type = msg.get_content_type()
|
||
content = msg.get_payload(decode=True)
|
||
charset = guess_charset(msg)
|
||
if charset:
|
||
content = content.decode(charset)
|
||
else:
|
||
content = content.decode('utf-8')
|
||
return content
|
||
|
||
class TransferGateway(Gateway):
|
||
def __init__(self, from_mail="", pop3server="", email="", password="", account_no=""):
|
||
self.from_email = from_email
|
||
self.pop3server = pop3server
|
||
self.email = email
|
||
self.password = password
|
||
self.account_no = account_no
|
||
self.running = False
|
||
|
||
async def new_tcode(self, sor):
|
||
tcode = self.gen_mailcode()
|
||
sql = "select * from transfercode where tcode=${tcode}$ and status='0'"
|
||
while True:
|
||
recs = await sor.sqlExe(sql, {'tcode': tcode})
|
||
if len(recs) == 0:
|
||
break
|
||
tcode = self.gen_mailcode()
|
||
return tcode
|
||
|
||
async def create_payment(self, payload: Dict[str, Any]) -> str:
|
||
"""
|
||
返回一个可以在 H5 里直接重定向的支付宝支付 URL
|
||
"""
|
||
ns = {
|
||
"id": payload.out_trade_no,
|
||
"customerid": payload.customerid,
|
||
"amount": payload.amount,
|
||
"curdate": curDateString(),
|
||
"curtime": timestampstr(),
|
||
"status": '0'
|
||
}
|
||
ns = DictObject(**ns)
|
||
ns.account_no = self.account_no
|
||
env = payload.request._run_ns
|
||
db = DBPools()
|
||
dbname = env.get_module_dbname('unipay')
|
||
async with db.sqlorContext(dbname) as sor:
|
||
sql = "select * from transfercode where tcode=${tcode}$ and status='0'"
|
||
ns.tcoce = await self.new_tcode(sor)
|
||
await sor.C('transfercode', ns.copy())
|
||
url = env.entire_url('transfer_info.ui')
|
||
query_str = urllib.parse.urlencode(ns)
|
||
return f'{url}?{query_str}'
|
||
return None
|
||
|
||
def get_transfer_data(self, mail):
|
||
assert mail.mailfrom == '95555@message.cmbchina.com'
|
||
assert mail.mailto == self.email
|
||
assert mail.body.startswith('动账业务通知')
|
||
ns = DictObject()
|
||
match = re.search(r'交易金额\s*[::]?\s*(\d+(?:\.\d+)?)', mail.body)
|
||
if match:
|
||
ns.amount = float(match.group(1))
|
||
p = r'摘要[::]\s*(\d{7})(?!\d)'
|
||
match = re.search(r'摘要[::]\s*(\d{7})(?!\d)', mail.body)
|
||
if match:
|
||
ns.code = match.group(1)
|
||
assert ns.amount
|
||
assert ns.code
|
||
return ns
|
||
|
||
def gen_mailcode(self):
|
||
c = '1'
|
||
for i in range(6):
|
||
c += randint(0,9)
|
||
return c
|
||
|
||
def run(self):
|
||
self.running = True
|
||
while self.running:
|
||
ec = EmailClient(self.pop3server, self.email, self.password)
|
||
mail = ec.get_mail(1)
|
||
|
||
async def query(self, out_trade_no: str) -> Dict[str, Any]:
|
||
pass
|
||
|
||
async def refund(self, *, out_trade_no: str, refund_amount: str, out_request_no: str) -> Dict[str, Any]:
|
||
pass
|
||
|
||
async def handle_notify(self, request) -> Dict[str, Any]:
|
||
pass
|