diff --git a/.gitignore b/.gitignore index 4f53015..d560af3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ fir_client/yarn.lock fir_download/package-lock.json fir_client/src/assets/down_left.png fir_client/src/assets/down_right.png +mailhtml/build/ +mailhtml/node_modules/ +mailhtml/.idea/ diff --git a/fir_ser/common/base/magic.py b/fir_ser/common/base/magic.py index f2203bb..7cf145a 100644 --- a/fir_ser/common/base/magic.py +++ b/fir_ser/common/base/magic.py @@ -7,6 +7,7 @@ import datetime import logging import time from functools import wraps +from importlib import import_module from django.core.cache import cache @@ -115,3 +116,23 @@ def magic_notify(notify_rules, timeout=30 * 24 * 60 * 60): else: notify_cache.del_storage_cache() + + +def import_from_string(dotted_path): + """ + Import a dotted module path and return the attribute/class designated by the + last name in the path. Raise ImportError if the import failed. + """ + try: + module_path, class_name = dotted_path.rsplit('.', 1) + except ValueError as err: + raise ImportError("%s doesn't look like a module path" % dotted_path) from err + + module = import_module(module_path) + + try: + return getattr(module, class_name) + except AttributeError as err: + raise ImportError('Module "%s" does not define a "%s" attribute/class' % ( + module_path, class_name) + ) from err diff --git a/fir_ser/common/core/sysconfig.py b/fir_ser/common/core/sysconfig.py index 5dc71c6..fcf7340 100644 --- a/fir_ser/common/core/sysconfig.py +++ b/fir_ser/common/core/sysconfig.py @@ -14,7 +14,7 @@ from rest_framework import serializers from api.models import SystemConfig from common.cache.storage import SystemConfigCache -from config import BASECONF, API_DOMAIN, MOBILEPROVISION, WEB_DOMAIN, THIRDLOGINCONF, AUTHCONF, IPACONF, MSGCONF, \ +from config import BASECONF, API_DOMAIN, MOBILEPROVISION, WEB_DOMAIN, THIRDLOGINCONF, AUTHCONF, IPACONF, \ DOWNLOADTIMESCONF, PAYCONF, STORAGEKEYCONF, SENDERCONF, APPLEDEVELOPERCONF logger = logging.getLogger(__name__) @@ -268,27 +268,6 @@ class UserDownloadTimesCache(ConfigCacheBase): return super().get_value('AUTH_USER_GIVE_DOWNLOAD_TIMES', DOWNLOADTIMESCONF.AUTH_USER_GIVE_DOWNLOAD_TIMES) -class EmailMsgCache(ConfigCacheBase): - def __init__(self): - super(EmailMsgCache, self).__init__() - - @property - def MSG_NOT_EXIST_DEVELOPER(self): - return super().get_value('MSG_NOT_EXIST_DEVELOPER', MSGCONF.MSG_NOT_EXIST_DEVELOPER) - - @property - def MSG_SING_APP_OVER_LIMIT(self): - return super().get_value('MSG_SING_APP_OVER_LIMIT', MSGCONF.MSG_SING_APP_OVER_LIMIT) - - @property - def MSG_ERROR_DEVELOPER(self): - return super().get_value('MSG_ERROR_DEVELOPER', MSGCONF.MSG_ERROR_DEVELOPER) - - @property - def MSG_AUTO_CHECK_DEVELOPER(self): - return super().get_value('MSG_AUTO_CHECK_DEVELOPER', MSGCONF.MSG_AUTO_CHECK_DEVELOPER) - - class PayConfCache(ConfigCacheBase): def __init__(self): super(PayConfCache, self).__init__() @@ -356,8 +335,8 @@ class AppleDeveloperConfCache(ConfigCacheBase): return super().get_value('DEVELOPER_UID_KEY', APPLEDEVELOPERCONF.DEVELOPER_UID_KEY) -class ConfigCache(BaseConfCache, IpaConfCache, AuthConfCache, EmailMsgCache, UserDownloadTimesCache, GeeTestConfCache, - PayConfCache, ThirdPartConfCache, AppleDeveloperConfCache): +class ConfigCache(BaseConfCache, IpaConfCache, AuthConfCache, UserDownloadTimesCache, GeeTestConfCache, PayConfCache, + ThirdPartConfCache, AppleDeveloperConfCache): def __init__(self): super(ConfigCache, self).__init__() diff --git a/fir_ser/common/libs/sendmsg/emailApi.py b/fir_ser/common/libs/sendmsg/emailApi.py index f1d8eb9..838e35d 100644 --- a/fir_ser/common/libs/sendmsg/emailApi.py +++ b/fir_ser/common/libs/sendmsg/emailApi.py @@ -7,6 +7,8 @@ from django.conf import settings from django.core.mail import send_mail +from common.base.magic import import_from_string + class EmailMsgSender(object): def __init__(self, email_host, email_port, use_tls, use_ssl, subject, username, password, form, template_code): @@ -33,7 +35,9 @@ class EmailMsgSender(object): def send_msg(self, template_code, email, code): try: - response = send_mail(self.subject % {'code': ''}, template_code % {'code': code}, self.form, [email], ) + html_content_obj = import_from_string(template_code) + content = html_content_obj(code) + response = send_mail(self.subject % {'code': ''}, content, self.form, [email], html_message=content) if response == 1: return True, 'OK' else: diff --git a/fir_ser/common/libs/sendmsg/template_content.py b/fir_ser/common/libs/sendmsg/template_content.py new file mode 100644 index 0000000..f02bc53 --- /dev/null +++ b/fir_ser/common/libs/sendmsg/template_content.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# project: fir_ser +# filename: send_template_msg +# author: liuyu +# data: 2022/4/8 + +from django.template import loader + +from common.base.baseutils import get_format_time + + +def get_pay_success_html_content(user_obj, order_obj): + return loader.render_to_string('pay_success.html', + { + 'username': user_obj.first_name, + 'order_obj': order_obj, + }) + + +def get_sign_failed_html_content(user_obj, app_obj, developer_obj, now_time): + return loader.render_to_string('xsign/app_sign_failed.html', + { + 'username': user_obj.first_name, + 'app_obj': app_obj, + 'developer_obj': developer_obj, + 'now_time': now_time + }) + + +def get_sign_unavailable_developer_html_content(user_obj, app_obj, now_time): + return loader.render_to_string('xsign/apple_developer_unavailable.html', + { + 'username': user_obj.first_name, + 'app_obj': app_obj, + 'now_time': now_time + }) + + +def get_sign_app_over_limit_html_content(user_obj, app_obj, now_time, used_num, limit_number): + return loader.render_to_string('xsign/app_sign_over_limit.html', + { + 'username': user_obj.first_name, + 'app_obj': app_obj, + 'now_time': now_time, + 'used_num': used_num, + 'limit_number': limit_number, + }) + + +def get_check_developer_report_html_content(user_obj, developer_obj_list, developer_used_info, yesterday_used_number): + return loader.render_to_string('xsign/timing_task_notify.html', + { + 'username': user_obj.first_name, + 'developer_obj_list': developer_obj_list, + 'developer_used_info': developer_used_info, + 'yesterday_used_number': yesterday_used_number, + }) + + +def get_user_download_times_over_limit_html_content(user_obj): + return loader.render_to_string('download_times_over_limit.html', + { + 'username': user_obj.first_name, + 'user_obj': user_obj, + }) + + +def get_developer_devices_not_enough_html_content(user_obj, device_count): + return loader.render_to_string('xsign/apple_developer_devices_over_limit.html', + { + 'username': user_obj.first_name, + 'user_obj': user_obj, + 'device_count': device_count, + }) + + +def get_developer_cert_expired_html_content(user_obj, developer_obj_list): + return loader.render_to_string('xsign/apple_developer_cert_expired.html', + { + 'username': user_obj.first_name, + 'developer_obj_list': developer_obj_list, + }) + + +def get_user_download_times_not_enough_html_content(user_obj): + return loader.render_to_string('download_times_not_enough.html', + { + 'username': user_obj.first_name, + 'user_obj': user_obj, + }) + + +def get_userinfo_change_html_content(code): + return loader.render_to_string('userinfo/change_userinfo.html', + { + 'now_time': get_format_time().replace('_', ' '), + 'code': code, + }) + + +def get_userinfo_change_code_html_content(code): + return loader.render_to_string('userinfo/change_userinfo.html', + { + 'now_time': get_format_time().replace('_', ' '), + 'code': code, + }) + + +def get_code_notify_html_content(code): + return loader.render_to_string('userinfo/code_notify.html', + { + 'now_time': get_format_time().replace('_', ' '), + 'code': code, + }) + + +def get_userinfo_login_code_html_content(code): + return loader.render_to_string('userinfo/login_code.html', + { + 'now_time': get_format_time().replace('_', ' '), + 'code': code, + }) + + +def get_userinfo_register_code_html_content(code): + return loader.render_to_string('userinfo/register_code.html', + { + 'now_time': get_format_time().replace('_', ' '), + 'code': code, + }) + + +def get_userinfo_reset_pwd_html_content(code): + return loader.render_to_string('userinfo/reset_password.html', + { + 'now_time': get_format_time().replace('_', ' '), + 'code': code, + }) diff --git a/fir_ser/common/libs/sendmsg/templates/check_developer.html b/fir_ser/common/libs/sendmsg/templates/check_developer.html deleted file mode 100644 index bb15fab..0000000 --- a/fir_ser/common/libs/sendmsg/templates/check_developer.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - 开发者状态监测报告 - - - -
-
-

