增加邮件通知
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
- [x] 分布式运行
|
||||
- [x] Docker 支持
|
||||
- [x] 动态修改配置文件
|
||||
- [ ] 邮件通知
|
||||
- [x] 邮件通知
|
||||
- [ ] Web 管理页面
|
||||
|
||||
## 使用
|
||||
@@ -49,7 +49,7 @@ cp env.py.example env.py
|
||||
python main.py -t
|
||||
```
|
||||
|
||||
测试语音通知 -t -n
|
||||
测试通知消息 (语音, 邮件) -t -n
|
||||
```bash
|
||||
# 默认不会进行通知测试,要对通知进行测试需要加上 -n 参数
|
||||
python main.py -t -n
|
||||
|
||||
@@ -37,7 +37,7 @@ AUTO_CODE_ACCOUNT = {
|
||||
# 没找到比较好用的,现在用的这个是阿里云 API 市场上的,基本满足要求,价格也便宜
|
||||
# 购买成功后到控制台找到 APPCODE 放在下面就可以了
|
||||
# 地址:https://market.aliyun.com/products/57126001/cmapi019902.html
|
||||
NOTIFICATION_BY_VOICE_CODE = 1 # 开启语音验证码
|
||||
NOTIFICATION_BY_VOICE_CODE = 1 # 开启语音通知
|
||||
NOTIFICATION_API_APP_CODE = 'your app code'
|
||||
NOTIFICATION_VOICE_CODE_PHONE = 'your phone' # 接受通知的手机号
|
||||
|
||||
@@ -57,6 +57,14 @@ REDIS_HOST = 'localhost' # Redis host
|
||||
REDIS_PORT = '6379' # Redis post
|
||||
REDIS_PASSWORD = '' # # Redis 密码 没有可以留空
|
||||
|
||||
# 邮箱配置
|
||||
EMAIL_ENABLED = 0 # 是否开启邮件通知
|
||||
EMAIL_SENDER = 'sender@example.com' # 邮件发送者
|
||||
EMAIL_RECEIVER = 'receiver@example.com' # 邮件接受者 # 可以多个 [email1@gmail.com, email2@gmail.com]
|
||||
EMAIL_SERVER_HOST = 'localhost' # 邮件服务 host
|
||||
EMAIL_SERVER_USER = ''
|
||||
EMAIL_SERVER_PASSWORD = ''
|
||||
|
||||
# 查询任务
|
||||
QUERY_JOBS = [
|
||||
{
|
||||
|
||||
@@ -37,7 +37,7 @@ AUTO_CODE_ACCOUNT = {
|
||||
# 没找到比较好用的,现在用的这个是阿里云 API 市场上的,基本满足要求,价格也便宜
|
||||
# 购买成功后到控制台找到 APPCODE 放在下面就可以了
|
||||
# 地址:https://market.aliyun.com/products/57126001/cmapi019902.html
|
||||
NOTIFICATION_BY_VOICE_CODE = 1 # 开启语音验证码
|
||||
NOTIFICATION_BY_VOICE_CODE = 1 # 开启语音通知
|
||||
NOTIFICATION_API_APP_CODE = 'your app code'
|
||||
NOTIFICATION_VOICE_CODE_PHONE = 'your phone' # 接受通知的手机号
|
||||
|
||||
@@ -54,6 +54,15 @@ REDIS_HOST = 'localhost' # Redis host
|
||||
REDIS_PORT = '6379' # Redis post
|
||||
REDIS_PASSWORD = '' # # Redis 密码 没有可以留空
|
||||
|
||||
|
||||
# 邮箱配置
|
||||
EMAIL_ENABLED = 0 # 是否开启邮件通知
|
||||
EMAIL_SENDER = 'sender@example.com' # 邮件发送者
|
||||
EMAIL_RECEIVER = 'receiver@example.com' # 邮件接受者 # 可以多个 [email1@gmail.com, email2@gmail.com]
|
||||
EMAIL_SERVER_HOST = 'localhost' # 邮件服务 host
|
||||
EMAIL_SERVER_USER = ''
|
||||
EMAIL_SERVER_PASSWORD = ''
|
||||
|
||||
# 查询任务
|
||||
QUERY_JOBS = [
|
||||
{
|
||||
|
||||
@@ -93,6 +93,9 @@ class App:
|
||||
Notification.voice_code(Config().NOTIFICATION_VOICE_CODE_PHONE, '张三',
|
||||
OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_CONTENT.format('北京',
|
||||
'深圳'))
|
||||
if Config().EMAIL_ENABLED: # 语音通知
|
||||
CommonLog.add_quick_log(CommonLog.MESSAGE_TEST_SEND_EMAIL).flush()
|
||||
Notification.send_email(Config().EMAIL_RECEIVER, '测试发送邮件', 'By py12306')
|
||||
|
||||
@classmethod
|
||||
def run_check(cls):
|
||||
|
||||
@@ -53,6 +53,14 @@ class Config:
|
||||
REDIS_PORT = '6379'
|
||||
REDIS_PASSWORD = ''
|
||||
|
||||
# 邮箱配置
|
||||
EMAIL_ENABLED = 0
|
||||
EMAIL_SENDER = ''
|
||||
EMAIL_RECEIVER = ''
|
||||
EMAIL_SERVER_HOST = ''
|
||||
EMAIL_SERVER_USER = ''
|
||||
EMAIL_SERVER_PASSWORD = ''
|
||||
|
||||
envs = []
|
||||
retry_time = 5
|
||||
last_modify_time = 0
|
||||
|
||||
@@ -20,6 +20,11 @@ class Notification():
|
||||
self = cls()
|
||||
self.send_voice_code_of_yiyuan(phone, name=name, content=content)
|
||||
|
||||
@classmethod
|
||||
def send_email(cls, to, title='', content=''):
|
||||
self = cls()
|
||||
self.send_email_by_smtp(to, title, content)
|
||||
|
||||
def send_voice_code_of_yiyuan(self, phone, name='', content=''):
|
||||
"""
|
||||
发送语音验证码
|
||||
@@ -54,6 +59,27 @@ class Notification():
|
||||
else:
|
||||
return CommonLog.add_quick_log(CommonLog.MESSAGE_VOICE_API_SEND_FAIL.format(response_message)).flush()
|
||||
|
||||
def send_email_by_smtp(self, to, title, content):
|
||||
import smtplib
|
||||
from email.message import EmailMessage
|
||||
to = to if isinstance(to, list) else [to]
|
||||
message = EmailMessage()
|
||||
message['Subject'] = title
|
||||
message['From'] = 'service@pjialin.com'
|
||||
message['To'] = to
|
||||
message.set_content(content)
|
||||
try:
|
||||
server = smtplib.SMTP(Config().EMAIL_SERVER_HOST)
|
||||
server.login(Config().EMAIL_SERVER_USER, Config().EMAIL_SERVER_PASSWORD)
|
||||
server.send_message(message)
|
||||
server.quit()
|
||||
CommonLog.add_quick_log(CommonLog.MESSAGE_SEND_EMAIL_SUCCESS).flush()
|
||||
except Exception as e:
|
||||
CommonLog.add_quick_log(CommonLog.MESSAGE_SEND_EMAIL_FAIL.format(e)).flush()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Notification.voice_code('13065667742', '张三', '你的车票 广州 到 深圳 购买成功,请登录 12306 进行支付')
|
||||
name = '张三3'
|
||||
content = '你的车票 广州 到 深圳 购买成功,请登录 12306 进行支付'
|
||||
# Notification.voice_code('13800138000', name, content)
|
||||
Notification.send_email('admin@pjialin.com', name, content)
|
||||
|
||||
@@ -33,6 +33,7 @@ class OrderSeatType:
|
||||
|
||||
@singleton
|
||||
class SeatType:
|
||||
NO_SEAT = 26
|
||||
dicts = {
|
||||
'特等座': 25,
|
||||
'商务座': 32,
|
||||
@@ -42,7 +43,5 @@ class SeatType:
|
||||
'硬卧': 28,
|
||||
'动卧': 33,
|
||||
'硬座': 29,
|
||||
'无座': 26,
|
||||
'无座': NO_SEAT,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -22,8 +22,13 @@ class CommonLog(BaseLog):
|
||||
MESSAGE_CHECK_EMPTY_USER_ACCOUNT = '请配置 12306 账号密码'
|
||||
|
||||
MESSAGE_TEST_SEND_VOICE_CODE = '正在测试发送语音验证码...'
|
||||
MESSAGE_TEST_SEND_EMAIL = '正在测试发送邮件...'
|
||||
|
||||
MESSAGE_CONFIG_FILE_DID_CHANGED = '配置文件已修改,正在重新加载中\n'
|
||||
MESSAGE_API_RESPONSE_CAN_NOT_BE_HANDLE = '接口返回错误'
|
||||
|
||||
MESSAGE_SEND_EMAIL_SUCCESS = '邮件发送成功,请检查收件箱'
|
||||
MESSAGE_SEND_EMAIL_FAIL = '邮件发送失败,请手动检查配置,错误原因 {}'
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@@ -18,13 +18,14 @@ class OrderLog(BaseLog):
|
||||
MESSAGE_CHECK_ORDER_INFO_SUCCESS = '检查订单成功'
|
||||
|
||||
MESSAGE_GET_QUEUE_COUNT_SUCCESS = '排队成功,你当前排在第 {} 位, 余票还剩余 {} 张'
|
||||
MESSAGE_GET_QUEUE_LESS_TICKET = '排队失败,目前排队人数已经超过余票张数'
|
||||
MESSAGE_GET_QUEUE_COUNT_FAIL = '排队失败,错误原因 {}'
|
||||
|
||||
MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_SUCCESS = '# 提交订单成功!#'
|
||||
MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_ERROR = '提交订单出错,错误原因 {}'
|
||||
MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_ERROR = '出票失败,错误原因 {}'
|
||||
MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_FAIL = '提交订单失败,错误原因 {}'
|
||||
|
||||
MESSAGE_QUERY_ORDER_WAIT_TIME_WAITING = '排队等待中,预计还需要 {} 秒'
|
||||
MESSAGE_QUERY_ORDER_WAIT_TIME_WAITING = '排队等待中,排队人数 {},预计还需要 {} 秒'
|
||||
MESSAGE_QUERY_ORDER_WAIT_TIME_FAIL = '排队失败,错误原因 {}'
|
||||
MESSAGE_QUERY_ORDER_WAIT_TIME_INFO = '第 {} 次排队,请耐心等待'
|
||||
|
||||
@@ -34,6 +35,9 @@ class OrderLog(BaseLog):
|
||||
MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_START_SEND = '正在发送语音通知, 第 {} 次'
|
||||
MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_CONTENT = '你的车票 {} 到 {} 购买成功,请登录 12306 进行支付'
|
||||
|
||||
MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_EMAIL_CONTENT = '订单号 {},请及时器登录12306,打开 \'未完成订单\',在30分钟内完成支付!'
|
||||
|
||||
|
||||
MESSAGE_JOB_CLOSED = '当前任务已结束'
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -5,7 +5,8 @@ from py12306.config import Config
|
||||
from py12306.helpers.api import *
|
||||
from py12306.helpers.func import *
|
||||
from py12306.helpers.notification import Notification
|
||||
from py12306.helpers.type import UserType
|
||||
from py12306.helpers.type import UserType, SeatType
|
||||
from py12306.log.common_log import CommonLog
|
||||
from py12306.log.order_log import OrderLog
|
||||
|
||||
|
||||
@@ -51,6 +52,8 @@ class Order:
|
||||
"""
|
||||
# Debug
|
||||
if Config().IS_DEBUG:
|
||||
self.order_id = 'test'
|
||||
self.order_did_success()
|
||||
return random.randint(0, 10) > 7
|
||||
return self.normal_order()
|
||||
|
||||
@@ -76,6 +79,9 @@ class Order:
|
||||
def send_notification(self):
|
||||
num = 0 # 通知次数
|
||||
sustain_time = self.notification_sustain_time
|
||||
if Config().EMAIL_ENABLED: # 邮件通知
|
||||
Notification.send_email(Config().EMAIL_RECEIVER, OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE,
|
||||
OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_EMAIL_CONTENT.format(self.order_id))
|
||||
while sustain_time: # TODO 后面直接查询有没有待支付的订单就可以
|
||||
num += 1
|
||||
if Config().NOTIFICATION_BY_VOICE_CODE: # 语音通知
|
||||
@@ -83,10 +89,12 @@ class Order:
|
||||
Notification.voice_code(Config().NOTIFICATION_VOICE_CODE_PHONE, self.user_ins.get_name(),
|
||||
OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_CONTENT.format(
|
||||
self.query_ins.left_station, self.query_ins.arrive_station))
|
||||
else:
|
||||
break
|
||||
sustain_time -= self.notification_interval
|
||||
sleep(self.notification_interval)
|
||||
|
||||
OrderLog.add_quick_log(OrderLog.MESSAGE_JOB_CLOSED)
|
||||
OrderLog.add_quick_log(OrderLog.MESSAGE_JOB_CLOSED).flush()
|
||||
|
||||
def submit_order_request(self):
|
||||
data = {
|
||||
@@ -136,15 +144,23 @@ class Order:
|
||||
response = self.session.post(API_CHECK_ORDER_INFO, data)
|
||||
result = response.json()
|
||||
if result.get('data.submitStatus'): # 成功
|
||||
# ifShowPassCode 需要验证码
|
||||
OrderLog.add_quick_log(OrderLog.MESSAGE_CHECK_ORDER_INFO_SUCCESS).flush()
|
||||
if result.get('data.ifShowPassCode') != 'N':
|
||||
self.is_need_auth_code = True
|
||||
|
||||
# if ( ticketInfoForPassengerForm.isAsync == ticket_submit_order.request_flag.isAsync & & ticketInfoForPassengerForm.queryLeftTicketRequestDTO.ypInfoDetail != "") { 不需要排队检测 js TODO
|
||||
return True
|
||||
else:
|
||||
result_data = result.get('data', {})
|
||||
OrderLog.add_quick_log(OrderLog.MESSAGE_CHECK_ORDER_INFO_FAIL.format(
|
||||
result_data.get('errMsg', result.get('messages', '-'))
|
||||
)).flush()
|
||||
error = CommonLog.MESSAGE_API_RESPONSE_CAN_NOT_BE_HANDLE
|
||||
if not result.get('data.isNoActive'):
|
||||
error = result.get('data.errMsg')
|
||||
else:
|
||||
if result.get('data.checkSeatNum'):
|
||||
error = '无法提交您的订单! ' + result.get('data.errMsg')
|
||||
else:
|
||||
error = '出票失败! ' + result.get('data.errMsg')
|
||||
OrderLog.add_quick_log(OrderLog.MESSAGE_CHECK_ORDER_INFO_FAIL.format(error)).flush()
|
||||
return False
|
||||
|
||||
def get_queue_count(self):
|
||||
@@ -182,7 +198,7 @@ class Order:
|
||||
}
|
||||
response = self.session.post(API_GET_QUEUE_COUNT, data)
|
||||
result = response.json()
|
||||
if result.get('data.countT') or result.get('data.ticket'): # 成功
|
||||
if result.get('status', False): # 成功
|
||||
"""
|
||||
"data": {
|
||||
"count": "66",
|
||||
@@ -191,10 +207,22 @@ class Order:
|
||||
"countT": "0",
|
||||
"op_1": "true"
|
||||
}
|
||||
|
||||
"""
|
||||
ticket = result.get('data.ticket').split(',') # 暂不清楚具体作用
|
||||
ticket_number = sum(map(int, ticket))
|
||||
current_position = int(data.get('countT', 0))
|
||||
# if result.get('isRelogin') == 'Y': # 重新登录 TODO
|
||||
|
||||
ticket = result.get('data.ticket').split(',') # 余票列表
|
||||
# 这里可以判断 是真实是 硬座还是无座,避免自动分配到无座
|
||||
ticket_number = ticket[0] # 余票
|
||||
if ticket_number != '充足' or int(ticket_number) <= 0:
|
||||
if self.query_ins.current_seat == SeatType.NO_SEAT: # 允许无座
|
||||
ticket_number = ticket[1]
|
||||
|
||||
if result.get('data.op_2') == 'true':
|
||||
OrderLog.add_quick_log(OrderLog.MESSAGE_GET_QUEUE_LESS_TICKET).flush()
|
||||
return False
|
||||
|
||||
current_position = int(result.get('data.countT', 0))
|
||||
OrderLog.add_quick_log(
|
||||
OrderLog.MESSAGE_GET_QUEUE_COUNT_SUCCESS.format(current_position, ticket_number)).flush()
|
||||
return True
|
||||
@@ -275,7 +303,7 @@ class Order:
|
||||
"""
|
||||
self.current_queue_wait = self.max_queue_wait
|
||||
while self.current_queue_wait:
|
||||
self.current_queue_wait -= 1
|
||||
self.current_queue_wait -= self.wait_queue_interval
|
||||
# TODO 取消超时订单,待优化
|
||||
data = { #
|
||||
'random': str(random.random())[2:],
|
||||
@@ -303,9 +331,10 @@ class Order:
|
||||
order_id = result_data.get('orderId')
|
||||
if order_id: # 成功
|
||||
return order_id
|
||||
elif result_data.get('waitTime') and result_data.get('waitTime') >= 0:
|
||||
elif result_data.get('waitTime') != -100:
|
||||
OrderLog.add_quick_log(
|
||||
OrderLog.MESSAGE_QUERY_ORDER_WAIT_TIME_WAITING.format(result_data.get('waitTime'))).flush()
|
||||
OrderLog.MESSAGE_QUERY_ORDER_WAIT_TIME_WAITING.format(result_data.get('waitCount', 0),
|
||||
result_data.get('waitTime'))).flush()
|
||||
elif result_data.get('msg'): # 失败 对不起,由于您取消次数过多,今日将不能继续受理您的订票请求。1月8日您可继续使用订票功能。
|
||||
# TODO 需要增加判断 直接结束
|
||||
OrderLog.add_quick_log(
|
||||
|
||||
Reference in New Issue
Block a user