mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-08-23 08:02:24 +02:00
1. Added Mail Marketing Automation trigger tasks 2. Added Mail Marketing Groups Import, Export, Merge 3. Added Mail Marketing Subscribers to support paste import 4. Added Mail Marketing Template Import Export Duplicate 5. Added Mail server add timed automatic reply 6. Added HTTPS Protection function for Website (disables automatic HTTP to HTTPS redirection when enabled) 7. Optimize Website Interface Button Integration 8. Optimize the response speed of WP Toolkit interface
348 lines
13 KiB
Python
348 lines
13 KiB
Python
import json
|
|
import time
|
|
|
|
from datetime import datetime
|
|
from typing import Tuple, Union, Optional
|
|
|
|
from .send_tool import WxAccountMsg
|
|
from .base_task import BaseTask
|
|
from .mods import PUSH_DATA_PATH, TaskConfig, PANEL_PATH
|
|
from .util import read_file, DB, write_file
|
|
from mod.base.web_conf import RealSSLManger
|
|
import public
|
|
|
|
class DomainEndTimeTask(BaseTask):
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.source_name = "domain_endtime"
|
|
self.template_name = "Domain expiration"
|
|
# self.title = "Domain expiration"
|
|
self._tip_file = "{}/domain_endtime.tip".format(PUSH_DATA_PATH)
|
|
self._tip_data: Optional[dict] = None
|
|
self._task_config = TaskConfig()
|
|
|
|
# 每次任务使用
|
|
self.domain_list = []
|
|
self.push_keys = []
|
|
self.task_id = None
|
|
|
|
@property
|
|
def tips(self) -> dict:
|
|
if self._tip_data is not None:
|
|
return self._tip_data
|
|
try:
|
|
self._tip_data = json.loads(read_file(self._tip_file))
|
|
except:
|
|
self._tip_data = {}
|
|
return self._tip_data
|
|
|
|
def save_tip(self):
|
|
write_file(self._tip_file, json.dumps(self.tips))
|
|
|
|
def get_keyword(self, task_data: dict) -> str:
|
|
return task_data["project"]
|
|
|
|
def get_push_data(self, task_id: str, task_data: dict) -> Optional[dict]:
|
|
self.title = self.get_title(task_data)
|
|
# 过滤单独设置提醒的域名
|
|
not_push_web = [i["task_data"]["project"] for i in self._task_config.config if i["source"] == self.source_name]
|
|
|
|
sql = DB("ssl_domains")
|
|
total = self._task_config.get_by_id(task_id).get("number_rule", {}).get("total", 1)
|
|
if "all" in not_push_web:
|
|
not_push_web.remove("all")
|
|
# need_check_list = []
|
|
if task_data["project"] == "all":
|
|
# 所有域名
|
|
domain_list = sql.select()
|
|
for domain in domain_list:
|
|
if domain['domain'] in not_push_web:
|
|
continue
|
|
if self.tips.get(task_id, {}).get(domain['domain'], 0) > total:
|
|
continue
|
|
end_time = datetime.strptime(domain['endtime'], '%Y-%m-%d')
|
|
if int((end_time.timestamp() - time.time()) / 86400) <= task_data['cycle']:
|
|
self.push_keys.append(domain['domain'])
|
|
self.domain_list.append(domain)
|
|
# need_check_list.append(domain['domain'])
|
|
|
|
else:
|
|
find = sql.where('domain=?', (task_data['project'],)).find()
|
|
if not find:
|
|
return None
|
|
|
|
end_time = datetime.strptime(find['endtime'], '%Y-%m-%d')
|
|
if int((end_time.timestamp() - time.time()) / 86400) <= task_data['cycle']:
|
|
self.push_keys.append(find['domain'])
|
|
self.domain_list.append(find)
|
|
|
|
# need_check_list.append((find['domain']))
|
|
|
|
# for name, project_type in need_check_list:
|
|
# info = self._check_end_time(name, task_data['cycle'], project_type)
|
|
# if isinstance(info, dict): # 返回的是详情,说明需要推送了
|
|
# info['site_name'] = name
|
|
# self.push_keys.append(name)
|
|
# self.domain_list.append(info)
|
|
|
|
if len(self.domain_list) == 0:
|
|
return None
|
|
|
|
s_list = ['>About to expire: <font color=#ff0000>{} </font>'.format(len(self.domain_list))]
|
|
for x in self.domain_list:
|
|
s_list.append(">Domain: {} Expiration:{}".format(x['domain'], x['endtime']))
|
|
|
|
self.task_id = task_id
|
|
return {"msg_list": s_list}
|
|
|
|
@staticmethod
|
|
def _check_end_time(site_name, limit, prefix) -> Optional[dict]:
|
|
info = RealSSLManger(conf_prefix=prefix).get_site_ssl_info(site_name)
|
|
if info is not None:
|
|
end_time = datetime.strptime(info['notAfter'], '%Y-%m-%d')
|
|
if int((end_time.timestamp() - time.time()) / 86400) <= limit:
|
|
return info
|
|
return None
|
|
|
|
def get_title(self, task_data: dict) -> str:
|
|
if task_data["project"] == "all":
|
|
return "Domain expiration -- All"
|
|
return "Domain expiration -- [{}]".format(task_data["project"])
|
|
|
|
def to_sms_msg(self, push_data: dict, push_public_data: dict) -> Tuple[str, dict]:
|
|
return 'domain_end|Domain expiration reminders', {
|
|
"name": push_public_data["ip"],
|
|
"domain": self.domain_list[0]['domain'],
|
|
'time': self.domain_list[0]["endtime"],
|
|
'total': len(self.domain_list)
|
|
}
|
|
|
|
def to_wx_account_msg(self, push_data: dict, push_public_data: dict) -> WxAccountMsg:
|
|
msg = WxAccountMsg.new_msg()
|
|
msg.thing_type = "Domain expiration reminders"
|
|
msg.msg = "There are {} domain names that will expire and will affect access".format(len(self.domain_list))
|
|
return msg
|
|
|
|
def check_task_data(self, task_data: dict) -> Union[dict, str]:
|
|
task_data["interval"] = 60 * 60 * 24 # 默认检测间隔时间 1 天
|
|
if not (isinstance(task_data['cycle'], int) and task_data['cycle'] > 1):
|
|
return "The remaining time parameter is incorrect, at least 1 day"
|
|
return task_data
|
|
|
|
def filter_template(self, template) -> dict:
|
|
domain_list = DB("ssl_domains").select()
|
|
|
|
items = [{"title": i["domain"], "value": i["domain"]}for i in domain_list]
|
|
|
|
template["field"][0]["items"].extend(items)
|
|
return template
|
|
|
|
|
|
def check_num_rule(self, num_rule: dict) -> Union[dict, str]:
|
|
num_rule["get_by_func"] = "can_send_by_num_rule"
|
|
return num_rule
|
|
|
|
# 实际的次数检查已在 get_push_data 其他位置完成
|
|
def can_send_by_num_rule(self, task_id: str, task_data: dict, number_rule: dict, push_data: dict) -> Optional[str]:
|
|
return None
|
|
|
|
def task_run_end_hook(self, res) -> None:
|
|
if not res["do_send"]:
|
|
return
|
|
if self.task_id:
|
|
if self.task_id not in self.tips:
|
|
self.tips[self.task_id] = {}
|
|
|
|
for w in self.push_keys:
|
|
if w in self.tips[self.task_id]:
|
|
self.tips[self.task_id][w] += 1
|
|
else:
|
|
self.tips[self.task_id][w] = 1
|
|
|
|
self.save_tip()
|
|
|
|
def task_config_update_hook(self, task: dict) -> None:
|
|
if task["id"] in self.tips:
|
|
self.tips.pop(task["id"])
|
|
self.save_tip()
|
|
|
|
def task_config_remove_hook(self, task: dict) -> None:
|
|
if task["id"] in self.tips:
|
|
self.tips.pop(task["id"])
|
|
self.save_tip()
|
|
|
|
|
|
class CertEndTimeTask(BaseTask):
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.source_name = "cert_endtime"
|
|
self.template_name = "Certificate expiration"
|
|
# self.title = "Certificate expiration"
|
|
self._tip_file = "{}/cert_endtime.tip".format(PUSH_DATA_PATH)
|
|
self._tip_data: Optional[dict] = None
|
|
self._task_config = TaskConfig()
|
|
|
|
# 每次任务使用
|
|
self.cert_list = []
|
|
self.push_keys = []
|
|
self.task_id = None
|
|
|
|
@property
|
|
def tips(self) -> dict:
|
|
if self._tip_data is not None:
|
|
return self._tip_data
|
|
try:
|
|
self._tip_data = json.loads(read_file(self._tip_file))
|
|
except:
|
|
self._tip_data = {}
|
|
return self._tip_data
|
|
|
|
def save_tip(self):
|
|
write_file(self._tip_file, json.dumps(self.tips))
|
|
|
|
def get_keyword(self, task_data: dict) -> str:
|
|
return task_data["project"]
|
|
|
|
def get_push_data(self, task_id: str, task_data: dict) -> Optional[dict]:
|
|
from .util import get_cert_list, to_dict_obj
|
|
|
|
exclude_ids = [i["task_data"]["project"] for i in self._task_config.config if i["source"] == self.source_name]
|
|
total = self._task_config.get_by_id(task_id).get("number_rule", {}).get("total", 1)
|
|
|
|
if "all" in exclude_ids:
|
|
exclude_ids.remove("all")
|
|
data = get_cert_list(to_dict_obj({"status_id": 1}))['data']
|
|
if task_data["project"] == "all":
|
|
for cert in data:
|
|
if cert["ssl_id"] in exclude_ids:
|
|
continue
|
|
if self.tips.get(task_id, {}).get(cert['ssl_id'], 0) > total:
|
|
continue
|
|
if not cert.get("endDay") and cert.get("endDay") != 0:
|
|
continue
|
|
if cert["endDay"] <= task_data["cycle"]:
|
|
self.cert_list.append(cert)
|
|
else:
|
|
for cert in data:
|
|
if cert["ssl_id"] != task_data["project"]:
|
|
continue
|
|
if not cert.get("endDay") and cert.get("endDay") != 0:
|
|
continue
|
|
if cert["endDay"] <= task_data["cycle"]:
|
|
self.cert_list.append(cert)
|
|
self.title = self.get_title(task_data)
|
|
if len(self.cert_list) == 0:
|
|
return None
|
|
|
|
s_list = ['>About to expire: <font color=#ff0000>{} </font>'.format(len(self.cert_list))]
|
|
for x in self.cert_list:
|
|
s_list.append(
|
|
">Certificates: {} [{}]expire in days Websites that may be affected:{}".format("{} | {}".format(x["title"],",".join(x.get("domainName", []) or "None")), x['endDay'], ','.join(x.get('use_site', [])) or "None")
|
|
)
|
|
|
|
self.task_id = task_id
|
|
return {"msg_list": s_list}
|
|
|
|
@staticmethod
|
|
def _check_end_time(site_name, limit, prefix) -> Optional[dict]:
|
|
info = RealSSLManger(conf_prefix=prefix).get_site_ssl_info(site_name)
|
|
if info is not None:
|
|
end_time = datetime.strptime(info['notAfter'], '%Y-%m-%d')
|
|
if int((end_time.timestamp() - time.time()) / 86400) <= limit:
|
|
return info
|
|
return None
|
|
|
|
def get_title(self, task_data: dict) -> str:
|
|
from .util import get_cert_list, to_dict_obj
|
|
if task_data["project"] == "all":
|
|
return "Certificate expiration -- All"
|
|
data = get_cert_list(to_dict_obj({}))['data']
|
|
for cert in data:
|
|
if cert["ssl_id"] == task_data["project"]:
|
|
return "Certificate expiration -- [{} | {}]".format(cert["title"],",".join(cert.get("domainName", []) or "None"))
|
|
return "Domain [{}] expiration reminder".format(task_data["project"])
|
|
|
|
def to_sms_msg(self, push_data: dict, push_public_data: dict) -> Tuple[str, dict]:
|
|
return 'cert_end|Certificate expiration reminders', {
|
|
"name": push_public_data["ip"],
|
|
"cert": self.cert_list[0]['domain'],
|
|
'time': self.cert_list[0]["endtime"],
|
|
'total': len(self.cert_list)
|
|
}
|
|
|
|
def to_wx_account_msg(self, push_data: dict, push_public_data: dict) -> WxAccountMsg:
|
|
msg = WxAccountMsg.new_msg()
|
|
msg.thing_type = "Certificate expiration reminders"
|
|
msg.msg = "There are {} certificates that will expire and will affect access".format(len(self.cert_list))
|
|
return msg
|
|
|
|
def check_task_data(self, task_data: dict) -> Union[dict, str]:
|
|
task_data["interval"] = 60 * 60 * 24 # 默认检测间隔时间 1 天
|
|
if not (isinstance(task_data['cycle'], int) and task_data['cycle'] > 1):
|
|
return "The remaining time parameter is incorrect, at least 1 day"
|
|
return task_data
|
|
|
|
def filter_template(self, template) -> dict:
|
|
from .util import get_cert_list, to_dict_obj
|
|
|
|
items = [
|
|
{"title": "{} | {}".format(i["title"],",".join(i.get("domainName", []) or "None")), "value": i["ssl_id"]}
|
|
for i in get_cert_list(to_dict_obj({}))['data']
|
|
if i.get("endDay")
|
|
]
|
|
|
|
template["field"][0]["items"].extend(items)
|
|
|
|
return template
|
|
|
|
def check_num_rule(self, num_rule: dict) -> Union[dict, str]:
|
|
num_rule["get_by_func"] = "can_send_by_num_rule"
|
|
return num_rule
|
|
|
|
# 实际的次数检查已在 get_push_data 其他位置完成
|
|
def can_send_by_num_rule(self, task_id: str, task_data: dict, number_rule: dict, push_data: dict) -> Optional[str]:
|
|
return None
|
|
|
|
def task_run_end_hook(self, res) -> None:
|
|
if not res["do_send"]:
|
|
return
|
|
if self.task_id:
|
|
if self.task_id not in self.tips:
|
|
self.tips[self.task_id] = {}
|
|
|
|
for w in self.push_keys:
|
|
if w in self.tips[self.task_id]:
|
|
self.tips[self.task_id][w] += 1
|
|
else:
|
|
self.tips[self.task_id][w] = 1
|
|
|
|
self.save_tip()
|
|
|
|
def task_config_update_hook(self, task: dict) -> None:
|
|
if task["id"] in self.tips:
|
|
self.tips.pop(task["id"])
|
|
self.save_tip()
|
|
|
|
def task_config_remove_hook(self, task: dict) -> None:
|
|
if task["id"] in self.tips:
|
|
self.tips.pop(task["id"])
|
|
self.save_tip()
|
|
|
|
class ViewMsgFormat(object):
|
|
_FORMAT = {
|
|
"1": (
|
|
lambda x: "<span>Time remaining less than {} days {}</span>".format(
|
|
x["task_data"].get("cycle"),
|
|
("(If it is not processed, it will be resent 1 time the next day for %d days)" % x.get("number_rule", {}).get("total", 0)) if x.get("number_rule", {}).get("total", 0) else ""
|
|
)
|
|
)
|
|
}
|
|
|
|
def get_msg(self, task: dict) -> Optional[str]:
|
|
if task["template_id"] in ["70", "71"]:
|
|
return self._FORMAT["1"](task)
|
|
if task["template_id"] in self._FORMAT:
|
|
return self._FORMAT[task["template_id"]](task)
|
|
return None |