Compare commits

...
350 Commits
Author SHA1 Message Date
Mr Chen 3421bf6ab5 Merge pull request #397 from midoks/dev
0.13.4
2023-03-28 23:54:51 +08:00
midoks 2f39bd600b Update config_api.py
### 版本更新 0.13.4

无重大更新

* 国内安装不在依赖gitee。
* tgbot优化。
2023-03-28 23:53:14 +08:00
midoks acd5ec69e8 Update tgbot.py 2023-03-28 23:49:59 +08:00
midoks 09878728af Update push_ad.py 2023-03-28 20:25:09 +08:00
midoks af82e9f129 Update push_notice_msg.py 2023-03-28 20:23:08 +08:00
midoks c74630e738 Update push_notice_msg.py 2023-03-28 20:19:49 +08:00
midoks e4e0697b4b Update push_notice_msg.py 2023-03-28 20:18:52 +08:00
midoks 11b5ac658b Update mw.tpl 2023-03-28 18:00:50 +08:00
midoks 1306731164 up 2023-03-28 17:47:59 +08:00
midoks bb6c933aee Update README.md 2023-03-28 17:41:50 +08:00
midoks d6a93ef1e6 Update info.json 2023-03-28 17:18:59 +08:00
midoks 6610da402a Update info.json 2023-03-28 17:18:47 +08:00
midoks 3ace9cf51e Update install.sh 2023-03-28 16:54:21 +08:00
midoks 49c7ec6073 Update tgbot.py 2023-03-28 16:31:46 +08:00
midoks 8cf526667e up 2023-03-25 22:05:19 +08:00
midoks 6c42876411 Update receive_faq.py 2023-03-25 21:58:08 +08:00
midoks 79471e3806 Update receive_faq.py 2023-03-25 21:56:50 +08:00
midoks cad06425fc Update lib.sh 2023-03-23 15:24:49 +08:00
midoks 6f1e11e474 Update lib.sh 2023-03-23 15:21:22 +08:00
midoks 59d13e50ce Update rhel.sh 2023-03-22 22:26:32 +08:00
midoks 5da0746240 Update push_bbs_ntid.py 2023-03-22 18:00:32 +08:00
midoks 192ea8b029 Update push_bbs_ntid.py 2023-03-22 17:34:18 +08:00
midoks bfc20b3e42 Update push_tmp_msg.py 2023-03-22 17:01:50 +08:00
midoks 56bee5c752 Update push_tmp_msg.py 2023-03-22 16:41:26 +08:00
midoks 312df5de1f Create push_bbs_ntid.py 2023-03-22 16:41:23 +08:00
midoks 4d3640286c Update README.md 2023-03-20 17:49:48 +08:00
midoks 20930806b6 Update install.sh 2023-03-20 12:19:35 +08:00
midoks 71360b61da Update install.sh 2023-03-20 12:04:54 +08:00
midoks 411645c9e2 Update install.sh 2023-03-20 12:01:46 +08:00
midoks 3de4e1bfff up 2023-03-19 00:21:36 +08:00
midoks 34285f6051 Update push_tmp_msg.py 2023-03-19 00:20:23 +08:00
midoks 84f0cda89b up 2023-03-18 18:32:30 +08:00
midoks 04012085ce Update mdw.jpg 2023-03-17 19:18:27 +08:00
midoks 9ad00f3ce7 Update push_tmp_msg.py 2023-03-16 22:36:25 +08:00
midoks 609a4ed351 Update tgbot.py 2023-03-16 21:34:44 +08:00
midoks 5ca74fd312 Update push_tmp_msg.py 2023-03-16 19:22:36 +08:00
midoks 3b1bb06c68 Update push_tmp_msg.py 2023-03-16 18:57:09 +08:00
midoks b6b7de42d6 Update push_tmp_msg.py 2023-03-16 18:53:29 +08:00
midoks 3aa3b532ac Update push_tmp_msg.py 2023-03-16 18:48:19 +08:00
midoks 290c740ab1 Update push_tmp_msg.py 2023-03-16 18:43:02 +08:00
midoks 23fd4ca1de Create push_tmp_msg.py 2023-03-16 18:42:42 +08:00
midoks c128a799b2 Update receive_faq.py 2023-03-16 15:50:52 +08:00
midoks 401c103b76 Update receive_faq.py 2023-03-16 15:47:14 +08:00
midoks 6fb88eb428 Update push_ad.py 2023-03-16 15:33:18 +08:00
midoks 956f20d295 tgbot init命令分离 2023-03-16 15:30:43 +08:00
midoks 03f8578a37 Update README.md 2023-03-16 13:04:29 +08:00
Mr Chen 265e17beac Merge pull request #393 from midoks/dev
0.13.3
2023-03-16 13:00:56 +08:00
midoks f3d83ad8a5 Update README.md 2023-03-16 12:58:06 +08:00
midoks 39b376a7cb Update webstats_common.lua 2023-03-16 12:24:02 +08:00
midoks 07858794ef Update webstats_common.lua 2023-03-16 12:02:33 +08:00
midoks 391473fc14 Update lib.sh 2023-03-15 23:26:23 +08:00
midoks 0993adcc5f Update lib.sh 2023-03-15 23:24:47 +08:00
midoks 90b1d88111 Update lib.sh 2023-03-15 23:17:49 +08:00
midoks 87098cff95 up 2023-03-15 23:00:37 +08:00
midoks e6e64b2a4c Update mysql.js 2023-03-15 22:59:23 +08:00
midoks 81436ea81b Update index.html 2023-03-15 22:57:22 +08:00
midoks cf7d29190d Update index.html 2023-03-15 22:53:36 +08:00
midoks 4ff62ec6ad Update tgbot.py 2023-03-15 22:09:53 +08:00
midoks dac3ccce8d Update tgbot.py 2023-03-15 21:53:41 +08:00
midoks 10bd7aa70f Update tool_migrate.py 2023-03-15 18:28:31 +08:00
midoks dec0afc3d3 Update tool_migrate.py 2023-03-15 18:25:43 +08:00
midoks 2331853b3b Update info.json 2023-03-15 18:13:34 +08:00
midoks b9e063e423 Update README.md 2023-03-15 18:11:35 +08:00
midoks 52294948b2 Update config_api.py 2023-03-15 18:09:20 +08:00
midoks 87bec2b988 Update tgbot.py 2023-03-15 18:06:14 +08:00
midoks 9ab91ecc93 Update index.py 2023-03-15 17:48:05 +08:00
midoks 18312a3596 Update tgbot.py 2023-03-15 17:37:35 +08:00
midoks 8fb35440c8 Update info.json 2023-03-15 17:35:28 +08:00
midoks a874934379 Update receive_faq.py 2023-03-15 17:34:05 +08:00
midoks 2c4e4aea3f Update info.json 2023-03-15 17:22:36 +08:00
midoks 6b115261be up 2023-03-15 17:19:15 +08:00
midoks 059ce6228b Update receive_faq.py 2023-03-15 15:09:03 +08:00
midoks cfa396b4bb 更新 2023-03-14 20:03:53 +08:00
midoks 11e4b377ed up 2023-03-14 15:21:33 +08:00
midoks 31fe2aab92 Update receive_faq.py 2023-03-14 13:36:00 +08:00
midoks 19042a9088 Update receive_faq.py 2023-03-14 11:48:54 +08:00
midoks 2eb4543c3b Update receive_faq.py 2023-03-14 01:54:58 +08:00
midoks e33ccbfc7d Update tgbot.py 2023-03-14 01:54:08 +08:00
midoks ed8c9eed0a Update receive_faq.py 2023-03-14 01:50:56 +08:00
midoks 7163a7bbcf Update receive_faq.py 2023-03-14 01:46:19 +08:00
midoks 3f1c23ec8b Update receive_faq.py 2023-03-14 01:32:52 +08:00
midoks 3a6cb0ae2a Update receive_faq.py 2023-03-14 01:15:14 +08:00
midoks 936492d410 up 2023-03-14 01:10:04 +08:00
midoks 39d265aae7 Update tgbot.py 2023-03-14 00:15:27 +08:00
midoks 5a33098dd3 Update tgbot.py 2023-03-14 00:09:52 +08:00
midoks c9927c3fb9 tgbot加入扩展机制 2023-03-14 00:09:30 +08:00
midoks da90386816 Update tool_migrate.py 2023-03-13 11:29:00 +08:00
midoks 6be4c5977b up 2023-03-13 02:33:29 +08:00
midoks bbf93bfd9e up 2023-03-13 02:33:22 +08:00
midoks a2570af5f7 Update webstats_common.lua 2023-03-13 01:33:07 +08:00
midoks 77120cf31b up 2023-03-12 12:13:43 +08:00
midoks 395f449b93 Update webstats_common.lua 2023-03-12 12:09:53 +08:00
midoks 8be5f4aa7b Update info.json 2023-03-11 22:54:23 +08:00
midoks 3ccebf4f47 Update index.py 2023-03-11 22:48:42 +08:00
midoks 15d48accad Update tgbot.py 2023-03-11 22:43:15 +08:00
midoks d0045d831c Update tgbot.py 2023-03-11 22:42:39 +08:00
midoks a7cac3d671 up 2023-03-11 20:47:31 +08:00
midoks 7bc7fdecae Update webstats_common.lua 2023-03-11 16:40:45 +08:00
midoks 480663e2ad Update tools.py 2023-03-11 15:41:15 +08:00
midoks 2290efd060 Update config_api.py 2023-03-11 15:36:11 +08:00
midoks dece5a0532 Update config_api.py 2023-03-11 15:30:16 +08:00
midoks b0a44d24d4 Update config_api.py 2023-03-11 15:28:13 +08:00
midoks d092d9f5f2 up 2023-03-11 15:24:40 +08:00
midoks 944b3e779c Update config_api.py 2023-03-11 15:21:43 +08:00
midoks 55dc2715e9 Update config_api.py 2023-03-11 15:20:13 +08:00
midoks 84bf3abd5d Update config_api.py 2023-03-11 15:15:49 +08:00
midoks 00c9157f9b up 2023-03-11 15:15:27 +08:00
midoks faa95b0d88 Update config_api.py 2023-03-11 15:07:06 +08:00
midoks 52d0b3c940 Update config_api.py 2023-03-11 15:04:20 +08:00
midoks 0141028d41 Update config_api.py 2023-03-11 15:02:15 +08:00
midoks 9e6bf08a72 Update config_api.py 2023-03-11 15:01:46 +08:00
midoks 49ff9750cb Update config_api.py 2023-03-11 14:58:18 +08:00
midoks 75b2b4dbc2 Update config_api.py 2023-03-11 14:56:43 +08:00
midoks 667c60dda0 Update config.js 2023-03-11 14:55:48 +08:00
midoks aa6818f953 Update config_api.py 2023-03-11 14:52:58 +08:00
midoks 6f884fe60a panel ssl https 功能添加 2023-03-11 14:48:38 +08:00
midoks a56d53c672 Update config_api.py 2023-03-11 14:29:28 +08:00
midoks 00b1788172 up 2023-03-11 14:26:22 +08:00
midoks cee268fcbc Update config_api.py 2023-03-11 13:56:20 +08:00
midoks 40dd929823 Update config_api.py 2023-03-11 13:47:16 +08:00
midoks b59949e181 Update config_api.py 2023-03-11 13:41:36 +08:00
midoks 9c5975253a Update cert_api.py 2023-03-11 13:23:30 +08:00
midoks 62003b987a Update discuzx.conf 2023-03-10 14:12:27 +08:00
midoks df0a454c3a up 2023-03-10 14:09:40 +08:00
midoks 02048c3265 Update webstats_common.lua 2023-03-10 13:19:58 +08:00
midoks 65649d171d Update tgbot.py 2023-03-09 19:11:51 +08:00
midoks a136da6ec2 Update tgbot.py 2023-03-09 17:23:28 +08:00
midoks 3b25ca7e60 Update tgbot.py 2023-03-09 16:28:11 +08:00
midoks c5cf8f8afb Update info.json 2023-03-09 15:40:54 +08:00
midoks 89f7d464ab Update info.json 2023-03-09 15:28:00 +08:00
midoks 4cac6d1921 Update info.json 2023-03-09 15:25:37 +08:00
midoks dca5c82d2f Update webstats_common.lua 2023-03-09 14:56:43 +08:00
midoks 08988130b5 Update config_api.py 2023-03-09 03:00:30 +08:00
Mr Chen 8849001384 Merge pull request #392 from midoks/dev
升级图表echarts
2023-03-09 02:49:57 +08:00
midoks ae0a6b5079 升级图表echarts 2023-03-09 02:44:57 +08:00
Mr Chen d6c6ae5561 Merge pull request #391 from midoks/dev
0.13.2
2023-03-09 01:49:10 +08:00
midoks a6dc15f22d 0.13.2
* supervisor添加重启功能。
* 加入滚动写入日志 mw.writeFileLog方法。
* mysql导出优化优化。
* 添加tgbot插件[仅测试]。
* TelegramBot机器人通知-加入配置。
* mariadb更新版本。
* 在线文件编辑优化。
2023-03-09 01:47:35 +08:00
midoks 360b962bd2 Update mw.py 2023-03-09 01:42:55 +08:00
midoks 37d37e0f1d Update task.py 2023-03-09 01:32:05 +08:00
midoks ddc6da9172 Update mw.py 2023-03-09 01:30:19 +08:00
midoks ceba7ab673 up 2023-03-09 01:26:39 +08:00
midoks 384704b8e5 Update mw.py 2023-03-09 01:10:04 +08:00
midoks 232d0c2f74 Update mw.py 2023-03-09 01:01:00 +08:00
midoks ef8e6f07f5 Update mw.py 2023-03-09 00:43:34 +08:00
midoks 435e565559 Update mw.py 2023-03-09 00:42:15 +08:00
midoks ec9d7e337d Update mw.py 2023-03-09 00:36:46 +08:00
midoks b5c7a2a778 Update task.py 2023-03-09 00:32:23 +08:00
midoks 72d9c9b761 Update task.py 2023-03-09 00:28:59 +08:00
midoks 30812e1fba Update task.py 2023-03-09 00:08:49 +08:00
midoks c95cb07e8d Update task.py 2023-03-09 00:05:45 +08:00
midoks f3f2ea8ef0 通知限制频率 2023-03-08 19:40:23 +08:00
midoks 9e5a5192cb Update mw.py 2023-03-08 18:02:30 +08:00
midoks 271b3d448c Update mw.py 2023-03-08 18:01:06 +08:00
midoks b7424e7195 Update config_api.py 2023-03-08 17:57:23 +08:00
midoks b607527e1f Update config_api.py 2023-03-08 17:56:18 +08:00
midoks 3c42a4e450 对通知配置进行加密处理 2023-03-08 17:56:07 +08:00
midoks b11fd9508a Update .gitignore 2023-03-08 17:29:42 +08:00
midoks dc0504cf24 Delete notify.json 2023-03-08 17:25:12 +08:00
midoks 1d8b82395f Update public.js 2023-03-08 16:25:30 +08:00
midoks 39ac55760e Update config_api.py 2023-03-08 16:20:02 +08:00
midoks ef6071956d 在线文件编辑优化 2023-03-08 16:14:28 +08:00
midoks bbbe1c84ce Update mw.py 2023-03-07 19:24:03 +08:00
midoks 064252daad Update config.html 2023-03-07 19:20:07 +08:00
midoks 3cb63c6265 Update index.html 2023-03-07 16:28:48 +08:00
midoks b541abad42 Update index.py 2023-03-07 13:44:28 +08:00
midoks 547027be0d Update install.sh 2023-03-06 23:40:56 +08:00
midoks d786b2524a up 2023-03-06 23:21:55 +08:00
midoks abac345628 Update info.json 2023-03-06 23:10:12 +08:00
midoks d4290cbdd2 mariadb更新版本 2023-03-06 22:29:20 +08:00
midoks cfd2d99e24 Update mw.py 2023-03-06 21:31:24 +08:00
midoks 28437ccfb0 Update mw.py 2023-03-06 21:30:18 +08:00
midoks 43bf755609 Update mw.py 2023-03-06 20:35:06 +08:00
midoks de225fc8b9 0.13.1.2 2023-03-06 20:28:29 +08:00
midoks 44f891f7a3 Update mw.py 2023-03-06 20:12:52 +08:00
midoks 64d1387b03 Telegram Bot机器人通知 加入配置 2023-03-06 19:32:36 +08:00
midoks 51ccbefb04 up 2023-03-06 17:15:41 +08:00
midoks 29e3017e51 up 2023-03-06 16:49:42 +08:00
midoks 197e2d80c6 Update tgbot.py 2023-03-06 16:42:29 +08:00
midoks b8f04043bc Update tgbot.service.tpl 2023-03-06 16:41:25 +08:00
midoks 2ed70b4b96 Update tgbot.py 2023-03-06 16:39:27 +08:00
midoks d056c37be5 Update index.py 2023-03-06 16:33:18 +08:00
midoks e75abae4b9 Update tgbot.service.tpl 2023-03-06 16:32:05 +08:00
midoks 3e695770d7 Update config_api.py 2023-03-06 16:26:49 +08:00
midoks 7301edbc5a 添加tgbot插件
现在只是为了获取chat_id
2023-03-06 16:19:13 +08:00
Mr Chen 704b256408 Merge pull request #390 from midoks/dev
网站统计优化
2023-03-05 18:36:57 +08:00
midoks e129051a06 Update webstats_common.lua 2023-03-05 18:34:35 +08:00
Mr Chen d38e9f7ad0 Merge pull request #389 from midoks/dev
OP防火墙优化
2023-03-05 18:07:54 +08:00
midoks c696742866 Update init.lua 2023-03-05 18:03:41 +08:00
midoks 046389df99 Update init.lua 2023-03-05 17:37:01 +08:00
midoks 3e244ed227 导出优化 2023-03-05 14:04:16 +08:00
midoks 5016aedb0f Update index.py 2023-03-05 02:08:04 +08:00
midoks c1cd45a5f3 Update my8.0.cnf 2023-03-05 00:00:59 +08:00
midoks 79c9865a5d Update index.py 2023-03-04 23:53:54 +08:00
midoks 4082f29424 加入滚动写入日志 2023-03-04 23:07:23 +08:00
midoks d777a29d8c Update update.sh 2023-03-04 21:47:12 +08:00
Mr Chen 04e43e051e Merge pull request #388 from midoks/dev
局部优化
2023-03-02 16:57:17 +08:00
midoks dffe9a77e7 Update layout.html 2023-03-02 00:57:02 +08:00
midoks 1b1462586e Update orm.py 2023-03-02 00:49:44 +08:00
midoks f11d2db761 添加重启功能 2023-03-01 18:41:32 +08:00
midoks 842c16540a Update index.py 2023-03-01 18:03:14 +08:00
midoks 614cc1032f Update webstats_log.lua 2023-03-01 14:03:46 +08:00
midoks ad46b2050e Update config.json 2023-03-01 01:40:57 +08:00
midoks 8109989927 Update layout.html 2023-02-28 19:41:13 +08:00
Mr Chen 9d9b39dfe2 Merge pull request #387 from midoks/dev
0.13.1
2023-02-28 19:11:06 +08:00
midoks 422514c40a 0.13.1
* 关闭issue,建立bbs.midoks.me。问题集中处理,发挥群众的力量。
* 添加站操作回调钩子site_cb。 网站统计和OP防火墙不再手动重载配置
* 修复ubuntu20 pureftp 安装时,端口没有加入安全里
* 增加global_static hook关键字,并优化menu的文件加载hook
* 各种细节优化。
2023-02-28 19:09:54 +08:00
midoks 632568643b Update site_api.py 2023-02-28 17:08:26 +08:00
midoks a5f29a2a6a Update cert_api.py 2023-02-28 16:26:31 +08:00
midoks b02705aa5a up 2023-02-28 03:00:46 +08:00
midoks 1f9ab560e3 Update files.js 2023-02-28 02:18:39 +08:00
midoks b3970326cd Update index.py 2023-02-28 01:57:19 +08:00
midoks f6d008e0b6 Update index.py 2023-02-28 01:50:54 +08:00
midoks 6f9a49ad7a up 2023-02-28 01:48:51 +08:00
midoks fc3c7d334a Update public.js 2023-02-28 00:17:39 +08:00
midoks 1030d1b923 site_cb 添加站操作回调钩子。 网站统计和OP防火墙不再手动重载配置 2023-02-28 00:02:16 +08:00
midoks 94d4a90bcc Update webstats_common.lua 2023-02-27 19:35:52 +08:00
midoks da4b872666 Update README.md 2023-02-27 17:57:17 +08:00
midoks cf15b19f4b Update install.sh 2023-02-26 21:46:25 +08:00
midoks aa9cdaada4 Update commit.tpl 2023-02-26 03:16:45 +08:00
midoks 659c9fe16b 修复ubuntu 20 pureftp 安装时,端口没有加入安全里 2023-02-26 02:20:06 +08:00
midoks 2b8c6d6e43 Update firewall_api.py 2023-02-26 01:39:52 +08:00
midoks 263f83088f Update firewall_api.py 2023-02-26 01:38:55 +08:00
midoks 374c938ac0 Update firewall_api.py 2023-02-26 01:38:32 +08:00
midoks 6aa73b0cae Update firewall_api.py 2023-02-26 01:36:45 +08:00
midoks 7f731ae06f Update README.md 2023-02-26 01:12:08 +08:00
midoks f87aff704c Update rhel.sh 2023-02-25 23:36:14 +08:00
midoks be9fa87133 Update rhel.sh 2023-02-25 23:31:36 +08:00
midoks de6fc19dee Create discuz.conf 2023-02-25 21:33:50 +08:00
midoks 3987c6d3dc Update config_api.py 2023-02-25 08:37:26 +08:00
midoks 96875052cd Update index.py 2023-02-25 08:25:05 +08:00
midoks 583de57f96 Update plugins_api.py 2023-02-25 08:21:20 +08:00
midoks 41b7245f03 Update plugins_api.py 2023-02-25 08:15:38 +08:00
midoks ee3684706f Update info.json 2023-02-25 07:48:32 +08:00
midoks 07936dfb81 update 2023-02-25 07:35:46 +08:00
midoks 5c46202be0 增加global_static hook关键字,并优化menu的文件加载hook
"hook":[
		{
			"tag":"global_static",
			"global_static": {
				"css_path":"menu/own_style.css",
				"js_path":"js/own_style.js"
			}
		}
	],
