Browse Source

chore: adjust coupon creation ui

Cat 2 years ago
parent
commit
bd261f55ed

+ 11 - 11
README.md

@@ -12,7 +12,7 @@
 ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/Anankke/SSPanel-Uim/lint.yml?branch=dev&label=lint&style=flat-square)
 
 
-[配套SS/SSR后端](https://github.com/sspanel-uim/shadowsocks-mod) | [配套Trojan后端](https://github.com/sspanel-uim/TrojanX) | [Telegram 水群](https://t.me/ssunion) | [Telegram 通知频道](https://t.me/sspanel_uim) | [Telegram 开发频道](https://t.me/sspanel_uim_dev) | [开发 Blog](https://blog.sspanel.org)
+[配套Trojan后端](https://github.com/sspanel-uim/TrojanX) | [Telegram 水群](https://t.me/ssunion) | [Telegram 通知频道](https://t.me/sspanel_uim) | [Telegram 开发频道](https://t.me/sspanel_uim_dev) | [Dev Blog](https://blog.sspanel.org)
 
 ## 简介
 
@@ -22,27 +22,27 @@ SSPanel UIM 是一款专为 Shadowsocks / V2Ray / Trojan 设计的多用户管
 
 - 集成 支付宝当面付,Stripe 银行卡,彩虹易支付 等多种支付系统
 - 数据库化配置,管理面板一键配置
-- 内置邮件队列功能,无需第三方组件即可使用
-- 内置 Bootstrap 5 主题,Smarty 模板引擎支持
+- 支持多种邮件服务,内置队列功能,无需第三方组件即可使用
+- 内置基于 Bootstrap 5 的 tabler 主题,Smarty 模板引擎支持
+- 自定义节点配置,支持 Shadowsocks 2022,Shadowsocks AEAD,Trojan-Go 等最新代理协议
 - 通用订阅接口,一键 json/clash 格式订阅下发,自定义客户端更简单
-- 支持 用户IP匿名化,无日志模式,数据删除请求 等隐私保护功能,满足用户个人资料安全需求
+- 模块化订阅系统,支持多种传统订阅模式,自定义订阅更方便
+- 支持 用户IP匿名化,无日志模式,用户自助删除数据 等隐私保护功能,满足合规性需求
 
 ## 安装
 
 SSPanel UIM 的需要以下程序才能正常的安装和运行:
 
 - Git
-- Nginx / Apache
+- Nginx
 - PHP 8.0
 - MySQL 8.0 / MariaDB 10.6+
 
-SSPanel UIM 支持安装在 Oneinstack 等集成环境中。安装教程请参阅 [文档](https://wiki.sspanel.org)。
-
 ## 文档
 
 > 我们安装,我们更新,我们开发
 
-[SSPanel UIM 的文档](https://wiki.sspanel.org),在这里你可以找到大部分问题的解答。
+[SSPanel UIM Wiki](https://wiki.sspanel.org),在这里你可以找到大部分问题的解答。
 
 ## 项目
 
@@ -52,16 +52,16 @@ SSPanel-UIM 不单单是一个面板,它还包括了一系列周边项目来
 
 ## 贡献
 
-[功能请求 & 问题回报](https://github.com/Anankke/SSPanel-Uim/issues/new) | [改善文档](https://github.com/sspanel-uim/Wiki) | [Fork & Pull Request](https://github.com/Anankke/SSPanel-Uim/fork) | [贡献者列表](https://wiki.sspanel.org/#/contributors)
+[功能请求 & 问题回报](https://github.com/Anankke/SSPanel-Uim/issues/new) | [Fork & Pull Request](https://github.com/Anankke/SSPanel-Uim/fork) | [文档 Repo](https://github.com/sspanel-uim/Wiki) | [贡献者列表](https://wiki.sspanel.org/#/contributors)
 
 SSPanel UIM 欢迎各种贡献,包括但不限于改进,新功能,文档和代码改进,问题和错误报告。
 
-## 捐贈
+## 支持开发者
 
 ### M1Screw
 [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/O5O850UEH)
 
-## Sponsor
+## Sponsor / 赞助商
 [![](.github/jetbrains.png)](https://www.jetbrains.com/?from=SSPanel-UIM)
 
 ## 协议

+ 1 - 1
app/routes.php

@@ -290,7 +290,6 @@ return function (SlimApp $app): void {
         // 流媒体检测
         $this->post('/media/saveReport', App\Controllers\WebAPI\NodeController::class . ':saveReport');
         // 节点
-        $this->get('/nodes', App\Controllers\WebAPI\NodeController::class . ':getAllInfo');
         $this->get('/nodes/{id}/info', App\Controllers\WebAPI\NodeController::class . ':getInfo');
         // 用户
         $this->get('/users', App\Controllers\WebAPI\UserController::class . ':index');
@@ -301,6 +300,7 @@ return function (SlimApp $app): void {
         $this->get('/func/detect_rules', App\Controllers\WebAPI\FuncController::class . ':getDetectLogs');
         $this->get('/func/ping', App\Controllers\WebAPI\FuncController::class . ':ping');
         // Dummy API for old version
+        $this->get('/nodes', App\Controllers\WebAPI\NodeController::class . ':getAllInfo');
         $this->post('/func/block_ip', App\Controllers\WebAPI\FuncController::class . ':addBlockIp');
         $this->get('/func/block_ip', App\Controllers\WebAPI\FuncController::class . ':getBlockip');
         $this->get('/func/unblock_ip', App\Controllers\WebAPI\FuncController::class . ':getUnblockip');

+ 2 - 3
config/.config.example.php

@@ -2,13 +2,13 @@
 
 //基本设置--------------------------------------------------------------------------------------------
 $_ENV['key']        = 'ChangeMe';                     //请务必修改此key为随机字符串
-$_ENV['pwdMethod']  = 'bcrypt';                          //密码加密 可选 md5, sha256, bcrypt, argon2i, argon2id(argon2i需要至少php7.2)
+$_ENV['pwdMethod']  = 'bcrypt';                       //密码加密 可选 md5, sha256, bcrypt, argon2i, argon2id(argon2i需要至少php7.2)
 $_ENV['salt']       = '';                             //推荐配合 md5/sha256, bcrypt/argon2i/argon2id 会忽略此项
 
 $_ENV['debug']      = false;                          //debug模式开关,生产环境请保持为false
 $_ENV['appName']    = 'SSPanel-UIM';                  //站点名称
 $_ENV['baseUrl']    = 'https://example.com';          //站点地址
-$_ENV['muKey']      = 'SSPanel';                      //WebAPI密钥,用于节点服务端与面板通信
+$_ENV['muKey']      = 'ChangeMe';                      //WebAPI密钥,用于节点服务端与面板通信,请务必修改此key为随机字符串
 
 //数据库设置--------------------------------------------------------------------------------------------
 // db_host|db_socket 二选一,若设置 db_socket 则 db_host 会被忽略,不用请留空。若数据库在本机上推荐用 db_socket。
@@ -208,7 +208,6 @@ $_ENV['theme']                  = 'tabler';              //默认主题
 $_ENV['jump_delay']             = 1200;                  //跳转延时,单位ms,不建议太长
 
 $_ENV['checkNodeIp']            = true;                 //是否webapi验证节点ip
-$_ENV['muKeyList']              = [];                   //多 key 列表
 $_ENV['keep_connect']           = false;               // 流量耗尽用户限速至 1Mbps
 $_ENV['money_from_admin']       = false;            //是否开启管理员修改用户余额时创建充值记录
 

+ 2 - 2
config/clients.json

@@ -51,12 +51,12 @@
         },
         {
             "name": "v2rayN",
-            "tagMethod": "github_release",
+            "tagMethod": "github_pre_release",
             "gitRepo": "2dust/v2rayN",
             "savePath": "public/clients/",
             "downloads": [
                 {
-                    "sourceName": "v2rayN-Core.zip",
+                    "sourceName": "v2rayN-With-Core.zip",
                     "saveName": "v2rayN-Core.zip",
                     "apkpureUrl": ""
                 }

+ 4 - 3
resources/views/tabler/admin/coupon.tpl

@@ -1,7 +1,8 @@
 {include file='admin/tabler_header.tpl'}
 
-<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
-<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
+<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
+<script src="//cdn.jsdelivr.net/npm/flatpickr"></script>
+<script src="//cdn.jsdelivr.net/npm/flatpickr/dist/l10n/zh.js"></script>
 
 <div class="page-wrapper">
     <div class="container-xl">
@@ -103,7 +104,7 @@
                 </div>
                 <div class="modal-footer">
                     <button type="button" class="btn me-auto" data-bs-dismiss="modal">取消</button>
-                    <button id="create-button" onclick="createGiftCard()"
+                    <button id="create-button" onclick="createCoupon()"
                         type="button" class="btn btn-primary" data-bs-dismiss="modal">创建</button>
                 </div>
             </div>

+ 5 - 4
resources/views/tabler/user/edit.tpl

@@ -106,7 +106,8 @@
                                                         </select>
                                                     </div>
                                                     <div class="mb-3">
-                                                        <input id="wechat" type="text" class="form-control"
+                                                        <input id="imvalue" type="text" class="form-control" 
+                                                            {if $user->im_type == '4'} disabled="" {/if}
                                                             value="{$user->im_value}" placeholder="社交账户">
                                                     </div>
                                                 </div>
@@ -322,7 +323,7 @@
                                             <div class="card">
                                                 <div class="card-body">
                                                     <h3 class="card-title">更换连接端口</h3>
-                                                    <p>随机分配一个连接端口,这将用于 SS / SSR 客户端</p>
+                                                    <p>随机分配一个连接端口,这将用于 Shadowsocks 客户端</p>
                                                     <p>当前端口是:<code>{$user->port}</code></p>
                                                 </div>
                                                 <div class="card-footer">
@@ -735,11 +736,11 @@
         $("#modify-im").click(function() {
             $.ajax({
                 type: "POST",
-                url: "/user/wechat",
+                url: "/user/contact_update",
                 dataType: "json",
                 data: {
                     imtype: $('#imtype').val(),
-                    wechat: $('#wechat').val()
+                    imvalue: $('#imvalue').val()
                 },
                 success: function(data) {
                     if (data.ret == 1) {

+ 1 - 1
scripts/block-whoops-env.sh

@@ -28,7 +28,7 @@ backup()
 
 run()
 {
-    list='key baseUrl db_host db_database db_username db_password muKey muKeyList adminApiToken telegram_token telegram_request_token cloudflare_email cloudflare_key cloudflare_name sentry_dsn github_access_token pwdMethod salt'
+    list='key baseUrl db_host db_database db_username db_password muKey telegram_token telegram_request_token cloudflare_email cloudflare_key cloudflare_name sentry_dsn github_access_token pwdMethod salt'
     for key in $list
     do
         sed -i "${line}i \ \ \ \ \ \ \ \ \$this->blacklist('_ENV', '${key}');" ${file}

+ 7 - 4
src/Controllers/Admin/CouponController.php

@@ -66,8 +66,11 @@ final class CouponController extends BaseController
             [
                 'id' => 'new_user',
                 'info' => '仅限新用户使用',
-                'type' => 'input',
-                'placeholder' => '',
+                'type' => 'select',
+                'select' => [
+                    '1' => '启用',
+                    '0' => '禁用',
+                ],
             ],
             [
                 'id' => 'generate_method',
@@ -192,7 +195,7 @@ final class CouponController extends BaseController
 
         return $response->withJson([
             'ret' => 1,
-            'msg' => '优惠码 <code>' . $code . '</code> 添加成功',
+            'msg' => '优惠码 ' . $code . ' 添加成功',
         ]);
     }
 
@@ -218,7 +221,7 @@ final class CouponController extends BaseController
             $content = \json_decode($coupon->content);
             $limit = \json_decode($coupon->limit);
             $coupon->op = '<button type="button" class="btn btn-red" id="delete-coupon-' . $coupon->id . '" 
-        onclick="deleteCoupons(' . $coupon->id . ')">删除</button>';
+        onclick="deleteCoupon(' . $coupon->id . ')">删除</button>';
             $coupon->type = Tools::getCouponType($content);
             $coupon->value = $content->value;
             $coupon->product_id = $limit->product_id;

+ 1 - 0
src/Controllers/Admin/SettingController.php

@@ -8,6 +8,7 @@ use App\Controllers\BaseController;
 use App\Models\Setting;
 use App\Services\Mail;
 use App\Services\Payment;
+use Exception;
 
 final class SettingController extends BaseController
 {

+ 35 - 19
src/Controllers/UserController.php

@@ -688,33 +688,43 @@ final class UserController extends BaseController
      */
     public function updateContact(Request $request, Response $response, array $args)
     {
-        $type = $request->getParam('imtype');
-        $contact = trim($request->getParam('contact'));
+        $antiXss = new AntiXSS();
+
+        $type = $antiXss->xss_clean($request->getParam('imtype'));
+        $value = $antiXss->xss_clean($request->getParam('imvalue'));
 
         $user = $this->user;
 
         if ($user->telegram_id !== null) {
-            return ResponseHelper::error(
-                $response,
-                '绑定了 Telegram ,所以此项并不能被修改'
-            );
+            return $response->withJson([
+                'ret' => 0,
+                'msg' => '你的账户绑定了 Telegram ,所以此项并不能被修改',
+            ]);
         }
 
-        if ($contact === '' || $type === '') {
-            return ResponseHelper::error($response, '非法输入');
+        if ($value === '' || $type === '') {
+            return $response->withJson([
+                'ret' => 0,
+                'msg' => '联络方式不能为空',
+            ]);
         }
 
-        $user1 = User::where('im_value', $contact)->where('im_type', $type)->first();
-        if ($user1 !== null) {
-            return ResponseHelper::error($response, '此联络方式已经被注册');
+        $user_exist = User::where('im_value', $value)->where('im_type', $type)->first();
+        if ($user_exist !== null) {
+            return $response->withJson([
+                'ret' => 0,
+                'msg' => '此联络方式已经被注册',
+            ]);
         }
 
         $user->im_type = $type;
-        $antiXss = new AntiXSS();
-        $user->im_value = $antiXss->xss_clean($contact);
+        $user->im_value = $value;
         $user->save();
 
-        return ResponseHelper::successfully($response, '修改成功');
+        return $response->withJson([
+            'ret' => 1,
+            'msg' => '修改成功',
+        ]);
     }
 
     /**
@@ -722,19 +732,25 @@ final class UserController extends BaseController
      */
     public function updateTheme(Request $request, Response $response, array $args)
     {
-        $theme = $request->getParam('theme');
+        $antiXss = new AntiXSS();
+        $theme = $antiXss->xss_clean($request->getParam('theme'));
 
         $user = $this->user;
 
         if ($theme === '') {
-            return ResponseHelper::error($response, '非法输入');
+            return $response->withJson([
+                'ret' => 0,
+                'msg' => '主题不能为空',
+            ]);
         }
 
-        $antiXss = new AntiXSS();
-        $user->theme = $antiXss->xss_clean($theme);
+        $user->theme = $theme;
         $user->save();
 
-        return ResponseHelper::successfully($response, '设置成功');
+        return $response->withJson([
+            'ret' => 1,
+            'msg' => '修改成功',
+        ]);
     }
 
     /**

+ 1 - 10
src/Controllers/WebAPI/NodeController.php

@@ -85,18 +85,9 @@ final class NodeController extends BaseController
      */
     public function getAllInfo(Request $request, Response $response, array $args): ResponseInterface
     {
-        $nodes = Node::where('node_ip', '<>', null)->where(
-            static function ($query): void {
-                $query->where('sort', '=', 0)
-                    ->orWhere('sort', '=', 1)
-                    ->orWhere('sort', '=', 11)
-                    ->orWhere('sort', '=', 14);
-            }
-        )->get();
-
         return ResponseHelper::etagJson($request, $response, [
             'ret' => 1,
-            'data' => $nodes,
+            'data' => [],
         ]);
     }
 }

+ 1 - 1
src/Controllers/WebAPI/UserController.php

@@ -67,7 +67,7 @@ final class UserController extends BaseController
             ];
         }
 
-        $alive_ip = (new \App\Models\Ip())->getUserAliveIpCount();
+        $alive_ip = (new Ip())->getUserAliveIpCount();
         $users = [];
         foreach ($users_raw as $user_raw) {
             if (isset($alive_ip[strval($user_raw->id)]) && $user_raw->node_connector !== 0) {

+ 5 - 6
src/Middleware/NodeToken.php

@@ -5,7 +5,6 @@ declare(strict_types=1);
 namespace App\Middleware;
 
 use App\Models\Node;
-use App\Services\Config;
 use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Request;
 use Slim\Http\Response;
@@ -28,15 +27,15 @@ final class NodeToken
             // 未提供 key
             return $response->withJson([
                 'ret' => 0,
-                'data' => 'Your key is null.',
+                'data' => 'Invalid request.',
             ]);
         }
 
-        if (!\in_array($key, Config::getMuKey())) {
+        if ($key !== $_ENV['muKey']) {
             // key 不存在
             return $response->withJson([
                 'ret' => 0,
-                'data' => 'Token is invalid.',
+                'data' => 'Invalid request.',
             ]);
         }
 
@@ -44,7 +43,7 @@ final class NodeToken
             // 主站不提供 WebAPI
             return $response->withJson([
                 'ret' => 0,
-                'data' => 'WebAPI is disabled.',
+                'data' => 'Invalid request.',
             ]);
         }
 
@@ -54,7 +53,7 @@ final class NodeToken
                 if (! Node::where('node_ip', 'LIKE', "${ip}%")->exists()) {
                     return $response->withJson([
                         'ret' => 0,
-                        'data' => "IP is invalid. Now, your IP address is ${ip}",
+                        'data' => "Invalid request IP.",
                     ]);
                 }
             }

+ 1 - 28
src/Services/Config.php

@@ -106,12 +106,6 @@ final class Config
         ];
     }
 
-    public static function getMuKey()
-    {
-        $muKeyList = \array_key_exists('muKeyList', $_ENV) ? $_ENV['muKeyList'] : [' '];
-        return array_merge(explode(',', $_ENV['muKey']), $muKeyList);
-    }
-
     public static function getSupportParam($type)
     {
         switch ($type) {
@@ -138,34 +132,13 @@ final class Config
                 ];
             default:
                 return [
-                    'rc4-md5',
-                    'rc4-md5-6',
-                    'aes-128-cfb',
-                    'aes-192-cfb',
-                    'aes-256-cfb',
-                    'aes-128-ctr',
-                    'aes-192-ctr',
-                    'aes-256-ctr',
-                    'camellia-128-cfb',
-                    'camellia-192-cfb',
-                    'camellia-256-cfb',
-                    'bf-cfb',
-                    'cast5-cfb',
-                    'des-cfb',
-                    'des-ede3-cfb',
-                    'idea-cfb',
-                    'rc2-cfb',
-                    'seed-cfb',
-                    'salsa20',
-                    'chacha20',
-                    'xsalsa20',
-                    'chacha20-ietf',
                     'aes-128-gcm',
                     'aes-192-gcm',
                     'aes-256-gcm',
                     'chacha20-ietf-poly1305',
                     'xchacha20-ietf-poly1305',
                     'none',
+                    'plain',
                     '2022-blake3-aes-128-gcm',
                     '2022-blake3-aes-256-gcm',
                     '2022-blake3-chacha20-poly1305',