- 尊敬的用户 {{ username }} 你好,苹果开发者状态监测如下: -

-
-

- 当前正常设备总量:{{ developer_used_info.used_sign_number }} -

-

- 已使用:【平台:{{ developer_used_info.used_number }} 】【其他:{{ developer_used_info.can_other_used }}】 -

-

- 还剩:{{ developer_used_info.can_sign_number }} 可用 -

-
-
- 昨天消耗设备数:{{ yesterday_used_number }} -
-
- - - - - - - - - - {% for developer_obj in developer_obj_list %} - - - - - - - {% endfor %} - -
- 苹果开发者ID - - 苹果开发者备注 - - 苹果开发者状态 -
- {{ developer_obj.issuer_id }} - - {{ developer_obj.description }} - - {{ developer_obj.get_status_display }} -
-
-
-
- - diff --git a/fir_ser/common/libs/sendmsg/templates/download_times_not_enough.html b/fir_ser/common/libs/sendmsg/templates/download_times_not_enough.html new file mode 100644 index 0000000..82b64e9 --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/download_times_not_enough.html @@ -0,0 +1,291 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 账户下载余额不足通知 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+
+ 尊敬的用户{{ username }},您好: +
+
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + +
+
+ 您当前账户下载次数仅剩 {{ user_obj.download_times }}
+
+
+ 您当前账户下载次数不足,应用已经无法下载安装。为了避免业务使用,望您尽快充值 +
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/libs/sendmsg/templates/download_times_over_limit.html b/fir_ser/common/libs/sendmsg/templates/download_times_over_limit.html new file mode 100644 index 0000000..e1ed46e --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/download_times_over_limit.html @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 账户下载余额超过阈值通知 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+
+ 尊敬的用户{{ username }},您好: +
+
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + +
+
+ 您当前账户下载次数仅剩 {{ user_obj.download_times }}
+
+
+ 已超过您设置的阈值 {{ user_obj.notify_available_downloads }}
+
+
+ 为了避免业务使用,望您尽快充值! +
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/libs/sendmsg/templates/pay_success.html b/fir_ser/common/libs/sendmsg/templates/pay_success.html new file mode 100644 index 0000000..64b6707 --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/pay_success.html @@ -0,0 +1,321 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 充值到账通知 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+
+ 尊敬的用户{{ username }},您好: +
+
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + +
+
+ 您已经成功充值,订单信息如下 +
+
+
+ 订单号:{{ order_obj.order_number }}
+
+
+ 支付时间:{{ order_obj.pay_time }}
+
+
+ 支付方式:{{ order_obj.get_payment_type_display }}
+
+
+ 订单信息:您充值了 {{ order_obj.actual_download_times }} + 下载次数,【赠送 {{ order_obj.actual_download_gift_times }}】 +
+
+
+ 备注:{{ order_obj.description }}
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/libs/sendmsg/templates/userinfo/change_userinfo.html b/fir_ser/common/libs/sendmsg/templates/userinfo/change_userinfo.html new file mode 100644 index 0000000..08b8718 --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/userinfo/change_userinfo.html @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 重要信息变更验证码 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + +
+
+ 您的验证码:【{{ code }}】 +
+
+
+ 操作时间:{{ now_time }}
+
+
+ 备注:您正在尝试变更重要信息,请妥善保管账户信息 +
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/libs/sendmsg/templates/userinfo/code_notify.html b/fir_ser/common/libs/sendmsg/templates/userinfo/code_notify.html new file mode 100644 index 0000000..31b7f0d --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/userinfo/code_notify.html @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 验证码通知 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + +
+
+ 您的验证码:【{{ code }}】 +
+
+
+ 操作时间:{{ now_time }}
+
+
+ 备注:若非本人操作,请忽略 +
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/libs/sendmsg/templates/userinfo/login_code.html b/fir_ser/common/libs/sendmsg/templates/userinfo/login_code.html new file mode 100644 index 0000000..7f55a48 --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/userinfo/login_code.html @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 登录验证码 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + +
+
+ 您的验证码:【{{ code }}】 +
+
+
+ 操作时间:{{ now_time }}
+
+
+ 备注:您正在进行登录操作,若非本人操作,请勿泄露 +
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/libs/sendmsg/templates/userinfo/register_code.html b/fir_ser/common/libs/sendmsg/templates/userinfo/register_code.html new file mode 100644 index 0000000..a199ff4 --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/userinfo/register_code.html @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 注册验证码 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + +
+
+ 您的验证码:【{{ code }}】 +
+
+
+ 操作时间:{{ now_time }}
+
+
+ 备注:您正在注册成为新用户,感谢您的支持 +
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/libs/sendmsg/templates/userinfo/reset_password.html b/fir_ser/common/libs/sendmsg/templates/userinfo/reset_password.html new file mode 100644 index 0000000..58859a1 --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/userinfo/reset_password.html @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 重置密码通知 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + +
+
+ 您的新密码:【{{ code }}】 +
+
+
+ 操作时间:{{ now_time }}
+
+
+ 备注:您的密码已经重置成功,请用新密码登录,并妥善保管账户信息 +
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/libs/sendmsg/templates/xsign/app_sign_failed.html b/fir_ser/common/libs/sendmsg/templates/xsign/app_sign_failed.html new file mode 100644 index 0000000..496311e --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/xsign/app_sign_failed.html @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 应用【{{ app_obj.name }}】签名失败通知 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+
+ 尊敬的用户{{ username }},您好: +
+
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + + + +
+
+ 应用【{{ app_obj.name }}】签名失败了 +
+
+
+ 签名时间:{{ now_time }}
+
+
+ 失败原因:开发者 {{ developer_obj.issuer_id }} 状态 + {developer_obj.get_status_display()} +
+
+
+ 开发者备注:{{ developer_obj.description }}。请登录后台查看具体失败信息 +
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/libs/sendmsg/templates/xsign/app_sign_over_limit.html b/fir_ser/common/libs/sendmsg/templates/xsign/app_sign_over_limit.html new file mode 100644 index 0000000..95372a6 --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/xsign/app_sign_over_limit.html @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 应用限额-签名失败通知 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+
+ 尊敬的用户{{ username }},您好: +
+
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + +
+
+ 应用【{{ app_obj.name }}】签名失败了 +
+
+
+ 签名时间:{{ now_time }}
+
+
+ 失败原因:该应用已经使用设备数 {{ used_num }},已超过您设置该应用的签名限额 {{ limit_number }},当前已经无法安装新设备,为了避免业务使用,您可以修改该应用签名限额 +
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/libs/sendmsg/templates/xsign/apple_developer_cert_expired.html b/fir_ser/common/libs/sendmsg/templates/xsign/apple_developer_cert_expired.html new file mode 100644 index 0000000..a8ecc5d --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/xsign/apple_developer_cert_expired.html @@ -0,0 +1,312 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 苹果开发者证书即将到期通知 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+
+ 尊敬的用户{{ username }},您好: +
+
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 你以下苹果开发者账号证书即将到期 +
+
+
+ +
+ + + + + + +
+ + + + + + {% for developer_obj in developer_obj_list %} + + + + + {% endfor %} +
苹果开发者ID苹果开发者备注证书到期时间
{{ developer_obj.issuer_id }}{{ developer_obj.description }}{{ developer_obj.cert_expire_time }}
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/libs/sendmsg/templates/xsign/apple_developer_devices_over_limit.html b/fir_ser/common/libs/sendmsg/templates/xsign/apple_developer_devices_over_limit.html new file mode 100644 index 0000000..44b83be --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/xsign/apple_developer_devices_over_limit.html @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 账户超级签名余额超过阈值通知 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+
+ 尊敬的用户{{ username }},您好: +
+
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + +
+
+ 您当前账户超级签名可用设备仅剩 {{ device_count }}
+
+
+ 已超过您设置的阈值 {{ user_obj.notify_available_signs }}
+
+
+ 为了避免业务使用,望您尽快添加苹果开发者! +
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/libs/sendmsg/templates/xsign/apple_developer_unavailable.html b/fir_ser/common/libs/sendmsg/templates/xsign/apple_developer_unavailable.html new file mode 100644 index 0000000..5d74172 --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/xsign/apple_developer_unavailable.html @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 超级签名设备余额不足-签名失败通知 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+
+ 尊敬的用户{{ username }},您好: +
+
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + +
+
+ 应用【{{ app_obj.name }}】签名失败了 +
+
+
+ 签名时间:{{ now_time }}
+
+
+ 失败原因:可用设备量已经不足或超限,请添加新的苹果开发者或修改开发者设备数量 +
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/libs/sendmsg/templates/xsign/timing_task_notify.html b/fir_ser/common/libs/sendmsg/templates/xsign/timing_task_notify.html new file mode 100644 index 0000000..8c772fa --- /dev/null +++ b/fir_ser/common/libs/sendmsg/templates/xsign/timing_task_notify.html @@ -0,0 +1,370 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ 苹果开发者定时任务报告 +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+
+ 尊敬的用户{{ username }},您好: +
+
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + +
+
+ 设备数消耗统计 +
+
+
+ 当前正常设备总量:{{ developer_used_info.used_sign_number }}
+
+
+ 已使用:【平台:{{ developer_used_info.used_number }} + 】【其他:{{ developer_used_info.can_other_used }}】 +
+
+
+ 还剩:{{ developer_used_info.can_sign_number }} 可用 +
+
+
+ 昨天消耗设备数:{{ yesterday_used_number }}
+
+
+ +
+ + + + + + + + + +
+