2023-02-25 07:26:48 +08:00
midoks 7123a15457 Update install.sh 2023-02-24 18:08:46 +08:00
midoks 4aeb45b1d5 Update install.sh 2023-02-24 17:55:13 +08:00
midoks 006a62be22 Update lib.sh 2023-02-24 17:25:04 +08:00
midoks 1e91d11125 Update mw.tpl 2023-02-24 17:22:22 +08:00
midoks 99fb4aa723 up 2023-02-24 17:14:28 +08:00
midoks 5c5bbb2da2 up 2023-02-24 17:12:31 +08:00
midoks 8b05045901 Update install.sh 2023-02-24 17:07:24 +08:00
midoks 1b73439525 Update install_dev.sh 2023-02-24 17:00:10 +08:00
midoks ec51ad016a Update install_dev.sh 2023-02-24 16:57:24 +08:00
midoks a42fae66ac Update install_dev.sh 2023-02-24 16:53:48 +08:00
midoks b4c635c2e5 Update install_dev.sh 2023-02-24 16:49:03 +08:00
midoks 9802bc5915 Update pure-ftpd.conf 2023-02-24 13:29:16 +08:00
Mr Chen 196fbbdd7d Merge pull request #382 from midoks/dev
0.13.0
2023-02-24 05:59:59 +08:00
midoks fa278abd50 Update index.py 2023-02-24 05:53:33 +08:00
midoks f9b2dbcb5e Update index.py 2023-02-24 05:46:39 +08:00
midoks a8808be9ae Update index.py 2023-02-24 05:41:50 +08:00
midoks 4122de13e3 Update index.py 2023-02-24 05:39:52 +08:00
midoks 4acae8e5f5 up 2023-02-24 05:38:59 +08:00
midoks 1abb611c3e 版本更新 0.13.0 2023-02-24 05:17:44 +08:00
midoks 726f9fa0d2 #374 2023-02-24 04:15:23 +08:00
midoks cfb64caadc Update site_api.py 2023-02-24 04:09:50 +08:00
midoks f501dd5150 Update site_api.py 2023-02-24 04:07:19 +08:00
midoks d1fe006e39 Update site_api.py 2023-02-24 03:28:48 +08:00
midoks d4db5dbfac up 2023-02-24 03:28:18 +08:00
midoks efa512a3f6 #374 2023-02-24 03:16:52 +08:00
midoks b53436343d up 2023-02-24 02:40:09 +08:00
midoks bb1a634f3c Update site_api.py 2023-02-24 02:29:14 +08:00
midoks acda55cc55 Update index.py 2023-02-24 01:40:02 +08:00
midoks 0ff0728517 Update index.py 2023-02-24 01:30:17 +08:00
midoks c575f55354 Update app.js 2023-02-24 01:05:32 +08:00
midoks d58339dbcb Update index.py 2023-02-24 00:07:19 +08:00
midoks f6a18fa25f Update index.py 2023-02-24 00:03:48 +08:00
midoks 3016eff372 Update app.js 2023-02-23 17:29:38 +08:00
midoks ca518591f3 up 2023-02-23 17:27:15 +08:00
midoks d2c74f2243 up 2023-02-23 17:17:46 +08:00
midoks 71dbf8e359 Update app.js 2023-02-23 15:39:16 +08:00
midoks cb2ad0ca82 up 2023-02-23 15:18:44 +08:00
midoks a157db7879 Update index.py 2023-02-23 03:32:30 +08:00
midoks fb949f4ee6 up 2023-02-23 01:25:00 +08:00
midoks b91ae3fde2 Update index.py 2023-02-22 23:46:28 +08:00
midoks b508e8003b Update index.py 2023-02-22 23:13:44 +08:00
midoks 0632a4b535 Update index.py 2023-02-22 23:13:17 +08:00
midoks 397e0b89a5 Update index.py 2023-02-22 22:59:45 +08:00
midoks 2427bf81cd Update index.py 2023-02-22 22:44:16 +08:00
midoks 4179bbf580 Update index.py 2023-02-22 22:40:29 +08:00
midoks b93c3bb88e Update index.py 2023-02-22 22:37:19 +08:00
midoks a52c854afd Update index.py 2023-02-22 22:36:10 +08:00
midoks d7e5cf1f45 Update index.py 2023-02-22 21:55:49 +08:00
midoks cfb444deac Update files_api.py 2023-02-22 20:54:54 +08:00
midoks 78615451ac up 2023-02-22 20:52:12 +08:00
midoks 0134643c83 Update db.py 2023-02-22 18:18:40 +08:00
midoks 70ddd1c86f Update index.py 2023-02-22 17:55:17 +08:00
midoks 808dc743ef Update files_api.py 2023-02-22 14:59:40 +08:00
midoks e30693f9f2 Update files_api.py 2023-02-22 14:28:01 +08:00
midoks 5c97fbe011 Update __init__.py 2023-02-22 14:27:48 +08:00
midoks 6419a18525 up 2023-02-21 21:10:34 +08:00
midoks 4a804e9243 Update index.py 2023-02-19 18:12:08 +08:00
midoks d44526004f up 2023-02-19 18:02:26 +08:00
midoks c1f402b278 up 2023-02-19 00:10:06 +08:00
midoks 45a3eec1b5 Update install_dev.sh 2023-02-18 23:09:51 +08:00
midoks d6f41ceb6a Update install_dev.sh 2023-02-18 23:06:53 +08:00
midoks a1bc0f6faf Update install_dev.sh 2023-02-18 22:58:21 +08:00
midoks 8420961cf7 Update install_dev.sh 2023-02-18 22:54:58 +08:00
midoks 421594c01d Update install_dev.sh 2023-02-18 22:48:30 +08:00
midoks ca13e8ad77 Update install_dev.sh 2023-02-18 22:46:05 +08:00
midoks f161f24253 up 2023-02-18 22:44:42 +08:00
midoks e5ab03951f Update README.md 2023-02-18 22:08:13 +08:00
midoks 5b45bab36d Update install_dev.sh 2023-02-18 22:06:51 +08:00
midoks 0594d3f9ce Update README.md 2023-02-18 22:04:11 +08:00
midoks ad541216c5 up 2023-02-18 16:59:33 +08:00
midoks 1adc0c1405 Update rhel.sh 2023-02-18 15:35:16 +08:00
midoks b22185b374 Update rhel.sh 2023-02-18 14:09:02 +08:00
midoks 02f3107e93 Update app.js 2023-02-18 02:04:52 +08:00
midoks 52fece867d up 2023-02-18 01:49:20 +08:00
midoks 2e3578dcf1 up 2023-02-18 01:39:26 +08:00
midoks 73b09a7886 up 2023-02-17 22:39:49 +08:00
midoks f33c7e5a5e up 2023-02-17 19:57:03 +08:00
midoks 3e90db2c8d Update system_api.py 2023-02-17 19:54:44 +08:00
midoks d599363609 Update index.py 2023-02-17 16:30:32 +08:00
midoks ec3167f239 Update __init__.py 2023-02-17 16:30:25 +08:00
midoks 2b1099b6e9 Update __init__.py 2023-02-17 15:42:28 +08:00
midoks e55a0760e3 Update mw.tpl 2023-02-17 15:22:15 +08:00
midoks 5c1353a38f Update mw.tpl 2023-02-17 15:20:52 +08:00
midoks f95684b316 Update mw.tpl 2023-02-17 15:20:39 +08:00
midoks 6fc729ccf9 Update __init__.py 2023-02-17 15:17:41 +08:00
midoks 45d0c4fc4a Update __init__.py 2023-02-17 15:16:11 +08:00
midoks 6759b9055c ip 2023-02-17 15:01:26 +08:00
midoks de694b2465 up 2023-02-17 14:56:44 +08:00
midoks c7b3daca36 up 2023-02-16 17:02:33 +08:00
midoks 452769233f up 2023-02-16 17:00:09 +08:00
midoks 8d196a3aa1 Update index.py 2023-02-16 16:26:22 +08:00
midoks 01baf509ad up 2023-02-16 15:49:55 +08:00
midoks d59ee2c843 Update install.sh 2023-02-16 15:39:08 +08:00
midoks 8919d5734e Update index.py 2023-02-16 14:15:15 +08:00
midoks bb91b30d6d Update index.py 2023-02-16 14:06:41 +08:00
midoks 103ab2e099 Update index.py 2023-02-15 22:45:44 +08:00
midoks 0d33d0db79 Update install.sh 2023-02-15 22:35:29 +08:00
midoks 6d9f4cfa08 Update tools.py 2023-02-15 22:31:22 +08:00
midoks c88c95ba21 Update macos.sh 2023-02-15 22:26:53 +08:00
midoks a705f6a8e4 Update install.sh 2023-02-15 22:24:51 +08:00
midoks 3f40ed0a01 up 2023-02-15 22:24:46 +08:00
midoks 39653896bf Update install_dev.sh 2023-02-15 22:15:08 +08:00
midoks 31d665d962 Update install.sh 2023-02-15 22:05:16 +08:00
midoks 811fa4a40d Update install_dev.sh 2023-02-15 22:04:58 +08:00
midoks 320f58424d Update README.md 2023-02-15 21:56:19 +08:00
midoks 376f0f0a4e up 2023-02-15 21:55:21 +08:00
midoks 0efb700cee Update README.md 2023-02-15 15:54:14 +08:00
midoks ff3fcae366 Update config_api.py 2023-02-15 15:50:55 +08:00
Mr Chen 22d94ce67c Merge pull request #371 from midoks/dev
安装脚本优化3
2023-02-14 22:24:04 +08:00
midoks 042fd7ac6d Update ubuntu.sh 2023-02-14 22:23:04 +08:00
midoks 1a48f52dad up 2023-02-14 22:22:06 +08:00
Mr Chen fc5970c65d Merge pull request #370 from midoks/dev
安装脚本优化2
2023-02-14 22:09:05 +08:00
midoks e758698ee2 Update debian.sh 2023-02-14 22:02:28 +08:00
Mr Chen ea03bb056a Merge pull request #369 from midoks/dev
安装脚本优化
2023-02-14 21:59:22 +08:00
midoks 088346fd5e 安装脚本优化 2023-02-14 21:58:30 +08:00
midoks cbcb686363 Update firewall_api.py 2023-02-14 21:07:22 +08:00
112 changed files with 4734 additions and 513 deletions
+5 -1
View File
@@ -151,8 +151,10 @@ data/system.db-journal
data/hook_*.json
data/letsencrypt.json
data/basic_auth.json
data/notify.json
data/api.json
data/bind_domain.pl
data/unauthorized_status.pl
plugins/vip_*
plugins/own_*
@@ -162,6 +164,7 @@ plugins/openlitespeed
plugins/system_safe
plugins/tamper_proof
plugins/tamper_proof_*
plugins/cryptocurrency_trade
plugins/op_load_balance
plugins/gdrive
plugins/mtproxy
@@ -175,4 +178,5 @@ plugins/file_search
debug.out
data/unauthorized_status.pl
+21 -24
View File
@@ -29,6 +29,7 @@
基本上可以使用,后续会继续优化!欢迎提供意见!
- 吹水组 - https://t.me/mdserver_web
- 交流论坛 - https://bbs.midoks.me
```
如果出现问题,最好私给我面板信息。不要让我猜。如果不提供,不要提出问题,自行解决。 — 座右铭
@@ -73,7 +74,7 @@ phpMyAdmin[4.4.15]支持MySQL[5.5-5.7]
phpMyAdmin[5.2.0]支持MySQL[8.0]
PHP[53-72]支持phpMyAdmin[4.4.15]
PHP[72-81]支持phpMyAdmin[5.2.0]
PHP[72-82]支持phpMyAdmin[5.2.0]
```
# 特别赞助
@@ -98,35 +99,31 @@ docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:
```
### 版本更新 0.12.3
### 版本更新 0.13.4
* 优先使用firewalld防火墙。
* PHP[APT]加入curl扩展。
* 配置添加【未认证响应状态】功能。
* 存在ipv6时,启动时强制开启。
* OP防火墙-性能优化。
* 网站统计优化。
* 优化backup_ftp插件。
* 各种细节优化。
无重大更新
* 国内安装不在依赖gitee。
* tgbot优化。
### JSDelivr安装地址
- 初始安装
```
curl -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/install.sh | bash
curl --insecure -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/install.sh | bash
```
- 直接更新
```
curl -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/update.sh | bash
curl --insecure -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/update.sh | bash
```
- 卸载脚本
```
wget -O uninstall.sh https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/uninstall.sh && bash uninstall.sh
wget --no-check-certificate -O uninstall.sh https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/uninstall.sh && bash uninstall.sh
```
### 备用地址
@@ -134,20 +131,20 @@ wget -O uninstall.sh https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scri
- 初始安装
```
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/install.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/install.sh | bash
curl --insecure -fsSL https://gitee.com/midoks/mdserver-web/raw/master/scripts/install.sh | bash
```
- 直接更新
```
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/update.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/update.sh | bash
```
- 卸载脚本
```
wget -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/uninstall.sh && bash uninstall.sh
wget --no-check-certificate -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/uninstall.sh && bash uninstall.sh
```
@@ -156,22 +153,22 @@ wget -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/maste
- 需已经安装mdserver-web
```
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/app.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/app.sh | bash
```
### DEV使用
```
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install_dev.sh | bash
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/update_dev.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install_dev.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/update_dev.sh | bash
wget -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/uninstall.sh && bash uninstall.sh
wget --no-check-certificate -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/uninstall.sh && bash uninstall.sh
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/debug.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/debug.sh | bash
curl -fsSL https://gitee.com/midoks/mdserver-web/raw/dev/scripts/install_dev.sh | bash
curl -fsSL https://gitee.com/midoks/mdserver-web/raw/dev/scripts/update_dev.sh | bash
curl --insecure -fsSL https://code.midoks.me/midoks/mdserver-web/raw/branch/dev/scripts/install_dev.sh | bash
curl --insecure -fsSL https://code.midoks.me/midoks/mdserver-web/raw/branch/dev/scripts/update_dev.sh | bash
```
### 捐赠地址 USDT(TRC20)
+2 -3
View File
@@ -371,8 +371,7 @@ fi
response = urllib.request.urlopen(req, timeout=timeout)
return response
except Exception as ex:
self.getError()
# self.getError()
raise Exception("requestsPost: {}".format(self.getError(str(ex))))
def getRequestJson(self, response):
@@ -1522,7 +1521,7 @@ fullchain.pem 粘贴到证书输入框
self.__config['orders'][i]['auth_to'] = auth_to
# 是否到了允许重试的时间
if 'next_retry_time' in self._config['orders'][i]:
if 'next_retry_time' in self.__config['orders'][i]:
timeout = self.__config['orders'][i][
'next_retry_time'] - int(time.time())
if timeout > 0:
+185 -12
View File
@@ -27,7 +27,7 @@ from flask import request
class config_api:
__version = '0.12.3'
__version = '0.13.4'
__api_addr = 'data/api.json'
def __init__(self):
@@ -348,7 +348,23 @@ class config_api:
keyPath = 'ssl/private.pem'
certPath = 'ssl/cert.pem'
if not os.path.exists(certPath):
mw.createSSL()
# 不再自动生成证书
# mw.createSSL()
cert['privateKey'] = ''
cert['is_https'] = ''
cert['certPem'] = ''
cert['rep'] = os.path.exists('ssl/input.pl')
cert['info'] = {'endtime': 0, 'subject': '无',
'notAfter': '无', 'notBefore': '无', 'issuer': '无'}
return cert
panel_ssl = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
if not os.path.exists(panel_ssl):
cert['is_https'] = ''
else:
ssl_data = mw.readFile(panel_ssl)
if ssl_data.find('$server_port !~ 443') != -1:
cert['is_https'] = 'checked'
cert['privateKey'] = mw.readFile(keyPath)
cert['certPem'] = mw.readFile(certPath)
@@ -380,13 +396,86 @@ class config_api:
mw.writeFile('ssl/input.pl', 'True')
return mw.returnJson(True, '证书已保存!')
# 设置面板SSL证书设置
def setPanelHttpToHttpsApi(self):
bind_domain = 'data/bind_domain.pl'
if not os.path.exists(bind_domain):
return mw.returnJson(False, '先要绑定域名!')
keyPath = 'ssl/private.pem'
if not os.path.exists(keyPath):
return mw.returnJson(False, '未申请SSL证书!')
is_https = request.form.get('https', '').strip()
panel_ssl = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
if not os.path.exists(panel_ssl):
return mw.returnJson(False, '未开启面板SSL!')
if is_https == 'false':
conf = mw.readFile(panel_ssl)
if conf:
if conf.find('ssl_certificate') == -1:
return mw.returnJson(False, '当前未开启SSL')
to = "#error_page 404/404.html;\n\
#HTTP_TO_HTTPS_START\n\
if ($server_port !~ 443){\n\
rewrite ^(/.*)$ https://$host$1 permanent;\n\
}\n\
#HTTP_TO_HTTPS_END"
conf = conf.replace('#error_page 404/404.html;', to)
mw.writeFile(panel_ssl, conf)
else:
conf = mw.readFile(panel_ssl)
if conf:
rep = "\n\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
conf = re.sub(rep, '', conf)
rep = "\s+if.+server_port.+\n.+\n\s+\s*}"
conf = re.sub(rep, '', conf)
mw.writeFile(panel_ssl, conf)
mw.restartWeb()
action = '开启'
if is_https == 'true':
action = '关闭'
return mw.returnJson(True, action + 'HTTPS跳转成功!')
# 删除面板证书
def delPanelSslApi(self):
bind_domain = 'data/bind_domain.pl'
if not os.path.exists(bind_domain):
return mw.returnJson(False, '未绑定域名!')
siteName = mw.readFile(bind_domain).strip()
src_letpath = mw.getServerDir() + '/web_conf/letsencrypt/' + siteName
dst_letpath = mw.getRunDir() + '/ssl'
dst_csrpath = dst_letpath + '/cert.pem'
dst_keypath = dst_letpath + '/private.pem'
if os.path.exists(src_letpath) or os.path.exists(dst_csrpath):
if os.path.exists(src_letpath):
mw.execShell('rm -rf ' + src_letpath)
if os.path.exists(dst_csrpath):
mw.execShell('rm -rf ' + dst_csrpath)
if os.path.exists(dst_keypath):
mw.execShell('rm -rf ' + dst_keypath)
# mw.restartWeb()
return mw.returnJson(True, '已经删除SSL!')
# mw.restartWeb()
return mw.returnJson(False, '已经不存在SSL!')
# 申请面板let证书
def applyPanelLetSslApi(self):
# check domain is bind?
bind_domain = 'data/bind_domain.pl'
if not os.path.exists(bind_domain):
return mw.returnJson(False, '未绑定域名!')
return mw.returnJson(False, '先要绑定域名!')
siteName = mw.readFile(bind_domain).strip()
auth_to = mw.getRunDir() + "/tmp"
@@ -404,6 +493,8 @@ class config_api:
dst_csrpath = dst_letpath + '/cert.pem'
dst_keypath = dst_letpath + '/private.pem'
is_already_apply = False
if not os.path.exists(src_letpath):
import cert_api
data = cert_api.cert_api().applyCertApi(to_args)
@@ -415,6 +506,8 @@ class config_api:
msg = msg + '<p><span>响应状态:</span>' + str(emsg['status']) + '</p><p><span>错误类型:</span>' + emsg[
'type'] + '</p><p><span>错误代码:</span>' + emsg['detail'] + '</p>'
return mw.returnJson(data['status'], msg, data['msg'])
else:
is_already_apply = True
mw.buildSoftLink(src_csrpath, dst_csrpath, True)
mw.buildSoftLink(src_keypath, dst_keypath, True)
@@ -426,6 +519,9 @@ class config_api:
if os.path.exists(tmp_well_know):
mw.execShell('rm -rf ' + tmp_well_know)
if is_already_apply:
return mw.returnJson(True, '重复申请!', data)
return mw.returnJson(True, '申请成功!', data)
def setPanelDomainApi(self):
@@ -509,8 +605,6 @@ class config_api:
return mw.returnJson(True, 'SSL已关闭,请使用http协议访问面板!')
else:
try:
if not os.path.exists('ssl/input.ssl'):
mw.createSSL()
mw.writeFile(sslConf, 'True')
keyPath = mw.getRunDir() + '/ssl/private.pem'
@@ -661,6 +755,60 @@ class config_api:
mw.writeLog('面板设置', '将未授权响应状态码设置为:{}'.format(status_code))
return mw.returnJson(True, '设置成功!')
def getNotifyApi(self):
# 获取
data = mw.getNotifyData(True)
return mw.returnData(True, 'ok', data)
def setNotifyApi(self):
tag = request.form.get('tag', '').strip()
data = request.form.get('data', '').strip()
cfg = mw.getNotifyData(False)
crypt_data = mw.enDoubleCrypt(tag, data)
if tag in cfg:
cfg[tag]['cfg'] = crypt_data
else:
t = {'cfg': crypt_data}
cfg[tag] = t
mw.writeNotify(cfg)
return mw.returnData(True, '设置成功')
def setNotifyTestApi(self):
# 异步通知验证
tag = request.form.get('tag', '').strip()
tag_data = request.form.get('data', '').strip()
if tag == 'tgbot':
t = json.loads(tag_data)
test_bool = mw.tgbotNotifyTest(t['app_token'], t['chat_id'])
if test_bool:
return mw.returnData(True, '验证成功')
return mw.returnData(False, '验证失败')
return mw.returnData(False, '暂时未支持该验证')
def setNotifyEnableApi(self):
# 异步通知验证
tag = request.form.get('tag', '').strip()
tag_enable = request.form.get('enable', '').strip()
data = mw.getNotifyData(False)
op_enable = True
op_action = '开启'
if tag_enable != 'true':
op_enable = False
op_action = '关闭'
if tag in data:
data[tag]['enable'] = op_enable
mw.writeNotify(data)
return mw.returnData(True, op_action + '成功')
def getPanelTokenApi(self):
api_file = self.__api_addr
tmp = mw.readFile(api_file)
@@ -693,10 +841,6 @@ class config_api:
def setPanelTokenApi(self):
op_type = request.form.get('op_type', '').strip()
api_file = self.__api_addr
tmp = mw.readFile(api_file)
data = json.loads(tmp)
if op_type == '1':
token = mw.getRandomString(32)
data['token'] = mw.md5(token)
@@ -706,7 +850,14 @@ class config_api:
mw.writeFile(api_file, json.dumps(data))
return mw.returnJson(True, 'ok', token)
elif op_type == '2':
api_file = self.__api_addr
if not os.path.exists(api_file):
return mw.returnJson(False, "先在API接口配置")
else:
tmp = mw.readFile(api_file)
data = json.loads(tmp)
if op_type == '2':
data['open'] = not data['open']
stats = {True: '开启', False: '关闭'}
if not 'token_crypt' in data:
@@ -721,6 +872,7 @@ class config_api:
return mw.returnJson(not not data['open'], token)
elif op_type == '3':
limit_addr = request.form.get('limit_addr', '').strip()
data['limit_addr'] = limit_addr.split('\n')
mw.writeLog('API配置', '变更IP限制为[%s]' % limit_addr)
@@ -820,7 +972,9 @@ class config_api:
data['username'] = mw.M('users').where(
"id=?", (1,)).getField('username')
# databases hook 获取
data['hook_tag'] = request.args.get('tag', '')
# databases hook
database_hook_file = 'data/hook_database.json'
if os.path.exists(database_hook_file):
df = mw.readFile(database_hook_file)
@@ -829,7 +983,7 @@ class config_api:
else:
data['hook_database'] = []
# menu hook 获取
# menu hook
menu_hook_file = 'data/hook_menu.json'
if os.path.exists(menu_hook_file):
df = mw.readFile(menu_hook_file)
@@ -838,4 +992,23 @@ class config_api:
else:
data['hook_menu'] = []
# global_static hook
global_static_hook_file = 'data/hook_global_static.json'
if os.path.exists(global_static_hook_file):
df = mw.readFile(global_static_hook_file)
df = json.loads(df)
data['hook_global_static'] = df
else:
data['hook_global_static'] = []
# notiy config
notify_data = mw.getNotifyData(True)
notify_tag_list = ['tgbot', 'email']
for tag in notify_tag_list:
new_tag = 'notify_' + tag + '_enable'
data[new_tag] = ''
if tag in notify_data and 'enable' in notify_data[tag]:
if notify_data[tag]['enable']:
data[new_tag] = 'checked'
return data
+1 -1
View File
@@ -348,7 +348,7 @@ class Sql():
except Exception as ex:
return "error: " + str(ex)
def query(self, sql, param):
def query(self, sql, param=()):
# 执行SQL语句返回数据集
self.__getConn()
try:
+111 -2
View File
@@ -247,8 +247,8 @@ class files_api:
os.remove(task_log)
return mw.returnJson(True, '任务已删除!')
# 上传文件
def uploadFileApi(self):
# 上传文件
from werkzeug.utils import secure_filename
from flask import request
@@ -263,6 +263,8 @@ class files_api:
if os.path.exists(filename):
s_path = filename
p_stat = os.stat(s_path)
# print(filename)
f.save(filename)
os.chown(filename, p_stat.st_uid, p_stat.st_gid)
os.chmod(filename, p_stat.st_mode)
@@ -271,6 +273,86 @@ class files_api:
mw.writeLog('文件管理', msg)
return mw.returnMsg(True, '上传成功!')
# 设置文件和目录权限
def setMode(self, path):
s_path = os.path.dirname(path)
p_stat = os.stat(s_path)
os.chown(path, p_stat.st_uid, p_stat.st_gid)
os.chmod(path, p_stat.st_mode)
def uploadSegmentApi(self):
# 分段上传
path = request.form.get('path', '')
name = request.form.get('name', '')
size = request.form.get('size')
start = request.form.get('start')
dir_mode = request.form.get('dir_mode', '')
file_mode = request.form.get('file_mode', '')
if not mw.fileNameCheck(name):
return mw.returnJson(False, '文件名中不能包含特殊字符!')
if path == '/':
return mw.returnJson(False, '不能直接上传文件到系统根目录!')
if name.find('./') != -1 or path.find('./') != -1:
return mw.returnJson(False, '错误的参数')
if not os.path.exists(path):
os.makedirs(path, 493)
if not dir_mode != '' or not file_mode != '':
mw.setMode(path)
save_path = os.path.join(
path, name + '.' + str(int(size)) + '.upload.tmp')
d_size = 0
if os.path.exists(save_path):
d_size = os.path.getsize(save_path)
if d_size != int(start):
return str(d_size)
f = open(save_path, 'ab')
b64_data = request.form.get('b64_data', '0')
if b64_data == '1':
import base64
b64_data = base64.b64decode(args.b64_data)
f.write(b64_data)
else:
upload_files = request.files.getlist("blob")
for tmp_f in upload_files:
f.write(tmp_f.read())
f.close()
f_size = os.path.getsize(save_path)
if f_size != int(size):
return str(f_size)
new_name = os.path.join(path, name)
if os.path.exists(new_name):
if new_name.find('.user.ini') != -1:
mw.execShell("chattr -i " + new_name)
try:
os.remove(new_name)
except:
mw.execShell("rm -f %s" % new_name)
os.renames(save_path, new_name)
if dir_mode != '' and dir_mode != '':
mode_tmp1 = dir_mode.split(',')
mw.setMode(path, mode_tmp1[0])
mw.setOwn(path, mode_tmp1[1])
mode_tmp2 = file_mode.split(',')
mw.setMode(new_name, mode_tmp2[0])
mw.setOwn(new_name, mode_tmp2[1])
else:
self.setMode(new_name)
msg = mw.getInfo('上传文件[{1}] 到 [{2}]成功!', (new_name, path))
mw.writeLog('文件管理', msg)
return mw.returnMsg(True, '上传成功!')
def getRecycleBinApi(self):
rPath = self.rPath
if not os.path.exists(rPath):
@@ -626,7 +708,7 @@ class files_api:
return not path in nDirs
def getDirSize(self, path):
if mw.getOs() == 'darwin':
if mw.isAppleSystem():
tmp = mw.execShell('du -sh ' + path)
else:
tmp = mw.execShell('du -sbh ' + path)
@@ -905,6 +987,33 @@ class files_api:
return mw.getJson(data)
def execShellApi(self):
# 执行SHELL命令
shell = request.form.get('shell', '').strip()
path = request.form.get('path', '').strip()
disabled = ['vi', 'vim', 'top', 'passwd', 'su']
tmp = shell.split(' ')
if tmp[0] in disabled:
return mw.returnJson(False, '禁止执行[{}]'.format(tmp[0]))
shellStr = '''#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
cd %s
%s
''' % (path, shell)
mw.writeFile('/tmp/panelShell.sh', shellStr)
mw.execShell(
'nohup bash /tmp/panelShell.sh > /tmp/panelShell.pl 2>&1 &')
return mw.returnJson(True, 'ok')
def getExecShellMsgApi(self):
# 取SHELL执行结果
fileName = '/tmp/panelShell.pl'
if not os.path.exists(fileName):
return ''
status = not mw.processExists('bash', None, '/tmp/panelShell.sh')
return mw.returnJson(status, mw.getNumLines(fileName, 200))
def __get_stats(self, filename, path=None):
filename = filename.replace('//', '/')
try:
+12 -11
View File
@@ -36,10 +36,10 @@ class firewall_api:
iptables_file = mw.systemdCfgDir() + '/iptables.service'
if os.path.exists('/usr/sbin/firewalld'):
self.__isFirewalld = True
elif os.path.exists(iptables_file):
self.__isIptables = True
elif os.path.exists('/usr/sbin/ufw'):
self.__isUfw = True
elif os.path.exists(iptables_file):
self.__isIptables = True
elif mw.isAppleSystem():
self.__isMac = True
@@ -123,12 +123,12 @@ class firewall_api:
address = port
if self.__isUfw:
mw.execShell('ufw delete deny from ' + address + ' to any')
elif self.__isIptables:
cmd = 'iptables -D INPUT -s ' + address + ' -j DROP'
mw.execShell(cmd)
elif self.__isFirewalld:
mw.execShell(
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv4 source address="' + address + '" drop\'')
elif self.__isIptables:
cmd = 'iptables -D INPUT -s ' + address + ' -j DROP'
mw.execShell(cmd)
else:
pass
@@ -149,14 +149,15 @@ class firewall_api:
return mw.returnJson(False, '失败,不能删除当前面板端口!')
if self.__isUfw:
mw.execShell('ufw delete allow ' + port + '/tcp')
elif self.__isIptables:
mw.execShell(
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
elif self.__isFirewalld:
port = port.replace(':', '-')
mw.execShell(
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/tcp')
mw.execShell(
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/udp')
elif self.__isIptables:
mw.execShell(
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
else:
pass
msg = mw.getInfo('删除防火墙放行端口[{1}]成功!', (port,))
@@ -438,13 +439,13 @@ class firewall_api:
def addAcceptPort(self, port):
if self.__isUfw:
mw.execShell('ufw allow ' + port + '/tcp')
elif self.__isIptables:
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
mw.execShell(cmd)
elif self.__isFirewalld:
port = port.replace(':', '-')
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/tcp'
mw.execShell(cmd)
elif self.__isIptables:
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
mw.execShell(cmd)
else:
pass
return True
+238 -9
View File
@@ -22,6 +22,8 @@ import hashlib
import shlex
import datetime
import subprocess
import glob
import re
import db
from random import Random
@@ -80,6 +82,10 @@ def getPanelDataDir():
return getRunDir() + '/data'
def getPanelTmp():
return getRunDir() + '/tmp'
def getServerDir():
return getRootDir() + '/server'
@@ -123,6 +129,23 @@ def getAcmeDir():
return acme
def getAcmeDomainDir(domain):
acme_dir = getAcmeDir()
acme_domain = acme_dir + '/' + domain
acme_domain_ecc = acme_domain + '_ecc'
if os.path.exists(acme_domain_ecc):
acme_domain = acme_domain_ecc
return acme_domain
def fileNameCheck(filename):
f_strs = [';', '&', '<', '>']
for fs in f_strs:
if filename.find(fs) != -1:
return False
return True
def triggerTask():
isTask = getRunDir() + '/tmp/panelTask.pl'
writeFile(isTask, 'True')
@@ -519,6 +542,14 @@ def getDate():
return time.strftime('%Y-%m-%d %X', time.localtime())
def getDateFromNow(tf_format="%Y-%m-%d %H:%M:%S", time_zone="Asia/Shanghai"):
# 取格式时间
import time
os.environ['TZ'] = time_zone
time.tzset()
return time.strftime(tf_format, time.localtime())
def getDataFromInt(val):
time_format = '%Y-%m-%d %H:%M:%S'
time_str = time.localtime(val)
@@ -534,10 +565,39 @@ def writeLog(stype, msg, args=()):
uid = session['uid']
except Exception as e:
pass
# print(getTracebackInfo())
# writeFileLog(getTracebackInfo())
return writeDbLog(stype, msg, args, uid)
def writeFileLog(msg, path=None, limit_size=50 * 1024 * 1024, save_limit=3):
log_file = getServerDir() + '/mdserver-web/logs/debug.log'
if path != None:
log_file = path
if os.path.exists(log_file):
size = os.path.getsize(log_file)
if size > limit_size:
log_file_rename = log_file + "_" + \
time.strftime("%Y-%m-%d_%H%M%S") + '.log'
os.rename(log_file, log_file_rename)
logs = sorted(glob.glob(log_file + "_*"))
count = len(logs)
save_limit = count - save_limit
for i in range(count):
if i > save_limit:
break
os.remove(logs[i])
# print('|---多余日志[' + logs[i] + ']已删除!')
f = open(log_file, 'ab+')
msg += "\n"
if __name__ == '__main__':
print(msg)
f.write(msg.encode('utf-8'))
f.close()
return True
def writeDbLog(stype, msg, args=(), uid=1):
try:
import time
@@ -656,7 +716,7 @@ def enCrypt(key, strings):
result = f.encrypt(strings)
return result.decode('utf-8')
except:
print(getTracebackInfo())
writeFileLog(getTracebackInfo())
return strings
@@ -675,7 +735,7 @@ def deCrypt(key, strings):
result = f.decrypt(strings).decode('utf-8')
return result
except:
print(getTracebackInfo())
writeFileLog(getTracebackInfo())
return strings
@@ -694,7 +754,7 @@ def enDoubleCrypt(key, strings):
result = f.encrypt(strings)
return result.decode('utf-8')
except:
print(getTracebackInfo())
writeFileLog(getTracebackInfo())
return strings
@@ -712,7 +772,7 @@ def deDoubleCrypt(key, strings):
result = f.decrypt(strings).decode('utf-8')
return result
except:
print(getTracebackInfo())
writeFileLog(getTracebackInfo())
return strings
@@ -988,7 +1048,7 @@ def getLocalIp():
try:
ipaddress = readFile(filename)
if not ipaddress or ipaddress == '127.0.0.1':
cmd = "curl -4 -sS --connect-timeout 5 -m 60 https://v6r.ipip.net/?format=text"
cmd = "curl --insecure -4 -sS --connect-timeout 5 -m 60 https://v6r.ipip.net/?format=text"
ip = execShell(cmd)
result = ip[0].strip()
if result == '':
@@ -997,7 +1057,7 @@ def getLocalIp():
return result
return ipaddress
except Exception as e:
cmd = "curl -6 -sS --connect-timeout 5 -m 60 https://v6r.ipip.net/?format=text"
cmd = "curl --insecure -6 -sS --connect-timeout 5 -m 60 https://v6r.ipip.net/?format=text"
ip = execShell(cmd)
result = ip[0].strip()
if result == '':
@@ -1122,6 +1182,15 @@ def setOwn(filename, user, group=None):
return True
def setMode(filename, mode):
# 设置文件权限
if not os.path.exists(filename):
return False
mode = int(str(mode), 8)
os.chmod(filename, mode)
return True
def checkPort(port):
# 检查端口是否合法
ports = ['21', '443', '888']
@@ -1207,7 +1276,7 @@ def makeConf():
file = getRunDir() + '/data/json/config.json'
if not os.path.exists(file):
c = {}
c['title'] = '大圣面板'
c['title'] = '金蝉面板'
c['home'] = 'http://github/midoks/mdserver-web'
c['recycle_bin'] = True
c['template'] = 'default'
@@ -1507,7 +1576,7 @@ def getCertName(certPath):
result['notAfter'], "%Y-%m-%d")) - time.time()) / 86400)
return result
except Exception as e:
# print(getTracebackInfo())
writeFileLog(getTracebackInfo())
return None
@@ -1605,6 +1674,141 @@ def getMyORMDb():
o = ormDb.ORM()
return o
##################### notify start #########################################
def initNotifyConfig():
p = getNotifyPath()
if not os.path.exists(p):
writeFile(p, '{}')
return True
def getNotifyPath():
path = 'data/notify.json'
return path
def getNotifyData(is_parse=False):
initNotifyConfig()
notify_file = getNotifyPath()
notify_data = readFile(notify_file)
data = json.loads(notify_data)
if is_parse:
tag_list = ['tgbot']
for t in tag_list:
if t in data and 'cfg' in data[t]:
data[t]['data'] = json.loads(deDoubleCrypt(t, data[t]['cfg']))
return data
def writeNotify(data):
p = getNotifyPath()
return writeFile(p, json.dumps(data))
def tgbotNotifyChatID():
data = getNotifyData(True)
if 'tgbot' in data and 'enable' in data['tgbot']:
if data['tgbot']['enable']:
t = data['tgbot']['data']
return t['chat_id']
return ''
def tgbotNotifyObject():
data = getNotifyData(True)
if 'tgbot' in data and 'enable' in data['tgbot']:
if data['tgbot']['enable']:
t = data['tgbot']['data']
import telebot
bot = telebot.TeleBot(app_token)
return True, bot
return False, None
def tgbotNotifyMessage(app_token, chat_id, msg):
import telebot
bot = telebot.TeleBot(app_token)
try:
data = bot.send_message(chat_id, msg)
return True
except Exception as e:
writeFileLog(str(e))
return False
def tgbotNotifyHttpPost(app_token, chat_id, msg):
try:
url = 'https://api.telegram.org/bot' + app_token + '/sendMessage'
post_data = {
'chat_id': chat_id,
'text': msg,
}
rdata = httpPost(url, post_data)
return True
except Exception as e:
writeFileLog(str(e))
return False
def tgbotNotifyTest(app_token, chat_id):
msg = 'MW-通知验证测试OK'
return tgbotNotifyHttpPost(app_token, chat_id, msg)
def notifyMessageTry(msg, stype='common', trigger_time=300, is_write_log=True):
lock_file = getPanelTmp() + '/notify_lock.json'
if not os.path.exists(lock_file):
writeFile(lock_file, '{}')
lock_data = json.loads(readFile(lock_file))
if stype in lock_data:
diff_time = time.time() - lock_data[stype]['do_time']
if diff_time >= trigger_time:
lock_data[stype]['do_time'] = time.time()
else:
return False
else:
lock_data[stype] = {'do_time': time.time()}
writeFile(lock_file, json.dumps(lock_data))
if is_write_log:
writeLog("通知管理[" + stype + "]", msg)
data = getNotifyData(True)
# tag_list = ['tgbot', 'email']
# tagbot
do_notify = False
if 'tgbot' in data and 'enable' in data['tgbot']:
if data['tgbot']['enable']:
t = data['tgbot']['data']
i = sys.version_info
# telebot 在python小于3.7无法使用
if i[0] < 3 or i[1] < 7:
do_notify = tgbotNotifyHttpPost(
t['app_token'], t['chat_id'], msg)
else:
do_notify = tgbotNotifyMessage(
t['app_token'], t['chat_id'], msg)
return do_notify
def notifyMessage(msg, stype='common', trigger_time=300, is_write_log=True):
try:
return notifyMessageTry(msg, stype, trigger_time, is_write_log)
except Exception as e:
writeFileLog(getTracebackInfo())
return False
##################### notify end #########################################
##################### ssh start #########################################
def getSshDir():
@@ -1614,6 +1818,31 @@ def getSshDir():
return '/root/.ssh'
def processExists(pname, exe=None, cmdline=None):
# 进程是否存在
try:
import psutil
pids = psutil.pids()
for pid in pids:
try:
p = psutil.Process(pid)
if p.name() == pname:
if not exe and not cmdline:
return True
else:
if exe:
if p.exe() == exe:
return True
if cmdline:
if cmdline in p.cmdline():
return True
except:
pass
return False
except:
return True
def createRsa():
# ssh-keygen -t rsa -P "" -C "midoks@163.com"
ssh_dir = getSshDir()
+7 -5
View File
@@ -91,7 +91,7 @@ class plugins_api:
t = mw.readFile(menu_file)
tlist = json.loads(t)
for menu_data in tlist:
if 'path' in menu_data:
if tag == menu_data['name'] and 'path' in menu_data:
tpath = self.menuGetAbsPath(tag, menu_data['path'])
content = mw.readFile(tpath)
data['plugin_content'] = content
@@ -256,13 +256,14 @@ class plugins_api:
data = json.loads(t)
for idx in range(len(data)):
if data[idx]['title'] == info['title'] and data[idx]['name'] == info['name']:
if data[idx]['name'] == info['name']:
data.remove(data[idx])
break
mw.writeFile(hookPath, json.dumps(data))
def hookInstall(self, info):
valid_hook = ['backup', 'database']
valid_list_hook = ['menu']
valid_list_hook = ['menu', 'global_static', 'site_cb']
if 'hook' in info:
hooks = info['hook']
for h in hooks:
@@ -280,7 +281,7 @@ class plugins_api:
def hookUninstall(self, info):
valid_hook = ['backup', 'database']
valid_list_hook = ['menu']
valid_list_hook = ['menu', 'global_static', 'site_cb']
if 'hook' in info:
hooks = info['hook']
for h in hooks:
@@ -795,7 +796,8 @@ class plugins_api:
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
except Exception as e:
print(e)
print(json_file)
print(mw.getTracebackInfo())
start = (page - 1) * pageSize
end = start + pageSize
+42 -10
View File
@@ -72,6 +72,30 @@ class site_api:
mw.execShell("mkdir -p " + self.sslLetsDir +
" && chmod -R 755 " + self.sslLetsDir)
def runHook(self, hook_name, func_name):
# 站点操作Hook
hook_file = 'data/hook_site_cb.json'
hook_cfg = []
if os.path.exists(hook_file):
t = mw.readFile(hook_file)
hook_cfg = json.loads(t)
hook_num = len(hook_cfg)
if hook_num == 0:
return
import plugins_api
pa = plugins_api.plugins_api()
for x in range(hook_num):
hook_data = hook_cfg[x]
if func_name in hook_data:
app_name = hook_data["name"]
run_func = hook_data[func_name]['func']
# print(app_name, run_func)
pa.run(app_name, run_func)
return True
##### ----- start ----- ###
def listApi(self):
limit = request.form.get('limit', '10')
@@ -550,7 +574,7 @@ class site_api:
return mw.returnJson(False, '使用中,先关闭再删除')
mw.execShell('rm -rf ' + ssl_lets_dir)
elif ssl_type == 'acme':
ssl_acme_dir = mw.getAcmeDir() + '/' + site_name
ssl_acme_dir = mw.getAcmeDomainDir(site_name)
csr_acme_path = ssl_acme_dir + '/fullchain.cer' # 生成证书路径
if mw.md5(mw.readFile(csr_acme_path)) == mw.md5(mw.readFile(csr_path)):
return mw.returnJson(False, '使用中,先关闭再删除')
@@ -587,9 +611,9 @@ class site_api:
csr_path = self.sslLetsDir + '/' + site_name + '/fullchain.pem' # 生成证书路径
key_path = self.sslLetsDir + '/' + site_name + '/privkey.pem' # 密钥文件路径
elif ssl_type == 'acme':
csr_path = mw.getAcmeDir() + '/' + site_name + '/fullchain.cer' # 生成证书路径
key_path = mw.getAcmeDir() + '/' + site_name + '/' + \
site_name + '.key' # 密钥文件路径
acme_dir = mw.getAcmeDomainDir(site_name)
csr_path = acme_dir + '/fullchain.cer' # 生成证书路径
key_path = acme_dir + '/' + site_name + '.key' # 密钥文件路径
key = mw.readFile(key_path)
csr = mw.readFile(csr_path)
@@ -989,16 +1013,17 @@ class site_api:
# print(cmd)
result = mw.execShell(cmd)
src_path = acme_dir + '/' + domains[0]
src_path = mw.getAcmeDomainDir(domains[0])
src_cert = src_path + '/fullchain.cer'
src_key = src_path + '/' + domains[0] + '.key'
src_cert.replace("\*", "*")
msg = '签发失败,您尝试申请证书的失败次数已达上限!<p>1、检查域名是否绑定到对应站点</p>\
<p>2、检查域名是否正确解析到本服务器,或解析还未完全生效</p>\
<p>3、如果您的站点设置了反向代理,或使用了CDN,请先将其关闭</p>\
<p>4、如果您的站点设置了301重定向,请先将其关闭</p>\
<p>5、如果以上检查都确认没有问题,请尝试更换DNS服务商</p>'
if not os.path.exists(src_cert.replace("\*", "*")):
if not os.path.exists(src_cert):
data = {}
data['err'] = result
data['out'] = result[0]
@@ -1271,6 +1296,7 @@ class site_api:
mw.M('domain').add('pid,name,port,addtime',
(pid, domain_name, domain_port, mw.getDate()))
self.runHook('site_cb', 'add')
return mw.returnJson(True, '域名添加成功!')
def addDirBindApi(self):
@@ -1400,7 +1426,7 @@ class site_api:
data['filename'] = filename
return mw.getJson(data)
# 修改物理路径
# 修改物理路径
def setPathApi(self):
mid = request.form.get('id', '')
path = request.form.get('path', '')
@@ -2529,16 +2555,18 @@ location ^~ {from} {\n\
self.createRootDir(self.sitePath)
self.nginxAddConf()
mw.M('domain').add('pid,name,port,addtime',
(pid, self.siteName, self.sitePort, mw.getDate()))
# 添加更多域名
for domain in siteMenu['domainlist']:
self.addDomain(domain, self.siteName, pid)
mw.M('domain').add('pid,name,port,addtime',
(pid, self.siteName, self.sitePort, mw.getDate()))
data = {}
data['siteStatus'] = False
mw.restartWeb()
self.runHook('site_cb', 'add')
return mw.returnJson(True, '添加成功')
def deleteWSLogs(self, webname):
@@ -2588,6 +2616,8 @@ location ^~ {from} {\n\
mw.execShell('rm -rf ' + ssl_acme_dir)
mw.M('sites').where("id=?", (sid,)).delete()
mw.M('domain').where("pid=?", (sid,)).delete()
mw.M('domain').where("name=?", (webname,)).delete()
# binding domain delete
binding_list = mw.M('binding').field(
@@ -2605,6 +2635,8 @@ location ^~ {from} {\n\
mw.M('binding').where("pid=?", (sid,)).delete()
mw.restartWeb()
self.runHook('site_cb', 'delete')
return mw.returnJson(True, '站点删除成功!')
def setEndDate(self, sid, edate):
+27
View File
@@ -166,6 +166,33 @@ class system_api:
except:
return False
def getEnvInfoApi(self, get=None):
serverInfo = {}
serverInfo['status'] = True
sdir = mw.getServerDir()
serverInfo['webserver'] = '未安装'
if os.path.exists(sdir + '/openresty/nginx/sbin/nginx'):
serverInfo['webserver'] = 'OpenResty'
serverInfo['php'] = []
phpversions = ['52', '53', '54', '55', '56', '70', '71',
'72', '73', '74', '80', '81', '82', '83', '84']
phpPath = sdir + '/php/'
for pv in phpversions:
if not os.path.exists(phpPath + pv + '/bin/php'):
continue
serverInfo['php'].append(pv)
serverInfo['mysql'] = False
if os.path.exists(sdir + '/mysql/bin/mysql'):
serverInfo['mysql'] = True
import psutil
try:
diskInfo = psutil.disk_usage('/www')
except:
diskInfo = psutil.disk_usage('/')
serverInfo['disk'] = diskInfo[2]
return mw.returnJson(True, 'ok', serverInfo)
def getPanelInfo(self, get=None):
# 取面板配置
address = mw.GetLocalIp()
+3
View File
@@ -65,6 +65,9 @@ class ORM:
def setCharset(self, charset):
self.__DB_CHARSET = charset
def setHost(self, host):
self.__DB_HOST = host
def setPort(self, port):
self.__DB_PORT = port
+5 -1
View File
@@ -33,7 +33,11 @@ if [ ! -d $WEB_PATH ];then
mkdir -p $WEB_PATH
rsync -vauP --delete --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
else
rsync -vauP --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
if [ -f $GIT_PROJECT_DIR/exclude.list ];then
rsync -vauP --delete --exclude-from="$GIT_PROJECT_DIR/exclude.list" $GIT_PROJECT_DIR/ $WEB_PATH
else
rsync -vauP --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
fi
fi
sysName=`uname`
+2 -2
View File
@@ -1,8 +1,8 @@
{
"ps": "Gitea 是一个开源社区驱动的轻量级代码托管解决方案。",
"ps": "Gitea是一个开源社区驱动的轻量级代码托管解决方案。",
"name": "gitea",
"title": "Gitea",
"versions": ["1.17.2"],
"versions": ["1.17.2","1.18.5"],
"tip": "soft",
"install_pre_inspection":false,
"uninstall_pre_inspection":true,
+1 -1
View File
@@ -14,7 +14,7 @@ if [ -f ${rootPath}/bin/activate ];then
fi
URL_DOWNLOAD=https://dl.gitea.io/
URL_DOWNLOAD=https://dl.gitea.com
bash ${rootPath}/scripts/getos.sh
+1 -1
View File
@@ -8,7 +8,7 @@
"uninstall_pre_inspection":true,
"checks": "server/mariadb",
"path": "server/mariadb",
"versions":["10.6","10.7","10.8","10.9"],
"versions":["10.6","10.7","10.8","10.9","10.11","11.0"],
"shell":"install.sh",
"checks":"server/mariadb",
"path":"server/mariadb",
+1 -1
View File
@@ -1185,7 +1185,7 @@ function myLogs(){
<span class="f14 c6 mr20">二进制日志 </span><span class="f14 c6 mr20">' + toSize(rdata.msg) + '</span>\
'+line_status+'\
<p class="f14 c6 mtb10" style="border-top:#ddd 1px solid; padding:10px 0">错误日志<button class="btn btn-default btn-clear btn-xs" style="float:right;" >清理日志</button></p>\
<textarea readonly style="margin: 0px;width: 100%;height: 440px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
<textarea readonly style="margin: 0px;width: 100%;height: 438px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
</p>';
$(".soft-man-con").html(limitCon);
+119
View File
@@ -0,0 +1,119 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
#https://dev.mysql.com/downloads/file/?id=480541
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.11.2
Install_app()
{
mkdir -p ${mariadbDir}
echo '正在安装脚本文件...' > $install_tmp
if id mysql &> /dev/null ;then
echo "mysql uid is `id -u www`"
echo "mysql shell is `grep "^www:" /etc/passwd |cut -d':' -f7 `"
else
groupadd mysql
useradd -g mysql mysql
fi
if [ "$sysName" != "Darwin" ];then
mkdir -p /var/log/mariadb
touch /var/log/mariadb/mariadb.log
fi
# ----- cpu start ------
if [ -z "${cpuCore}" ]; then
cpuCore="1"
fi
if [ -f /proc/cpuinfo ];then
cpuCore=`cat /proc/cpuinfo | grep "processor" | wc -l`
fi
MEM_INFO=$(free -m|grep Mem|awk '{printf("%.f",($2)/1024)}')
if [ "${cpuCore}" != "1" ] && [ "${MEM_INFO}" != "0" ];then
if [ "${cpuCore}" -gt "${MEM_INFO}" ];then
cpuCore="${MEM_INFO}"
fi
else
cpuCore="1"
fi
if [ "$cpuCore" -gt "2" ];then
cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
else
cpuCore="1"
fi
# ----- cpu end ------
# if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
# wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://mirrors.aliyun.com/mariadb/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
# fi
# https://downloads.mariadb.org/interstitial/mariadb-10.9.1/source/mariadb-10.9.1.tar.gz
if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://archive.mariadb.org/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
fi
if [ ! -d ${mariadbDir}/mariadb-${MY_VER} ];then
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
fi
if [ ! -d $serverPath/mariadb ];then
cd ${mariadbDir}/mariadb-${MY_VER} && cmake \
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
-DMYSQL_USER=mysql \
-DMYSQL_UNIX_ADDR=$serverPath/mariadb/mysql.sock \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_MEMORY_STORAGE_ENGINE=1 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DEXTRA_CHARSETS=all \
-DDEFAULT_CHARSET=utf8mb4 \
-DDEFAULT_COLLATION=utf8mb4_general_ci \
-DCMAKE_C_COMPILER=/usr/bin/gcc \
-DCMAKE_CXX_COMPILER=/usr/bin/g++
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mariadb ];then
echo '10.11' > $serverPath/mariadb/version.pl
echo '安装完成' > $install_tmp
else
echo '安装失败' > $install_tmp
echo 'install fail'>&2
exit 1
fi
fi
rm -rf ${mariadbDir}/mariadb-${MY_VER}
rm -rf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
}
Uninstall_app()
{
rm -rf $serverPath/mariadb
echo '卸载完成' > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_app
else
Uninstall_app
fi
+1 -1
View File
@@ -13,7 +13,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.6.9
MY_VER=10.6.12
Install_app()
{
+1 -1
View File
@@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.7.4
MY_VER=10.7.8
Install_app()
{
+1 -1
View File
@@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.8.5
MY_VER=10.8.7
Install_app()
{
+1 -1
View File
@@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.9.2
MY_VER=10.9.5
Install_app()
{
+119
View File
@@ -0,0 +1,119 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
#https://dev.mysql.com/downloads/file/?id=480541
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=11.0.1
Install_app()
{
mkdir -p ${mariadbDir}
echo '正在安装脚本文件...' > $install_tmp
if id mysql &> /dev/null ;then
echo "mysql uid is `id -u www`"
echo "mysql shell is `grep "^www:" /etc/passwd |cut -d':' -f7 `"
else
groupadd mysql
useradd -g mysql mysql
fi
if [ "$sysName" != "Darwin" ];then
mkdir -p /var/log/mariadb
touch /var/log/mariadb/mariadb.log
fi
# ----- cpu start ------
if [ -z "${cpuCore}" ]; then
cpuCore="1"
fi
if [ -f /proc/cpuinfo ];then
cpuCore=`cat /proc/cpuinfo | grep "processor" | wc -l`
fi
MEM_INFO=$(free -m|grep Mem|awk '{printf("%.f",($2)/1024)}')
if [ "${cpuCore}" != "1" ] && [ "${MEM_INFO}" != "0" ];then
if [ "${cpuCore}" -gt "${MEM_INFO}" ];then
cpuCore="${MEM_INFO}"
fi
else
cpuCore="1"
fi
if [ "$cpuCore" -gt "2" ];then
cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
else
cpuCore="1"
fi
# ----- cpu end ------
# if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
# wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://mirrors.aliyun.com/mariadb/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
# fi
# https://downloads.mariadb.org/interstitial/mariadb-10.9.1/source/mariadb-10.9.1.tar.gz
if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://archive.mariadb.org/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
fi
if [ ! -d ${mariadbDir}/mariadb-${MY_VER} ];then
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
fi
if [ ! -d $serverPath/mariadb ];then
cd ${mariadbDir}/mariadb-${MY_VER} && cmake \
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
-DMYSQL_USER=mysql \
-DMYSQL_UNIX_ADDR=$serverPath/mariadb/mysql.sock \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_MEMORY_STORAGE_ENGINE=1 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DEXTRA_CHARSETS=all \
-DDEFAULT_CHARSET=utf8mb4 \
-DDEFAULT_COLLATION=utf8mb4_general_ci \
-DCMAKE_C_COMPILER=/usr/bin/gcc \
-DCMAKE_CXX_COMPILER=/usr/bin/g++
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mariadb ];then
echo '10.11' > $serverPath/mariadb/version.pl
echo '安装完成' > $install_tmp
else
echo '安装失败' > $install_tmp
echo 'install fail'>&2
exit 1
fi
fi
rm -rf ${mariadbDir}/mariadb-${MY_VER}
rm -rf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
}
Uninstall_app()
{
rm -rf $serverPath/mariadb
echo '卸载完成' > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_app
else
Uninstall_app
fi
+6 -6
View File
@@ -228,11 +228,11 @@ label.checkbox_label span {
</div>
<div class="mtb20">
<span class="panel_setp_span">接收数据的面板地址</span>
<input type="text" class="bt-input-text" name="psync_url" value="" placeholder="接收数据面板地址,如: http://127.0.0.1:8888">
<input type="text" class="bt-input-text" name="sync_url" value="" placeholder="接收数据面板地址,如: http://127.0.0.1:8888">
</div>
<div class="mtb20">
<span class="panel_setp_span">接收数据的面板API</span>
<input type="text" class="bt-input-text" name="psync_token" value="" placeholder="接收数据面板API密钥" />
<input type="text" class="bt-input-text" name="sync_token" value="" placeholder="接收数据面板API密钥" />
<a href="#" target="_blank" class="btlink ml5">获取API秘钥</a>
</div>
<div class="mtb20">
@@ -243,8 +243,7 @@ label.checkbox_label span {
<button class="btn btn-success infoNext">下一步</button>
</div>
</div>
<div class="pa15 psync_path" style="margin:0 50px">
</div>
<div class="pa15 psync_path" style="margin:0 50px;"></div>
<div class="pa15 psync_data" style="text-align: left;">
<div class="checkbox_conten">
<div class="checkbox_data">
@@ -253,7 +252,7 @@ label.checkbox_label span {
<input type="checkbox" id="sites_All" checked>
<span>网站</span>
</label>
<ul></ul>
<ul id="sites_li"></ul>
</div>
</div>
<div class="checkbox_data">
@@ -262,7 +261,7 @@ label.checkbox_label span {
<input type="checkbox" id="db_All" checked>
<span>数据库</span>
</label>
<ul></ul>
<ul id="db_li"></ul>
</div>
</div>
</div>
@@ -286,6 +285,7 @@ label.checkbox_label span {
<script type="text/javascript">
resetPluginWinWidth(700);
resetPluginWinWidth(700);
$.getScript( "/plugins/file?name=migration_api&f=js/app.js", function(){
initStep();
});
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
{
"sort": 7,
"ps": "[<span style='color:red;'>潜龙勿用</span>]一键迁移,仅网站数据和MySQL数据",
"ps": "[<span style='color:red;'>潜龙勿用</span>]一键迁移,仅网站数据和MySQL数据(仅支持源码安装软件)",
"name": "migration_api",
"title": "一键迁移API",
"shell": "install.sh",
+246 -22
View File
@@ -1,4 +1,24 @@
function maPost(method,args,callback){
function maPostNoMsg(method,args,callback){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
$.post('/plugins/run', {name:'migration_api', func:method, args:_args}, function(data) {
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function maPost(method,args,callback, msg = '正在获取...'){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
@@ -6,7 +26,7 @@ function maPost(method,args,callback){
_args = JSON.stringify(args);
}
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var loadT = layer.msg(msg, { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'migration_api', func:method, args:_args}, function(data) {
layer.close(loadT);
if (!data.status){
@@ -30,6 +50,7 @@ function maAsyncPost(method,args){
return syncPost('/plugins/run', {name:'migration_api', func:method, args:_args});
}
function maPostCallbak(method, args, callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
@@ -58,43 +79,246 @@ function maPostCallbak(method, args, callback){
}
function initStep1(){
maPost('step_one',{}, function(rdata){
console.log(rdata);
function selectProgress(val){
$('.step_head li').removeClass('active');
$('.step_head li').each(function(){
var v = $(this).find('span').text();
if (val == v){
$(this).addClass('active');
}
});
}
function initStep1(){
var url = $('input[name="sync_url"]').val();
var token = $('input[name="sync_token"]').val();
maPost('step_one',{url:url,token:token}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if (rdata.status){
initStep2();
}
},{ icon: rdata.status ? 1 : 2 });
},'API校验中...');
}
function initStep2(){
maPost('step_one',{}, function(rdata){
console.log(rdata);
});
maPost('step_two',{}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if (rdata.status){
selectProgress(2);
$('.psync_info').hide();
var info = rdata.data;
var body = '<div class="divtable">\
<table class="table table-hover">\
<thead>\
<tr><th style="border-right:1px solid #ddd">服务</th><th>当前服务器</th><th>远程服务器</th></tr>\
</thead>\
<tbody>\
<tr>\
<td style="border-right:1px solid #ddd">网站服务</td>\
<td>'+info['local']['webserver']+'</td>\
<td>'+info['remote']['webserver']+'</td>\
</tr>\
<tr>\
<td style="border-right:1px solid #ddd">安装MySQL</td>\
<td>'+(info['local']['mysql']?'是':'否')+'</td>\
<td>'+(info['remote']['mysql']?'是':'否')+'</td>\
</tr>\
<tr>\
<td style="border-right:1px solid #ddd">安装PHP</td>\
<td>'+(info['local']['php'].join('/'))+'</td>\
<td>'+(info['remote']['php'].join('/')) +'</td>\
</tr>\
<tr>\
<td style="border-right:1px solid #ddd">可用磁盘</td>\
<td>'+info['local']['disk']+'</td>\
<td>'+info['remote']['disk'][0]['size'][0]+'</td>\
</tr>\
</tbody>\
</table>\
</div>';
body += '<div class="line mtb20" style="text-align: left;">\
<button class="btn btn-default btn-sm mr20 pathTestting">重新检测</button>\
<button class="btn btn-default btn-sm mr20 pathBcak">上一步</button>\
<button class="btn btn-success btn-sm psync-next pathNext">下一步</button>\
</div>';
$('.psync_path').html(body);
$('.psync_path').show();
}
},{ icon: rdata.status ? 1 : 2 });
},'检测环境中...');
}
function initStep3(){
maPost('step_one',{}, function(rdata){
console.log(rdata);
maPost('step_three',{}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if (rdata.status){
selectProgress(3);
var pdata = rdata.data;
var site_li = '';
for (var i = 0; i < pdata.sites.length; i++) {
site_li+='<li>\
<label>\
<input type="checkbox" data-id="'+i+'" id="sites_'+pdata.sites[i]['name']+'" value="'+pdata.sites[i]['name']+'" name="sites" checked="">\
<span title="'+pdata.sites[i]['name']+'">'+pdata.sites[i]['name']+'</span>\
</label>\
</li>';
}
$('#sites_li').html(site_li);
var db_li = '';
for (var i = 0; i < pdata.databases.length; i++) {
db_li+='<li>\
<label>\
<input type="checkbox" data-id="'+i+'" id="sites_'+pdata.databases[i]['name']+'" value="'+pdata.databases[i]['name']+'" name="databases" checked="">\
<span title="'+pdata.databases[i]['name']+'">'+pdata.databases[i]['name']+'</span>\
</label>\
</li>';
}
$('#db_li').html(db_li);
$('.psync_path').hide();
$('.psync_data').show();
}
},{ icon: rdata.status ? 1 : 2 });
});
}
function renderMigrationProgress(){
maPostNoMsg('get_speed',{}, function(rdata){
var rdata = $.parseJSON(rdata.data);
// console.log('speed:',rdata.data);
if (rdata.status){
if (rdata['data']['action'] == 'True'){
var end = '<div class="line">\
<div class="success text-center" style="padding: 10px 0 15px;">\
<p>数据迁移完成,请务必检查数据完整性!</p>\
<p style="font-size: 14px;margin-top:2px;color: #939292;">传输大小: '+toSize(rdata['data']['total_size'])+',耗时: '+rdata['data']['total_time']+',平均速度: '+toSize(rdata['data']['speed'])+'/s</p>\
<p class="mtb15">\
<button class="btn btn-success btn-sm mr5 okBtn">确定完成</button>\
<a class="btn btn-default btn-sm" style="margin-left: 10px;" target="_blank" href="/files/download?filename='+rdata['data']['log_file']+'">迁移日志</a>\
</p>\
</div>\
</div>';
$('.psync_migrate').html(end);
} else{
$('.psync_migrate .action').text(rdata['data']['action']);
$('.psync_migrate .done').text(rdata['data']['done']);
$('.psync_migrate pre').text(rdata['data']['log']);
var p = (rdata['data']['all_speed']/rdata['data']['all_total'])*100;
if (p>100){
p = 100;
}
$('.psync_migrate .progress_info_bar').width(p+'%');
$('.psync_migrate .progress_info').text(p+'%');
renderMigrationProgress();
}
} else{
layer.msg(rdata.msg,{icon:1});
}
});
}
function initStep4(){
maPost('step_one',{}, function(rdata){
console.log(rdata);
var site_checked = '';
$('input[name="sites"]:checked').each(function(){
site_checked += $(this).val()+',';
});
var databases_checked = '';
$('input[name="databases"]:checked').each(function(){
databases_checked+=$(this).val()+',';
});
maPost('step_four',{sites:site_checked,databases:databases_checked}, function(rdata){
var rdata = $.parseJSON(rdata.data);
selectProgress(4);
var progress = '<div style="margin: 0 40px;">\
<div class="line">\
<div style="text-align:left"><span class="action">--</span>\
<span style="margin-left: 20px;" class="done">当前: --</span><img src="/static/img/ing.gif"><a style="position: absolute;right: 40px;" class="btlink psync_close" onclick="migrate.close();">[取消]</a></div>\
<div class="bt-progress" style="border-radius:0;height:20px;line-height:19px">\
<div class="bt-progress-bar progress_info_bar" style="border-radius: 0px; height: 20px; width: 0%;">\
<span class="bt-progress-text progress_info"></span></div>\
</div>\
</div>\
</div>\
<pre style="height: 222px;text-align: left;margin:5px 38px 0;font-size: 12px;line-height: 20px;padding: 10px;background-color: #333;color: #fff;"></pre>\
</div>';
$('.psync_data').hide();
$('.psync_migrate').html(progress);
$('.psync_migrate').show();
renderMigrationProgress();
});
}
function initStep(){
console.log($('.infoNext'));
maPost('get_conf',{}, function(rdata){
var rdata = $.parseJSON(rdata.data);
$('input[name="sync_url"]').val(rdata.data['url']);
$('input[name="sync_token"]').val(rdata.data['token']);
});
$('.infoNext').click(function(){
var step = $('.step_head .active span').text();
// console.log(step);
// initStep1();
switch(step){
case '1':initStep1();break;
case '2':initStep2();break;
case '3':initStep3();break;
case '4':initStep4();break;
}
initStep1();
});
// 重新检测按钮
$('.psync_path').on('click', '.pathTestting', function () {
initStep2();
});
$('.psync_path').on('click', '.pathBcak', function(){
$('.psync_path').hide();
$('.psync_info').show();
selectProgress(1);
});
$('.psync_path').on('click', '.pathNext', function(){
initStep3();
});
$('.psync_data').on('click', '.dataBack', function(){
$('.psync_data').hide();
$('.psync_path').show();
selectProgress(2);
});
$('.psync_data').on('click', '.dataMigrate', function(){
initStep4();
});
$('#sites_All').on('click',function(){
var ch = $(this).prop('checked');
$('#sites_li input').prop('checked',ch);
});
$('#db_All').on('click',function(){
var ch = $(this).prop('checked');
$('#db_li input').prop('checked',ch);
});
$('.psync_migrate').on('click', '.okBtn', function(){
$('.psync_migrate').hide();
$('.psync_info').show();
selectProgress(1);
});
}
+1
View File
@@ -65,6 +65,7 @@ binlog-ignore-db = performance_schema
#slave
log-slave-updates
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+1
View File
@@ -62,6 +62,7 @@ binlog-ignore-db = performance_schema
#slave
log_replica_updates
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+2 -1
View File
@@ -2474,7 +2474,8 @@ def doFullSyncUser(version=''):
if not os.path.exists(bak_file):
dump_sql_data = getServerDir() + "/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p" + apass + " " + sync_db + " > " + bak_file
port + " -u" + user + " -p" + apass + \
" --ssl-mode=DISABLED " + sync_db + " > " + bak_file
mw.execShell(dump_sql_data)
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
+1 -1
View File
@@ -1208,7 +1208,7 @@ function myLogs(){
<span class="f14 c6 mr20">二进制日志 </span><span class="f14 c6 mr20">' + toSize(rdata.msg) + '</span>\
'+line_status+'\
<p class="f14 c6 mtb10" style="border-top:#ddd 1px solid; padding:10px 0">错误日志<button class="btn btn-default btn-clear btn-xs" style="float:right;" >清理日志</button></p>\
<textarea readonly style="margin: 0px;width: 100%;height: 440px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
<textarea readonly style="margin: 0px;width: 100%;height: 438px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
</p>';
$(".soft-man-con").html(limitCon);
+1
View File
@@ -66,6 +66,7 @@ binlog-ignore-db = performance_schema
#slave
log-slave-updates
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+1
View File
@@ -62,6 +62,7 @@ binlog-ignore-db = performance_schema
#slave
log_replica_updates
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+2 -1
View File
@@ -2434,7 +2434,8 @@ def doFullSyncUser(version=''):
if not os.path.exists(bak_file):
dump_sql_data = getServerDir() + "/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p" + apass + " " + sync_db + " > " + bak_file
port + " -u" + user + " -p" + apass + \
" --ssl-mode=DISABLED " + sync_db + " > " + bak_file
mw.execShell(dump_sql_data)
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
+1 -1
View File
@@ -1208,7 +1208,7 @@ function myLogs(){
<span class="f14 c6 mr20">二进制日志 </span><span class="f14 c6 mr20">' + toSize(rdata.msg) + '</span>\
'+line_status+'\
<p class="f14 c6 mtb10" style="border-top:#ddd 1px solid; padding:10px 0">错误日志<button class="btn btn-default btn-clear btn-xs" style="float:right;" >清理日志</button></p>\
<textarea readonly style="margin: 0px;width: 100%;height: 440px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
<textarea readonly style="margin: 0px;width: 100%;height: 438px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
</p>';
$(".soft-man-con").html(limitCon);
+1
View File
@@ -70,6 +70,7 @@ log-slave-updates = 1
# Prevent replication from starting automatically with MySQL
#skip-slave-start = 1
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+1
View File
@@ -72,6 +72,7 @@ log-slave-updates = 1
# Prevent replication from starting automatically with MySQL
#skip-slave-start = 1
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+1
View File
@@ -73,6 +73,7 @@ binlog-ignore-db = performance_schema
# Prevent replication from starting automatically with MySQL
#skip-slave-start = 1
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+1
View File
@@ -71,6 +71,7 @@ log_replica_updates = 1
# Prevent replication from starting automatically with MySQL
#skip_replica_start = 1
#replicate-do-db
replica_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+1 -1
View File
@@ -16,7 +16,7 @@
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con" style="height: 530px; overflow: auto;"></div>
<div class="soft-man-con"></div>
</div>
</div>
+68 -13
View File
@@ -48,19 +48,20 @@ def getInitDFile():
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
if t.strip() == '':
tmp = []
else:
t = t.split(':', 1)
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
t = args[i].split(':', 1)
tmp[t[0]] = t[1]
return tmp
@@ -842,12 +843,29 @@ def setDbBackup():
return data[1]
scDir = mw.getRunDir() + '/scripts/backup.py'
cmd = 'python3 ' + scDir + ' database ' + args['name'] + ' 3'
os.system(cmd)
return mw.returnJson(True, 'ok')
# 数据库密码处理
def myPass(act, root):
conf_file = getConf()
mw.execShell("sed -i '/user=root/d' {}".format(conf_file))
mw.execShell("sed -i '/password=/d' {}".format(conf_file))
if act:
mycnf = mw.readFile(conf_file)
src_dump = "[mysqldump]\n"
sub_dump = src_dump + "user=root\npassword=\"{}\"\n".format(root)
if not mycnf:
return False
mycnf = mycnf.replace(src_dump, sub_dump)
if len(mycnf) > 100:
mw.writeFile(conf_file, mycnf)
return True
return True
def importDbExternal():
args = getArgs()
data = checkArgs(args, ['file', 'name'])
@@ -902,11 +920,16 @@ def importDbExternal():
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
os.environ["MYSQL_PWD"] = pwd
mysql_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + \
pwd + ' ' + name + ' < ' + import_sql
my_cnf = getConf()
myPass(True, pwd)
mysql_cmd = getServerDir() + '/bin/mysql --defaults-file=' + my_cnf + \
' -uroot -p\"' + pwd + '\" -f ' + name + ' < ' + import_sql
# print(mysql_cmd)
rdata = mw.execShell(mysql_cmd)
myPass(False, pwd)
# print(rdata)
if ext != 'sql':
os.remove(import_sql)
@@ -2371,6 +2394,25 @@ def initSlaveStatus(version=''):
return initSlaveStatusSyncUser(version)
def makeSyncUsercmd(u, version=''):
mode = recognizeDbMode()
sql = ''
ip = u['ip']
port = u['port']
username = u['user']
password = u['pass']
if mode == "gtid":
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
username + "', MASTER_PASSWORD='" + \
password + "', MASTER_AUTO_POSITION=1"
if version == '8.0':
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
username + "', SOURCE_PASSWORD='" + \
password + "', MASTER_AUTO_POSITION=1"
return sql
def initSlaveStatusSyncUser(version=''):
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').find()
@@ -2393,8 +2435,19 @@ def initSlaveStatusSyncUser(version=''):
if local_mode != mode_name:
return mw.returnJson(False, '同步模式不一致!')
t = db.query(u['cmd'])
# print(t)
if u['cmd'] == '' and local_mode == 'gtid':
sql = makeSyncUsercmd(u, version)
# print(sql)
t = db.query(sql)
else:
if u['cmd'] == '':
return mw.returnJson(False, '经典模式下,必须手写同步命令!')
# print(u['cmd'])
t = db.query(u['cmd'])
isError = isSqlError(t)
if isError:
return isError
db.query("start slave user='{}' password='{}';".format(
u['user'], u['pass']))
return mw.returnJson(True, '初始化成功!')
@@ -2612,8 +2665,10 @@ def doFullSyncUser(version=''):
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 20})
if not os.path.exists(bak_file):
dump_sql_data = getServerDir() + "/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p" + apass + " " + sync_db + " > " + bak_file
dump_sql_data = getServerDir() + "/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p\"" + apass + \
"\" --ssl-mode=DISABLED " + sync_db + " > " + bak_file
# print(dump_sql_data)
mw.execShell(dump_sql_data)
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
+1 -1
View File
@@ -1208,7 +1208,7 @@ function myLogs(){
<span class="f14 c6 mr20">二进制日志 </span><span class="f14 c6 mr20">' + toSize(rdata.msg) + '</span>\
'+line_status+'\
<p class="f14 c6 mtb10" style="border-top:#ddd 1px solid; padding:10px 0">错误日志<button class="btn btn-default btn-clear btn-xs" style="float:right;" >清理日志</button></p>\
<textarea readonly style="margin: 0px;width: 100%;height: 440px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
<textarea readonly style="margin: 0px;width: 100%;height: 438px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
</p>';
$(".soft-man-con").html(limitCon);
+13 -1
View File
@@ -1,4 +1,16 @@
{
"hook":[
{
"tag":"site_cb",
"site_cb": {
"title":"网站统计",
"name":"op_waf",
"add":{"func":"reload"},
"update":{"func":"reload"},
"delete":{"func":"reload"}
}
}
],
"title":"OP防火墙",
"tip":"soft",
"name":"op_waf",
@@ -12,5 +24,5 @@
"home":"https://github.com/loveshell/ngx_lua_waf",
"date":"2019-04-21",
"pid": "1",
"versions": ["0.2.5"]
"versions": ["0.2.6"]
}
+10 -1
View File
@@ -344,13 +344,22 @@ local function waf_cc_increase()
local make_uri = "/"..make_uri_str
if params['uri_request_args']['token'] then
ngx.header.content_type = "application/json"
local args_token = params['uri_request_args']['token']
if args_token == make_token then
ngx.shared.waf_limit:set(cache_token, 1, config['safe_verify']['time'])
ngx.shared.waf_limit:set(cache_token, 1, tonumber(config['safe_verify']['time']))
local data = get_return_state(0, "ok")
ngx.say(json.encode(data))
ngx.exit(200)
end
-- C:D("debug[args]:"..tostring(params['uri_request_args']['debug']))
-- if params['uri_request_args']['debug'] == 'ok' then
-- ngx.header.content_type = "application/json"
-- local data = get_return_state(0, "ok")
-- ngx.say(json.encode(data))
-- ngx.exit(200)
-- end
end
local cc_html = ngx.re.gsub(cc_safe_js_html, "{uri}", make_uri_str)
+2 -2
View File
@@ -204,8 +204,8 @@ def initDreplace():
mw.writeFile(file_bin, content)
mw.execShell('chmod +x ' + file_bin)
# config replace
confReplace()
# config replace
confReplace()
# systemd
# /usr/lib/systemd/system
+12 -1
View File
@@ -59,10 +59,21 @@ Install_openresty()
mkdir -p ${openrestyDir}
echo '正在安装脚本文件...' > $install_tmp
# wget -O openresty-1.21.4.1.tar.gz https://openresty.org/download/openresty-1.21.4.1.tar.gz
if [ ! -f ${openrestyDir}/openresty-${VERSION}.tar.gz ];then
wget -O ${openrestyDir}/openresty-${VERSION}.tar.gz https://openresty.org/download/openresty-${VERSION}.tar.gz
wget --no-check-certificate -O ${openrestyDir}/openresty-${VERSION}.tar.gz https://openresty.org/download/openresty-${VERSION}.tar.gz -T 3
fi
DOWNLOAD_SIZE=`wc -c ${openrestyDir}/openresty-${VERSION}.tar.gz | awk '{print $1}'`
if [ "$DOWNLOAD_SIZE" == "0" ];then
echo 'download failed, download again'
rm -rf ${openrestyDir}/openresty-${VERSION}.tar.gz
fi
# Last Download Method
if [ ! -f ${openrestyDir}/openresty-${VERSION}.tar.gz ];then
wget --no-check-certificate -O ${openrestyDir}/openresty-${VERSION}.tar.gz https://dl.midoks.me/soft/openresty/openresty-${VERSION}.tar.gz -T 3
fi
cd ${openrestyDir} && tar -zxvf openresty-${VERSION}.tar.gz
+1
View File
@@ -17,6 +17,7 @@
</div>
<script type="text/javascript">
resetPluginWinHeight(500);
$.getScript( "/plugins/file?name=phpmyadmin&f=js/phpmyadmin.js", function(){
pluginService('phpmyadmin');
});
+3 -2
View File
@@ -47,7 +47,8 @@ Install_phpmyadmin()
mkdir -p ${serverPath}/phpmyadmin
mkdir -p ${serverPath}/source/phpmyadmin
echo "${1}" > ${serverPath}/phpmyadmin/version.pl
VER=$1
FDIR=phpMyAdmin-${VER}-all-languages
@@ -67,7 +68,7 @@ Install_phpmyadmin()
cd $serverPath/phpmyadmin/ && mv $FDIR phpmyadmin
echo "${1}" > ${serverPath}/phpmyadmin/version.pl
echo '安装完成' > $install_tmp
cd ${rootPath} && python3 ${rootPath}/plugins/phpmyadmin/index.py start
-1
View File
@@ -26,7 +26,6 @@ AutoRename no
AnonymousCantUpload no
MaxDiskUsage 99
CustomerProof yes
PassivePortRange 48000 50000
PIDFile {$SERVER_PATH}/pureftp/etc/pure-ftpd.pid
PureDB {$SERVER_PATH}/pureftp/etc/pureftpd.pdb
+5
View File
@@ -9,6 +9,11 @@ serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
sysName=`uname`
echo "use system: ${sysName}"
+4 -3
View File
@@ -214,7 +214,8 @@ def initdStatus():
if mw.isAppleSystem():
return "Apple Computer does not support"
shell_cmd = 'systemctl status redis | grep loaded | grep "enabled;"'
shell_cmd = 'systemctl status ' + \
getPluginName() + ' | grep loaded | grep "enabled;"'
data = mw.execShell(shell_cmd)
if data[0] == '':
return 'fail'
@@ -225,7 +226,7 @@ def initdInstall():
if mw.isAppleSystem():
return "Apple Computer does not support"
mw.execShell('systemctl enable redis')
mw.execShell('systemctl enable ' + getPluginName())
return 'ok'
@@ -233,7 +234,7 @@ def initdUinstall():
if mw.isAppleSystem():
return "Apple Computer does not support"
mw.execShell('systemctl disable redis')
mw.execShell('systemctl disable ' + getPluginName())
return 'ok'
+2 -13
View File
@@ -1,14 +1,3 @@
function str2Obj(str){
var data = {};
kv = str.split('&');
for(i in kv){
v = kv[i].split('=');
data[v[0]] = v[1];
}
return data;
}
function redisPost(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
@@ -18,7 +7,7 @@ function redisPost(method, version, args,callback){
req_data['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(str2Obj(args));
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
@@ -46,7 +35,7 @@ function redisPostCallbak(method, version, args,callback){
args['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(str2Obj(args));
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
+4
View File
@@ -16,6 +16,10 @@ bash ${rootPath}/scripts/getos.sh
OSNAME=`cat ${rootPath}/data/osname.pl`
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
if id www &> /dev/null ;then
echo "www uid is `id -u www`"
echo "www shell is `grep "^www:" /etc/passwd |cut -d':' -f7 `"
+127
View File
@@ -0,0 +1,127 @@
#
# Discuz Sphinx Config File
#
indexer
{
mem_limit = 32M
write_buffer = 64M
}
searchd
{
listen = 9312
listen = 9306:mysql41
log = {$SERVER_APP}/index/searchd.log
query_log = {$SERVER_APP}/index/query.log
read_timeout = 5
max_children = 0
pid_file = {$SERVER_APP}/index/searchd.pid
seamless_rotate = 1
preopen_indexes = 1
unlink_old = 1
#workers = threads # for RT to work
binlog_path = {$SERVER_APP}/index/binlog
}
source pre_forum_thread
{
type = mysql
sql_host = 127.0.0.1
sql_user = bbs
sql_pass = bbs
sql_db = bbs
sql_port = 3306
sql_query_pre = SET NAMES UTF8
sql_query_pre = SET SESSION query_cache_type=OFF
sql_query_pre = REPLACE INTO bbs_common_sphinxcounter SELECT 1, MAX(tid) FROM bbs_forum_thread
sql_query = SELECT t.tid as id,t.tid,t.subject,t.digest,t.displayorder,t.authorid,t.lastpost,t.special \
FROM bbs_forum_thread AS t WHERE t.tid>=$start AND t.tid<=$end
sql_query_range = SELECT (SELECT MIN(tid) FROM bbs_forum_thread),maxid FROM bbs_common_sphinxcounter WHERE indexid=1
sql_range_step = 5000
sql_attr_uint = tid
sql_attr_uint = digest
sql_attr_uint = displayorder
sql_attr_uint = authorid
sql_attr_uint = special
sql_attr_timestamp =lastpost
}
index pre_forum_thread
{
source = pre_forum_thread
path = {$SERVER_APP}/index/db/pre_forum_thread/index
min_word_len = 2
html_strip = 1
ngram_len = 1
ngram_chars = U+3000..U+2FA1F
}
# threads_minute
source pre_forum_thread_minute : pre_forum_thread
{
sql_query_pre = SET NAMES UTF8
sql_query_pre = SET SESSION query_cache_type=OFF
sql_query_range = SELECT maxid-1,(SELECT MAX(tid) FROM bbs_forum_thread) FROM bbs_common_sphinxcounter WHERE indexid=1
}
# threads_minute
index pre_forum_thread_minute : pre_forum_thread
{
source = pre_forum_thread_minute
path = {$SERVER_APP}/index/db/pre_forum_thread/pre_forum_thread_minute
}
#posts
source pre_forum_post : pre_forum_thread
{
type = mysql
sql_query_pre =
sql_query_pre = SET NAMES UTF8
sql_query_pre = SET SESSION query_cache_type=OFF
sql_query_pre = REPLACE INTO bbs_common_sphinxcounter SELECT 2, MAX(pid) FROM bbs_forum_post
sql_query = SELECT p.pid AS id,p.tid,p.subject,p.message,t.digest,t.displayorder,t.authorid,t.lastpost,t.special \
FROM bbs_forum_post AS p LEFT JOIN bbs_forum_thread AS t USING(tid) where p.pid >=$start and p.pid <=$end \
AND p.first=1
sql_query_range = SELECT (SELECT MIN(pid) FROM bbs_forum_post),maxid FROM bbs_common_sphinxcounter WHERE indexid=2
sql_range_step = 5000
sql_attr_uint = tid
sql_attr_uint = digest
sql_attr_uint= displayorder
sql_attr_uint = authorid
sql_attr_uint = special
sql_attr_timestamp = lastpost
}
#posts
index pre_forum_post
{
source = pre_forum_post
path = {$SERVER_APP}/index/db/pre_forum_thread/pre_forum_post
min_word_len = 2
html_strip = 1
ngram_len = 1
ngram_chars = U+3000..U+2FA1F
}
#pre_forum_post_minute
source pre_forum_post_minute : pre_forum_post
{
sql_query_pre = SET NAMES UTF8
sql_query_pre = SET SESSION query_cache_type=OFF
sql_query_range = SELECT maxid-1,(SELECT MAX(pid) FROM bbs_forum_post) FROM bbs_common_sphinxcounter WHERE indexid=2
}
#pre_forum_post_minute
index pre_forum_post_minute : pre_forum_post
{
source = pre_forum_thread
path = {$SERVER_APP}/index/db/pre_forum_thread/pre_forum_post_minute
}
+1 -1
View File
@@ -23,7 +23,7 @@
.code span {display: block;margin-left: 15px;margin-bottom: 0;}
</style>
<script type="text/javascript">
resetPluginWinWidth(800);
resetPluginWinWidth(850);
$.getScript( "/plugins/file?name=supervisor&f=js/supervisor.js", function(){
pluginService('supervisor');
});
+28 -3
View File
@@ -220,7 +220,8 @@ def getSupList():
infos = fr.readlines()
for line in infos:
if "command=" in line.strip():
d["command"] = line.strip().split('=')[1]
# d["command"] = line.strip().split('=')[1]
d["command"] = "子配置查看"
if "user=" in line.strip():
d["user"] = line.strip().split('=')[1]
if "priority=" in line.strip():
@@ -329,6 +330,27 @@ def startJob():
return mw.returnJson(True, action + '[' + name + ']成功!')
def restartJob():
args = getArgs()
data = checkArgs(args, ['name', 'status'])
if not data[0]:
return data[1]
supCtl = 'supervisorctl -c ' + getServerDir() + "/supervisor.conf"
name = args['name']
status = args['status']
cmd = supCtl + " stop " + name
data = mw.execShell(cmd)
cmd = supCtl + " start " + name
data = mw.execShell(cmd)
if data[1] != '':
return mw.returnJson(False, '[' + name + ']重启失败!')
return mw.returnJson(True, '[' + name + ']重启成功!')
def delJob():
args = getArgs()
data = checkArgs(args, ['name'])
@@ -440,8 +462,9 @@ def configTpl():
pathFile = os.listdir(path)
tmp = []
for one in pathFile:
file = path + '/' + one
tmp.append(file)
if one.endswith(".ini"):
file = path + '/' + one
tmp.append(file)
return mw.getJson(tmp)
@@ -567,6 +590,8 @@ if __name__ == "__main__":
print(addJob())
elif func == 'start_job':
print(startJob())
elif func == 'restart_job':
print(restartJob())
elif func == 'del_job':
print(delJob())
elif func == 'update_job':
+11
View File
@@ -70,6 +70,7 @@ function supList(page, search){
list += '<td style="text-align:right">\
<a href="javascript:;" class="btlink" onclick="startOrStop(\''+rdata.data[i]['program']+'\',\''+sup_status+'\')" title="启动|停止">'+sup_status_desc+'</a> | ' +
'<a href="javascript:;" class="btlink" onclick="restartJob(\''+rdata.data[i]['program']+'\',\''+sup_status+'\')" title="重启">重启</a> | ' +
'<a href="javascript:;" class="btlink" onclick="updateJob(\''+rdata.data[i]['program']+'\')">修改</a> | ' +
'<a href="javascript:;" class="btlink" onclick="delJob(\''+rdata.data[i]['program']+'\')" title="删除">删除</a>' +
'</td>';
@@ -128,6 +129,16 @@ function startOrStop(name,status){
});
}
function restartJob(name,status){
myPost('restart_job',{'name':name,'status':status}, function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg,{icon:rdata.status?1:2});
setTimeout(function(){
supList(1,10);
},2000);
});
}
function updateJob(name){
myPost('get_job_info',{'name':name},function(data){
var rdata = $.parseJSON(data.data);
Binary file not shown.

After

Width:  |  Height:  |  Size: 974 B

+26
View File
@@ -0,0 +1,26 @@
<div class="bt-form">
<div class='plugin_version'></div>
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('tgbot');">服务</p>
<p onclick="pluginInitD('tgbot');">自启动</p>
<p onclick="botConf();">Bot配置</p>
<p onclick="botExtList();">扩展列表</p>
<p onclick="pluginLogs('tgbot','','run_log');">日志</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<style>
.conf_p span{
width: 70px;
}
</style>
<script type="text/javascript">
resetPluginWinHeight(350);
$.getScript( "/plugins/file?name=tgbot&f=js/tgbot.js", function(){
pluginService('tgbot');
});
</script>
+367
View File
@@ -0,0 +1,367 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import json
import base64
sys.path.append(os.getcwd() + "/class/core")
import mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'tgbot'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getInitDFile():
if app_debug:
return '/tmp/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getConfigData():
cfg_path = getServerDir() + "/data.cfg"
if not os.path.exists(cfg_path):
mw.writeFile(cfg_path, '{}')
t = mw.readFile(cfg_path)
return json.loads(t)
def writeConf(data):
cfg_path = getServerDir() + "/data.cfg"
mw.writeFile(cfg_path, json.dumps(data))
return True
def getExtCfg():
cfg_path = getServerDir() + "/extend.cfg"
if not os.path.exists(cfg_path):
mw.writeFile(cfg_path, '{}')
t = mw.readFile(cfg_path)
return json.loads(t)
def writeExtCfg(data):
cfg_path = getServerDir() + "/extend.cfg"
return mw.writeFile(cfg_path, json.dumps(data))
def getInitDTpl():
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
return path
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
if t.strip() == '':
tmp = []
else:
t = t.split(':')
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def status():
data = mw.execShell(
"ps -ef|grep tgbot |grep -v grep | grep -v mdserver-web | awk '{print $2}'")
if data[0] == '':
return 'stop'
return 'start'
def initDreplace():
file_tpl = getInitDTpl()
service_path = mw.getServerDir()
app_path = service_path + '/' + getPluginName()
initD_path = getServerDir() + '/init.d'
if not os.path.exists(initD_path):
os.mkdir(initD_path)
file_bin = initD_path + '/' + getPluginName()
# initd replace
# if not os.path.exists(file_bin):
content = mw.readFile(file_tpl)
content = content.replace('{$SERVER_PATH}', service_path + '/mdserver-web')
content = content.replace('{$APP_PATH}', app_path)
mw.writeFile(file_bin, content)
mw.execShell('chmod +x ' + file_bin)
# systemd
systemDir = mw.systemdCfgDir()
systemService = systemDir + '/tgbot.service'
systemServiceTpl = getPluginDir() + '/init.d/tgbot.service.tpl'
if os.path.exists(systemDir) and not os.path.exists(systemService):
service_path = mw.getServerDir()
se_content = mw.readFile(systemServiceTpl)
se_content = se_content.replace('{$APP_PATH}', app_path)
mw.writeFile(systemService, se_content)
mw.execShell('systemctl daemon-reload')
return file_bin
def tbOp(method):
file = initDreplace()
if not mw.isAppleSystem():
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
if data[1] == '':
return 'ok'
return data[1]
data = mw.execShell(file + ' ' + method)
# print(data)
if data[1] == '':
return 'ok'
return 'ok'
def start():
return tbOp('start')
def stop():
return tbOp('stop')
def restart():
status = tbOp('restart')
return status
def reload():
tgbot_tpl = getPluginDir() + '/startup/tgbot.py'
tgbot_dst = getServerDir() + '/tgbot.py'
content = mw.readFile(tgbot_tpl)
mw.writeFile(tgbot_dst, content)
ext_src = getPluginDir() + '/startup/extend'
ext_dst = getServerDir()
mw.execShell('cp -rf ' + ext_src + ' ' + ext_dst)
return tbOp('restart')
def initdStatus():
if mw.isAppleSystem():
return "Apple Computer does not support"
shell_cmd = 'systemctl status ' + \
getPluginName() + ' | grep loaded | grep "enabled;"'
data = mw.execShell(shell_cmd)
if data[0] == '':
return 'fail'
return 'ok'
def initdInstall():
if mw.isAppleSystem():
return "Apple Computer does not support"
mw.execShell('systemctl enable ' + getPluginName())
return 'ok'
def initdUinstall():
if mw.isAppleSystem():
return "Apple Computer does not support"
mw.execShell('systemctl disable ' + getPluginName())
return 'ok'
def getBotConf():
data = getConfigData()
if 'bot' in data:
return mw.returnJson(True, 'ok', data['bot'])
return mw.returnJson(False, 'ok', {})
def setBotConf():
args = getArgs()
data_args = checkArgs(args, ['app_token'])
if not data_args[0]:
return data_args[1]
data = getConfigData()
args['app_token'] = base64.b64decode(args['app_token']).decode('ascii')
data['bot'] = args
writeConf(data)
return mw.returnJson(True, '保存成功!', [])
def installPreInspection():
i = sys.version_info
if i[0] < 3 or i[1] < 7:
return "telebot在python小于3.7无法正常使用"
return 'ok'
def uninstallPreInspection():
stop()
return "请手动删除<br/> rm -rf {}".format(getServerDir())
def getExtCfgByName(name):
elist = getExtCfg()
for x in elist:
if x['name'] == name:
return x
return None
def botExtList():
args = getArgs()
data_args = checkArgs(args, ['p'])
if not data_args[0]:
return data_args[1]
ext_path = getServerDir() + '/extend'
if not os.path.exists(ext_path):
return mw.returnJson(False, 'ok', [])
elist_source = os.listdir(ext_path)
elist = []
for e in elist_source:
if e.endswith('py'):
elist.append(e)
page = int(args['p'])
page_size = 5
make_ext_list = []
for ex in elist:
tmp = {}
tmp['name'] = ex
edata = getExtCfgByName(ex)
if edata:
tmp['status'] = edata['status']
else:
tmp['status'] = 'stop'
tmp['tag'] = ex.split('_')[0]
make_ext_list.append(tmp)
writeExtCfg(make_ext_list)
dlist_sum = len(make_ext_list)
page_start = int((page - 1) * page_size)
page_end = page_start + page_size
if page_end >= dlist_sum:
ret_data = make_ext_list[page_start:]
else:
ret_data = make_ext_list[page_start:page_end]
data = {}
data['data'] = ret_data
data['args'] = args
data['list'] = mw.getPage(
{'count': dlist_sum, 'p': page, 'row': page_size, 'tojs': 'botExtListP'})
return mw.returnJson(True, 'ok', data)
def setExtStatus():
args = getArgs()
data_args = checkArgs(args, ['name', 'status'])
if not data_args[0]:
return data_args[1]
elist = getExtCfg()
name = args['name']
status = args['status']
for x in range(len(elist)):
if elist[x]['name'] == name:
elist[x]['status'] = status
break
writeExtCfg(elist)
action = '开启'
if status == 'stop':
action = '关闭'
return mw.returnJson(True, action + '[' + name + ']扩展成功')
def runLog():
p = getServerDir() + '/task.log'
return p
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
elif func == 'start':
print(start())
elif func == 'stop':
print(stop())
elif func == 'restart':
print(restart())
elif func == 'reload':
print(reload())
elif func == 'initd_status':
print(initdStatus())
elif func == 'initd_install':
print(initdInstall())
elif func == 'initd_uninstall':
print(initdUinstall())
elif func == 'install_pre_inspection':
print(installPreInspection())
elif func == 'uninstall_pre_inspection':
print(uninstallPreInspection())
elif func == 'get_bot_conf':
print(getBotConf())
elif func == 'set_bot_conf':
print(setBotConf())
elif func == 'bot_ext_list':
print(botExtList())
elif func == 'set_ext_status':
print(setExtStatus())
elif func == 'run_log':
print(runLog())
else:
print('error')
+20
View File
@@ -0,0 +1,20 @@
{
"sort": 7,
"ps": "简单Telegram机器人",
"name": "tgbot",
"title": "tgbot",
"shell": "install.sh",
"versions":["1.0"],
"tip": "soft",
"checks": "server/tgbot",
"path": "server/tgbot",
"install_pre_inspection":true,
"uninstall_pre_inspection":true,
"display": 1,
"author": "midokos",
"date": "2023-03-06",
"home": "https://core.telegram.org/bots/api",
"depend_doc1":"https://github.com/eternnoir/pyTelegramBotAPI",
"type": 0,
"pid": "5"
}
+14
View File
@@ -0,0 +1,14 @@
[Unit]
Description=Tgbot Service
After=network.target
[Service]
Type=forking
ExecStart={$APP_PATH}/init.d/tgbot start
ExecStop={$APP_PATH}/init.d/tgbot stop
ExecReload={$APP_PATH}/init.d/tgbot reload
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
+85
View File
@@ -0,0 +1,85 @@
#!/bin/sh
# chkconfig: 2345 55 25
# description: Tgbot Service
### BEGIN INIT INFO
# Provides: Tgbot
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts Tgbot
# Description: starts the MDW-Web
### END INIT INFO
# Simple Tgbot init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
PATH=/usr/local/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export LANG=en_US.UTF-8
mw_path={$SERVER_PATH}
PATH=$PATH:$mw_path/bin
if [ -f $mw_path/bin/activate ];then
source $mw_path/bin/activate
fi
tg_start(){
isStart=`ps -ef|grep 'tgbot.py' |grep -v grep | awk '{print $2}'`
if [ "$isStart" == '' ];then
echo -e "starting tgbot... \c"
cd $mw_path
python3 {$APP_PATH}/tgbot.py >> {$APP_PATH}/task.log &
isStart=""
while [[ "$isStart" == "" ]];
do
echo -e ".\c"
sleep 0.5
isStart=`ps -ef|grep 'tgbot.py' |grep -v grep | awk '{print $2}'`
let n+=1
if [ $n -gt 20 ];then
break;
fi
done
if [ "$isStart" == '' ];then
echo -e "\033[31mfailed\033[0m"
echo -e "\033[31mError: tgbot service startup failed.\033[0m"
return;
fi
echo -e "\033[32mdone\033[0m"
else
echo "starting tgbot...(pid $(echo $isStart)) already running"
fi
}
tg_stop(){
echo -e "stopping tgbot ... \c";
arr=`ps aux|grep 'tgbot.py'|grep -v grep|awk '{print $2}'`
for p in ${arr[@]}
do
kill -9 $p > /dev/null 2>&1
done
echo -e "\033[32mdone\033[0m"
}
case "$1" in
start)
tg_start
;;
stop)
tg_stop
;;
restart|reload)
tg_stop
sleep 0.3
tg_start
;;
*)
echo "Please use start or stop as first argument"
;;
esac
+59
View File
@@ -0,0 +1,59 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
# pip3 install ccxt
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
pip3 install pyTelegramBotAPI
pip3 install telebot
Install_App()
{
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/source
mkdir -p $serverPath/tgbot
echo "${VERSION}" > $serverPath/tgbot/version.pl
cp -rf ${rootPath}/plugins/tgbot/startup/* $serverPath/tgbot
cd ${rootPath} && python3 ${rootPath}/plugins/tgbot/index.py start
cd ${rootPath} && python3 ${rootPath}/plugins/tgbot/index.py initd_install
echo '安装完成' > $install_tmp
}
Uninstall_App()
{
if [ -f /usr/lib/systemd/system/tgbot.service ];then
systemctl stop tgbot
systemctl disable tgbot
rm -rf /usr/lib/systemd/system/tgbot.service
systemctl daemon-reload
fi
if [ -f $serverPath/tgbot/initd/tgbot ];then
$serverPath/tgbot/initd/tgbot stop
fi
rm -rf $serverPath/tgbot
echo "Uninstall_redis" > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_App
else
Uninstall_App
fi
+148
View File
@@ -0,0 +1,148 @@
function appPost(method, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'tgbot';
req_data['func'] = method;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/run', req_data, function(data) {
layer.close(loadT);
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function appPostCallbak(method, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'tgbot';
req_data['func'] = method;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function botConf(){
appPost('get_bot_conf','',function(data){
var rdata = $.parseJSON(data.data);
var app_token = 'app_token';
if(rdata['status']){
db_data = rdata['data'];
app_token = db_data['app_token'];
}
var mlist = '';
mlist += '<p><span>app_token</span><input style="width: 250px;" class="bt-input-text mr5" name="app_token" value="'+app_token+'" type="text"><font>必填写</font></p>'
var option = '<style>.conf_p p{margin-bottom: 2px}</style>\
<div class="conf_p" style="margin-bottom:0">\
' + mlist + '\
<div style="margin-top:10px; padding-right:15px" class="text-right">\
<button class="btn btn-success btn-sm" onclick="submitBotConf()">保存</button>\
</div>\
</div>';
$(".soft-man-con").html(option);
});
}
function submitBotConf(){
var pull_data = {};
pull_data['app_token'] = base64_encode($('input[name="app_token"]').val());
appPost('set_bot_conf',pull_data,function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata['msg'],{icon:rdata['status']?1:2,time:2000,shade: [0.3, '#000']});
});
}
function botExtList(){
var body = '<div class="divtable mtb10">\
<table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">\
<thead>\
<tr>\
<th width="20">脚本</th>\
<th width="120">类型</th>\
<th width="10">状态</th>\
</tr>\
</thead>\
<tbody id="ext_list"></tbody>\
</table>\
<div class="dataTables_paginate paging_bootstrap pagination">\
<ul id="ext_list_page" class="page"></ul>\
</div>\
</div>';
$('.soft-man-con').html(body);
botExtListP(1);
}
function setBotExtStatus(name,status){
appPost('set_ext_status',{'name':name,'status':status}, function(rdata){
var rdata = $.parseJSON(rdata.data);
layer.msg(rdata['msg'],);
showMsg(rdata['msg'], function(){
botExtListP(1);
},{icon:rdata['status']?1:2,shade: [0.3, '#000']},2000);
});
}
function botExtListP(p=1){
appPost('bot_ext_list',{'p':p}, function(rdata){
// console.log(rdata);
var rdata = $.parseJSON(rdata.data);
// console.log(rdata);
var tBody = '';
if (!rdata.status && rdata.data.length == 0 ){
var tBody = '<tr><td colspan="4"><div style="text-align:center;">无数据</div></td></tr>';
} else{
var ldata = rdata.data.data;
for (var i = 0; i < ldata.length; i++) {
tBody += '<tr data-name="'+ldata[i]['name']+'">'
tBody += '<td>'+ldata[i]['name']+'</td>';
tBody += '<td>'+ldata[i]['tag']+'</td>';
if (ldata[i]['status'] == 'start'){
tBody += '<td><span style="color:#20a53a;cursor: pointer;" class="ext_status glyphicon glyphicon-play"></span></td>';
} else{
tBody += '<td><span style="color:red;cursor: pointer;" class="ext_status glyphicon glyphicon-pause"></span></td>';
}
tBody +='<tr>';
}
}
$('#ext_list').html(tBody);
$('#ext_list_page').html(rdata.data.list);
$('#ext_list .ext_status').click(function(){
var name = $(this).parent().parent().data('name');
var status = 'stop';
if ($(this).hasClass('glyphicon-pause')){
status = 'start';
}
setBotExtStatus(name,status);
});
});
}
+27
View File
@@ -0,0 +1,27 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import json
import base64
import threading
sys.path.append(os.getcwd() + "/class/core")
import mw
import telebot
from telebot import types
from telebot.util import quick_markup
def init(bot):
bot.delete_my_commands(scope=None, language_code=None)
bot.set_my_commands(
commands=[
telebot.types.BotCommand("start", "查看帮助信息"),
telebot.types.BotCommand("faq", "查看bbs帖子主题【不要忘记:冒号】"),
],
)
+85
View File
@@ -0,0 +1,85 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import json
import base64
import threading
sys.path.append(os.getcwd() + "/class/core")
import mw
import telebot
from telebot import types
from telebot.util import quick_markup
# 广告推送实例
chat_id = -1001578009023
# chat_id = 5568699210
def send_msg(bot, tag='ad', trigger_time=300):
# 信号只在一个周期内执行一次|start
lock_file = mw.getServerDir() + '/tgbot/lock.json'
if not os.path.exists(lock_file):
mw.writeFile(lock_file, '{}')
lock_data = json.loads(mw.readFile(lock_file))
if tag in lock_data:
diff_time = time.time() - lock_data[tag]['do_time']
if diff_time >= trigger_time:
lock_data[tag]['do_time'] = time.time()
else:
return False, 0, 0
else:
lock_data[tag] = {'do_time': time.time()}
mw.writeFile(lock_file, json.dumps(lock_data))
# 信号只在一个周期内执行一次|end
keyboard = [
[
types.InlineKeyboardButton(
text="赞助联系ME", url='tg://user?id=5568699210')
],
[
types.InlineKeyboardButton(
text="♻️CMS导航网♻️", url='https://t.me/maccms_jccms')
],
[
types.InlineKeyboardButton(
text="💰流量变现💰", url='https://t.me/taohaozhan')
],
[
types.InlineKeyboardButton(
text="🙎‍♂️代实名🙍‍♀️过人脸🅾️国际阿里云腾讯云(赞助商)", url='https://t.me/gjgzs2022')
],
[
types.InlineKeyboardButton(
text="💎DigitalVirt(赞助商)", url='https://digitalvirt.com/aff.php?aff=154')
],
[
types.InlineKeyboardButton(
text="论坛", url='https://bbs.midoks.me'),
types.InlineKeyboardButton(
text="搜索", url='https://bbs.midoks.me/search.php')
]
]
markup = types.InlineKeyboardMarkup(keyboard)
image_file = mw.getPluginDir() + '/tgbot/static/image/ad.png'
telebot_image = telebot.types.InputFile(image_file)
msg = bot.send_photo(chat_id, telebot_image, reply_markup=markup)
# print(msg.message_id)
time.sleep(5 * 60)
del_msg = bot.delete_message(chat_id=chat_id, message_id=msg.message_id)
# print(del_msg)
def run(bot):
send_msg(bot, 'ad', 1 * 60 * 60)
@@ -0,0 +1,93 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import json
import base64
import threading
sys.path.append(os.getcwd() + "/class/core")
import mw
import telebot
from telebot import types
from telebot.util import quick_markup
# 推送最新的帖子
chat_id = -1001578009023
# chat_id = 5568699210
def get_newest_tid():
api_new = 'https://bbs.midoks.me/plugin.php?id=external_api&f=bbs_newest'
api_next = 'https://bbs.midoks.me/plugin.php?id=external_api&f=bbs_next_tid&tid='
tid_push = mw.getServerDir() + '/tgbot/bbs_newest_push.json'
if not os.path.exists(tid_push):
data = mw.httpGet(api_new)
data = json.loads(data)
if data['code'] == 0:
tid = data['data'][0]['tid']
mw.writeFile(tid_push, tid)
return True, data['data'][0]
tid = mw.readFile(tid_push)
data = mw.httpGet(api_next + tid)
data = json.loads(data)
if data['code'] == 0 and len(data['data']) > 0:
# print(data)
tid = data['data'][0]['tid']
mw.writeFile(tid_push, tid)
return True, data['data'][0]
return False, None
def send_msg(bot, tag='ad', trigger_time=300):
# 信号只在一个周期内执行一次|start
lock_file = mw.getServerDir() + '/tgbot/lock.json'
if not os.path.exists(lock_file):
mw.writeFile(lock_file, '{}')
lock_data = json.loads(mw.readFile(lock_file))
if tag in lock_data:
diff_time = time.time() - lock_data[tag]['do_time']
if diff_time >= trigger_time:
lock_data[tag]['do_time'] = time.time()
else:
return False, 0, 0
else:
lock_data[tag] = {'do_time': time.time()}
mw.writeFile(lock_file, json.dumps(lock_data))
# 信号只在一个周期内执行一次|end
yes, info = get_newest_tid()
if yes:
url = 'https://bbs.midoks.me/thread-' + info['tid'] + '-1-1.html'
keyboard = [
[
types.InlineKeyboardButton(text=info['subject'], url=url)
],
[
types.InlineKeyboardButton(
text="论坛", url='https://bbs.midoks.me'),
types.InlineKeyboardButton(
text="搜索", url='https://bbs.midoks.me/search.php')
]
]
markup = types.InlineKeyboardMarkup(keyboard)
bot.send_message(
chat_id, "由【" + info['author'] + "】发帖!", reply_markup=markup)
def run(bot):
send_msg(bot, 'push_bbs_newest_tid', 300)
if __name__ == "__main__":
print(get_newest_tid())
@@ -0,0 +1,87 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import json
import base64
import threading
sys.path.append(os.getcwd() + "/class/core")
import mw
import telebot
from telebot import types
from telebot.util import quick_markup
# 轮播实例
chat_id = -1001578009023
# chat_id = 5568699210
def send_msg(bot, tag='ad', trigger_time=300):
# 信号只在一个周期内执行一次|start
lock_file = mw.getServerDir() + '/tgbot/lock.json'
if not os.path.exists(lock_file):
mw.writeFile(lock_file, '{}')
lock_data = json.loads(mw.readFile(lock_file))
if tag in lock_data:
diff_time = time.time() - lock_data[tag]['do_time']
if diff_time >= trigger_time:
lock_data[tag]['do_time'] = time.time()
else:
return False, 0, 0
else:
lock_data[tag] = {'do_time': time.time()}
mw.writeFile(lock_file, json.dumps(lock_data))
# 信号只在一个周期内执行一次|end
# https://t.me/gjgzs2022 | 19/m
# ♻️CMS导航网♻️/💰流量变现💰 | 28/m
keyboard = [
[
types.InlineKeyboardButton(
text="为了不打扰双方,私聊解决问题先转100U,否则无视!", url='tg://user?id=5568699210')
],
[
types.InlineKeyboardButton(
text="♻️CMS导航网♻️", url='https://t.me/maccms_jccms')
],
[
types.InlineKeyboardButton(
text="💰流量变现💰", url='https://t.me/taohaozhan')
],
[
types.InlineKeyboardButton(
text="🙎‍♂️代实名🙍‍♀️过人脸🅾️国际阿里云腾讯云(赞助商)", url='https://t.me/gjgzs2022')
],
[
types.InlineKeyboardButton(
text="💎DigitalVirt(赞助商)", url='https://digitalvirt.com/aff.php?aff=154')
],
[
types.InlineKeyboardButton(
text="论坛", url='https://bbs.midoks.me'),
types.InlineKeyboardButton(
text="搜索", url='https://bbs.midoks.me/search.php')
]
]
markup = types.InlineKeyboardMarkup(keyboard)
msg = bot.send_message(
chat_id, "由于在解决的问题的时候,不给信息,无法了解情况。以后不再群里回答技术问题。全部去论坛提问。在解决问题的过程中,可能需要面板信息,和SSH信息,如无法提供请不要提问。为了让群里都知晓。轮播一年", reply_markup=markup)
# print(msg.message_id)
time.sleep(50)
try:
bot.delete_message(
chat_id=chat_id, message_id=msg.message_id)
except Exception as e:
pass
def run(bot):
send_msg(bot, 'tmp_msg', 200)
+1
View File
@@ -0,0 +1 @@
push_*.py 识别为推送插件
+220
View File
@@ -0,0 +1,220 @@
import sys
import io
import os
import time
import re
import json
import base64
import threading
sys.path.append(os.getcwd() + "/class/core")
import mw
import telebot
from telebot import types
from telebot.util import quick_markup
def isThisCmd(cmd, msg):
clen = len(cmd)
msg_len = len(msg)
if msg_len < clen:
return False
check_msg = msg[0:clen]
if cmd == check_msg:
return True
return False
def getReadCmd(cmd, msg):
clen = len(cmd)
msg_len = len(msg)
real_msg = msg[clen:]
return real_msg
def getFaqKw(cmd):
matchObj = re.match(r'寻找【(.*?)】问题如下', cmd, re.M | re.I)
data = matchObj.groups()
if len(data) > 0:
return True, data[0]
return False, ''
def searchHttpPage(kw='', p=1, size=1):
import urllib
kw = kw.strip()
kw = urllib.parse.quote_plus(kw)
api = 'https://bbs.midoks.me/plugin.php?id=external_api&f=bbs_search&q=' + kw + \
'&size=' + str(size) + '&p=' + str(p)
# print('url', api)
data = mw.httpGet(api)
# print(data)
data = json.loads(data)
# print(data)
if data['code'] > -1:
alist = data['data']['list']
r = []
for x in alist:
tmp = {}
tmp['tid'] = x['tid']
tmp['subject'] = x['subject']
tmp['url'] = 'https://bbs.midoks.me/thread-' + \
x['tid'] + '-1-1.html'
r.append(tmp)
data['data']['list'] = r
return data
def searchFaq(bot, message, cmd_text):
# cmd_text = 'mw'
data = searchHttpPage(cmd_text, 1, 5)
if data['code'] == 0 and len(data['data']['list']) > 0:
keyboard = []
dlist = data['data']['list']
for x in dlist:
keyboard.append([types.InlineKeyboardButton(
text=x['subject'], url=x['url'])])
keyboard.append([
types.InlineKeyboardButton(
text="下一页", callback_data='bbs_next_page_2'),
types.InlineKeyboardButton(
text="第" + str(data['data']['p']) + "页,共" + str(data['data']['page_num']) + "页", callback_data='bbs_page_total')
])
keyboard.append([types.InlineKeyboardButton(
text="关闭消息", callback_data='bbs_search_close')])
# print(keyboard)
markup = types.InlineKeyboardMarkup(keyboard)
bot.send_message(message.chat.id, "寻找【" +
cmd_text.strip() + "】问题如下:", reply_markup=markup)
else:
keyboard = [
[
types.InlineKeyboardButton(
text="论坛", url='https://bbs.midoks.me'),
types.InlineKeyboardButton(
text="搜索", url='https://bbs.midoks.me/search.php')
],
[
types.InlineKeyboardButton(
text="关闭消息", callback_data='bbs_search_close')
]
]
markup = types.InlineKeyboardMarkup(keyboard)
bot.send_message(
message.chat.id, "未找到合适内容,请在官方论坛[bbs.midoks.me]提问!", reply_markup=markup)
return True
def searchDebug(bot, message, cmd_text):
searchFaq(bot, message, cmd_text)
return True
def answer_callback_query(bot, call):
keyword = call.data
if keyword == 'bbs_search_close':
bot.delete_message(chat_id=call.message.chat.id,
message_id=call.message.message_id)
return
is_bbs_page = False
p = 1
if keyword.startswith('bbs_next_page'):
is_bbs_page = True
p = keyword.replace('bbs_next_page_', '')
if keyword.startswith('bbs_pre_page'):
is_bbs_page = True
p = keyword.replace('bbs_pre_page_', '')
# print("p", p)
if is_bbs_page:
is_match, cmd_text = getFaqKw(call.message.text)
if not is_match:
bot.edit_message_text(
chat_id=call.message.chat.id, message_id=call.message.message_id, text="出现错误!")
return
data = searchHttpPage(cmd_text, int(p), 5)
dlist = data['data']['list']
# print(data)
keyboard = []
for x in dlist:
keyboard.append([types.InlineKeyboardButton(
text=x['subject'], url=x['url'])])
page_nav = []
if int(data['data']['p']) > 1:
page_nav.append(types.InlineKeyboardButton(
text="上一页", callback_data='bbs_pre_page_' + str(int(p) - 1)))
if data['data']['page_num'] != data['data']['p']:
page_nav.append(types.InlineKeyboardButton(
text="下一页", callback_data='bbs_next_page_' + str(int(p) + 1)))
page_nav.append(types.InlineKeyboardButton(
text="第" + str(data['data']['p']) + "页,共" + str(data['data']['page_num']) + "页", callback_data='bbs_page_total'))
keyboard.append(page_nav)
keyboard.append([types.InlineKeyboardButton(
text="关闭消息", callback_data='bbs_search_close')])
markup = types.InlineKeyboardMarkup(keyboard)
bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id,
text=call.message.text, reply_markup=markup)
def run(bot, message):
text_body = message.text
# 过滤URL
is_has_url = re.search(
'(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]', text_body)
if is_has_url:
return bot
# print(text_body)
if isThisCmd('/faq:', text_body):
cmd_text = getReadCmd('/faq:', text_body)
return searchFaq(bot, message, cmd_text)
# if isThisCmd('/debug', text_body):
# cmd_text = getReadCmd('/debug', text_body)
# return searchDebug(bot, message, cmd_text)
if text_body.find('?') > -1 or text_body.find('?') > -1:
return_msg = "你似乎在寻找【" + text_body + "】答案:\n"
return_msg += "/faq:开始寻找你的问题\n"
keyboard = [
[
types.InlineKeyboardButton(
text="如未找到,可以在论坛补充你的提问!", url='https://bbs.midoks.me'),
]
]
markup = types.InlineKeyboardMarkup(keyboard)
bot.reply_to(message, return_msg, reply_markup=markup)
return bot
if __name__ == "__main__":
# print(isThisCmd('/?:', '/?:如何在安装面板'))
# print(getReadCmd('/?:', '/?:如何在安装面板'))
# print(searchHttpPage('mw'))
print(getFaqKw('寻找【mw】问题如下:'))
+207
View File
@@ -0,0 +1,207 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import json
import base64
import threading
sys.path.append(os.getcwd() + "/class/core")
import mw
import telebot
def getPluginName():
return 'tgbot'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
sys.path.append(getServerDir() + "/extend")
def getConfigData():
cfg_path = getServerDir() + "/data.cfg"
if not os.path.exists(cfg_path):
mw.writeFile(cfg_path, '{}')
t = mw.readFile(cfg_path)
return json.loads(t)
def writeConf(data):
cfg_path = getServerDir() + "/data.cfg"
mw.writeFile(cfg_path, json.dumps(data))
return True
def getExtCfg():
cfg_path = getServerDir() + "/extend.cfg"
if not os.path.exists(cfg_path):
mw.writeFile(cfg_path, '{}')
t = mw.readFile(cfg_path)
return json.loads(t)
def getStartExtCfgByTag(tag='push'):
# 获取开启的扩展
elist = getExtCfg()
rlist = []
for x in elist:
if x['tag'] == tag and x['status'] == 'start':
rlist.append(x)
return rlist
def writeLog(log_str):
if __name__ == "__main__":
print(log_str)
now = mw.getDateFromNow()
log_file = getServerDir() + '/task.log'
mw.writeFileLog(now + ':' + log_str, log_file, limit_size=5 * 1024)
return True
# start tgbot
cfg = getConfigData()
while True:
cfg = getConfigData()
if 'bot' in cfg and 'app_token' in cfg['bot']:
if cfg['bot']['app_token'] != '' and cfg['bot']['app_token'] != 'app_token':
break
writeLog('等待输入配置,填写app_token')
time.sleep(3)
bot = telebot.TeleBot(cfg['bot']['app_token'])
init_list = getStartExtCfgByTag('init')
for p in init_list:
try:
script = p['name'].split('.')[0]
__import__(script).init(bot)
except Exception as e:
writeLog('-----init error start -------')
writeLog(mw.getTracebackInfo())
writeLog('-----init error end -------')
# @bot.message_handler(commands=['start', 'help'])
# def hanle_start_help(message):
# bot.reply_to(message, "hello world")
# @bot.message_handler(commands=['mw_echo'])
# def hanle_mw_echo(message):
# bot.reply_to(message, message.text)
@bot.message_handler(commands=['chat_id'])
def hanle_get_chat_id(message):
bot.reply_to(message, message.chat.id)
@bot.message_handler(func=lambda message: True)
def all_message(message):
rlist = getStartExtCfgByTag('receive')
for r in rlist:
try:
script = r['name'].split('.')[0]
__import__(script).run(bot, message)
except Exception as e:
writeLog('-----all_message error start -------')
writeLog(mw.getTracebackInfo())
writeLog('-----all_message error end -------')
@bot.callback_query_handler(func=lambda call: True)
def callback_query_handler(call):
rlist = getStartExtCfgByTag('receive')
for r in rlist:
try:
script = r['name'].split('.')[0]
__import__(script).answer_callback_query(bot, call)
except Exception as e:
writeLog('-----callback_query_handler error start -------')
writeLog(mw.getTracebackInfo())
writeLog('-----callback_query_handler error end -------')
def runBotPushTask():
plist = getStartExtCfgByTag('push')
for p in plist:
try:
script = p['name'].split('.')[0]
__import__(script).run(bot)
except Exception as e:
writeLog('-----runBotPushTask error start -------')
writeLog(mw.getTracebackInfo())
writeLog('-----runBotPushTask error end -------')
def botPush():
while True:
runBotPushTask()
time.sleep(1)
def runBotPushOtherTask():
plist = getStartExtCfgByTag('other')
for p in plist:
try:
script = p['name'].split('.')[0]
__import__(script).run(bot)
except Exception as e:
writeLog('-----runBotPushOtherTask error start -------')
writeLog(mw.getTracebackInfo())
writeLog('-----runBotPushOtherTask error end -------')
def botPushOther():
while True:
runBotPushOtherTask()
time.sleep(1)
def setDaemon(t):
if sys.version_info.major == 3 and sys.version_info.minor >= 10:
t.daemon = True
else:
t.setDaemon(True)
def runBot(bot):
try:
bot.polling()
except Exception as e:
writeLog('-----runBot error start -------')
writeLog(str(e))
writeLog('-----runBot error end -------')
time.sleep(1)
runBot(bot)
if __name__ == "__main__":
# 机器人推送任务
botPushTask = threading.Thread(target=botPush)
botPushTask.start()
# 机器人其他推送任务
botPushOtherTask = threading.Thread(target=botPushOther)
botPushOtherTask.start()
writeLog('启动成功')
runBot(bot)
# asyncio.run(bot.polling())
Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

+19 -18
View File
@@ -25,7 +25,7 @@ class App():
self.__host_dir = self.getServerDir() + '/host'
if not os.path.exists(self.__host_dir):
os.makedirs(self.__host_dir)
mw.execShell('mkdir -p ' + self.__host_dir)
def getPluginName(self):
return 'webssh'
@@ -145,24 +145,25 @@ class App():
def get_server_list(self):
host_list = []
for name in os.listdir(self.__host_dir):
info_file = self.__host_dir + '/' + name + '/info.json'
if not os.path.exists(info_file):
continue
try:
info_tmp = self.getSshInfo(info_file)
host_info = {}
host_info['host'] = name
host_info['port'] = info_tmp['port']
host_info['ps'] = info_tmp['ps']
# host_info['sort'] = int(info_tmp['sort'])
except Exception as e:
print(e)
# if os.path.exists(info_file):
# os.remove(info_file)
# continue
if os.path.exists(self.__host_dir):
for name in os.listdir(self.__host_dir):
info_file = self.__host_dir + '/' + name + '/info.json'
if not os.path.exists(info_file):
continue
try:
info_tmp = self.getSshInfo(info_file)
host_info = {}
host_info['host'] = name
host_info['port'] = info_tmp['port']
host_info['ps'] = info_tmp['ps']
# host_info['sort'] = int(info_tmp['sort'])
except Exception as e:
print(e)
# if os.path.exists(info_file):
# os.remove(info_file)
# continue
host_list.append(host_info)
host_list.append(host_info)
host_list = sorted(host_list, key=lambda x: x['host'], reverse=False)
return mw.returnJson(True, 'ok!', host_list)
+8
View File
@@ -9,6 +9,14 @@
"css_path":"menu/index.css",
"js_path":"js/webssh.js"
}
},
{
"tag":"global_static",
"global_static": {
"title":"终端管理",
"name":"webssh",
"css_path":"menu/ico.css"
}
}
],
"id":3,
+10
View File
@@ -0,0 +1,10 @@
/* menu start */
.menu .menu_plugin_webssh {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAMBJREFUeNpiYKAQMM6cOVMASBuQozk9Pf0AC5AuAOJ6cgwAWt7IhMQvRKIfAPEEYgxhQWL3o9EFpBgwAeifQhKdD7YI5oWPUMEEmAQR4COyATBwAIgdgIacB2IFYkxhQouWB0BsCA3E86QGIsxvDSBXgGIDSxr5ALTgAk4XADWAQt4fiB2BChcAaQVoGoHheLwuAGqagBz/UNsciQ4DEgE/zAUfQM4DOt+eRANAYTMRZADIrxfIdMUFSnMzA0CAAQD0hjqnYxWD2gAAAABJRU5ErkJggg==");
}
.menu .current .menu_plugin_webssh:hover {
background-image: url("data:image/gif;base64,R0lGODlhEAAQAMQXAJ6ipUFITySRPIiMkDFRQuXm5jJKQy1kQCGeOzBXQSl3PiWLPVhfZSxrQCpxP9na2yeEPTREQ8LExmRqb5OXm/Hx8TU9RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ1IDc5LjE2MzQ5OSwgMjAxOC8wOC8xMy0xNjo0MDoyMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjMyQjYwMTU3OTA2QTExRUJCN0NFQUUwQjRDMzM4RDJDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjMyQjYwMTU4OTA2QTExRUJCN0NFQUUwQjRDMzM4RDJDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MzJCNjAxNTU5MDZBMTFFQkI3Q0VBRTBCNEMzMzhEMkMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzJCNjAxNTY5MDZBMTFFQkI3Q0VBRTBCNEMzMzhEMkMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4B//79/Pv6+fj39vX08/Lx8O/u7ezr6uno5+bl5OPi4eDf3t3c29rZ2NfW1dTT0tHQz87NzMvKycjHxsXEw8LBwL++vby7urm4t7a1tLOysbCvrq2sq6qpqKempaSjoqGgn56dnJuamZiXlpWUk5KRkI+OjYyLiomIh4aFhIOCgYB/fn18e3p5eHd2dXRzcnFwb25tbGtqaWhnZmVkY2JhYF9eXVxbWllYV1ZVVFNSUVBPTk1MS0pJSEdGRURDQkFAPz49PDs6OTg3NjU0MzIxMC8uLSwrKikoJyYlJCMiISAfHh0cGxoZGBcWFRQTEhEQDw4NDAsKCQgHBgUEAwIBAAAh+QQFMgAXACwAAAAAEAAQAAAFU6AljmRpBVOqrqtFVXAsy9Q7VMMDzHHN/5UawGQC1CiWg4IoOiINAoGB6BxBENSjyIE4oFKMprYhIFgYkvTQpWWOqm6RcVBI2+/2AuXL6k8CcSYhACH5BAUyABcALAcACQAFAAIAAAUIYJSMBLGcSggAIfkEBTIAFwAsBwAJAAUAAgAABQhgMI0MI51ACAAh+QQFMgAXACwHAAkABQACAAAFCGCUjASxnEoIADs=");
}
/* menu end */
-11
View File
@@ -1,15 +1,4 @@
/* menu start */
.menu .menu_plugin_webssh {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAMBJREFUeNpiYKAQMM6cOVMASBuQozk9Pf0AC5AuAOJ6cgwAWt7IhMQvRKIfAPEEYgxhQWL3o9EFpBgwAeifQhKdD7YI5oWPUMEEmAQR4COyATBwAIgdgIacB2IFYkxhQouWB0BsCA3E86QGIsxvDSBXgGIDSxr5ALTgAk4XADWAQt4fiB2BChcAaQVoGoHheLwuAGqagBz/UNsciQ4DEgE/zAUfQM4DOt+eRANAYTMRZADIrxfIdMUFSnMzA0CAAQD0hjqnYxWD2gAAAABJRU5ErkJggg==");
}
.menu .current .menu_plugin_webssh:hover {
background-image: url("data:image/gif;base64,R0lGODlhEAAQAMQXAJ6ipUFITySRPIiMkDFRQuXm5jJKQy1kQCGeOzBXQSl3PiWLPVhfZSxrQCpxP9na2yeEPTREQ8LExmRqb5OXm/Hx8TU9RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ1IDc5LjE2MzQ5OSwgMjAxOC8wOC8xMy0xNjo0MDoyMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjMyQjYwMTU3OTA2QTExRUJCN0NFQUUwQjRDMzM4RDJDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjMyQjYwMTU4OTA2QTExRUJCN0NFQUUwQjRDMzM4RDJDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MzJCNjAxNTU5MDZBMTFFQkI3Q0VBRTBCNEMzMzhEMkMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzJCNjAxNTY5MDZBMTFFQkI3Q0VBRTBCNEMzMzhEMkMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4B//79/Pv6+fj39vX08/Lx8O/u7ezr6uno5+bl5OPi4eDf3t3c29rZ2NfW1dTT0tHQz87NzMvKycjHxsXEw8LBwL++vby7urm4t7a1tLOysbCvrq2sq6qpqKempaSjoqGgn56dnJuamZiXlpWUk5KRkI+OjYyLiomIh4aFhIOCgYB/fn18e3p5eHd2dXRzcnFwb25tbGtqaWhnZmVkY2JhYF9eXVxbWllYV1ZVVFNSUVBPTk1MS0pJSEdGRURDQkFAPz49PDs6OTg3NjU0MzIxMC8uLSwrKikoJyYlJCMiISAfHh0cGxoZGBcWFRQTEhEQDw4NDAsKCQgHBgUEAwIBAAAh+QQFMgAXACwAAAAAEAAQAAAFU6AljmRpBVOqrqtFVXAsy9Q7VMMDzHHN/5UawGQC1CiWg4IoOiINAoGB6BxBENSjyIE4oFKMprYhIFgYkvTQpWWOqm6RcVBI2+/2AuXL6k8CcSYhACH5BAUyABcALAcACQAFAAIAAAUIYJSMBLGcSggAIfkEBTIAFwAsBwAJAAUAAgAABQhgMI0MI51ACAAh+QQFMgAXACwHAAkABQACAAAFCGCUjASxnEoIADs=");
}
/* menu end */
.xterm{
position: inherit;
}
+1
View File
@@ -27,6 +27,7 @@
"gif",
"jpg",
"css",
"svg",
"js",
"ico",
"woff2"
+5 -4
View File
@@ -191,8 +191,10 @@ def pSqliteDb(dbname='web_logs', site_name='unset', name="logs"):
conn = mw.M(dbname).dbPos(db_dir, name)
conn.execute("PRAGMA synchronous = 0")
conn.execute("PRAGMA page_size = 4096")
conn.execute("PRAGMA cache_size = 8000")
conn.execute("PRAGMA page_size = 32768")
conn.execute("PRAGMA journal_mode = wal")
conn.execute("PRAGMA journal_size_limit = 1073741824")
return conn
@@ -263,6 +265,8 @@ def initDreplace():
loadLuaSiteFile()
loadDebugLogFile()
if not mw.isAppleSystem():
mw.execShell("chown -R www:www " + getServerDir())
return 'ok'
@@ -277,9 +281,6 @@ def start():
import tool_task
tool_task.createBgTask()
if not mw.isAppleSystem():
mw.execShell("chown -R www:www " + getServerDir())
# issues:326
luaRestart()
return 'ok'
+14 -2
View File
@@ -1,10 +1,22 @@
{
"sort": 7,
"hook":[
{
"tag":"site_cb",
"site_cb": {
"title":"网站统计",
"name":"webstats",
"add":{"func":"reload"},
"update":{"func":"reload"},
"delete":{"func":"reload"}
}
}
],
"sort": "7",
"ps": "网站统计报表",
"name": "webstats",
"title": "网站统计",
"shell": "install.sh",
"versions":["0.2.4"],
"versions":["0.2.5"],
"tip": "soft",
"install_pre_inspection":true,
"checks": "server/webstats",
+17 -3
View File
@@ -14,12 +14,26 @@ install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
sys_os=`uname`
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
# cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
# HTTP_PREFIX="https://"
# if [ ! -z "$cn" ];then
# HTTP_PREFIX="https://ghproxy.com/"
# fi
HTTP_PREFIX="https://"
if [ ! -z "$cn" ];then
LOCAL_ADDR=common
ping -c 1 gihub.com > /dev/null 2>&1
if [ "$?" != "0" ];then
LOCAL_ADDR=cn
HTTP_PREFIX="https://ghproxy.com/"
fi
PIPSRC="https://pypi.python.org/simple"
if [ "$LOCAL_ADDR" != "common" ];then
PIPSRC="https://pypi.tuna.tsinghua.edu.cn/simple"
fi
if [ "$sys_os" == "Darwin" ];then
BAK='_bak'
else
@@ -96,7 +110,7 @@ Install_App()
fi
# https://github.com/P3TERX/GeoLite.mmdb
pip install geoip2
pip install geoip2 -i $PIPSRC
# if [ ! -f $serverPath/webstats/GeoLite2-City.mmdb ];then
# wget --no-check-certificate -O $serverPath/webstats/GeoLite2-City.mmdb https://github.com/P3TERX/GeoLite.mmdb/releases/download/2022.10.16/GeoLite2-City.mmdb
# fi
+51 -23
View File
@@ -210,18 +210,18 @@ function _M.get_http_origin(self)
if not headers then return data end
local req_method = ngx.req.get_method()
if req_method ~='GET' then
-- API disabled in the context of log_by_lua*
-- ngx.req.read_body()
-- proxy_pass, fastcgi_pass, uwsgi_pass, and scgi_pass
data = ngx.var.request_body
if not data then
data = ngx.req.get_body_data()
end
if not data then
data = ngx.req.get_post_args(1000000)
end
-- API disabled in the context of log_by_lua
-- if not data then
-- ngx.req.read_body()
-- data = ngx.req.get_post_args(1000000)
-- end
if "string" == type(data) then
headers["payload"] = data
@@ -239,6 +239,7 @@ function _M.cronPre(self)
local time_key = self:get_store_key()
local time_key_next = self:get_store_key_with_time(ngx.time()+3600)
for site_k, site_v in ipairs(sites) do
local input_sn = site_v["name"]
@@ -250,16 +251,24 @@ function _M.cronPre(self)
'spider_stat'
}
local v1 = true
local v2 = true
for _,ws_v in pairs(wc_stat) do
self:_update_stat_pre(db, ws_v, time_key)
self:_update_stat_pre(db, ws_v, time_key_next)
v1 = self:_update_stat_pre(db, ws_v, time_key)
v2 = self:_update_stat_pre(db, ws_v, time_key_next)
end
if db and db:isopen() then
db:execute([[COMMIT]])
db:close()
end
if not v1 or not v2 then
return false
end
end
return true
end
-- 后台任务
@@ -273,7 +282,17 @@ function _M.cron(self)
return true
end
self:cronPre()
-- self:D("dedebide:cron task is busy!")
local ready_ok = self:cronPre()
if not ready_ok then
self:D("cron task is busy!")
return true
end
local cron_key = 'cron_every_1s'
if self:is_working(cron_key) then
return true
end
ngx.update_time()
local begin = ngx.now()
@@ -316,17 +335,13 @@ function _M.cron(self)
end
end
local cron_key = 'cron_every_1s'
if self:is_working(cron_key) then
return true
end
self:lock_working(cron_key)
-- 每秒100条
for i=1,llen do
local data, _ = ngx.shared.mw_total:lpop(total_key)
if not data then
self:unlock_working(cron_key)
break
end
@@ -338,10 +353,17 @@ function _M.cron(self)
local db = dbs[input_sn]
local stat_fields_is = stat_fields[input_sn]
if not db then
ngx.shared.mw_total:rpush(total_key, data)
self:unlock_working(cron_key)
break
end
self:store_logs_line(db, stmts[input_sn]["web_logs"], input_sn, info)
local insert_ok = self:store_logs_line(db, stmts[input_sn]["web_logs"], input_sn, info)
if not insert_ok then
ngx.shared.mw_total:rpush(total_key, data)
self:unlock_working(cron_key)
break
end
local excluded = info["log_kv"]['excluded']
local stat_tmp_fields = info['stat_fields']
@@ -514,10 +536,8 @@ function _M.store_logs_line(self, db, stmt, input_sn, info)
local request_headers = logline["request_headers"]
local excluded = logline["excluded"]
-- self:D("json:"..json.encode(logline))
local time_key = logline["time_key"]
if not excluded then
stmt:bind_names {
time=time,
ip=ip,
@@ -539,13 +559,15 @@ function _M.store_logs_line(self, db, stmt, input_sn, info)
local res, err = stmt:step()
if tostring(res) == "5" then
self:D("step res:"..tostring(res) ..",step err:"..tostring(err))
self:D("the step database connection is busy, so it will be stored later.")
-- self:D("json:"..json.encode(logline))
-- self:D("the step database connection is busy, so it will be stored later | step res:"..tostring(res) ..",step err:"..tostring(err))
if stmt then
stmt:reset()
end
return false
end
stmt:reset()
end
return true
end
@@ -653,9 +675,14 @@ end
function _M._update_stat_pre(self, db, stat_table, key)
local local_sql = string.format("INSERT INTO %s(time) SELECT :time WHERE NOT EXISTS(SELECT time FROM %s WHERE time=:time);", stat_table, stat_table)
local update_stat_stmt = db:prepare(local_sql)
update_stat_stmt:bind_names{time=key}
update_stat_stmt:step()
update_stat_stmt:finalize()
if update_stat_stmt then
update_stat_stmt:bind_names{time=key}
update_stat_stmt:step()
update_stat_stmt:finalize()
return true
end
return false
end
function _M.update_stat_quick(self, db, stat_table, key,columns)
@@ -1084,6 +1111,7 @@ end
function _M.get_client_ip(self)
local client_ip = "unknown"
local cdn = auto_config['cdn']
local request_header = ngx.req.get_headers()
if cdn == true then
for _,v in ipairs(auto_config['cdn_headers']) do
if request_header[v] ~= nil and request_header[v] ~= "" then
+2 -1
View File
@@ -134,6 +134,7 @@ log_by_lua_block {
local function exclude_url()
if not ngx.var.uri then return false end
if not ngx.var.request_uri then return false end
if not auto_config['exclude_url'] then return false end
local the_uri = string.sub(ngx.var.request_uri, 2)
local url_conf = auto_config["exclude_url"]
@@ -441,7 +442,7 @@ log_by_lua_block {
local push_data = json.encode(data)
-- C:D(json.encode(push_data))
local key = C:getTotalKey()
ngx.shared.mw_total:rpush(key, push_data)
ngx.shared.mw_total:rpush(key, push_data)
end
local function store_logs_line(db, stmt, input_server_name, lineno)
+6
View File
@@ -85,6 +85,7 @@ def migrateSiteHotLogs(site_name, query_date):
import shutil
print("coping {} to {} ...".format(hot_db, hot_db_tmp))
mw.writeFile(migrating_flag, "yes")
time.sleep(3)
shutil.copy(hot_db, hot_db_tmp)
if not os.path.exists(hot_db_tmp):
return mw.returnMsg(False, "migrating fail, copy tmp file!")
@@ -182,6 +183,11 @@ def migrateSiteHotLogs(site_name, query_date):
os.remove(hot_db_tmp)
print("{} logs migrate ok.".format(site_name))
if not mw.isAppleSystem():
mw.execShell("chown -R www:www " + getServerDir())
mw.opWeb('restart')
return mw.returnMsg(True, "{} logs migrate ok".format(site_name))
+2
View File
@@ -29,3 +29,5 @@ flask-caching>=1.10.1
bcrypt==3.1.3
PyMySQL==1.0.2
whitenoise==5.3.0
pyTelegramBotAPI
telebot
+10 -10
View File
@@ -1,12 +1,12 @@
location / {
rewrite "^/list-([0-9]+)\.html$" /plus/list.php?tid=$1 last;
rewrite "^/list-([0-9]+)-([0-9]+)-([0-9]+)\.html$" /plus/list.php?tid=$1&totalresult=$2&PageNo=$3 last;
rewrite "^/view-([0-9]+)-1\.html$" /plus/view.php?arcID=$1 last;
rewrite "^/view-([0-9]+)-([0-9]+)\.html$" /plus/view.php?aid=$1&pageno=$2 last;
rewrite "^/plus/list-([0-9]+)\.html$" /plus/list.php?tid=$1 last;
rewrite "^/plus/list-([0-9]+)-([0-9]+)-([0-9]+)\.html$" /plus/list.php?tid=$1&totalresult=$2&PageNo=$3 last;
rewrite "^/plus/view-([0-9]+)-1\.html$" /plus/view.php?arcID=$1 last;
rewrite "^/plus/view-([0-9]+)-([0-9]+)\.html$" /plus/view.php?aid=$1&pageno=$2 last;
rewrite "^/tags.html$" /tags.php last;
rewrite "^/tag-([0-9]+)-([0-9]+)\.html$" /tags.php?/$1/$2/ last;
rewrite ^/list-([0-9]+)\.html$ /plus/list.php?tid=$1 last;
rewrite ^/list-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /plus/list.php?tid=$1&totalresult=$2&PageNo=$3 last;
rewrite ^/view-([0-9]+)-1\.html$ /plus/view.php?arcID=$1 last;
rewrite ^/view-([0-9]+)-([0-9]+)\.html$" /plus/view.php?aid=$1&pageno=$2 last;
rewrite ^/plus/list-([0-9]+)\.html$ /plus/list.php?tid=$1 last;
rewrite ^/plus/list-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /plus/list.php?tid=$1&totalresult=$2&PageNo=$3 last;
rewrite ^/plus/view-([0-9]+)-1\.html$ /plus/view.php?arcID=$1 last;
rewrite ^/plus/view-([0-9]+)-([0-9]+)\.html$ /plus/view.php?aid=$1&pageno=$2 last;
rewrite ^/tags.html$ /tags.php last;
rewrite ^/tag-([0-9]+)-([0-9]+)\.html$ /tags.php?/$1/$2/ last;
}
-7
View File
@@ -1,7 +0,0 @@
location / {
rewrite ^/archiver/((fid|tid)-[\w\-]+\.html)$ /archiver/index.php?$1 last;
rewrite ^/forum-([0-9]+)-([0-9]+)\.html$ /forumdisplay.php?fid=$1&page=$2 last;
rewrite ^/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /viewthread.php?tid=$1&extra=page%3D$3&page=$2 last;
rewrite ^/space-(username|uid)-(.+)\.html$ /space.php?$1=$2 last;
rewrite ^/tag-(.+)\.html$ /tag.php?name=$1 last;
}
+5 -1
View File
@@ -9,6 +9,10 @@ location / {
rewrite ^([^\.]*)/(fid|tid)-([0-9]+)\.html$ $1/index.php?action=$2&value=$3 last;
rewrite ^([^\.]*)/([a-z]+[a-z0-9_]*)-([a-z0-9_\-]+)\.html$ $1/plugin.php?id=$2:$3 last;
if (!-e $request_filename) {
return 404;
rewrite ^(.*)$ /index.php last;
}
#if (!-e $request_filename) {
# return 404;
#}
}
+1 -1
View File
@@ -9,6 +9,6 @@ location /bbs/ {
rewrite ^([^\.]*)/(fid|tid)-([0-9]+)\.html$ $1/index.php?action=$2&value=$3 last;
rewrite ^([^\.]*)/([a-z]+[a-z0-9_]*)-([a-z0-9_\-]+)\.html$ $1/plugin.php?id=$2:$3 last;
if (!-e $request_filename) {
return 404;
rewrite ^(.*)$ /index.php last;
}
}
+1 -1
View File
@@ -9,7 +9,7 @@ location / {
rewrite ^([^\.]*)/(fid|tid)-([0-9]+)\.html$ $1/index.php?action=$2&value=$3 last;
rewrite ^([^\.]*)/([a-z]+[a-z0-9_]*)-([a-z0-9_\-]+)\.html$ $1/plugin.php?id=$2:$3 last;
if (!-e $request_filename) {
return 404;
rewrite ^(.*)$ /index.php last;
}
}
+8 -7
View File
@@ -179,7 +179,6 @@ def requestCheck():
def isLogined():
# print('isLogined', session)
if 'login' in session and 'username' in session and session['login'] == True:
userInfo = mw.M('users').where(
"id=?", (1,)).field('id,username,password').find()
@@ -445,7 +444,6 @@ def login_temp_user(token):
@app.route('/api/<reqClass>/<reqAction>', methods=['POST', 'GET'])
def api(reqClass=None, reqAction=None, reqData=None):
comReturn = common.local()
if comReturn:
return comReturn
@@ -458,15 +456,18 @@ def api(reqClass=None, reqAction=None, reqData=None):
request_time = request.form.get('request_time', '')
request_token = request.form.get('request_token', '')
request_ip = request.remote_addr
request_ip = request_ip.replace('::ffff:', '')
token_md5 = mw.md5(str(request_time) + mw.md5(data['token_crypt']))
# print(request_time, request_token)
if not mw.inArray(data['limit_addr'], request_ip):
return mw.returnJson(False, 'IP校验失败,您的访问IP为[' + request_ip + ']')
local_token = mw.deCrypt(data['token'], data['token_crypt'])
token_md5 = mw.md5(str(request_time) + mw.md5(local_token))
if not (token_md5 == request_token):
return mw.returnJson(False, '密钥错误')
if not mw.inArray(data['limit_addr'], request_ip):
return mw.returnJson(False, '非法请求')
if reqClass == None:
return mw.returnJson(False, '请指定请求方法类')
@@ -477,7 +478,7 @@ def api(reqClass=None, reqAction=None, reqData=None):
'plugins_api', 'system_api', 'site_api', 'task_api')
className = reqClass + '_api'
if not className in classFile:
return "external api request error"
return mw.returnJson(False, 'external api request error')
eval_str = "__import__('" + className + "')." + className + '()'
newInstance = eval(eval_str)
+110 -3
View File
@@ -354,6 +354,78 @@ function setPanelSSL(){
});
}
function setNotifyApi(tag, obj){
var enable = $(obj).prop("checked");
console.log(tag,obj,enable);
$.post('/config/set_notify_enable', {'tag':tag, 'enable':enable},function(rdata){
showMsg(rdata.msg, function(){
if (rdata.status){}
} ,{icon:rdata.status?1:2}, 1000);
},'json');
}
function getTgbot(){
var loadT = layer.msg('正在获取TgBot信息...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/config/get_notify',{},function(data){
layer.close(loadT);
var app_token = '';
var chat_id = '';
if (data.status){
if (typeof(data['data']['tgbot']) !='undefined'){
app_token = data['data']['tgbot']['data']['app_token'];
chat_id = data['data']['tgbot']['data']['chat_id'];
}
}
layer.open({
type: 1,
area: "500px",
title: '配置TgBot配置',
closeBtn: 1,
shift: 5,
btn:["确定","关闭","验证"],
shadeClose: false,
content: "<div class='bt-form pd20'>\
<div class='line'>\
<span class='tname'>APP_TOKEN</span>\
<div class='info-r'><input class='bt-input-text' type='text' name='app_token' value='"+app_token+"' style='width:100%'/></div>\
</div>\
<div class='line'>\
<span class='tname'>CHAT_ID</span>\
<div class='info-r'><input class='bt-input-text' type='text' name='chat_id' value='"+chat_id+"' style='width:100%' /></div>\
</div>\
</div>",
yes:function(index){
var pdata = {};
pdata['app_token'] = $('input[name="app_token"]').val();
pdata['chat_id'] = $('input[name="chat_id"]').val();
$.post('/config/set_notify',{'tag':'tgbot', 'data':JSON.stringify(pdata)},function(rdata){
showMsg(rdata.msg, function(){
if (rdata.status){
layer.close(index);
}
},{icon:rdata.status?1:2},2000);
});
},
btn3:function(index){
var pdata = {};
pdata['app_token'] = $('input[name="app_token"]').val();
pdata['chat_id'] = $('input[name="chat_id"]').val();
$.post('/config/set_notify_test',{'tag':'tgbot', 'data':JSON.stringify(pdata)},function(rdata){
showMsg(rdata.msg, function(){
if (rdata.status){
layer.close(index);
}
},{icon:rdata.status?1:2},2000);
});
return false;
}
});
});
}
function getPanelSSL(){
var loadT = layer.msg('正在获取证书信息...',{icon:16,time:0,shade: [0.3, '#000']});
@@ -364,11 +436,21 @@ function getPanelSSL(){
var cert_data = '';
if (cert['info']){
cert_data = "<div class='ssl_state_info'><div class='state_info_flex'>\
<div class='state_item'><span>证书品牌:</span><span class='ellipsis_text ssl_issue'>"+cert['info']['issuer']+"</span></div>\
<div class='state_item'><span>到期时间:</span><span class='btlink ssl_endtime'>剩余"+cert['info']['endtime']+"天到期</span></div>\
<div class='state_item'><span>证书品牌:</span>\
<span class='ellipsis_text ssl_issue'>"+cert['info']['issuer']+"</span></div>\
<div class='state_item'><span>到期时间:</span>\
<span class='btlink ssl_endtime'>剩余"+cert['info']['endtime']+"天到期</span></div>\
</div>\
<div class='state_info_flex'>\
<div class='state_item'><span>认证域名:</span><span class='ellipsis_text ssl_subject'>"+cert['info']['subject']+"</span></div>\
<div class='state_item'><span>认证域名:</span>\
<span class='ellipsis_text ssl_subject'>"+cert['info']['subject']+"</span></div>\
<div class='state_item'>\
<span>强制HTTPS:</span>\
<span class='switch'>\
<input class='btswitch btswitch-ios' id='toHttps' type='checkbox' "+cert['is_https']+">\
<label class='btswitch-btn set_panel_http_to_https' for='toHttps'></label>\
</span>\
</div>\
</div></div>";
}
@@ -385,6 +467,7 @@ function getPanelSSL(){
</div>\
<div class="ssl-btn pull-left mtb15" style="width:100%">\
<button class="btn btn-success btn-sm save-panel-ssl">保存</button>\
<button class="btn btn-success btn-sm del-panel-ssl">删除</button>\
<button class="btn btn-success btn-sm apply-lets-ssl">申请Lets证书</button>\
</div>\
</div>\
@@ -419,6 +502,30 @@ function getPanelSSL(){
},'json');
});
//删除SSL
$('.del-panel-ssl').click(function(){
var loadT = layer.msg('正在删除SSL...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/config/del_panel_ssl',data,function(rdata){
layer.close(loadT);
if(rdata.status){
layer.closeAll();
}
layer.msg(rdata.msg,{icon:rdata.status?1:2});
},'json');
});
// 设置面板SSL的Http
$('.set_panel_http_to_https').click(function(){
var https = $('#toHttps').prop('checked');
$.post('/config/set_panel_http_to_https',{'https':https},function(rdata){
layer.close(loadT);
if(rdata.status){
layer.closeAll();
}
layer.msg(rdata.msg,{icon:rdata.status?1:2});
},'json');
});
//申请Lets证书
$('.apply-lets-ssl').click(function(){
showSpeedWindow('正在申请...', 'site.get_let_logs', function(layers,index){
+1 -1
View File
@@ -1110,7 +1110,7 @@ function reName(type, fileName) {
</div>',
success:function(){
$("#newFileName").focus().keyup(function(e){
if(e.keyCode == 13) $("#ReNameBtn").click();
if(e.keyCode == 13) $(".layui-layer-btn0").click();
});
},
yes:function(){
+227 -70
View File
@@ -515,29 +515,24 @@ function openPath(a) {
window.location.href = "/files/"
}
function onlineEditFile(k, f) {
function onlineEditFile(k, f, callback) {
if(k != 0) {
var l = $("#PathPlace input").val();
var h = encodeURIComponent($("#textBody").val());
var a = $("select[name=encoding]").val();
var loadT = layer.msg(lan.bt.save_file, {
icon: 16,
time: 0
});
$.post("/files/save_body", "data=" + h + "&path=" + encodeURIComponent(f) + "&encoding=" + a, function(m) {
var loadT = layer.msg('正在保存,请稍候...', {icon: 16,time: 0});
$.post("/files/save_body", "data=" + h + "&path=" + encodeURIComponent(f) + "&encoding=" + a, function(data) {
if(k == 1) {
layer.close(loadT);
}
layer.msg(m.msg, {
icon: m.status ? 1 : 2
});
layer.msg(data.msg, {icon: data.status ? 1 : 2});
if (data.status && typeof(callback) == 'function'){
callback(k, f);
}
},'json');
return
}
var e = layer.msg(lan.bt.read_file, {
icon: 16,
time: 0
});
var e = layer.msg('正在读取文件,请稍候...', {icon: 16,time: 0});
var g = f.split(".");
var b = g[g.length - 1];
var d;
@@ -595,15 +590,12 @@ function onlineEditFile(k, f) {
default:
var j = {
name: "htmlmixed",
scriptTypes: [{
matches: /\/x-handlebars-template|\/x-mustache/i,
mode: null
}, {
matches: /(text|application)\/(x-)?vb(a|script)/i,
mode: "vbscript"
}]
scriptTypes: [
{matches: /\/x-handlebars-template|\/x-mustache/i,mode: null},
{matches: /(text|application)\/(x-)?vb(a|script)/i,mode: "vbscript"}
]
};
d = j
d = j;
}
$.post("/files/get_body", "path=" + encodeURIComponent(f), function(s) {
if(s.status === false){
@@ -619,51 +611,57 @@ function onlineEditFile(k, f) {
m = s.data.encoding == u[p] ? "selected" : "";
n += '<option value="' + u[p] + '" ' + m + ">" + u[p] + "</option>";
}
var code_mirror = null;
var r = layer.open({
type: 1,
shift: 5,
closeBtn: 1,
area: ["90%", "90%"],
title: lan.bt.edit_title+"[" + f + "]",
content: '<form class="bt-form pd20 pb70">\
btn:['保存','关闭'],
title: "在线编辑[" + f + "]",
content: '<form class="bt-form pd20">\
<div class="line">\
<p style="color:red;margin-bottom:10px">' + lan.bt.edit_ps + '\
<p style="color:red;margin-bottom:10px">提示:Ctrl+F 搜索关键字,Ctrl+G 查找下一个,Ctrl+S 保存,Ctrl+Shift+R 查找替换!\
<select class="bt-input-text" name="encoding" style="width: 74px;position: absolute;top: 31px;right: 19px;height: 22px;z-index: 9999;border-radius: 0;">' + n + '</select>\
</p>\
<textarea class="mCustomScrollbar bt-input-text" id="textBody" style="width:100%;margin:0 auto;line-height: 1.8;position: relative;top: 10px;" value="" />\
</div>\
<div class="bt-form-submit-btn" style="position:absolute; bottom:0; width:100%">\
<button type="button" class="btn btn-danger btn-sm btn-editor-close">'+lan.public.close+'</button>\
<button id="OnlineEditFileBtn" type="button" class="btn btn-success btn-sm">'+lan.public.save+'</button>\
</div>\
</form>'
});
$("#textBody").text(s.data.data);
var q = $(window).height() * 0.9;
$("#textBody").height(q - 160);
var t = CodeMirror.fromTextArea(document.getElementById("textBody"), {
extraKeys: {
"Ctrl-F": "findPersistent",
"Ctrl-H": "replaceAll",
"Ctrl-S": function() {
$("#textBody").text(t.getValue());
onlineEditFile(2, f)
}
</form>',
success:function(){
$("#textBody").text(s.data.data);
var q = $(window).height() * 0.9;
$("#textBody").height(q - 160);
code_mirror = CodeMirror.fromTextArea(document.getElementById("textBody"), {
extraKeys: {
"Ctrl-F": "findPersistent",
"Ctrl-H": "replaceAll",
"Ctrl-S": function() {
$("#textBody").text(code_mirror.getValue());
onlineEditFile(2, f,callback);
},
"Cmd-S":function() {
$("#textBody").text(code_mirror.getValue());
onlineEditFile(2, f,callback);
},
},
mode: d,
lineNumbers: true,
matchBrackets: true,
matchtags: true,
autoMatchParens: true
});
code_mirror.focus();
code_mirror.setSize("auto", q - 150);
$(window).resize(function(){
var q = $(window).height() * 0.9;
code_mirror.setSize("auto", q - 150);
});
},
mode: d,
lineNumbers: true,
matchBrackets: true,
matchtags: true,
autoMatchParens: true
});
t.focus();
t.setSize("auto", q - 150);
$("#OnlineEditFileBtn").click(function() {
$("#textBody").text(t.getValue());
onlineEditFile(1, f);
});
$(".btn-editor-close").click(function() {
layer.close(r);
yes:function(){
$("#textBody").text(code_mirror.getValue());
onlineEditFile(1, f,callback);
}
});
},'json');
}
@@ -1133,18 +1131,21 @@ function bindPanel(a,type,ip,btid,url,user,pw){
<li><font style='color:red'>注意,开启广告拦截会导致无法快捷登录。</font></li></ul>\
</div>\
<div class='bt-form-submit-btn'><button type='button' class='btn btn-danger btn-sm' onclick=\"layer.closeAll()\">关闭</button> "+btn+"</div>\
</div>"
});
$("#btaddress").on("input",function(){
var str =$(this).val();
var isip = /([\w-]+\.){2,6}\w+/;
var iptext = str.match(isip);
if(iptext) $("#bttitle").val(iptext[0]);
}).blur(function(){
var str =$(this).val();
var isip = /([\w-]+\.){2,6}\w+/;
var iptext = str.match(isip);
if(iptext) $("#bttitle").val(iptext[0]);
</div>",
success:function(){
$("#btaddress").on("input",function(){
var str =$(this).val();
var isip = /([\w-]+\.){2,6}\w+/;
var iptext = str.match(isip);
if(iptext) $("#bttitle").val(iptext[0]);
}).blur(function(){
var str =$(this).val();
var isip = /([\w-]+\.){2,6}\w+/;
var iptext = str.match(isip);
if(iptext) $("#bttitle").val(iptext[0]);
});
}
});
}
//删除快捷登录
@@ -1769,6 +1770,159 @@ function entitiesDecode(text) {
return text;
}
// base64.js
// base64加密
function base64_encode(str) {
var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var out, i, len;
var c1, c2, c3;
len = str.length;
i = 0;
out = "";
while(i < len) {
c1 = str.charCodeAt(i++) & 0xff;
if(i == len)
{
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt((c1 & 0x3) << 4);
out += "==";
break;
}
c2 = str.charCodeAt(i++);
if(i == len)
{
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
out += base64EncodeChars.charAt((c2 & 0xF) << 2);
out += "=";
break;
}
c3 = str.charCodeAt(i++);
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));
out += base64EncodeChars.charAt(c3 & 0x3F);
}
return out;
}
// base64解密
function base64_decode(str) {
var base64DecodeChars = new Array(
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
var c1, c2, c3, c4;
var i, len, out;
len = str.length;
i = 0;
out = "";
while(i < len) {
/* c1 */
do {
c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
} while(i < len && c1 == -1);
if(c1 == -1)
break;
/* c2 */
do {
c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
} while(i < len && c2 == -1);
if(c2 == -1)
break;
out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
/* c3 */
do {
c3 = str.charCodeAt(i++) & 0xff;
if(c3 == 61)
return out;
c3 = base64DecodeChars[c3];
} while(i < len && c3 == -1);
if(c3 == -1)
break;
out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
/* c4 */
do {
c4 = str.charCodeAt(i++) & 0xff;
if(c4 == 61)
return out;
c4 = base64DecodeChars[c4];
} while(i < len && c4 == -1);
if(c4 == -1)
break;
out += String.fromCharCode(((c3 & 0x03) << 6) | c4);
}
return out;
}
function utf16to8(str) {
var out, i, len, c;
out = "";
len = str.length;
for(i = 0; i < len; i++) {
c = str.charCodeAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
out += str.charAt(i);
} else if (c > 0x07FF) {
out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
} else {
out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
}
}
return out;
}
function utf8to16(str) {
var out, i, len, c;
var char2, char3;
out = "";
len = str.length;
i = 0;
while(i < len) {
c = str.charCodeAt(i++);
switch(c >> 4)
{
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
// 0xxxxxxx
out += str.charAt(i-1);
break;
case 12: case 13:
// 110x xxxx 10xx xxxx
char2 = str.charCodeAt(i++);
out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
break;
case 14:
// 1110 xxxx 10xx xxxx 10xx xxxx
char2 = str.charCodeAt(i++);
char3 = str.charCodeAt(i++);
out += String.fromCharCode(((c & 0x0F) << 12) |
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0));
break;
}
}
return out;
}
function pluginService(_name, version){
var data = {name:_name, func:'status'}
@@ -2120,6 +2274,8 @@ function pluginOpInitD(a, _version, b) {
}
function pluginLogs(_name, version, func, line){
var _this = this;
if ( typeof(version) == 'undefined' ){
version = '';
}
@@ -2160,9 +2316,10 @@ function pluginLogs(_name, version, func, line){
if(rdata.data == '') {
rdata.data = '当前没有日志!';
}
var ebody = '<div class="soft-man-con">\
<textarea readonly="" style="margin: 0px;width: 100%;height: 520px;background-color: #333;color:#fff; padding:0 5px" id="info_log">'+rdata.data+'</textarea>\
</div>';
var h = parseInt($('.bt-w-menu').css('height')) - 40;
var ebody = '<textarea readonly="" style="margin: 0px;height: '+h+'px;width: 100%;background-color: #333;color:#fff; padding:0 5px" id="info_log">'+rdata.data+'</textarea>';
$(".soft-man-con").html(ebody);
var ob = document.getElementById('info_log');
ob.scrollTop = ob.scrollHeight;
Vendored Executable → Regular
+45 -29
View File
File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

After

Width:  |  Height:  |  Size: 65 KiB

+15 -1
View File
@@ -102,7 +102,6 @@
</div>
<div class="title c6 plr15"><h3 class="f16">安全</h3></div>
<div class="setting-con pd15">
<p class="mtb15">
@@ -148,6 +147,21 @@
<span class="set-info c7">为非管理员临时提供面板访问权限</span>
</p>
</div>
<div class="title c6 plr15"><h3 class="f16">通知</h3></div>
<div class="setting-con pd15">
<p class="mtb15">
<span class="set-tit text-right" title="TelegramBot" style="float: left;">TG机器人通知</span>
<input id="cfg_tgbot" name="cfg_tgbot" onclick="setNotifyApi('tgbot',this)" class="btswitch btswitch-ios" type="checkbox" {{data['notify_tgbot_enable']}}>
<label class="btswitch-btn ml5" for="cfg_tgbot" style="float: left;margin-top:4px;"></label>
<button ype="button" class="btn btn-default btn-xs panel_api_btn" style="vertical-align: middle; margin-left: 10px" onclick="getTgbot();">TelegramBot配置</button>
<span class="set-info c7">Telegram Bot机器人通知【<b style="color:red;">国内可能无法使用</b>】</span>
</p>
</div>
</div>
</div>
</div>
-1
View File
@@ -146,7 +146,6 @@
</div>
</div>
</div>
<script src="/static/js/echarts.min.js?v={{config.version}}"></script>
<script src="/static/app/control.js?v={{config.version}}"></script>
{% endblock %}
+47 -30
View File
@@ -2,35 +2,42 @@
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="renderer" content="webkit">
<title>{{data['title']}}</title>
<link rel="shortcut icon" href="/static/favicon.ico" type="image/x-icon" />
<link href="/static/bootstrap-3.3.5/css/bootstrap.min.css?v={{config.version}}" rel="stylesheet">
<link href="/static/css/site.css?v={{config.version}}" rel="stylesheet">
<link href="/static/codemirror/lib/codemirror.css?v={{config.version}}" rel="stylesheet">
<script src="/static/language/Simplified_Chinese/lan.js?v={{config.version}}"></script>
<!--[if lte IE 9]>
<script src="/static/js/requestAnimationFrame.js"></script>
<![endif]-->
<!-- 统计一下用户量,让我的开发更有激情 -->
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-FC74BB2RGD"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-FC74BB2RGD');
</script>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="renderer" content="webkit">
<title>{{data['title']}}</title>
<link rel="shortcut icon" href="/static/favicon.ico" type="image/x-icon" />
<link href="/static/bootstrap-3.3.5/css/bootstrap.min.css?v={{config.version}}" rel="stylesheet">
<link href="/static/css/site.css?v={{config.version}}" rel="stylesheet">
<link href="/static/codemirror/lib/codemirror.css?v={{config.version}}" rel="stylesheet">
<script src="/static/language/Simplified_Chinese/lan.js?v={{config.version}}"></script>
<!--[if lte IE 9]>
<script src="/static/js/requestAnimationFrame.js"></script>
<![endif]-->
<!-- 统计一下用户量,让我的开发更有激情 -->
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-FC74BB2RGD"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-FC74BB2RGD');
</script>
{% for menu in data['hook_menu'] %}
{% if menu['js_path'] %}
<!-- 加载插件css -->
<link href="/plugins/file?name={{menu['name']}}&v={{config.version}}&f={{menu['css_path']}}" rel="stylesheet" />
{% endif %}
{% endfor %}
{% for menu in data['hook_menu'] %}
{% if menu['css_path'] and data['hook_tag'] == menu['name'] %}
<!-- 加载插件css -->
<link href="/plugins/file?name={{menu['name']}}&v={{config.version}}&f={{menu['css_path']}}" rel="stylesheet" />
{% endif %}
{% endfor %}
<!-- 全局静态HOOK -->
{% for menu in data['hook_global_static'] %}
{% if menu['css_path'] %}
<link href="/plugins/file?name={{menu['name']}}&v={{config.version}}&f={{menu['css_path']}}" rel="stylesheet" />
{% endif %}
{% endfor %}
</head>
<body>
@@ -83,11 +90,15 @@
{% block content %}{% endblock %}
<div class="footer bgw">mdserver-web &copy;2018-∞ Linux面板 (<a class="btlink" target="_blank" href="//github.com/midoks/mdserver-web">源码</a>) <span style="margin-left:5px;">/</span>
<a class="btlink" style="margin-left:5px;" href="//github.com/midoks/mdserver-web/wiki" target="_blank">WIKI</a><span style="margin-left:5px;">/</span>
<a class="btlink" target="_blank" style="margin-left:5px;" href="//github.com/midoks/mdserver-web/wiki">WIKI</a><span style="margin-left:5px;">/</span>
<a class='btlink panel_ad_list_mode' style="margin-left:5px;">AD</a>
<span style="margin-left:5px;">/</span>
<a class='btlink' target="_blank" href="https://bbs.midoks.me" style="margin-left:5px;">交流论坛</a>
<span style="margin-left:5px;">/</span>
<a class='btlink' target="_blank" href="https://t.me/mdserver_web" style="margin-left:5px;">TG吹水群</a>
</div>
</div>
</div>
</div>
</body>
<script type="text/javascript">
@@ -158,8 +169,14 @@ if (thisPath.indexOf('?')>-1){
<script src="/static/laydate/laydate.js?v={{config.version}}"></script>
{% for menu in data['hook_menu'] %}
{% if menu['js_path'] and data['hook_tag'] == menu['name'] %}
<script src="/plugins/file?name={{menu['name']}}&f={{menu['js_path']}}&v={{config.version}}"></script>
{% endif %}
{% endfor %}
<!-- 全局静态HOOK -->
{% for menu in data['hook_global_static'] %}
{% if menu['js_path'] %}
<!-- 加载插件js -->
<script src="/plugins/file?name={{menu['name']}}&f={{menu['js_path']}}&v={{config.version}}"></script>
{% endif %}
{% endfor %}
+29 -15
View File
@@ -5,6 +5,7 @@
import sys
import os
import re
if sys.platform != 'darwin':
os.chdir('/www/server/mdserver-web')
@@ -50,7 +51,6 @@ class backupTools:
mw.execShell(cmd)
endDate = time.strftime('%Y/%m/%d %X', time.localtime())
print(filename)
if not os.path.exists(filename):
log = "网站[" + name + "]备份失败!"
@@ -83,6 +83,27 @@ class backupTools:
if num < 1:
break
def getConf(self, mtype='mysql'):
path = mw.getServerDir() + '/' + mtype + '/etc/my.cnf'
return path
# 数据库密码处理
def mypass(self, act, root):
conf_file = self.getConf('mysql')
mw.execShell("sed -i '/user=root/d' {}".format(conf_file))
mw.execShell("sed -i '/password=/d' {}".format(conf_file))
if act:
mycnf = mw.readFile(conf_file)
src_dump = "[mysqldump]\n"
sub_dump = src_dump + "user=root\npassword=\"{}\"\n".format(root)
if not mycnf:
return False
mycnf = mycnf.replace(src_dump, sub_dump)
if len(mycnf) > 100:
mw.writeFile(conf_file, mycnf)
return True
return True
def backupDatabase(self, name, count):
db_path = mw.getServerDir() + '/mysql'
db_name = 'mysql'
@@ -104,17 +125,11 @@ class backupTools:
filename = backup_path + "/db_" + name + "_" + \
time.strftime('%Y%m%d_%H%M%S', time.localtime()) + ".sql.gz"
import re
mysql_root = mw.M('config').dbPos(db_path, db_name).where(
"id=?", (1,)).getField('mysql_root')
mycnf = mw.readFile(db_path + '/etc/my.cnf')
rep = "\[mysqldump\]\nuser=root"
sea = "[mysqldump]\n"
subStr = sea + "user=root\npassword=" + mysql_root + "\n"
mycnf = mycnf.replace(sea, subStr)
if len(mycnf) > 100:
mw.writeFile(db_path + '/etc/my.cnf', mycnf)
my_cnf = self.getConf('mysql')
self.mypass(True, mysql_root)
# mw.execShell(db_path + "/bin/mysqldump --opt --default-character-set=utf8 " +
# name + " | gzip > " + filename)
@@ -125,8 +140,10 @@ class backupTools:
# mw.execShell(db_path + "/bin/mysqldump --single-transaction --quick --default-character-set=utf8 " +
# name + " | gzip > " + filename)
mw.execShell(db_path + "/bin/mysqldump --force --opt --default-character-set=utf8 " +
name + " | gzip > " + filename)
cmd = db_path + "/bin/mysqldump --defaults-file=" + my_cnf + " --force --opt --default-character-set=utf8 " + \
name + " | gzip > " + filename
# print(cmd)
mw.execShell(cmd)
if not os.path.exists(filename):
endDate = time.strftime('%Y/%m/%d %X', time.localtime())
@@ -136,10 +153,7 @@ class backupTools:
"----------------------------------------------------------------------------")
return
mycnf = mw.readFile(db_path + '/etc/my.cnf')
mycnf = mycnf.replace(subStr, sea)
if len(mycnf) > 100:
mw.writeFile(db_path + '/etc/my.cnf', mycnf)
self.mypass(False, mysql_root)
endDate = time.strftime('%Y/%m/%d %X', time.localtime())
outTime = time.time() - startTime

Some files were not shown because too many files have changed in this diff Show More