+

+ +
+
+ 定时任务检测已经执行完成 +
+
+
+ +
+ + + + + + +
+ + + + + + {% for developer_obj in developer_obj_list %} + + + + + {% endfor %} +
苹果开发者ID苹果开发者备注苹果开发者状态
{{ developer_obj.issuer_id }}{{ developer_obj.description }}{{ developer_obj.get_status_display }}
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/fir_ser/common/notify/notify.py b/fir_ser/common/notify/notify.py index 9588424..e4692b0 100644 --- a/fir_ser/common/notify/notify.py +++ b/fir_ser/common/notify/notify.py @@ -8,8 +8,10 @@ import logging from api.utils.modelutils import get_notify_wx_queryset, get_wx_nickname from common.base.baseutils import get_format_time -from common.core.sysconfig import Config from common.libs.mp.wechat import WxTemplateMsg +from common.libs.sendmsg.template_content import get_pay_success_html_content, get_sign_failed_html_content, \ + get_sign_unavailable_developer_html_content, get_sign_app_over_limit_html_content, \ + get_check_developer_report_html_content from common.notify.utils import notify_by_email logger = logging.getLogger(__name__) @@ -27,7 +29,6 @@ def pay_success_notify(user_obj, order_obj): title = f'{order_obj.actual_download_times} 下载次数' if order_obj.actual_download_gift_times > 0: title = f'{title} 【赠送 {order_obj.actual_download_gift_times}】' - msg = f"用户 {user_obj.first_name} 您好,{order_obj.description}。您购买了 {title}。感谢有你!" for wx_user_obj in get_notify_wx_queryset(user_obj, message_type): res = WxTemplateMsg(wx_user_obj.openid, get_wx_nickname(wx_user_obj.openid)).pay_success_msg( title, @@ -37,7 +38,7 @@ def pay_success_notify(user_obj, order_obj): order_obj.order_number, order_obj.description) logger.info(f'user_obj {user_obj} weixin notify pay success result: {res}') - notify_by_email(user_obj, message_type, msg) + notify_by_email(user_obj, message_type, get_pay_success_html_content(user_obj, order_obj)) def sign_failed_notify(user_obj, developer_obj, app_obj): @@ -48,9 +49,6 @@ def sign_failed_notify(user_obj, developer_obj, app_obj): message_type = 3 now_time = get_format_time().replace('_', ' ') - msg = Config.MSG_ERROR_DEVELOPER % ( - user_obj.first_name, app_obj.name, now_time, developer_obj.issuer_id, developer_obj.description) - for wx_user_obj in get_notify_wx_queryset(user_obj, message_type): res = WxTemplateMsg(wx_user_obj.openid, get_wx_nickname(wx_user_obj.openid)).operate_failed_msg( user_obj.first_name, f'应用 {app_obj.name} 签名失败了', @@ -58,7 +56,7 @@ def sign_failed_notify(user_obj, developer_obj, app_obj): f'开发者备注:{developer_obj.description},请登录后台查看具体信息') logger.info(f'user_obj {user_obj} sign_failed_notify result: {res}') - notify_by_email(user_obj, message_type, msg) + notify_by_email(user_obj, message_type, get_sign_failed_html_content(user_obj, app_obj, developer_obj, now_time)) def sign_unavailable_developer_notify(user_obj, app_obj): @@ -68,14 +66,13 @@ def sign_unavailable_developer_notify(user_obj, app_obj): """ message_type = 3 now_time = get_format_time().replace('_', ' ') - msg = Config.MSG_NOT_EXIST_DEVELOPER % (user_obj.first_name, app_obj.name, now_time) for wx_user_obj in get_notify_wx_queryset(user_obj, message_type): res = WxTemplateMsg(wx_user_obj.openid, get_wx_nickname(wx_user_obj.openid)).operate_failed_msg( user_obj.first_name, f'应用 {app_obj.name} 签名失败了', f'苹果开发者总设备量已经超限', now_time, '添加新的苹果开发者或者修改开发者设备数量') logger.info(f'user_obj {user_obj} sign_unavailable_developer result: {res}') - notify_by_email(user_obj, message_type, msg) + notify_by_email(user_obj, message_type, get_sign_unavailable_developer_html_content(user_obj, app_obj, now_time)) def sign_app_over_limit_notify(user_obj, app_obj, used_num, limit_number): @@ -89,16 +86,16 @@ def sign_app_over_limit_notify(user_obj, app_obj, used_num, limit_number): """ message_type = 2 now_time = get_format_time().replace('_', ' ') - msg = Config.MSG_SING_APP_OVER_LIMIT % (user_obj.first_name, app_obj.name, now_time, used_num, limit_number) for wx_user_obj in get_notify_wx_queryset(user_obj, message_type): res = WxTemplateMsg(wx_user_obj.openid, get_wx_nickname(wx_user_obj.openid)).operate_failed_msg( user_obj.first_name, f'应用 {app_obj.name} 签名失败了', f'超过该应用的签名限额 {limit_number}', now_time, f'该应用已经使用设备数 {used_num},已超过您设置该应用的签名限额 {limit_number},当前已经无法安装新设备,为了避免业务使用,您可以修改该应用签名限额') logger.info(f'user_obj {user_obj} sign devices not enough result: {res}') - notify_by_email(user_obj, message_type, msg) + notify_by_email(user_obj, message_type, + get_sign_app_over_limit_html_content(user_obj, app_obj, now_time, used_num, limit_number)) -def check_developer_status_notify(user_obj, developer_obj_list, content): +def check_developer_status_notify(user_obj, developer_obj_list, developer_used_info, yesterday_used_number): """ 7, '系统提醒' @@ -121,4 +118,6 @@ def check_developer_status_notify(user_obj, developer_obj_list, content): res = WxTemplateMsg(wx_user_obj.openid, nick_name).task_finished_msg(title, '苹果开发者状态检测', '完成', now_time, description) logger.info(f'user_obj {user_obj} sign devices not enough result: {res}') - notify_by_email(user_obj, message_type, html=content) + notify_by_email(user_obj, message_type, + get_check_developer_report_html_content(user_obj, developer_obj_list, developer_used_info, + yesterday_used_number)) diff --git a/fir_ser/common/notify/ntasks.py b/fir_ser/common/notify/ntasks.py index de3c1f9..b25ddd2 100644 --- a/fir_ser/common/notify/ntasks.py +++ b/fir_ser/common/notify/ntasks.py @@ -12,6 +12,9 @@ from common.base.magic import magic_wrapper, magic_notify from common.cache.storage import NotifyLoopCache from common.core.sysconfig import Config from common.libs.mp.wechat import WxTemplateMsg +from common.libs.sendmsg.template_content import get_user_download_times_not_enough_html_content, \ + get_developer_devices_not_enough_html_content, get_developer_cert_expired_html_content, \ + get_user_download_times_over_limit_html_content from common.notify.utils import notify_by_email from xsign.models import AppIOSDeveloperInfo from xsign.utils.modelutils import get_developer_devices @@ -31,7 +34,7 @@ def download_times_not_enough(user_obj, msg): res = WxTemplateMsg(wx_user_obj.openid, get_wx_nickname(wx_user_obj.openid)).download_times_not_enough_msg( user_obj.first_name, user_obj.download_times, msg) logger.info(f'user_obj {user_obj} download times not enough result: {res}') - notify_by_email(user_obj, message_type, msg) + notify_by_email(user_obj, message_type, get_user_download_times_not_enough_html_content(user_obj)) def apple_developer_devices_not_enough(user_obj, device_count): @@ -47,7 +50,7 @@ def apple_developer_devices_not_enough(user_obj, device_count): get_wx_nickname(wx_user_obj.openid)).apple_developer_devices_not_enough_msg( user_obj.first_name, device_count, msg) logger.info(f'user_obj {user_obj} sign devices not enough result: {res}') - notify_by_email(user_obj, message_type, msg) + notify_by_email(user_obj, message_type, get_developer_devices_not_enough_html_content(user_obj, device_count)) def apple_developer_cert_expired(user_obj, developer_queryset): @@ -64,11 +67,9 @@ def apple_developer_cert_expired(user_obj, developer_queryset): if developer_count == 1: issuer_id = developer_obj.issuer_id cert_id = developer_obj.certid - msg = f"用户 {user_obj.first_name} 您好,您苹果开发者 {issuer_id} ,证书 {cert_id} 即将到期,到期时间 {expired_time},为了保证您开发者可用,请您尽快更新开发者证书,感谢您的关注" else: issuer_id = f'{developer_obj.issuer_id} 等 {developer_count} 个开发者ID' cert_id = f'{developer_obj.certid} 等 {developer_count} 个证书ID' - msg = f"用户 {user_obj.first_name} 您好,您苹果开发者 {issuer_id} ,证书 {cert_id} 即将到期,到期时间 {expired_time},为了保证您开发者可用,请您尽快更新开发者证书,感谢您的关注 " for wx_user_obj in get_notify_wx_queryset(user_obj, message_type): res = WxTemplateMsg(wx_user_obj.openid, get_wx_nickname(wx_user_obj.openid)).cert_expired_msg(issuer_id, @@ -76,7 +77,7 @@ def apple_developer_cert_expired(user_obj, developer_queryset): expired_time) logger.info(f'user_obj {user_obj} apple developer cert expired result: {res}') - notify_by_email(user_obj, message_type, msg) + notify_by_email(user_obj, message_type, get_developer_cert_expired_html_content(user_obj, developer_queryset)) def check_user_download_times(user_obj, days=None): @@ -84,7 +85,7 @@ def check_user_download_times(user_obj, days=None): days = [0, 3, 7] if user_obj.notify_available_downloads == 0 or user_obj.notify_available_downloads < user_obj.download_times: return - msg = f"您当前账户下载次数仅剩 {user_obj.download_times},已超过您设置的阈值 {user_obj.notify_available_downloads},为了避免业务使用,望您尽快充值!" + msg = get_user_download_times_over_limit_html_content(user_obj) notify_rules = [ { 'func': magic_wrapper(lambda obj: obj.download_times < obj.notify_available_downloads, user_obj), diff --git a/fir_ser/common/notify/utils.py b/fir_ser/common/notify/utils.py index 48bd4a9..0372dee 100644 --- a/fir_ser/common/notify/utils.py +++ b/fir_ser/common/notify/utils.py @@ -12,8 +12,8 @@ from common.utils.sendmsg import get_sender_email_token logger = logging.getLogger(__name__) -def notify_by_email(user_obj, message_type, msg='', html=None): +def notify_by_email(user_obj, message_type, html): for notify_email in get_notify_email_queryset(user_obj, message_type): email = notify_email.get('email') if email: - get_sender_email_token('email', email, 'msg', html if html else f'您好,{user_obj.first_name},{msg}') + get_sender_email_token('email', email, 'msg', html) diff --git a/fir_ser/config.py b/fir_ser/config.py index 54e88a7..28f1e6f 100644 --- a/fir_ser/config.py +++ b/fir_ser/config.py @@ -205,11 +205,11 @@ class SENDERCONF(object): 'form': 'fly分发平台 ', 'subject': '%(code)s验证', 'template_code': { - 'login': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s ,您正在登录,若非本人操作,请勿泄露。', - 'change': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s ,您正在尝试变更重要信息,请妥善保管账户信息。', - 'register': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s ,您正在注册成为新用户,感谢您的支持!', - 'password': '欢迎使用FLY 应用分发平台。 您的新密码为%(code)s , 请用新密码登录之后,及时修改密码,并妥善保管账户信息。', - 'common': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s , 若非本人操作,请忽略。' + 'login': 'common.libs.sendmsg.template_content.get_userinfo_login_code_html_content', + 'change': 'common.libs.sendmsg.template_content.get_userinfo_change_code_html_content', + 'register': 'common.libs.sendmsg.template_content.get_userinfo_register_code_html_content', + 'password': 'common.libs.sendmsg.template_content.get_userinfo_reset_pwd_html_content', + 'common': 'common.libs.sendmsg.template_content.get_code_notify_html_content' } }, 'active': True @@ -379,13 +379,6 @@ bIX1aWjPxirQX9mzaL3oEQI= ] -class MSGCONF(object): - MSG_NOT_EXIST_DEVELOPER = '用户 %s 你好,应用 %s 在 %s 签名失败了,苹果开发者总设备量已经超限,请添加新的苹果开发者或者修改开发者设备数量。感谢有你!' - MSG_ERROR_DEVELOPER = '用户 %s 你好,应用 %s 在 %s 签名失败了,苹果开发者【%s】开发者备注【%s】 信息异常,请重新检查苹果开发者状态是否正常。感谢有你!' - MSG_AUTO_CHECK_DEVELOPER = '用户 %s 你好,苹果开发者 %s 信息异常,请重新检查苹果开发者状态是否正常。感谢有你!' - MSG_SING_APP_OVER_LIMIT = '用户 %s 你好,应用 %s 在 %s 签名失败了,该应用已经使用设备数 %s,超过您设置的签名限额 %s,当前已经无法安装新设备,为了避免业务使用,您可以修改该应用签名限额 ' - - class DOWNLOADTIMESCONF(object): USER_FREE_DOWNLOAD_TIMES = 5 AUTH_USER_FREE_DOWNLOAD_TIMES = 10 diff --git a/fir_ser/xsign/utils/ctasks.py b/fir_ser/xsign/utils/ctasks.py index 17dd07d..f3eb6ee 100644 --- a/fir_ser/xsign/utils/ctasks.py +++ b/fir_ser/xsign/utils/ctasks.py @@ -10,8 +10,6 @@ import random import time from concurrent.futures import ThreadPoolExecutor -from django.template import loader - from common.core.sysconfig import Config from common.notify.notify import check_developer_status_notify from fir_ser.settings import SUPER_SIGN_ROOT, SYNC_CACHE_TO_DATABASE @@ -76,15 +74,7 @@ def auto_check_ios_developer_active(): yesterday_used_number = APPSuperSignUsedInfo.objects.filter(developerid__user_id=userinfo, created_time__range=[start_time, end_time]).count() developer_obj_list = sorted(developer_obj_list, key=lambda obj: obj.status) - content = loader.render_to_string('check_developer.html', - { - 'username': userinfo.first_name, - 'developer_obj_list': developer_obj_list, - 'developer_used_info': developer_used_info, - 'yesterday_used_number': yesterday_used_number, - }) - # send_ios_developer_active_status(userinfo, content) - check_developer_status_notify(userinfo, developer_obj_list, content) + check_developer_status_notify(userinfo, developer_obj_list, developer_used_info, yesterday_used_number) def auto_clean_sign_log(clean_day=30 * 6): diff --git a/fir_ser/xsign/utils/iproxy.py b/fir_ser/xsign/utils/iproxy.py index 09dbddb..d6eae95 100644 --- a/fir_ser/xsign/utils/iproxy.py +++ b/fir_ser/xsign/utils/iproxy.py @@ -9,6 +9,7 @@ import time from concurrent.futures import ThreadPoolExecutor import requests +from django.core.cache import cache from common.cache.storage import IpProxyListCache, IpProxyActiveCache from common.core.sysconfig import Config @@ -61,7 +62,10 @@ def get_proxy_ip_from_cache(issuer_id, change_ip=False): list_proxy_cache = IpProxyListCache() ip_proxy_result = list_proxy_cache.get_storage_cache() if not ip_proxy_result: - ip_proxy_result = get_best_proxy_ips() + with cache.lock('get_best_proxy_ips_locker', timeout=360): + ip_proxy_result = list_proxy_cache.get_storage_cache() + if not ip_proxy_result: + ip_proxy_result = get_best_proxy_ips() if change_ip and ip_proxy_result: try: diff --git a/fir_ser/xsign/utils/utils.py b/fir_ser/xsign/utils/utils.py index 1013dc9..cf57006 100644 --- a/fir_ser/xsign/utils/utils.py +++ b/fir_ser/xsign/utils/utils.py @@ -6,7 +6,6 @@ import logging from api.utils.utils import delete_local_files -from common.utils.sendmsg import get_sender_email_token from common.utils.storage import Storage from xsign.models import APPToDeveloper @@ -21,12 +20,3 @@ def delete_app_to_dev_and_file(developer_obj, app_id): storage = Storage(developer_obj.user_id) storage.delete_file(binary_file) app_to_developer_obj.delete() - - -def send_ios_developer_active_status(user_info, msg): - act = 'email' - email = user_info.email - if email: - get_sender_email_token(act, email, 'msg', msg) - else: - logger.warning(f"user {user_info} has no email. so {msg} can't send!") diff --git a/mailhtml/build.js b/mailhtml/build.js new file mode 100644 index 0000000..46b2598 --- /dev/null +++ b/mailhtml/build.js @@ -0,0 +1,61 @@ +const spawn = require("child_process").spawn; +const path = require('path') +const fs = require('fs') +const cmdPath = path.resolve('./node_modules/.bin/mjml.cmd') + + +function build_html(file_full_path, buildPath) { + let output_path = file_full_path.replace('mjml.html','html') + output_path = path.join(buildPath,path.basename(output_path)) + return new Promise(function(resolve, reject) { + let result = spawn(cmdPath, [file_full_path,'-o',output_path]); + result.on('close', function(code) { + if(code === 0){ + console.log('build success. output:'+output_path) + }else { + console.log('child process exited with code :' + code); + } + }); + result.stdout.on('data', function(data) { + console.log('stdout: ' + data); + }); + result.stderr.on('data', function(data) { + console.log('stderr: ' + data); + reject(new Error(data.toString())); + }); + resolve(); + }); +} +let filePath = path.resolve('./src') +let buildPath = path.resolve('./build') +fs.exists(buildPath,function (exists) { + if(!exists){ + fs.mkdir(buildPath,res=>{ + }) + }else { + fs.rmdir(buildPath,{recursive:true},res=>{ + fs.mkdir(buildPath,res=>{ + }) + }) + } +}) +fs.readdir(filePath,function (err,files) { + if (err) { + console.warn(err, "读取文件夹错误!") + } else { + files.forEach(function(filename) { + //获取当前文件的绝对路径 + let file_full_path = path.join(filePath, filename); + fs.stat(file_full_path, function(error, stats) { + if (error) { + console.warn('获取文件stats失败'); + } else { + if(stats.isFile() && file_full_path.endsWith('.mjml.html')){ + build_html(file_full_path, buildPath).then() + } + } + }) + + }) + } +}) diff --git a/mailhtml/package-lock.json b/mailhtml/package-lock.json new file mode 100644 index 0000000..b1d78c1 --- /dev/null +++ b/mailhtml/package-lock.json @@ -0,0 +1,1115 @@ +{ + "name": "mailhtml", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/runtime": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "cheerio": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", + "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", + "requires": { + "cheerio-select": "^1.5.0", + "dom-serializer": "^1.3.2", + "domhandler": "^4.2.0", + "htmlparser2": "^6.1.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "tslib": "^2.2.0" + } + }, + "cheerio-select": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.6.0.tgz", + "integrity": "sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g==", + "requires": { + "css-select": "^4.3.0", + "css-what": "^6.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.3.1", + "domutils": "^2.8.0" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "clean-css": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", + "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "requires": { + "source-map": "~0.6.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" + }, + "dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "requires": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-goat": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", + "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "html-minifier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", + "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", + "requires": { + "camel-case": "^3.0.0", + "clean-css": "^4.2.1", + "commander": "^2.19.0", + "he": "^1.2.0", + "param-case": "^2.1.1", + "relateurl": "^0.2.7", + "uglify-js": "^3.5.1" + } + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "js-beautify": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.2.tgz", + "integrity": "sha512-H85kX95a53os+q1OCqtYe8AXAmgy3BvtysA/V83S3fdhznm6WlUpGi14DqSPbKFsL3dXZFXYl7YQwW9U1+76ng==", + "requires": { + "config-chain": "^1.1.12", + "editorconfig": "^0.15.3", + "glob": "^7.1.3", + "nopt": "^5.0.0" + } + }, + "juice": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/juice/-/juice-7.0.0.tgz", + "integrity": "sha512-AjKQX31KKN+uJs+zaf+GW8mBO/f/0NqSh2moTMyvwBY+4/lXIYTU8D8I2h6BAV3Xnz6GGsbalUyFqbYMe+Vh+Q==", + "requires": { + "cheerio": "^1.0.0-rc.3", + "commander": "^5.1.0", + "mensch": "^0.3.4", + "slick": "^1.12.2", + "web-resource-inliner": "^5.0.0" + }, + "dependencies": { + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + } + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "mensch": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", + "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==" + }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mjml": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml/-/mjml-4.12.0.tgz", + "integrity": "sha512-uWDu1pPQVyoX4iKIrM02J6qOBN6PC1rSMP64DKi2qGU4dpOztVgvTBh6JttIbINV4ZiALtpeGu+jeEUqp2ROXA==", + "requires": { + "@babel/runtime": "^7.14.6", + "mjml-cli": "4.12.0", + "mjml-core": "4.12.0", + "mjml-migrate": "4.12.0", + "mjml-preset-core": "4.12.0", + "mjml-validator": "4.12.0" + } + }, + "mjml-accordion": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-accordion/-/mjml-accordion-4.12.0.tgz", + "integrity": "sha512-vqBk4NhXN+w6F3c5vnLxkvgneREpkwTzZpbxtMzpNqkUW2yei0oSQ26j/wLgXYTaX+4Czp+oVr0cnNxjyCZHjA==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-body": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-body/-/mjml-body-4.12.0.tgz", + "integrity": "sha512-IQBAHhdRKsNUXat+oxvRTjVJ1qzTRkNjFe/mtD/Pbn9olUnQmV+RKxnkqRZf7QtiTxVIOGC4kU9VLPjNymsFXQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-button": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-button/-/mjml-button-4.12.0.tgz", + "integrity": "sha512-XJfLP+mHvCr6Ky16ooYz5+8ODkf10+ATyvENCKyrof+rietr5WxN2FxWCZA9Orq20OE74/hvaOeZZdkxwtsXig==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-carousel": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-carousel/-/mjml-carousel-4.12.0.tgz", + "integrity": "sha512-vQ5Aqvix9mbAE0GspxIDpKK4dVMRuKFO3qV6N/CkrIAOe4+2CKV4AMn2fWUvQEx6hA6CGxayeLkI7E0hNOWcZA==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-cli": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-cli/-/mjml-cli-4.12.0.tgz", + "integrity": "sha512-//Y4XsN6aFgpZtDbQZRu4qe+CQzGWV3i5K3rC1dwPcdtpDMsXBPKiwIZFrQxpRVBwxs0hU4ZBQOMtvYZkoicdQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "chokidar": "^3.0.0", + "glob": "^7.1.1", + "html-minifier": "^4.0.0", + "js-beautify": "^1.6.14", + "lodash": "^4.17.21", + "mjml-core": "4.12.0", + "mjml-migrate": "4.12.0", + "mjml-parser-xml": "4.12.0", + "mjml-validator": "4.12.0", + "yargs": "^16.1.0" + } + }, + "mjml-column": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-column/-/mjml-column-4.12.0.tgz", + "integrity": "sha512-Ub/7ov2B1T2jfSpxvF61o3UCU4gGDFUqIelr7ghuazLc2KvTwdHYeR8mWt8l8RBM6zZiWjkYEFMP22ty7WXztg==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-core": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-4.12.0.tgz", + "integrity": "sha512-B3gUkV3kFN1IlzIV3GnpWBmE21XHH5ARyydMxacR75iC53PvJ9c50hr6DWLGdrrDCC6Fdud8jTmgD9dnWPmJhQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "cheerio": "1.0.0-rc.10", + "detect-node": "2.0.4", + "html-minifier": "^4.0.0", + "js-beautify": "^1.6.14", + "juice": "^7.0.0", + "lodash": "^4.17.21", + "mjml-migrate": "4.12.0", + "mjml-parser-xml": "4.12.0", + "mjml-validator": "4.12.0" + } + }, + "mjml-divider": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-divider/-/mjml-divider-4.12.0.tgz", + "integrity": "sha512-L87iqrhVS+PnUInYbXK4lcTQcHfWMTL7ZqDL9XEMBywzX8cCfviLNMbqmLCO2HD8nMPVMRbcE32H04T6LyZ2qw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-group": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-group/-/mjml-group-4.12.0.tgz", + "integrity": "sha512-Rl7Iydd7M2SnbH1ItIi07hYY+FrEai5c6kYMKbcFWAuNupCuvUThuhx1AphMPCZFMLbbPSKNWMarBkWhepS7cw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-head": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-head/-/mjml-head-4.12.0.tgz", + "integrity": "sha512-LcI4ykOB6nMV5W//tF9S1unlXxexfNZUnnyZ2OOzP1V7J5poLXdKXqB8XATN2YGGTsDZ5Q/5V1KO+NnjpW7zSw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-head-attributes": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-head-attributes/-/mjml-head-attributes-4.12.0.tgz", + "integrity": "sha512-tRwKUzIrtcw1FGy8Xpy4vrFo0u2daZgqx3X0cM5WWrGFcKe7ZdjNEAkU/3w+WsFjeMcb0fHdKvd+sxBjPJ6fpA==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-head-breakpoint": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-head-breakpoint/-/mjml-head-breakpoint-4.12.0.tgz", + "integrity": "sha512-BVVbvAIcIu49P1EJkEPPIY8Gu4GleyzpkdddqD3ihAPn3Pz07SEsFlHvI35eCszuaJeeMbSSxLrsF4m+aQQlvw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-head-font": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-head-font/-/mjml-head-font-4.12.0.tgz", + "integrity": "sha512-ja5sWbGOIr1gF/7IIPzrgOlWYiKk57BC8JWYRANV7CxNKa635sd6aBJHbzXv1A6Ph+zH5KtE0MSQCK8n49BIsw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-head-html-attributes": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-head-html-attributes/-/mjml-head-html-attributes-4.12.0.tgz", + "integrity": "sha512-XJesJuW9uzlNN5w/S7t5ZquSVDay7BehOKmIZKMwKn1y0SJBXiakcwt9M9hhF0HB189Bew0gpGt3m7QYvTez8g==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-head-preview": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-head-preview/-/mjml-head-preview-4.12.0.tgz", + "integrity": "sha512-pr02ZkxwU6/LWhrL3xP/hLrUXx27I1FnfgaYjgvMjh6pMURuy7W+W8BrNJKeyXZo685b2A5lNFDJV7rCJ6HrEQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-head-style": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-head-style/-/mjml-head-style-4.12.0.tgz", + "integrity": "sha512-64IVdJ2Xl000SrwLt4cebl+MiZcino/ywMkuLQ/c48XeR6pkvbjXYAInWsdlMG1y041n1bOZICNnQQc4xhNJrw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-head-title": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-head-title/-/mjml-head-title-4.12.0.tgz", + "integrity": "sha512-c7thJUmNLIdVy1ftLbYUjchHwrIfAb9SHdbuVQHdtQz45a3Ni2nie4AWxF/srn90k8q/uEKtQq1taOa4f71Zug==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-hero": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-hero/-/mjml-hero-4.12.0.tgz", + "integrity": "sha512-j87DgSAyLzMMuNtVqR1okkI/orKnvZoR7i+RsA1yueNql9dZtnw3Ezy8cas8MJaAoGOmqIy9AqGRJIr82w4mxQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-image": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-image/-/mjml-image-4.12.0.tgz", + "integrity": "sha512-P77M+PLLNn7QvGhL8sx+6yzkQbEMxIQO3yxqUC+x8Ie8kXS8phSNGcqx8qfhdN7p7sQ3CZdOIZSXkG7RRAF94w==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-migrate": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.12.0.tgz", + "integrity": "sha512-KDdPkuOzL9CAekY0CslM0Yqiomk4TubNMszw6UFfylp5xRA3CfBo0HdGcnewHBkZ8+isjPlzDWf3n+NkU11OiA==", + "requires": { + "@babel/runtime": "^7.14.6", + "js-beautify": "^1.6.14", + "lodash": "^4.17.21", + "mjml-core": "4.12.0", + "mjml-parser-xml": "4.12.0", + "yargs": "^16.1.0" + } + }, + "mjml-navbar": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-navbar/-/mjml-navbar-4.12.0.tgz", + "integrity": "sha512-TWKV5lFgwUvRbG+FNz6Uo7mGPJRU/BK1v0BeQr1e5Ykft4052iYIuv2XNwRkeoORmLT+7AN8FbkP+TVBpflbWw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-parser-xml": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.12.0.tgz", + "integrity": "sha512-cmCcvoiirH0kuCglGAjwBVfDrlnqS3e83uBwPN6wDN6IfxSgsPT6IV0vRfcJERsr2ThpFjvoSq4GmYi9oCUSMw==", + "requires": { + "@babel/runtime": "^7.14.6", + "detect-node": "2.0.4", + "htmlparser2": "^4.1.0", + "lodash": "^4.17.15" + }, + "dependencies": { + "domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "requires": { + "domelementtype": "^2.0.1" + } + }, + "htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } + } + } + }, + "mjml-preset-core": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-preset-core/-/mjml-preset-core-4.12.0.tgz", + "integrity": "sha512-zoiCKcl/bK43ltr2J8dY9Qg5fcB3TbhaWcTG84oGYWdii5WEkKTXj5hpP1ss1XqdOGMNLij/HVwmli+xQCo6FQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "mjml-accordion": "4.12.0", + "mjml-body": "4.12.0", + "mjml-button": "4.12.0", + "mjml-carousel": "4.12.0", + "mjml-column": "4.12.0", + "mjml-divider": "4.12.0", + "mjml-group": "4.12.0", + "mjml-head": "4.12.0", + "mjml-head-attributes": "4.12.0", + "mjml-head-breakpoint": "4.12.0", + "mjml-head-font": "4.12.0", + "mjml-head-html-attributes": "4.12.0", + "mjml-head-preview": "4.12.0", + "mjml-head-style": "4.12.0", + "mjml-head-title": "4.12.0", + "mjml-hero": "4.12.0", + "mjml-image": "4.12.0", + "mjml-navbar": "4.12.0", + "mjml-raw": "4.12.0", + "mjml-section": "4.12.0", + "mjml-social": "4.12.0", + "mjml-spacer": "4.12.0", + "mjml-table": "4.12.0", + "mjml-text": "4.12.0", + "mjml-wrapper": "4.12.0" + } + }, + "mjml-raw": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-raw/-/mjml-raw-4.12.0.tgz", + "integrity": "sha512-vQUmrEZEgu0DCca7tiPdQ/vf8GM5QyeaabbLd1rX3XCt5Mid47LCdszmVcrk1WxqNuExIw1fNyEGCCDeP2qCJg==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-section": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-section/-/mjml-section-4.12.0.tgz", + "integrity": "sha512-5BdHrAghS/XJ40t3qtLHpY3rIVuBnJXv8dGm8U+oMVAzw3L4ySk5WI+FulRkchdPFCKpeXQZjXZaX0C7pmNaIw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-social": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-social/-/mjml-social-4.12.0.tgz", + "integrity": "sha512-eTsqJoKP65Imawh+WEX2dv4N34ItUmvIbsCeSQPhC/NG6klxDjzg5oDA1F2tZk+CPIuXVmJiauQ5/vPHLzUiVw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-spacer": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-spacer/-/mjml-spacer-4.12.0.tgz", + "integrity": "sha512-YB+VCixcuWXDzICrGLFw7PJDkL166e4OG8IUUB2yhvd5VHtFFBc0iRksaEAumOL1r6MnXVCRq4Wcmxlzj7zOfQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-table": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-table/-/mjml-table-4.12.0.tgz", + "integrity": "sha512-IuLvyiJOsM6RgobuIfZuM36fJcoH8pK/A4awCLTEme0HCxEkkjzDkl4RBMK/KX53Cpor0U6oR6RlQfZcducpLg==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-text": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-text/-/mjml-text-4.12.0.tgz", + "integrity": "sha512-AFcXiQBC48ZfKKgAdU0NRS2nqftc8zLGxBtPwHNgFkuh5Lf2rWgPK6JRubNi7qhb8Sd7M8stU+LIRA5sxM1nRQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0" + } + }, + "mjml-validator": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-validator/-/mjml-validator-4.12.0.tgz", + "integrity": "sha512-EmOScfcJJ4LdIyHnE+K4FdkryQ+c6QRV7qp+zlunAHE5AUPaBS0OrHPHuNo1sOu7g1tc+bVl7eHR4FIb0Wkzwg==", + "requires": { + "@babel/runtime": "^7.14.6" + } + }, + "mjml-wrapper": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mjml-wrapper/-/mjml-wrapper-4.12.0.tgz", + "integrity": "sha512-u0pq+A9QBLwpeF/hdv2uWZIv3Qp4wwf+CMaHZsUpb3YfOJD/6YKwLvkeA7ngE+YxwwzgtgjmIEs4eDae1evlgQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.12.0", + "mjml-section": "4.12.0" + } + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "requires": { + "boolbase": "^1.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "requires": { + "no-case": "^2.2.0" + } + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "requires": { + "parse5": "^6.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, + "slick": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", + "integrity": "sha1-vQSN23TefRymkV+qSldXCzVQwtc=" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, + "uglify-js": { + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.3.tgz", + "integrity": "sha512-6iCVm2omGJbsu3JWac+p6kUiOpg3wFO2f8lIXjfEb8RrmLjzog1wTPMmwKB7swfzzqxj9YM+sGUM++u1qN4qJg==" + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" + }, + "valid-data-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", + "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==" + }, + "web-resource-inliner": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-5.0.0.tgz", + "integrity": "sha512-AIihwH+ZmdHfkJm7BjSXiEClVt4zUFqX4YlFAzjL13wLtDuUneSaFvDBTbdYRecs35SiU7iNKbMnN+++wVfb6A==", + "requires": { + "ansi-colors": "^4.1.1", + "escape-goat": "^3.0.0", + "htmlparser2": "^4.0.0", + "mime": "^2.4.6", + "node-fetch": "^2.6.0", + "valid-data-url": "^3.0.0" + }, + "dependencies": { + "domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "requires": { + "domelementtype": "^2.0.1" + } + }, + "htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } + } + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + } + } +} diff --git a/mailhtml/package.json b/mailhtml/package.json new file mode 100644 index 0000000..504173e --- /dev/null +++ b/mailhtml/package.json @@ -0,0 +1,16 @@ +{ + "name": "mailhtml", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "build.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "mjml": "^4.12.0" + } +} diff --git a/mailhtml/src/app_sign_failed.mjml.html b/mailhtml/src/app_sign_failed.mjml.html new file mode 100644 index 0000000..250d947 --- /dev/null +++ b/mailhtml/src/app_sign_failed.mjml.html @@ -0,0 +1,41 @@ + + + + + + + 应用【{{app_obj.name}}】签名失败通知 + + + + + + + + + + 应用【{{app_obj.name}}】签名失败了 + + + 签名时间:{{ now_time }} + + + 失败原因:开发者 {{developer_obj.issuer_id}} 状态 {developer_obj.get_status_display()} + + + 开发者备注:{{developer_obj.description}}。请登录后台查看具体失败信息 + + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/app_sign_over_limit.mjml.html b/mailhtml/src/app_sign_over_limit.mjml.html new file mode 100644 index 0000000..ba79076 --- /dev/null +++ b/mailhtml/src/app_sign_over_limit.mjml.html @@ -0,0 +1,38 @@ + + + + + + + 应用限额-签名失败通知 + + + + + + + + + + 应用【{{app_obj.name}}】签名失败了 + + + 签名时间:{{ now_time }} + + + 失败原因:该应用已经使用设备数 {{used_num}},已超过您设置该应用的签名限额 {{limit_number}},当前已经无法安装新设备,为了避免业务使用,您可以修改该应用签名限额 + + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/apple_developer_cert_expired.mjml.html b/mailhtml/src/apple_developer_cert_expired.mjml.html new file mode 100644 index 0000000..4b751b6 --- /dev/null +++ b/mailhtml/src/apple_developer_cert_expired.mjml.html @@ -0,0 +1,56 @@ + + + + + + + 苹果开发者证书即将到期通知 + + + + + + + + + + 你以下苹果开发者账号证书即将到期 + + + + + + + + + 苹果开发者ID + 苹果开发者备注 + 证书到期时间 + + + {% for developer_obj in developer_obj_list %} + + + {{ developer_obj.issuer_id }} + {{ developer_obj.description }} + {{ developer_obj.cert_expire_time }} + + {% endfor %} + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/apple_developer_devices_over_limit.mjml.html b/mailhtml/src/apple_developer_devices_over_limit.mjml.html new file mode 100644 index 0000000..72a0323 --- /dev/null +++ b/mailhtml/src/apple_developer_devices_over_limit.mjml.html @@ -0,0 +1,37 @@ + + + + + + + 账户超级签名余额超过阈值通知 + + + + + + + + + + 您当前账户超级签名可用设备仅剩 {{device_count}} + + + 已超过您设置的阈值 {{user_obj.notify_available_signs}} + + + 为了避免业务使用,望您尽快添加苹果开发者! + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/apple_developer_unavailable.mjml.html b/mailhtml/src/apple_developer_unavailable.mjml.html new file mode 100644 index 0000000..40dc436 --- /dev/null +++ b/mailhtml/src/apple_developer_unavailable.mjml.html @@ -0,0 +1,38 @@ + + + + + + + 超级签名设备余额不足-签名失败通知 + + + + + + + + + + 应用【{{app_obj.name}}】签名失败了 + + + 签名时间:{{ now_time }} + + + 失败原因:可用设备量已经不足或超限,请添加新的苹果开发者或修改开发者设备数量 + + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/base/footer.mjml b/mailhtml/src/base/footer.mjml new file mode 100644 index 0000000..a13868e --- /dev/null +++ b/mailhtml/src/base/footer.mjml @@ -0,0 +1,7 @@ + + + + FLY 应用分发平台 + + + diff --git a/mailhtml/src/base/username.mjml b/mailhtml/src/base/username.mjml new file mode 100644 index 0000000..e53cb8a --- /dev/null +++ b/mailhtml/src/base/username.mjml @@ -0,0 +1,8 @@ + + + + 尊敬的用户{{ + username }},您好: + + + \ No newline at end of file diff --git a/mailhtml/src/change_userinfo.mjml.html b/mailhtml/src/change_userinfo.mjml.html new file mode 100644 index 0000000..68b9972 --- /dev/null +++ b/mailhtml/src/change_userinfo.mjml.html @@ -0,0 +1,37 @@ + + + + + + + 重要信息变更验证码 + + + + + + + + + 您的验证码:【{{ code }}】 + + + 操作时间:{{ now_time }} + + + 备注:您正在尝试变更重要信息,请妥善保管账户信息 + + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/code_notify.mjml.html b/mailhtml/src/code_notify.mjml.html new file mode 100644 index 0000000..3e63aa9 --- /dev/null +++ b/mailhtml/src/code_notify.mjml.html @@ -0,0 +1,37 @@ + + + + + + + 验证码通知 + + + + + + + + + 您的验证码:【{{ code }}】 + + + 操作时间:{{ now_time }} + + + 备注:若非本人操作,请忽略 + + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/download_times_not_enough.mjml.html b/mailhtml/src/download_times_not_enough.mjml.html new file mode 100644 index 0000000..6f30929 --- /dev/null +++ b/mailhtml/src/download_times_not_enough.mjml.html @@ -0,0 +1,34 @@ + + + + + + + 账户下载余额不足通知 + + + + + + + + + + 您当前账户下载次数仅剩 {{user_obj.download_times}} + + + 您当前账户下载次数不足,应用已经无法下载安装。为了避免业务使用,望您尽快充值 + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/download_times_over_limit.mjml.html b/mailhtml/src/download_times_over_limit.mjml.html new file mode 100644 index 0000000..3293053 --- /dev/null +++ b/mailhtml/src/download_times_over_limit.mjml.html @@ -0,0 +1,37 @@ + + + + + + + 账户下载余额超过阈值通知 + + + + + + + + + + 您当前账户下载次数仅剩 {{user_obj.download_times}} + + + 已超过您设置的阈值 {{user_obj.notify_available_downloads}} + + + 为了避免业务使用,望您尽快充值! + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/index.html b/mailhtml/src/index.html new file mode 100644 index 0000000..8034673 --- /dev/null +++ b/mailhtml/src/index.html @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+
+ 尊敬的用户{{ username }},您好: +
+
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + +
+
+ 应用【{{app_obj.name}}】签名失败了 +
+
+
+ 签名时间:{{ now_time }} +
+
+
+ 失败原因:该应用已经使用设备数 {{used_num}},已超过您设置该应用的签名限额 + {{limit_number}},当前已经无法安装新设备,为了避免业务使用,您可以修改该应用签名限额 +
+
+
+ +
+
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ FLY 应用分发平台 +
+
+
+ +
+
+ +
+ + + diff --git a/mailhtml/src/index.mjml.html b/mailhtml/src/index.mjml.html new file mode 100644 index 0000000..28b2940 --- /dev/null +++ b/mailhtml/src/index.mjml.html @@ -0,0 +1,34 @@ + + + + + + + 账户下载余额不足通知 + + + + + + + + + + 您当前账户下载次数仅剩 {{user_obj.download_times}} + + + 为了避免业务使用,望您尽快充值! + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/login_code.mjml.html b/mailhtml/src/login_code.mjml.html new file mode 100644 index 0000000..ced6377 --- /dev/null +++ b/mailhtml/src/login_code.mjml.html @@ -0,0 +1,37 @@ + + + + + + + 登录验证码 + + + + + + + + + 您的验证码:【{{ code }}】 + + + 操作时间:{{ now_time }} + + + 备注:您正在进行登录操作,若非本人操作,请勿泄露 + + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/pay_success.mjml.html b/mailhtml/src/pay_success.mjml.html new file mode 100644 index 0000000..36366a8 --- /dev/null +++ b/mailhtml/src/pay_success.mjml.html @@ -0,0 +1,47 @@ + + + + + + + 充值到账通知 + + + + + + + + + + 您已经成功充值,订单信息如下 + + + 订单号:{{order_obj.order_number}} + + + 支付时间:{{order_obj.pay_time}} + + + 支付方式:{{order_obj.get_payment_type_display}} + + + 订单信息:您充值了 {{order_obj.actual_download_times}} 下载次数,【赠送 {{order_obj.actual_download_gift_times}}】 + + + 备注:{{order_obj.description}} + + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/register_code.mjml.html b/mailhtml/src/register_code.mjml.html new file mode 100644 index 0000000..e3801c7 --- /dev/null +++ b/mailhtml/src/register_code.mjml.html @@ -0,0 +1,37 @@ + + + + + + + 注册验证码 + + + + + + + + + 您的验证码:【{{ code }}】 + + + 操作时间:{{ now_time }} + + + 备注:您正在注册成为新用户,感谢您的支持 + + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/reset_password.mjml.html b/mailhtml/src/reset_password.mjml.html new file mode 100644 index 0000000..3909ad2 --- /dev/null +++ b/mailhtml/src/reset_password.mjml.html @@ -0,0 +1,37 @@ + + + + + + + 重置密码通知 + + + + + + + + + 您的新密码:【{{ code }}】 + + + 操作时间:{{ now_time }} + + + 备注:您的密码已经重置成功,请用新密码登录,并妥善保管账户信息 + + + + + + + + + + + + \ No newline at end of file diff --git a/mailhtml/src/timing_task_notify.mjml.html b/mailhtml/src/timing_task_notify.mjml.html new file mode 100644 index 0000000..7db1dda --- /dev/null +++ b/mailhtml/src/timing_task_notify.mjml.html @@ -0,0 +1,75 @@ + + + + + + + 苹果开发者定时任务报告 + + + + + + + + + + + 设备数消耗统计 + + + 当前正常设备总量:{{ developer_used_info.used_sign_number }} + + + 已使用:【平台:{{ developer_used_info.used_number }} 】【其他:{{ developer_used_info.can_other_used }}】 + + + + 还剩:{{ developer_used_info.can_sign_number }} 可用 + + + 昨天消耗设备数:{{ yesterday_used_number }} + + + + + + + + 定时任务检测已经执行完成 + + + + + + + + 苹果开发者ID + 苹果开发者备注 + 苹果开发者状态 + + + {% for developer_obj in developer_obj_list %} + + + {{ developer_obj.issuer_id }} + {{ developer_obj.description }} + {{ developer_obj.get_status_display }} + + {% endfor %} + + + + + + + + + + + + + \ No newline at end of file