mirror of
https://github.com/v2board/v2board.git
synced 2025-08-02 21:38:49 +08:00
Compare commits
422 Commits
Author | SHA1 | Date | |
---|---|---|---|
516b2626ae | |||
b9312f362c | |||
102f18bef1 | |||
1fc36d8e29 | |||
a3837f83cb | |||
47f27f4852 | |||
e73eaea66c | |||
bc5ddbf40a | |||
a2c674f00c | |||
218338960b | |||
d9dcea4e4f | |||
fad12a62ce | |||
1ee104ec88 | |||
19dcd0ffba | |||
ab2e39f7dd | |||
8f4ebe1764 | |||
3763320261 | |||
376c79aa91 | |||
47686d50c5 | |||
c8cb1f8e83 | |||
620ed8e04c | |||
c28a6ec1d3 | |||
3c78bed800 | |||
72fb0d131d | |||
378c96d4c7 | |||
ca2a744b10 | |||
0f72e9a091 | |||
bb49fb15d1 | |||
47d8dfd7c8 | |||
60b197410c | |||
e2b73094c0 | |||
7d8b8ad8ac | |||
1992b0a9e9 | |||
b4bede869d | |||
a11e65f84a | |||
e1a8ffe7c4 | |||
2217286d03 | |||
dd924d95c6 | |||
53710f2e01 | |||
f03c53815c | |||
6e98e42f51 | |||
9932e34634 | |||
6ba4702539 | |||
b29ac8ac2c | |||
866fda84ed | |||
95c7c48cc7 | |||
010f0cbc03 | |||
0d2b8bc976 | |||
3b9e9cbe7f | |||
a7b47d8f77 | |||
dea26121fc | |||
10e4de39de | |||
e7fd81bf4c | |||
0f9cb9696d | |||
a7b3d6e778 | |||
637bacd62f | |||
2171ef59d7 | |||
0a92308ad2 | |||
8ff53673d7 | |||
07772ceb66 | |||
fc8333d757 | |||
64dbd11e62 | |||
bfeab8eae2 | |||
5ee6fc2996 | |||
018e4aa810 | |||
17d6d04cc6 | |||
e174ef193b | |||
1887259554 | |||
8b804913f5 | |||
a2ea88beb5 | |||
d969220654 | |||
5154993887 | |||
61b31c1925 | |||
a0454577cb | |||
f7fc6b9dfc | |||
1b7fc9529f | |||
a56faa7e8e | |||
0a2c626f89 | |||
19df032b57 | |||
de8f95ee3d | |||
568648dc2f | |||
9f5be4e83a | |||
14d0de18ec | |||
64ae39aa2d | |||
fb09baa3c1 | |||
153bdcaad1 | |||
f3ac8a37be | |||
9925ab6b47 | |||
84ff8d3ab3 | |||
fcec3af75f | |||
2a9a8805a8 | |||
72eafb9698 | |||
e837e774ef | |||
00fcff5f0d | |||
6b43597eaf | |||
c576299a60 | |||
4926264160 | |||
0c1a53faab | |||
0f0b092f86 | |||
3beb938cbc | |||
c45578417f | |||
088dc2cfa6 | |||
0b4c884824 | |||
7b9390a6cb | |||
2b69e83132 | |||
56820346d0 | |||
1ea307854f | |||
290ef77c03 | |||
172a639f59 | |||
bff92180b0 | |||
e094a2f4d1 | |||
b852180b4d | |||
a0a5327f42 | |||
874648a4c0 | |||
15cd13c26c | |||
76c50e01bf | |||
9ae3994705 | |||
cab7cc9d19 | |||
dbac9d9dac | |||
2e18b1b108 | |||
c1583a1014 | |||
01c5901c71 | |||
0446e7d99f | |||
557f6bc0c2 | |||
e49dc87fda | |||
edf88cbccf | |||
19940f599d | |||
ace06630d8 | |||
50582137e4 | |||
ab8da6bb02 | |||
0a58930619 | |||
9d9866689d | |||
2d21fa3fb7 | |||
5cd020ea7a | |||
43e7bb6c9f | |||
2b8456fdf5 | |||
b34fa70165 | |||
d845439f14 | |||
d356722482 | |||
72ac20d387 | |||
878a7da62c | |||
4fd0c9ce51 | |||
18ed6947b3 | |||
b8b1e1043b | |||
705ceb80b2 | |||
47be10f274 | |||
540b331f16 | |||
e9ba149c0f | |||
895e0f177b | |||
9dc64114f5 | |||
168b0ad72e | |||
c82acafdf8 | |||
e14489cf66 | |||
96a36b1afb | |||
df9d99c271 | |||
79bd46c0da | |||
e638660bf7 | |||
880b8e8ad9 | |||
ba40e3a1bf | |||
8fafdc9bb5 | |||
e07b97b14e | |||
c817710556 | |||
19fd19fbcf | |||
26e63cbe1c | |||
5bd524fbf1 | |||
3a7a0c6e62 | |||
23bfb20307 | |||
7f9ad68e1b | |||
cb8cdb2e0e | |||
5db26d862b | |||
13bc683faf | |||
e9229781bc | |||
6b9e424b74 | |||
078e1e7bd6 | |||
d417e70475 | |||
214fb2a2bf | |||
f61e37aeaf | |||
98e23be297 | |||
5bc4bff8f9 | |||
ab97db552d | |||
2e2a0bf273 | |||
1f471545d4 | |||
ffe05a5467 | |||
ec73224671 | |||
3f4e3d46fb | |||
6920352c0e | |||
e57a70970f | |||
406f1ee80d | |||
f7558fecc7 | |||
43d98a485d | |||
be2caad604 | |||
984abba50d | |||
62f7d5b3e8 | |||
37844c1bb4 | |||
87e0d34961 | |||
ce6bd80702 | |||
79bb987c37 | |||
ec8357aa3e | |||
24f5324c2a | |||
0299cd63ad | |||
bb566f01d9 | |||
c03bd0098d | |||
073f7611e1 | |||
517f7d0122 | |||
32d6a983a3 | |||
a8db24492b | |||
1b23998248 | |||
d744fba683 | |||
3f6799aa4b | |||
1d704a4424 | |||
ab5aeb545e | |||
5e7e42e52c | |||
241cbd3016 | |||
9ff815f853 | |||
b61e641dad | |||
a9eff7bea9 | |||
fc3c4b3b73 | |||
b75104475c | |||
6c606527b1 | |||
34892d9c34 | |||
51bb2779b9 | |||
45a257778c | |||
4286bbb988 | |||
2f8f3afebf | |||
15fc60d3c7 | |||
b8218f2c51 | |||
9080de4d0a | |||
50ffdd9db9 | |||
6cf3b73da2 | |||
e963a61910 | |||
038effdd42 | |||
5a4b208aab | |||
af400b3a0b | |||
9a4b2027f6 | |||
9ae2fc3f1d | |||
ba9d00f088 | |||
7fc34fa2b8 | |||
7cb5eb03b9 | |||
d7063191f4 | |||
deb7e4ed04 | |||
602e12d745 | |||
f2ffb184d4 | |||
6dd562df8c | |||
5fae1f2bd8 | |||
a60d68a13f | |||
dad9e43114 | |||
aac4ce8098 | |||
52b9ed47b0 | |||
6d76e30299 | |||
0675268a16 | |||
aaf94e61a2 | |||
47d5031fe6 | |||
8d4575ede9 | |||
e9a69cd0f6 | |||
625bcc59e8 | |||
34533ae10c | |||
b4fc90c133 | |||
12278e143e | |||
10510164e4 | |||
75e91b281c | |||
c027c1127b | |||
0dbdb55ed2 | |||
66042904e8 | |||
508961c4fb | |||
f03dbd1dcb | |||
e576d82955 | |||
88d7e2d35e | |||
9b6919e9c9 | |||
3e86cdcbbf | |||
9fc4a6129c | |||
db9743a67f | |||
0f5942bc03 | |||
28cc21e09b | |||
fc7f73b558 | |||
fb0ebea836 | |||
7d7cef5f37 | |||
abd488d247 | |||
e3916aaa06 | |||
32795cf541 | |||
415850184e | |||
afa3c0aa52 | |||
82875ae6f0 | |||
bcd85ef71a | |||
8f35924dee | |||
4a01b8f11e | |||
fc18168aa2 | |||
abdb6f80af | |||
fbf3a83104 | |||
515e23762f | |||
f7fdfadfb0 | |||
35f954cd84 | |||
ed0fe84687 | |||
a96ca5a363 | |||
6a051f469e | |||
5e9bc09396 | |||
1ef8eab552 | |||
4d66941ef6 | |||
2e505a9759 | |||
85e0eb2760 | |||
c68440ce32 | |||
1cd0dbdd31 | |||
d268f6ddec | |||
b75c33b1d9 | |||
0ee67ef270 | |||
44e57b7073 | |||
0de4a137bf | |||
392c849241 | |||
2f3f457ad9 | |||
776e866b3c | |||
9541bc8cd0 | |||
dc52c3191c | |||
85a29d3a8b | |||
7a0c9ce4c4 | |||
b4bb93e23e | |||
11d9654010 | |||
52163329da | |||
45b03b4fba | |||
0749372f34 | |||
588577d513 | |||
e3431c6ae7 | |||
2346b1a2dc | |||
c61f64d623 | |||
25fbdf0013 | |||
3a9b3ab32d | |||
a524fb6f76 | |||
2172f088a2 | |||
93fa074358 | |||
27e417a5f2 | |||
97e1d9b3bd | |||
1a0d8e9c55 | |||
b49b941e50 | |||
b9cee36641 | |||
2ecdc27921 | |||
2d58744de4 | |||
869a6a920b | |||
c82a189d76 | |||
7543819ef2 | |||
4ceca1957f | |||
44bd189259 | |||
b6752e3952 | |||
45ba9b0c15 | |||
52e7925cac | |||
54273a8f16 | |||
c6461f0bdf | |||
145f55ae29 | |||
a201b19940 | |||
f4166bed45 | |||
8f8be2ea33 | |||
df02973756 | |||
9e55cb2f5d | |||
5699fe09e9 | |||
34fa75b4cc | |||
96d3a27a5b | |||
b8c8335542 | |||
aceff450ec | |||
5d7b5eb8f6 | |||
afc9d64aab | |||
09e31dc70b | |||
d653541ef3 | |||
dc37499df9 | |||
2911680eaf | |||
6ff24f77b8 | |||
9f4c19bcab | |||
453a078cd5 | |||
20be5c3182 | |||
7639f07b83 | |||
2a693e4911 | |||
89d67279c6 | |||
8bc5004654 | |||
ec4c0ba339 | |||
b4e5eb26e3 | |||
1bf03b28c7 | |||
aa8f5bfa79 | |||
495aa04273 | |||
202a21c17a | |||
9eefb32a4c | |||
2eb594a4fa | |||
34e71ff049 | |||
63c1faba5e | |||
5b2e18f702 | |||
784b53c9f3 | |||
01d0f6b29d | |||
2d7d5a564e | |||
70c1d5c874 | |||
10029c8362 | |||
9cd377f8ed | |||
f5db443668 | |||
e1fce3ae37 | |||
fae5ef21e6 | |||
4c976b1cbe | |||
6de46f5c36 | |||
4992ea635c | |||
928e59a977 | |||
2be5b8e357 | |||
76ce89c17f | |||
8c5b32de90 | |||
0b89446b63 | |||
0d4a86c9e9 | |||
aa1d54137c | |||
eee6351e35 | |||
4b43bd2b9e | |||
ff6aeb92ec | |||
a9abdcd9d3 | |||
7965a020b6 | |||
17e626493a | |||
0de055a36b | |||
5070c851ed | |||
157a97b35d | |||
8e6ee35efb | |||
ec284241ee | |||
a3f59aac0a | |||
35c71be4a9 | |||
abf6dbf73c | |||
037ecc0a2a | |||
5a87d59d30 | |||
1351ec583e | |||
5b29257227 | |||
551073cb83 | |||
a1b466e2c2 | |||
0b3cf4a2a4 | |||
0dccfd9f09 | |||
988f088a58 |
12
.env.example
12
.env.example
@ -7,16 +7,16 @@ APP_URL=http://localhost
|
||||
LOG_CHANNEL=stack
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=db
|
||||
DB_HOST=localhost
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=laravel
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=123456
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
CACHE_DRIVER=redis
|
||||
QUEUE_CONNECTION=redis
|
||||
SESSION_DRIVER=redis
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
@ -31,6 +31,8 @@ MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS=null
|
||||
MAIL_FROM_NAME=null
|
||||
MAILGUN_DOMAIN=
|
||||
MAILGUN_SECRET=
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
@ -43,4 +45,4 @@ PUSHER_APP_SECRET=
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,5 +1,5 @@
|
||||
/node_modules
|
||||
/config/v2panel.php
|
||||
/config/v2board.php
|
||||
/public/hot
|
||||
/public/storage
|
||||
/public/env.example.js
|
||||
@ -16,4 +16,4 @@ yarn-error.log
|
||||
composer.phar
|
||||
composer.lock
|
||||
yarn.lock
|
||||
docker-compose.yml
|
||||
docker-compose.yml
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2019 Bruskyii Panda
|
||||
Copyright (c) 2019 Tokumeikoi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -54,5 +54,5 @@ class CheckCommission extends Command
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\Order;
|
||||
use App\Models\User;
|
||||
|
||||
class CheckExpire extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'check:expire';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '过期检查';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$user = User::all();
|
||||
foreach ($user as $item) {
|
||||
if ($item->expired_at < time() || $item->u + $item->d >= $item->transfer_enable) {
|
||||
$item->enable = 0;
|
||||
} else {
|
||||
$item->enable = 1;
|
||||
}
|
||||
$item->save();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,7 @@ use App\Models\Order;
|
||||
use App\Models\User;
|
||||
use App\Models\Plan;
|
||||
use App\Utils\Helper;
|
||||
use App\Models\Coupon;
|
||||
|
||||
class CheckOrder extends Command
|
||||
{
|
||||
@ -55,19 +56,34 @@ class CheckOrder extends Command
|
||||
$this->orderHandle($item);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private function orderHandle ($order) {
|
||||
|
||||
private function orderHandle(Order $order)
|
||||
{
|
||||
$user = User::find($order->user_id);
|
||||
return $this->buy($order, $user);
|
||||
}
|
||||
|
||||
private function buy ($order, $user) {
|
||||
$plan = Plan::find($order->plan_id);
|
||||
if ($order->cycle === 'onetime_price') {
|
||||
return $this->buyByOneTime($order, $user, $plan);
|
||||
}
|
||||
return $this->buyByCycle($order, $user, $plan);
|
||||
}
|
||||
|
||||
private function buyByCycle(Order $order, User $user, Plan $plan)
|
||||
{
|
||||
// change plan process
|
||||
if ($order->type == 3) {
|
||||
$user->expired_at = time();
|
||||
}
|
||||
if ($order->refund_amount) {
|
||||
$user->balance = $user->balance + $order->refund_amount;
|
||||
}
|
||||
$user->transfer_enable = $plan->transfer_enable * 1073741824;
|
||||
$user->enable = 1;
|
||||
if ((int)config('v2board.renew_reset_traffic_enable', 1)) {
|
||||
$user->u = 0;
|
||||
$user->d = 0;
|
||||
}
|
||||
$user->plan_id = $plan->id;
|
||||
$user->group_id = $plan->group_id;
|
||||
$user->expired_at = $this->getTime($order->cycle, $user->expired_at);
|
||||
@ -76,16 +92,38 @@ class CheckOrder extends Command
|
||||
$order->save();
|
||||
}
|
||||
}
|
||||
|
||||
private function getTime ($str, $timestamp) {
|
||||
|
||||
private function buyByOneTime(Order $order, User $user, Plan $plan)
|
||||
{
|
||||
if ($order->refund_amount) {
|
||||
$user->balance = $user->balance + $order->refund_amount;
|
||||
}
|
||||
$user->transfer_enable = $plan->transfer_enable * 1073741824;
|
||||
$user->u = 0;
|
||||
$user->d = 0;
|
||||
$user->plan_id = $plan->id;
|
||||
$user->group_id = $plan->group_id;
|
||||
$user->expired_at = NULL;
|
||||
if ($user->save()) {
|
||||
$order->status = 3;
|
||||
$order->save();
|
||||
}
|
||||
}
|
||||
|
||||
private function getTime($str, $timestamp)
|
||||
{
|
||||
if ($timestamp < time()) {
|
||||
$timestamp = time();
|
||||
}
|
||||
switch ($str) {
|
||||
case 'month_price': return strtotime('+1 month', $timestamp);
|
||||
case 'quarter_price': return strtotime('+3 month', $timestamp);
|
||||
case 'half_year_price': return strtotime('+6 month', $timestamp);
|
||||
case 'year_price': return strtotime('+12 month', $timestamp);
|
||||
case 'month_price':
|
||||
return strtotime('+1 month', $timestamp);
|
||||
case 'quarter_price':
|
||||
return strtotime('+3 month', $timestamp);
|
||||
case 'half_year_price':
|
||||
return strtotime('+6 month', $timestamp);
|
||||
case 'year_price':
|
||||
return strtotime('+12 month', $timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Models\User;
|
||||
|
||||
class ResetTraffic extends Command
|
||||
{
|
||||
@ -38,9 +38,45 @@ class ResetTraffic extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
DB::table('v2_user')->update([
|
||||
$user = User::where('expired_at', '!=', NULL);
|
||||
$resetTrafficMethod = config('v2board.reset_traffic_method', 0);
|
||||
switch ((int)$resetTrafficMethod) {
|
||||
// 1 a month
|
||||
case 0:
|
||||
$this->resetByMonthFirstDay($user);
|
||||
break;
|
||||
// expire day
|
||||
case 1:
|
||||
$this->resetByExpireDay($user);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function resetByMonthFirstDay(User $user):void
|
||||
{
|
||||
$user->update([
|
||||
'u' => 0,
|
||||
'd' => 0
|
||||
]);
|
||||
}
|
||||
|
||||
private function resetByExpireDay(User $user):void
|
||||
{
|
||||
$date = date('Y-m-d', time());
|
||||
$startAt = strtotime((string)$date);
|
||||
$endAt = (int)$startAt + 24 * 3600;
|
||||
$lastDay = date('d', strtotime('last day of +0 months'));
|
||||
if ((string)$lastDay === '29') {
|
||||
$endAt = (int)$startAt + 72 * 3600;
|
||||
}
|
||||
if ((string)$lastDay === '30') {
|
||||
$endAt = (int)$startAt + 48 * 3600;
|
||||
}
|
||||
$user->where('expired_at', '>=', (int)$startAt)
|
||||
->where('expired_at', '<', (int)$endAt)
|
||||
->update([
|
||||
'u' => 0,
|
||||
'd' => 0
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
91
app/Console/Commands/SendRemindMail.php
Normal file
91
app/Console/Commands/SendRemindMail.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\User;
|
||||
use App\Models\MailLog;
|
||||
use App\Jobs\SendEmail;
|
||||
|
||||
class SendRemindMail extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'send:remindMail';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '发送提醒邮件';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$users = User::all();
|
||||
foreach ($users as $user) {
|
||||
if ($user->remind_expire) $this->remindExpire($user);
|
||||
if ($user->remind_traffic) $this->remindTraffic($user);
|
||||
}
|
||||
}
|
||||
|
||||
private function remindExpire($user)
|
||||
{
|
||||
if (($user->expired_at - 86400) < time() && $user->expired_at > time()) {
|
||||
SendEmail::dispatch([
|
||||
'email' => $user->email,
|
||||
'subject' => '在' . config('v2board.app_name', 'V2board') . '的服务即将到期',
|
||||
'template_name' => 'mail.sendRemindExpire',
|
||||
'template_value' => [
|
||||
'name' => config('v2board.app_name', 'V2Board'),
|
||||
'url' => config('v2board.app_url')
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function remindTraffic($user)
|
||||
{
|
||||
if ($this->remindTrafficIsWarnValue(($user->u + $user->d), $user->transfer_enable)) {
|
||||
$sendCount = MailLog::where('created_at', '>=', strtotime(date('Y-m-1')))
|
||||
->where('template_name', 'mail.sendRemindTraffic')
|
||||
->count();
|
||||
if ($sendCount > 0) return;
|
||||
SendEmail::dispatch([
|
||||
'email' => $user->email,
|
||||
'subject' => '在' . config('v2board.app_name', 'V2board') . '的流量使用已达到80%',
|
||||
'template_name' => 'mail.sendRemindTraffic',
|
||||
'template_value' => [
|
||||
'name' => config('v2board.app_name', 'V2Board'),
|
||||
'url' => config('v2board.app_url')
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function remindTrafficIsWarnValue($ud, $transfer_enable)
|
||||
{
|
||||
if ($ud <= 0) return false;
|
||||
if (($ud / $transfer_enable * 100) < 80) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\User;
|
||||
use App\Models\Order;
|
||||
use App\Models\Server;
|
||||
use App\Models\ServerLog;
|
||||
use App\Utils\Helper;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
|
||||
class SystemCache extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'system:cache';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '系统缓存任务';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->setMonthIncome();
|
||||
$this->setMonthRegisterTotal();
|
||||
}
|
||||
|
||||
private function setMonthIncome() {
|
||||
Redis::set(
|
||||
'month_income',
|
||||
Order::where('created_at', '>=', strtotime(date('Y-m-1')))
|
||||
->where('created_at', '<', time())
|
||||
->where('status', '3')
|
||||
->sum('total_amount')
|
||||
);
|
||||
}
|
||||
|
||||
private function setMonthRegisterTotal() {
|
||||
Redis::set(
|
||||
'month_register_total',
|
||||
User::where('created_at', '>=', strtotime(date('Y-m-1')))
|
||||
->where('created_at', '<', time())
|
||||
->count()
|
||||
);
|
||||
}
|
||||
}
|
@ -4,23 +4,27 @@ namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\User;
|
||||
use App\Models\Order;
|
||||
use App\Models\Server;
|
||||
use App\Models\ServerLog;
|
||||
use App\Utils\Helper;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class ImportReset extends Command
|
||||
class V2boardCache extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'import:reset';
|
||||
protected $signature = 'v2board:cache';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '为导入用户重置所有uuid及token';
|
||||
protected $description = '缓存任务';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
@ -39,11 +43,5 @@ class ImportReset extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$user = User::all();
|
||||
foreach ($user as $item) {
|
||||
$item->v2ray_uuid = Helper::guid(true);
|
||||
$item->token = Helper::guid();
|
||||
$item->save();
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Encryption\Encrypter;
|
||||
use App\Models\User;
|
||||
use App\Utils\Helper;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@ -40,51 +41,114 @@ class V2boardInstall extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (\File::exists(base_path() . '/.lock')) {
|
||||
abort(500, 'V2board 已安装,如需重新安装请删除目录下.lock文件');
|
||||
try {
|
||||
$this->info("__ ______ ____ _ ");
|
||||
$this->info("\ \ / /___ \| __ ) ___ __ _ _ __ __| | ");
|
||||
$this->info(" \ \ / / __) | _ \ / _ \ / _` | '__/ _` | ");
|
||||
$this->info(" \ V / / __/| |_) | (_) | (_| | | | (_| | ");
|
||||
$this->info(" \_/ |_____|____/ \___/ \__,_|_| \__,_| ");
|
||||
if (\File::exists(base_path() . '/.lock')) {
|
||||
abort(500, 'V2board 已安装,如需重新安装请删除目录下.lock文件');
|
||||
}
|
||||
if (!\File::exists(base_path() . '/.env')) {
|
||||
if (!copy(base_path() . '/.env.example', base_path() . '/.env')) {
|
||||
abort(500, '复制环境文件失败,请检查目录权限');
|
||||
}
|
||||
}
|
||||
$this->saveToEnv([
|
||||
'APP_KEY' => 'base64:' . base64_encode(Encrypter::generateKey('AES-256-CBC')),
|
||||
'DB_HOST' => $this->ask('请输入数据库地址(默认:localhost)', 'localhost'),
|
||||
'DB_DATABASE' => $this->ask('请输入数据库名'),
|
||||
'DB_USERNAME' => $this->ask('请输入数据库用户名'),
|
||||
'DB_PASSWORD' => $this->ask('请输入数据库密码')
|
||||
]);
|
||||
\Artisan::call('config:clear');
|
||||
\Artisan::call('config:cache');
|
||||
try {
|
||||
DB::connection()->getPdo();
|
||||
} catch (\Exception $e) {
|
||||
abort(500, '数据库连接失败');
|
||||
}
|
||||
$file = \File::get(base_path() . '/database/install.sql');
|
||||
if (!$file) {
|
||||
abort(500, '数据库文件不存在');
|
||||
}
|
||||
$sql = str_replace("\n", "", $file);
|
||||
$sql = preg_split("/;/", $sql);
|
||||
if (!is_array($sql)) {
|
||||
abort(500, '数据库文件格式有误');
|
||||
}
|
||||
$this->info('正在导入数据库请稍等...');
|
||||
foreach ($sql as $item) {
|
||||
try {
|
||||
DB::select(DB::raw($item));
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
$this->info('数据库导入完成');
|
||||
$email = '';
|
||||
while (!$email) {
|
||||
$email = $this->ask('请输入管理员邮箱?');
|
||||
}
|
||||
$password = '';
|
||||
while (!$password) {
|
||||
$password = $this->ask('请输入管理员密码?');
|
||||
}
|
||||
if (!$this->registerAdmin($email, $password)) {
|
||||
abort(500, '管理员账号注册失败,请重试');
|
||||
}
|
||||
|
||||
$this->info('一切就绪');
|
||||
$this->info('访问 http(s)://你的站点/admin 进入管理面板');
|
||||
\File::put(base_path() . '/.lock', time());
|
||||
} catch (\Exception $e) {
|
||||
$this->error($e->getMessage());
|
||||
}
|
||||
\Artisan::call('key:generate');
|
||||
sleep(2);
|
||||
\Artisan::call('config:cache');
|
||||
DB::connection()->getPdo();
|
||||
$file = \File::get(base_path() . '/install.sql');
|
||||
if (!$file) {
|
||||
abort(500, '数据库文件不存在');
|
||||
}
|
||||
$sql = str_replace("\n", "", $file);
|
||||
$sql = preg_split("/;/", $sql);
|
||||
if (!is_array($sql)) {
|
||||
abort(500, '数据库文件格式有误');
|
||||
}
|
||||
$this->info('正在导入数据库请稍等...');
|
||||
foreach($sql as $item) {
|
||||
try {
|
||||
DB::select(DB::raw($item));
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
$email = '';
|
||||
while (!$email) {
|
||||
$email = $this->ask('请输入管理员邮箱?');
|
||||
}
|
||||
$password = '';
|
||||
while (!$password) {
|
||||
$password = $this->ask('请输入管理员密码?');
|
||||
}
|
||||
if (!$this->registerAdmin($email, $password)) {
|
||||
abort(500, '管理员账号注册失败,请重试');
|
||||
}
|
||||
|
||||
$this->info('一切就绪');
|
||||
\File::put(base_path() . '/.lock', time());
|
||||
}
|
||||
|
||||
private function registerAdmin ($email, $password) {
|
||||
|
||||
private function registerAdmin($email, $password)
|
||||
{
|
||||
$user = new User();
|
||||
$user->email = $email;
|
||||
if (strlen($password) < 8) {
|
||||
abort(500, '管理员密码长度最小为8位字符');
|
||||
}
|
||||
$user->password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$user->v2ray_uuid = Helper::guid(true);
|
||||
$user->token = Helper::guid();
|
||||
$user->is_admin = 1;
|
||||
return $user->save();
|
||||
}
|
||||
|
||||
private function saveToEnv($data = [])
|
||||
{
|
||||
function set_env_var($key, $value)
|
||||
{
|
||||
if (! is_bool(strpos($value, ' '))) {
|
||||
$value = '"' . $value . '"';
|
||||
}
|
||||
$key = strtoupper($key);
|
||||
|
||||
$envPath = app()->environmentFilePath();
|
||||
$contents = file_get_contents($envPath);
|
||||
|
||||
preg_match("/^{$key}=[^\r\n]*/m", $contents, $matches);
|
||||
|
||||
$oldValue = count($matches) ? $matches[0] : '';
|
||||
|
||||
if ($oldValue) {
|
||||
$contents = str_replace("{$oldValue}", "{$key}={$value}", $contents);
|
||||
} else {
|
||||
$contents = $contents . "\n{$key}={$value}\n";
|
||||
}
|
||||
|
||||
$file = fopen($envPath, 'w');
|
||||
fwrite($file, $contents);
|
||||
return fclose($file);
|
||||
}
|
||||
foreach($data as $key => $value) {
|
||||
set_env_var($key, $value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -39,22 +39,23 @@ class V2boardUpdate extends Command
|
||||
public function handle()
|
||||
{
|
||||
\Artisan::call('config:cache');
|
||||
DB::connection()->getPdo();
|
||||
$file = \File::get(base_path() . '/update.sql');
|
||||
if (!$file) {
|
||||
abort(500, '数据库文件不存在');
|
||||
}
|
||||
$sql = str_replace("\n", "", $file);
|
||||
$sql = preg_split("/;/", $sql);
|
||||
if (!is_array($sql)) {
|
||||
abort(500, '数据库文件格式有误');
|
||||
DB::connection()->getPdo();
|
||||
$file = \File::get(base_path() . '/database/update.sql');
|
||||
if (!$file) {
|
||||
abort(500, '数据库文件不存在');
|
||||
}
|
||||
$sql = str_replace("\n", "", $file);
|
||||
$sql = preg_split("/;/", $sql);
|
||||
if (!is_array($sql)) {
|
||||
abort(500, '数据库文件格式有误');
|
||||
}
|
||||
$this->info('正在导入数据库请稍等...');
|
||||
foreach($sql as $item) {
|
||||
try {
|
||||
DB::select(DB::raw($item));
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
foreach ($sql as $item) {
|
||||
try {
|
||||
DB::select(DB::raw($item));
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
$this->info('更新完毕');
|
||||
}
|
||||
}
|
||||
|
@ -19,22 +19,21 @@ class Kernel extends ConsoleKernel
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
*
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
* @return void
|
||||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
// check order
|
||||
// v2board
|
||||
$schedule->command('v2board:cache')->hourly();
|
||||
// check
|
||||
$schedule->command('check:order')->everyMinute();
|
||||
// check expire
|
||||
$schedule->command('check:expire')->everyMinute();
|
||||
// check commission
|
||||
$schedule->command('check:commission')->everyMinute();
|
||||
// system cache
|
||||
$schedule->command('system:cache')->hourly();
|
||||
// reset
|
||||
$schedule->command('reset:traffic')->monthlyOn(1, '00:00');
|
||||
$schedule->command('reset:serverLog')->monthlyOn(1, '00:00');
|
||||
$schedule->command('reset:traffic')->daily();
|
||||
$schedule->command('reset:serverLog')->monthly();
|
||||
// send
|
||||
$schedule->command('send:remindMail')->dailyAt('11:30');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,7 +43,7 @@ class Kernel extends ConsoleKernel
|
||||
*/
|
||||
protected function commands()
|
||||
{
|
||||
$this->load(__DIR__.'/Commands');
|
||||
$this->load(__DIR__ . '/Commands');
|
||||
|
||||
require base_path('routes/console.php');
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class Handler extends ExceptionHandler
|
||||
/**
|
||||
* Report or log an exception.
|
||||
*
|
||||
* @param \Exception $exception
|
||||
* @param \Exception $exception
|
||||
* @return void
|
||||
*/
|
||||
public function report(Exception $exception)
|
||||
@ -40,12 +40,15 @@ class Handler extends ExceptionHandler
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Exception $exception
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Exception $exception
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function render($request, Exception $exception)
|
||||
{
|
||||
if($exception instanceof \Illuminate\Http\Exceptions\ThrottleRequestsException) {
|
||||
abort(429, '请求频繁,请稍后再试');
|
||||
}
|
||||
return parent::render($request, $exception);
|
||||
}
|
||||
|
||||
|
@ -4,18 +4,14 @@ namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\Admin\ConfigSave;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Utils\Dict;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Plan;
|
||||
use App\Models\Order;
|
||||
use App\Models\User;
|
||||
|
||||
class ConfigController extends Controller
|
||||
{
|
||||
public function init () {
|
||||
|
||||
}
|
||||
|
||||
public function fetch () {
|
||||
public function fetch()
|
||||
{
|
||||
// TODO: default should be in Dict
|
||||
return response([
|
||||
'data' => [
|
||||
'invite' => [
|
||||
@ -25,13 +21,22 @@ class ConfigController extends Controller
|
||||
'invite_never_expire' => config('v2board.invite_never_expire', 0)
|
||||
],
|
||||
'site' => [
|
||||
'safe_mode_enable' => (int)config('v2board.safe_mode_enable', 0),
|
||||
'stop_register' => (int)config('v2board.stop_register', 0),
|
||||
'email_verify' => (int)config('v2board.email_verify', 0),
|
||||
'app_name' => config('v2board.app_name', 'V2Board'),
|
||||
'app_description' => config('v2board.app_description', 'V2Board is best!'),
|
||||
'app_url' => config('v2board.app_url'),
|
||||
'subscribe_url' => config('v2board.subscribe_url'),
|
||||
'plan_update_fee' => config('v2board.plan_update_fee', 0.5),
|
||||
'plan_is_update' => (int)config('v2board.plan_is_update', 1)
|
||||
'try_out_plan_id' => (int)config('v2board.try_out_plan_id', 0),
|
||||
'try_out_hour' => (int)config('v2board.try_out_hour', 1),
|
||||
'email_whitelist_enable' => (int)config('v2board.email_whitelist_enable', 0),
|
||||
'email_whitelist_suffix' => config('v2board.email_whitelist_suffix', Dict::EMAIL_WHITELIST_SUFFIX_DEFAULT)
|
||||
],
|
||||
'subscribe' => [
|
||||
'plan_change_enable' => (int)config('v2board.plan_change_enable', 1),
|
||||
'reset_traffic_method' => (int)config('v2board.reset_traffic_method', 0),
|
||||
'renew_reset_traffic_enable' => (int)config('v2board.renew_reset_traffic_enable', 1)
|
||||
],
|
||||
'pay' => [
|
||||
// alipay
|
||||
@ -45,12 +50,24 @@ class ConfigController extends Controller
|
||||
'stripe_alipay_enable' => (int)config('v2board.stripe_alipay_enable'),
|
||||
'stripe_wepay_enable' => (int)config('v2board.stripe_wepay_enable'),
|
||||
'stripe_webhook_key' => config('v2board.stripe_webhook_key'),
|
||||
'stripe_currency' => config('v2board.stripe_currency', 'hkd'),
|
||||
// bitpayx
|
||||
'bitpayx_enable' => config('v2board.bitpayx_enable'),
|
||||
'bitpayx_appsecret' => config('v2board.bitpayx_appsecret')
|
||||
'bitpayx_appsecret' => config('v2board.bitpayx_appsecret'),
|
||||
// paytaro
|
||||
'paytaro_enable' => config('v2board.paytaro_enable'),
|
||||
'paytaro_app_id' => config('v2board.paytaro_app_id'),
|
||||
'paytaro_app_secret' => config('v2board.paytaro_app_secret')
|
||||
],
|
||||
'frontend' => [
|
||||
'frontend_theme_sidebar' => config('v2board.frontend_theme_sidebar', 'light'),
|
||||
'frontend_theme_header' => config('v2board.frontend_theme_header', 'dark'),
|
||||
'frontend_theme_color' => config('v2board.frontend_theme_color', 'default'),
|
||||
'frontend_background_url' => config('v2board.frontend_background_url')
|
||||
],
|
||||
'server' => [
|
||||
'server_token' => config('v2board.server_token')
|
||||
'server_token' => config('v2board.server_token'),
|
||||
'server_license' => config('v2board.server_license')
|
||||
],
|
||||
'tutorial' => [
|
||||
'apple_id' => config('v2board.apple_id')
|
||||
@ -58,18 +75,19 @@ class ConfigController extends Controller
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function save (ConfigSave $request) {
|
||||
|
||||
public function save(ConfigSave $request)
|
||||
{
|
||||
$data = $request->input();
|
||||
$array = \Config::get('v2board');
|
||||
foreach ($data as $k => $v) {
|
||||
if (!in_array($k, ConfigSave::filter())) {
|
||||
abort(500, '禁止修改');
|
||||
if (!in_array($k, array_keys(ConfigSave::RULES))) {
|
||||
abort(500, '参数' . $k . '不在规则内,禁止修改');
|
||||
}
|
||||
$array[$k] = $v;
|
||||
}
|
||||
$data = var_export($array, 1);
|
||||
if(!\File::put(base_path() . '/config/v2board.php', "<?php\n return $data ;")) {
|
||||
if (!\File::put(base_path() . '/config/v2board.php', "<?php\n return $data ;")) {
|
||||
abort(500, '修改失败');
|
||||
}
|
||||
\Artisan::call('config:cache');
|
||||
|
64
app/Http/Controllers/Admin/CouponController.php
Normal file
64
app/Http/Controllers/Admin/CouponController.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\Admin\CouponSave;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Coupon;
|
||||
use App\Utils\Helper;
|
||||
|
||||
class CouponController extends Controller
|
||||
{
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
return response([
|
||||
'data' => Coupon::all()
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(CouponSave $request)
|
||||
{
|
||||
$params = $request->only([
|
||||
'name',
|
||||
'type',
|
||||
'value',
|
||||
'started_at',
|
||||
'ended_at',
|
||||
'limit_use'
|
||||
]);
|
||||
|
||||
if (!$request->input('id')) {
|
||||
$params['code'] = Helper::randomChar(8);
|
||||
if (!Coupon::create($params)) {
|
||||
abort(500, '创建失败');
|
||||
}
|
||||
} else {
|
||||
if (!Coupon::find($request->input('id'))->update($params)) {
|
||||
abort(500, '保存失败');
|
||||
}
|
||||
}
|
||||
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
public function drop(Request $request)
|
||||
{
|
||||
if (empty($request->input('id'))) {
|
||||
abort(500, '参数有误');
|
||||
}
|
||||
$coupon = Coupon::find($request->input('id'));
|
||||
if (!$coupon) {
|
||||
abort(500, '优惠券不存在');
|
||||
}
|
||||
if (!$coupon->delete()) {
|
||||
abort(500, '删除失败');
|
||||
}
|
||||
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
}
|
47
app/Http/Controllers/Admin/MailController.php
Normal file
47
app/Http/Controllers/Admin/MailController.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\Admin\MailSend;
|
||||
use App\Services\UserService;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Jobs\SendEmail;
|
||||
|
||||
class MailController extends Controller
|
||||
{
|
||||
public function send(MailSend $request)
|
||||
{
|
||||
$userService = new UserService();
|
||||
$users = [];
|
||||
switch ($request->input('type')) {
|
||||
case 1: $users = $userService->getAllUsers();
|
||||
break;
|
||||
case 2: $users = $userService->getUsersByIds($request->input('receiver'));
|
||||
break;
|
||||
// available users
|
||||
case 3: $users = $userService->getAvailableUsers();
|
||||
break;
|
||||
// un available users
|
||||
case 4: $users = $userService->getUnAvailbaleUsers();
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($users as $user) {
|
||||
SendEmail::dispatch([
|
||||
'email' => $user->email,
|
||||
'subject' => $request->input('subject'),
|
||||
'template_name' => 'mail.sendEmailCustom',
|
||||
'template_value' => [
|
||||
'name' => config('v2board.app_name', 'V2Board'),
|
||||
'url' => config('v2board.app_url'),
|
||||
'content' => $request->input('content')
|
||||
]
|
||||
])->onQueue('other_mail');
|
||||
}
|
||||
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
}
|
@ -6,45 +6,40 @@ use App\Http\Requests\Admin\NoticeSave;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Notice;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class NoticeController extends Controller
|
||||
{
|
||||
public function fetch (Request $request) {
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
return response([
|
||||
'data' => Notice::orderBy('id', 'DESC')->get()
|
||||
]);
|
||||
}
|
||||
|
||||
public function save (NoticeSave $request) {
|
||||
public function save(NoticeSave $request)
|
||||
{
|
||||
$data = $request->only([
|
||||
'title',
|
||||
'content',
|
||||
'img_url'
|
||||
]);
|
||||
if (!Notice::create($data)) {
|
||||
abort(500, '保存失败');
|
||||
if (!$request->input('id')) {
|
||||
if (!Notice::create($data)) {
|
||||
abort(500, '保存失败');
|
||||
}
|
||||
} else {
|
||||
if (!Notice::find($request->input('id'))->update($data)) {
|
||||
abort(500, '保存失败');
|
||||
}
|
||||
}
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
public function update (NoticeSave $request) {
|
||||
$data = $request->only([
|
||||
'title',
|
||||
'content',
|
||||
'img_url'
|
||||
]);
|
||||
if (!Notice::where('id', $request->input('id'))->update($data)) {
|
||||
abort(500, '保存失败');
|
||||
}
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
public function drop (Request $request) {
|
||||
public function drop(Request $request)
|
||||
{
|
||||
if (empty($request->input('id'))) {
|
||||
abort(500, '参数错误');
|
||||
}
|
||||
|
@ -11,7 +11,8 @@ use App\Models\Plan;
|
||||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
public function fetch (Request $request) {
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
$current = $request->input('current') ? $request->input('current') : 1;
|
||||
$pageSize = $request->input('pageSize') >= 10 ? $request->input('pageSize') : 10;
|
||||
$orderModel = Order::orderBy('created_at', 'DESC');
|
||||
@ -25,6 +26,9 @@ class OrderController extends Controller
|
||||
if ($request->input('id')) {
|
||||
$orderModel->where('id', $request->input('id'));
|
||||
}
|
||||
if ($request->input('user_id')) {
|
||||
$orderModel->where('user_id', $request->input('user_id'));
|
||||
}
|
||||
$total = $orderModel->count();
|
||||
$res = $orderModel->forPage($current, $pageSize)
|
||||
->get();
|
||||
@ -42,7 +46,8 @@ class OrderController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function update (OrderUpdate $request) {
|
||||
public function update(OrderUpdate $request)
|
||||
{
|
||||
$updateData = $request->only([
|
||||
'status',
|
||||
'commission_status'
|
||||
@ -63,7 +68,8 @@ class OrderController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function repair (Request $request) {
|
||||
public function repair(Request $request)
|
||||
{
|
||||
if (empty($request->input('trade_no'))) {
|
||||
abort(500, '参数错误');
|
||||
}
|
||||
|
@ -9,42 +9,54 @@ use App\Http\Controllers\Controller;
|
||||
use App\Models\Plan;
|
||||
use App\Models\Order;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class PlanController extends Controller
|
||||
{
|
||||
public function fetch (Request $request) {
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
return response([
|
||||
'data' => Plan::get()
|
||||
]);
|
||||
}
|
||||
|
||||
public function save (PlanSave $request) {
|
||||
|
||||
public function save(PlanSave $request)
|
||||
{
|
||||
$params = $request->only(array_keys(PlanSave::RULES));
|
||||
if ($request->input('id')) {
|
||||
$plan = Plan::find($request->input('id'));
|
||||
if (!$plan) {
|
||||
abort(500, '该订阅不存在');
|
||||
}
|
||||
} else {
|
||||
$plan = new Plan();
|
||||
DB::beginTransaction();
|
||||
if (isset($params->group_id) && ($params->group_id !== $plan->group_id)) {
|
||||
if (!User::where('plan_id', $plan->id)
|
||||
->get()
|
||||
->update(['group_id', $plan->group_id])
|
||||
) {
|
||||
DB::rollBack();
|
||||
abort(500, '保存失败');
|
||||
}
|
||||
}
|
||||
if (!$plan->update($params)) {
|
||||
DB::rollBack();
|
||||
abort(500, '保存失败');
|
||||
}
|
||||
DB::commit();
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
$plan->name = $request->input('name');
|
||||
$plan->content = $request->input('content');
|
||||
if ($plan->content) {
|
||||
$plan->content = str_replace(PHP_EOL, '', $plan->content);
|
||||
if (!Plan::create($params)) {
|
||||
abort(500, '创建失败');
|
||||
}
|
||||
$plan->transfer_enable = $request->input('transfer_enable');
|
||||
$plan->group_id = $request->input('group_id');
|
||||
$plan->month_price = $request->input('month_price');
|
||||
$plan->quarter_price = $request->input('quarter_price');
|
||||
$plan->half_year_price = $request->input('half_year_price');
|
||||
$plan->year_price = $request->input('year_price');
|
||||
|
||||
return response([
|
||||
'data' => $plan->save()
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
public function drop (Request $request) {
|
||||
|
||||
public function drop(Request $request)
|
||||
{
|
||||
if (Order::where('plan_id', $request->input('id'))->first()) {
|
||||
abort(500, '该订阅下存在订单无法删除');
|
||||
}
|
||||
@ -62,12 +74,13 @@ class PlanController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function update (PlanUpdate $request) {
|
||||
public function update(PlanUpdate $request)
|
||||
{
|
||||
$updateData = $request->only([
|
||||
'show',
|
||||
'renew'
|
||||
]);
|
||||
|
||||
|
||||
$plan = Plan::find($request->input('id'));
|
||||
if (!$plan) {
|
||||
abort(500, '该订阅不存在');
|
||||
|
@ -10,54 +10,72 @@ use App\Models\ServerGroup;
|
||||
use App\Models\Server;
|
||||
use App\Models\Plan;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class ServerController extends Controller
|
||||
{
|
||||
public function fetch (Request $request) {
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
$server = Server::get();
|
||||
for ($i = 0; $i < count($server); $i++) {
|
||||
if (!empty($server[$i]['tags'])) {
|
||||
$server[$i]['tags'] = json_decode($server[$i]['tags']);
|
||||
}
|
||||
$server[$i]['group_id'] = json_decode($server[$i]['group_id']);
|
||||
$server[$i]['last_check_at'] = Redis::get('server_last_check_at_' . $server[$i]['id']);
|
||||
if ($server[$i]['parent_id']) {
|
||||
$server[$i]['last_check_at'] = Cache::get('server_last_check_at_' . $server[$i]['parent_id']);
|
||||
} else {
|
||||
$server[$i]['last_check_at'] = Cache::get('server_last_check_at_' . $server[$i]['id']);
|
||||
}
|
||||
}
|
||||
return response([
|
||||
'data' => $server
|
||||
]);
|
||||
}
|
||||
|
||||
public function save (ServerSave $request) {
|
||||
|
||||
public function save(ServerSave $request)
|
||||
{
|
||||
$params = $request->only(array_keys(ServerSave::RULES));
|
||||
$params['group_id'] = json_encode($params['group_id']);
|
||||
if (isset($params['tags'])) {
|
||||
$params['tags'] = json_encode($params['tags']);
|
||||
}
|
||||
if (isset($params['rules'])) {
|
||||
if (!is_object(json_decode($params['rules']))) {
|
||||
abort(500, '审计规则配置格式不正确');
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($params['settings'])) {
|
||||
if (!is_object(json_decode($params['settings']))) {
|
||||
abort(500, '传输协议配置格式不正确');
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->input('id')) {
|
||||
$server = Server::find($request->input('id'));
|
||||
if (!$server) {
|
||||
abort(500, '服务器不存在');
|
||||
}
|
||||
} else {
|
||||
$server = new Server();
|
||||
}
|
||||
$server->group_id = json_encode($request->input('group_id'));
|
||||
$server->name = $request->input('name');
|
||||
$server->host = $request->input('host');
|
||||
$server->port = $request->input('port');
|
||||
$server->server_port = $request->input('server_port');
|
||||
$server->tls = $request->input('tls');
|
||||
$server->tags = $request->input('tags') ? json_encode($request->input('tags')) : NULL;
|
||||
$server->rate = $request->input('rate');
|
||||
$server->network = $request->input('network');
|
||||
if ($request->input('settings')) {
|
||||
if (!is_object(json_decode($request->input('settings')))) {
|
||||
abort(500, '传输协议配置格式不正确');
|
||||
if (!$server->update($params)) {
|
||||
abort(500, '保存失败');
|
||||
}
|
||||
$server->settings = $request->input('settings');
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
if (!Server::create($params)) {
|
||||
abort(500, '创建失败');
|
||||
}
|
||||
|
||||
return response([
|
||||
'data' => $server->save()
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
public function groupFetch (Request $request) {
|
||||
|
||||
public function groupFetch(Request $request)
|
||||
{
|
||||
if ($request->input('group_id')) {
|
||||
return response([
|
||||
'data' => [ServerGroup::find($request->input('group_id'))]
|
||||
@ -68,11 +86,12 @@ class ServerController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function groupSave (Request $request) {
|
||||
public function groupSave(Request $request)
|
||||
{
|
||||
if (empty($request->input('name'))) {
|
||||
abort(500, '组名不能为空');
|
||||
}
|
||||
|
||||
|
||||
if ($request->input('id')) {
|
||||
$serverGroup = ServerGroup::find($request->input('id'));
|
||||
} else {
|
||||
@ -85,7 +104,8 @@ class ServerController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function groupDrop (Request $request) {
|
||||
public function groupDrop(Request $request)
|
||||
{
|
||||
if ($request->input('id')) {
|
||||
$serverGroup = ServerGroup::find($request->input('id'));
|
||||
if (!$serverGroup) {
|
||||
@ -111,8 +131,9 @@ class ServerController extends Controller
|
||||
'data' => $serverGroup->delete()
|
||||
]);
|
||||
}
|
||||
|
||||
public function drop (Request $request) {
|
||||
|
||||
public function drop(Request $request)
|
||||
{
|
||||
if ($request->input('id')) {
|
||||
$server = Server::find($request->input('id'));
|
||||
if (!$server) {
|
||||
@ -124,16 +145,18 @@ class ServerController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function update (ServerUpdate $request) {
|
||||
$updateData = $request->only([
|
||||
public function update(ServerUpdate $request)
|
||||
{
|
||||
$params = $request->only([
|
||||
'show',
|
||||
]);
|
||||
|
||||
|
||||
$server = Server::find($request->input('id'));
|
||||
|
||||
if (!$server) {
|
||||
abort(500, '该服务器不存在');
|
||||
}
|
||||
if (!$server->update($updateData)) {
|
||||
if (!$server->update($params)) {
|
||||
abort(500, '保存失败');
|
||||
}
|
||||
|
||||
|
@ -10,22 +10,27 @@ use App\Models\Plan;
|
||||
use App\Models\User;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\Order;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class StatController extends Controller
|
||||
{
|
||||
public function getOverride (Request $request) {
|
||||
public function getOverride(Request $request)
|
||||
{
|
||||
return response([
|
||||
'data' => [
|
||||
'month_income' => Redis::get('month_income'),
|
||||
'month_register_total' => Redis::get('month_register_total'),
|
||||
'month_income' => Order::where('created_at', '>=', strtotime(date('Y-m-1')))
|
||||
->where('created_at', '<', time())
|
||||
->where('status', '3')
|
||||
->sum('total_amount'),
|
||||
'month_register_total' => User::where('created_at', '>=', strtotime(date('Y-m-1')))
|
||||
->where('created_at', '<', time())
|
||||
->count(),
|
||||
'ticket_pendding_total' => Ticket::where('status', 0)
|
||||
->count(),
|
||||
'commission_pendding_total' => Order::where('commission_status', 0)
|
||||
->where('invite_user_id', '!=', NULL)
|
||||
->where('status', 3)
|
||||
->count(),
|
||||
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
@ -10,7 +10,8 @@ use Illuminate\Support\Facades\DB;
|
||||
|
||||
class TicketController extends Controller
|
||||
{
|
||||
public function fetch (Request $request) {
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
if ($request->input('id')) {
|
||||
$ticket = Ticket::where('id', $request->input('id'))
|
||||
->first();
|
||||
@ -43,7 +44,8 @@ class TicketController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function reply (Request $request) {
|
||||
public function reply(Request $request)
|
||||
{
|
||||
if (empty($request->input('id'))) {
|
||||
abort(500, '参数错误');
|
||||
}
|
||||
@ -75,7 +77,8 @@ class TicketController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function close (Request $request) {
|
||||
public function close(Request $request)
|
||||
{
|
||||
if (empty($request->input('id'))) {
|
||||
abort(500, '参数错误');
|
||||
}
|
||||
|
74
app/Http/Controllers/Admin/TutorialController.php
Normal file
74
app/Http/Controllers/Admin/TutorialController.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\Admin\TutorialSave;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Tutorial;
|
||||
|
||||
class TutorialController extends Controller
|
||||
{
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
return response([
|
||||
'data' => Tutorial::get()
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(TutorialSave $request)
|
||||
{
|
||||
$params = $request->only(array_keys(TutorialSave::RULES));
|
||||
|
||||
if (!$request->input('id')) {
|
||||
if (!Tutorial::create($params)) {
|
||||
abort(500, '创建失败');
|
||||
}
|
||||
} else {
|
||||
if (!Tutorial::find($request->input('id'))->update($params)) {
|
||||
abort(500, '保存失败');
|
||||
}
|
||||
}
|
||||
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(Request $request)
|
||||
{
|
||||
if (empty($request->input('id'))) {
|
||||
abort(500, '参数有误');
|
||||
}
|
||||
$tutorial = Tutorial::find($request->input('id'));
|
||||
if (!$tutorial) {
|
||||
abort(500, '教程不存在');
|
||||
}
|
||||
$tutorial->show = $tutorial->show ? 0 : 1;
|
||||
if (!$tutorial->save()) {
|
||||
abort(500, '保存失败');
|
||||
}
|
||||
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
public function drop(Request $request)
|
||||
{
|
||||
if (empty($request->input('id'))) {
|
||||
abort(500, '参数有误');
|
||||
}
|
||||
$tutorial = Tutorial::find($request->input('id'));
|
||||
if (!$tutorial) {
|
||||
abort(500, '教程不存在');
|
||||
}
|
||||
if (!$tutorial->delete()) {
|
||||
abort(500, '删除失败');
|
||||
}
|
||||
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
}
|
@ -11,13 +11,19 @@ use App\Models\Plan;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function fetch (Request $request) {
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
$current = $request->input('current') ? $request->input('current') : 1;
|
||||
$pageSize = $request->input('pageSize') >= 10 ? $request->input('pageSize') : 10;
|
||||
$userModel = User::orderBy('created_at', 'DESC');
|
||||
$sortType = in_array($request->input('sort_type'), ['ASC', 'DESC']) ? $request->input('sort_type') : 'DESC';
|
||||
$sort = $request->input('sort') ? $request->input('sort') : 'created_at';
|
||||
$userModel = User::orderBy($sort, $sortType);
|
||||
if ($request->input('email')) {
|
||||
$userModel->where('email', $request->input('email'));
|
||||
}
|
||||
if ($request->input('invite_user_id')) {
|
||||
$userModel->where('invite_user_id', $request->input('invite_user_id'));
|
||||
}
|
||||
$total = $userModel->count();
|
||||
$res = $userModel->forPage($current, $pageSize)
|
||||
->get();
|
||||
@ -35,8 +41,9 @@ class UserController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function id2UserInfo ($id) {
|
||||
if (empty($id)) {
|
||||
public function getUserInfoById(Request $request)
|
||||
{
|
||||
if (empty($request->input('id'))) {
|
||||
abort(500, '参数错误');
|
||||
}
|
||||
return response([
|
||||
@ -46,42 +53,33 @@ class UserController extends Controller
|
||||
'd',
|
||||
'transfer_enable',
|
||||
'expired_at'
|
||||
])->find($id)
|
||||
])->find($request->input('id'))
|
||||
]);
|
||||
}
|
||||
|
||||
public function update (UserUpdate $request) {
|
||||
$updateData = $request->only([
|
||||
'email',
|
||||
'password',
|
||||
'transfer_enable',
|
||||
'expired_at',
|
||||
'banned',
|
||||
'plan_id',
|
||||
'commission_rate',
|
||||
'is_admin'
|
||||
]);
|
||||
public function update(UserUpdate $request)
|
||||
{
|
||||
$params = $request->only(array_keys(UserUpdate::RULES));
|
||||
$user = User::find($request->input('id'));
|
||||
if (!$user) {
|
||||
abort(500, '用户不存在');
|
||||
}
|
||||
if (User::where('email', $updateData['email'])->first() && $user->email !== $updateData['email']) {
|
||||
if (User::where('email', $params['email'])->first() && $user->email !== $params['email']) {
|
||||
abort(500, '邮箱已被使用');
|
||||
}
|
||||
if (isset($updateData['password'])) {
|
||||
$updateData['password'] = password_hash($updateData['password'], PASSWORD_DEFAULT);
|
||||
if (isset($params['password'])) {
|
||||
$params['password'] = password_hash($params['password'], PASSWORD_DEFAULT);
|
||||
} else {
|
||||
unset($updateData['password']);
|
||||
unset($params['password']);
|
||||
}
|
||||
$updateData['transfer_enable'] = $updateData['transfer_enable'] * 1073741824;
|
||||
if (isset($updateData['plan_id'])) {
|
||||
$plan = Plan::find($updateData['plan_id']);
|
||||
if (isset($params['plan_id'])) {
|
||||
$plan = Plan::find($params['plan_id']);
|
||||
if (!$plan) {
|
||||
abort(500, '订阅计划不存在');
|
||||
}
|
||||
$updateData['group_id'] = $plan->group_id;
|
||||
$params['group_id'] = $plan->group_id;
|
||||
}
|
||||
if (!$user->update($updateData)) {
|
||||
if (!$user->update($params)) {
|
||||
abort(500, '保存失败');
|
||||
}
|
||||
return response([
|
||||
|
@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
namespace App\Http\Controllers\Client;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\User;
|
||||
use App\Models\Plan;
|
||||
use App\Models\Server;
|
||||
@ -12,11 +12,13 @@ use App\Utils\Helper;
|
||||
|
||||
class AppController extends Controller
|
||||
{
|
||||
CONST CLIENT_CONFIG = '{"policy":{"levels":{"0":{"uplinkOnly":0}}},"dns":{"servers":["114.114.114.114","8.8.8.8"]},"outboundDetour":[{"protocol":"freedom","tag":"direct","settings":{}}],"inbound":{"listen":"0.0.0.0","port":31211,"protocol":"socks","settings":{"auth":"noauth","udp":true,"ip":"127.0.0.1"}},"inboundDetour":[{"listen":"0.0.0.0","allocate":{"strategy":"always","refresh":5,"concurrency":3},"port":31210,"protocol":"http","tag":"httpDetour","domainOverride":["http","tls"],"streamSettings":{},"settings":{"timeout":0}}],"routing":{"strategy":"rules","settings":{"domainStrategy":"IPIfNonMatch","rules":[{"port":"1-52","type":"field","outboundTag":"direct"},{"port":"54-79","type":"field","outboundTag":"direct"},{"port":"81-442","type":"field","outboundTag":"direct"},{"port":"444-65535","type":"field","outboundTag":"direct"},{"type":"field","ip":["0.0.0.0/8","10.0.0.0/8","100.64.0.0/10","127.0.0.0/8","169.254.0.0/16","172.16.0.0/12","192.0.0.0/24","192.0.2.0/24","192.168.0.0/16","198.18.0.0/15","198.51.100.0/24","203.0.113.0/24","::1/128","fc00::/7","fe80::/10"],"outboundTag":"direct"},{"type":"field","ip":["geoip:cn"],"outboundTag":"direct"}]}},"outbound":{"tag":"proxy","sendThrough":"0.0.0.0","mux":{"enabled":false,"concurrency":8},"protocol":"vmess","settings":{"vnext":[{"address":"server","port":443,"users":[{"id":"uuid","alterId":2,"security":"auto","level":0}],"remark":"remark"}]},"streamSettings":{"network":"tcp","tcpSettings":{"header":{"type":"none"}},"security":"none","tlsSettings":{"allowInsecure":true,"allowInsecureCiphers":true},"kcpSettings":{"header":{"type":"none"},"mtu":1350,"congestion":false,"tti":20,"uplinkCapacity":5,"writeBufferSize":1,"readBufferSize":1,"downlinkCapacity":20},"wsSettings":{"path":"","headers":{"Host":"server.cc"}}}}}';
|
||||
CONST CLIENT_CONFIG = '{"policy":{"levels":{"0":{"uplinkOnly":0}}},"dns":{"servers":["114.114.114.114","8.8.8.8"]},"outboundDetour":[{"protocol":"freedom","tag":"direct","settings":{}}],"inbound":{"listen":"0.0.0.0","port":31211,"protocol":"socks","settings":{"auth":"noauth","udp":true,"ip":"127.0.0.1"}},"inboundDetour":[{"listen":"0.0.0.0","allocate":{"strategy":"always","refresh":5,"concurrency":3},"port":31210,"protocol":"http","tag":"httpDetour","domainOverride":["http","tls"],"streamSettings":{},"settings":{"timeout":0}}],"routing":{"strategy":"rules","settings":{"domainStrategy":"IPIfNonMatch","rules":[{"type":"field","ip":["geoip:cn"],"outboundTag":"direct"},{"type":"field","ip":["0.0.0.0/8","10.0.0.0/8","100.64.0.0/10","127.0.0.0/8","169.254.0.0/16","172.16.0.0/12","192.0.0.0/24","192.0.2.0/24","192.168.0.0/16","198.18.0.0/15","198.51.100.0/24","203.0.113.0/24","::1/128","fc00::/7","fe80::/10"],"outboundTag":"direct"}]}},"outbound":{"tag":"proxy","sendThrough":"0.0.0.0","mux":{"enabled":false,"concurrency":8},"protocol":"vmess","settings":{"vnext":[{"address":"server","port":443,"users":[{"id":"uuid","alterId":2,"security":"auto","level":0}],"remark":"remark"}]},"streamSettings":{"network":"tcp","tcpSettings":{"header":{"type":"none"}},"security":"none","tlsSettings":{"allowInsecure":true,"allowInsecureCiphers":true},"kcpSettings":{"header":{"type":"none"},"mtu":1350,"congestion":false,"tti":20,"uplinkCapacity":5,"writeBufferSize":1,"readBufferSize":1,"downlinkCapacity":20},"wsSettings":{"path":"","headers":{"Host":"server.cc"}}}}}';
|
||||
CONST SOCKS_PORT = 10010;
|
||||
CONST HTTP_PORT = 10011;
|
||||
|
||||
public function data (Request $request) {
|
||||
// TODO: 1.1.1 abolish
|
||||
public function data(Request $request)
|
||||
{
|
||||
$user = $request->user;
|
||||
$nodes = [];
|
||||
if ($user->plan_id) {
|
||||
@ -49,7 +51,8 @@ class AppController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function config (Request $request) {
|
||||
public function config(Request $request)
|
||||
{
|
||||
if (empty($request->input('server_id'))) {
|
||||
abort(500, '参数错误');
|
||||
}
|
||||
@ -77,22 +80,28 @@ class AppController extends Controller
|
||||
$json->outbound->streamSettings->network = $server->network;
|
||||
if ($server->settings) {
|
||||
switch ($server->network) {
|
||||
case 'tcp': $json->outbound->streamSettings->tcpSettings = json_decode($server->settings);
|
||||
case 'tcp':
|
||||
$json->outbound->streamSettings->tcpSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'kcp': $json->outbound->streamSettings->kcpSettings = json_decode($server->settings);
|
||||
case 'kcp':
|
||||
$json->outbound->streamSettings->kcpSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'ws': $json->outbound->streamSettings->wsSettings = json_decode($server->settings);
|
||||
case 'ws':
|
||||
$json->outbound->streamSettings->wsSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'http': $json->outbound->streamSettings->httpSettings = json_decode($server->settings);
|
||||
case 'http':
|
||||
$json->outbound->streamSettings->httpSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'domainsocket': $json->outbound->streamSettings->dsSettings = json_decode($server->settings);
|
||||
case 'domainsocket':
|
||||
$json->outbound->streamSettings->dsSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'quic': $json->outbound->streamSettings->quicSettings = json_decode($server->settings);
|
||||
case 'quic':
|
||||
$json->outbound->streamSettings->quicSettings = json_decode($server->settings);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($request->input('is_global')) {
|
||||
$json->routing->settings->rules[5]->outboundTag = 'proxy';
|
||||
$json->routing->settings->rules[0]->outboundTag = 'proxy';
|
||||
}
|
||||
if ($server->tls) {
|
||||
$json->outbound->streamSettings->security = "tls";
|
171
app/Http/Controllers/Client/ClientController.php
Executable file
171
app/Http/Controllers/Client/ClientController.php
Executable file
@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Client;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Middleware\User;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Server;
|
||||
use App\Utils\Helper;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use App\Services\UserService;
|
||||
|
||||
class ClientController extends Controller
|
||||
{
|
||||
public function subscribe(Request $request)
|
||||
{
|
||||
$user = $request->user;
|
||||
$server = [];
|
||||
// account not expired and is not banned.
|
||||
$userService = new UserService();
|
||||
if ($userService->isAvailable($user)) {
|
||||
$servers = Server::where('show', 1)
|
||||
->orderBy('name')
|
||||
->get();
|
||||
foreach ($servers as $item) {
|
||||
$groupId = json_decode($item['group_id']);
|
||||
if (in_array($user->group_id, $groupId)) {
|
||||
array_push($server, $item);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($_SERVER['HTTP_USER_AGENT'])) {
|
||||
if (strpos($_SERVER['HTTP_USER_AGENT'], 'Quantumult%20X') !== false) {
|
||||
die($this->quantumultX($user, $server));
|
||||
}
|
||||
if (strpos($_SERVER['HTTP_USER_AGENT'], 'Quantumult') !== false) {
|
||||
die($this->quantumult($user, $server));
|
||||
}
|
||||
if (strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'clash') !== false) {
|
||||
die($this->clash($user, $server));
|
||||
}
|
||||
}
|
||||
die($this->origin($user, $server));
|
||||
}
|
||||
|
||||
private function quantumultX($user, $server)
|
||||
{
|
||||
$uri = '';
|
||||
foreach ($server as $item) {
|
||||
$uri .= "vmess=" . $item->host . ":" . $item->port . ", method=none, password=" . $user->v2ray_uuid . ", fast-open=false, udp-relay=false, tag=" . $item->name;
|
||||
if ($item->network == 'ws') {
|
||||
$uri .= ', obfs=ws';
|
||||
if ($item->settings) {
|
||||
$wsSettings = json_decode($item->settings);
|
||||
if (isset($wsSettings->path)) $uri .= ', obfs-uri=' . $wsSettings->path;
|
||||
if (isset($wsSettings->headers->Host)) $uri .= ', obfs-host=' . $wsSettings->headers->Host;
|
||||
}
|
||||
}
|
||||
$uri .= "\r\n";
|
||||
}
|
||||
return base64_encode($uri);
|
||||
}
|
||||
|
||||
private function quantumult($user, $server)
|
||||
{
|
||||
$uri = '';
|
||||
header('subscription-userinfo: upload=' . $user->u . '; download=' . $user->d . ';total=' . $user->transfer_enable);
|
||||
foreach ($server as $item) {
|
||||
$str = '';
|
||||
$str .= $item->name . '= vmess, ' . $item->host . ', ' . $item->port . ', chacha20-ietf-poly1305, "' . $user->v2ray_uuid . '", over-tls=' . ($item->tls ? "true" : "false") . ', certificate=0, group=' . config('v2board.app_name', 'V2Board');
|
||||
if ($item->network === 'ws') {
|
||||
$str .= ', obfs=ws';
|
||||
if ($item->settings) {
|
||||
$wsSettings = json_decode($item->settings);
|
||||
if (isset($wsSettings->path)) $str .= ', obfs-path="' . $wsSettings->path . '"';
|
||||
if (isset($wsSettings->headers->Host)) $str .= ', obfs-header="Host:' . $wsSettings->headers->Host . '"';
|
||||
}
|
||||
}
|
||||
$uri .= "vmess://" . base64_encode($str) . "\r\n";
|
||||
}
|
||||
return base64_encode($uri);
|
||||
}
|
||||
|
||||
private function origin($user, $server)
|
||||
{
|
||||
$uri = '';
|
||||
foreach ($server as $item) {
|
||||
$uri .= Helper::buildVmessLink($item, $user);
|
||||
}
|
||||
return base64_encode($uri);
|
||||
}
|
||||
|
||||
private function clash($user, $server)
|
||||
{
|
||||
$proxy = [];
|
||||
$proxyGroup = [];
|
||||
$proxies = [];
|
||||
$rules = [];
|
||||
foreach ($server as $item) {
|
||||
$array = [];
|
||||
$array['name'] = $item->name;
|
||||
$array['type'] = 'vmess';
|
||||
$array['server'] = $item->host;
|
||||
$array['port'] = $item->port;
|
||||
$array['uuid'] = $user->v2ray_uuid;
|
||||
$array['alterId'] = $user->v2ray_alter_id;
|
||||
$array['cipher'] = 'auto';
|
||||
if ($item->tls) {
|
||||
$array['tls'] = true;
|
||||
$array['skip-cert-verify'] = true;
|
||||
}
|
||||
if ($item->network == 'ws') {
|
||||
$array['network'] = $item->network;
|
||||
if ($item->settings) {
|
||||
$wsSettings = json_decode($item->settings);
|
||||
if (isset($wsSettings->path)) $array['ws-path'] = $wsSettings->path;
|
||||
if (isset($wsSettings->headers->Host)) $array['ws-headers'] = [
|
||||
'Host' => $wsSettings->headers->Host
|
||||
];
|
||||
}
|
||||
}
|
||||
array_push($proxy, $array);
|
||||
array_push($proxies, $item->name);
|
||||
}
|
||||
|
||||
array_push($proxyGroup, [
|
||||
'name' => 'auto',
|
||||
'type' => 'url-test',
|
||||
'proxies' => $proxies,
|
||||
'url' => 'https://www.bing.com',
|
||||
'interval' => 300
|
||||
]);
|
||||
array_push($proxyGroup, [
|
||||
'name' => 'fallback-auto',
|
||||
'type' => 'fallback',
|
||||
'proxies' => $proxies,
|
||||
'url' => 'https://www.bing.com',
|
||||
'interval' => 300
|
||||
]);
|
||||
array_push($proxyGroup, [
|
||||
'name' => 'select',
|
||||
'type' => 'select',
|
||||
'proxies' => array_merge($proxies, [
|
||||
'auto',
|
||||
'fallback-auto'
|
||||
])
|
||||
]);
|
||||
|
||||
try {
|
||||
$rules = [];
|
||||
foreach (glob(base_path() . '/resources/rules/' . '*.clash.yaml') as $file) {
|
||||
$rules = array_merge($rules, Yaml::parseFile($file)['Rule']);
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
$config = [
|
||||
'port' => 7890,
|
||||
'socks-port' => 7891,
|
||||
'allow-lan' => false,
|
||||
'mode' => 'Rule',
|
||||
'log-level' => 'info',
|
||||
'external-controller' => '0.0.0.0:9090',
|
||||
'secret' => '',
|
||||
'Proxy' => $proxy,
|
||||
'Proxy Group' => $proxyGroup,
|
||||
'Rule' => $rules
|
||||
];
|
||||
|
||||
return Yaml::dump($config);
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use App\Models\Plan;
|
||||
use App\Models\Server;
|
||||
use App\Utils\Helper;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class ClientController extends Controller
|
||||
{
|
||||
public function subscribe (Request $request) {
|
||||
$user = $request->user;
|
||||
$server = [];
|
||||
if ($user->expired_at > time()) {
|
||||
$servers = Server::where('show', 1)
|
||||
->orderBy('name')
|
||||
->get();
|
||||
foreach ($servers as $item) {
|
||||
$groupId = json_decode($item['group_id']);
|
||||
if (in_array($user->group_id, $groupId)) {
|
||||
array_push($server, $item);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isset($_SERVER['HTTP_USER_AGENT'])) {
|
||||
if(strpos($_SERVER['HTTP_USER_AGENT'], 'Quantumult%20X') !== false) {
|
||||
die($this->quantumultX($user, $server));
|
||||
}
|
||||
if(strpos($_SERVER['HTTP_USER_AGENT'], 'Quantumult') !== false) {
|
||||
die($this->quantumult($user, $server));
|
||||
}
|
||||
if(strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'clash') !== false) {
|
||||
die($this->clash($user, $server));
|
||||
}
|
||||
}
|
||||
die($this->origin($user, $server));
|
||||
}
|
||||
|
||||
private function quantumultX ($user, $server) {
|
||||
$uri = '';
|
||||
foreach($server as $item) {
|
||||
$uri .= "vmess=".$item->host.":".$item->port.", method=none, password=".$user->v2ray_uuid.", fast-open=false, udp-relay=false, tag=".$item->name;
|
||||
if ($item->network == 'ws') {
|
||||
$uri .= ', obfs=ws';
|
||||
if ($item->settings) {
|
||||
$wsSettings = json_decode($item->settings);
|
||||
if ($wsSettings->path) $uri .= ', obfs-uri='.$wsSettings->path;
|
||||
}
|
||||
}
|
||||
$uri .= "\r\n";
|
||||
}
|
||||
return base64_encode($uri);
|
||||
}
|
||||
|
||||
private function quantumult ($user, $server) {
|
||||
$uri = '';
|
||||
header('subscription-userinfo: upload='.$user->u.'; download='.$user->d.';total='.$user->transfer_enable);
|
||||
foreach($server as $item) {
|
||||
$str = '';
|
||||
$str .= $item->name.'= vmess, '.$item->host.', '.$item->port.', chacha20-ietf-poly1305, "'.$user->v2ray_uuid.'", over-tls='.($item->tls?"true":"false").', certificate=0, group='.config('v2board.app_name', 'V2Board');
|
||||
if ($item->network === 'ws') {
|
||||
$str .= ', obfs=ws';
|
||||
if ($item->settings) {
|
||||
$wsSettings = json_decode($item->settings);
|
||||
if ($wsSettings->path) $str .= ', obfs-path="'.$wsSettings->path.'"';
|
||||
if ($wsSettings->headers->Host) $str .= ', obfs-header="Host:'.$wsSettings->headers->Host.'"';
|
||||
}
|
||||
}
|
||||
$uri .= "vmess://".base64_encode($str)."\r\n";
|
||||
}
|
||||
return base64_encode($uri);
|
||||
}
|
||||
|
||||
private function origin ($user, $server) {
|
||||
$uri = '';
|
||||
foreach($server as $item) {
|
||||
$uri .= Helper::buildVmessLink($item, $user);
|
||||
}
|
||||
return base64_encode($uri);
|
||||
}
|
||||
|
||||
private function clash ($user, $server) {
|
||||
$proxy = [];
|
||||
$proxyGroup = [];
|
||||
$proxies = [];
|
||||
foreach ($server as $item) {
|
||||
$array = [];
|
||||
$array['name'] = $item->name;
|
||||
$array['type'] = 'vmess';
|
||||
$array['server'] = $item->host;
|
||||
$array['port'] = $item->port;
|
||||
$array['uuid'] = $user->v2ray_uuid;
|
||||
$array['alterId'] = $user->v2ray_alter_id;
|
||||
$array['cipher'] = 'auto';
|
||||
if ($item->tls) {
|
||||
$array['tls'] = true;
|
||||
}
|
||||
if ($item->network == 'ws') {
|
||||
$array['network'] = $item->network;
|
||||
if ($item->settings) {
|
||||
$wsSettings = json_decode($item->settings);
|
||||
if ($wsSettings->path) $array['ws-path'] = $wsSettings->path;
|
||||
if ($wsSettings->headers->Host) $array['ws-headers'] = [
|
||||
'Host' => $wsSettings->headers->Host
|
||||
];
|
||||
}
|
||||
}
|
||||
array_push($proxy, $array);
|
||||
array_push($proxies, $item->name);
|
||||
}
|
||||
array_push($proxyGroup, [
|
||||
'name' => config('v2board.app_name', 'V2Board'),
|
||||
'type' => 'select',
|
||||
'proxies' => $proxies
|
||||
]);
|
||||
|
||||
$config = [
|
||||
'port' => 7890,
|
||||
'socks-port' => 0,
|
||||
'allow-lan' => false,
|
||||
'mode' => 'Rule',
|
||||
'log-level' => 'info',
|
||||
'external-controller' => '0.0.0.0:9090',
|
||||
'secret' => '',
|
||||
'Proxy' => $proxy,
|
||||
'Proxy Group' => $proxyGroup,
|
||||
'Rule' => [
|
||||
'DOMAIN-SUFFIX,google.com,'.config('v2board.app_name', 'V2Board'),
|
||||
'DOMAIN-KEYWORD,google,'.config('v2board.app_name', 'V2Board'),
|
||||
'DOMAIN,google.com,'.config('v2board.app_name', 'V2Board'),
|
||||
'DOMAIN-SUFFIX,ad.com,REJECT',
|
||||
'IP-CIDR,127.0.0.0/8,DIRECT',
|
||||
'GEOIP,CN,DIRECT',
|
||||
'MATCH,'.config('v2board.app_name', 'V2Board')
|
||||
]
|
||||
];
|
||||
return Yaml::dump($config);
|
||||
}
|
||||
}
|
@ -7,12 +7,14 @@ use App\Http\Controllers\Controller;
|
||||
use App\Models\Order;
|
||||
use Omnipay\Omnipay;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Library\BitpayX;
|
||||
use Library\PayTaro;
|
||||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
public function alipayNotify (Request $request) {
|
||||
public function alipayNotify(Request $request)
|
||||
{
|
||||
Log::info('alipayNotifyData: ' . json_encode($_POST));
|
||||
$gateway = Omnipay::create('Alipay_AopF2F');
|
||||
$gateway->setSignType('RSA2'); //RSA/RSA2
|
||||
@ -24,8 +26,8 @@ class OrderController extends Controller
|
||||
try {
|
||||
/** @var \Omnipay\Alipay\Responses\AopCompletePurchaseResponse $response */
|
||||
$response = $request->send();
|
||||
|
||||
if($response->isPaid()){
|
||||
|
||||
if ($response->isPaid()) {
|
||||
/**
|
||||
* Payment is successful
|
||||
*/
|
||||
@ -34,7 +36,7 @@ class OrderController extends Controller
|
||||
}
|
||||
|
||||
die('success'); //The response should be 'success' only
|
||||
}else{
|
||||
} else {
|
||||
/**
|
||||
* Payment is not successful
|
||||
*/
|
||||
@ -48,7 +50,8 @@ class OrderController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
public function stripeNotify (Request $request) {
|
||||
public function stripeNotify(Request $request)
|
||||
{
|
||||
Log::info('stripeNotifyData: ' . json_encode($request->input()));
|
||||
|
||||
\Stripe\Stripe::setApiKey(config('v2board.stripe_sk_live'));
|
||||
@ -70,14 +73,14 @@ class OrderController extends Controller
|
||||
'source' => $source['id'],
|
||||
]);
|
||||
if ($charge['status'] == 'succeeded') {
|
||||
$trade_no = Redis::get($source['id']);
|
||||
$trade_no = Cache::get($source['id']);
|
||||
if (!$trade_no) {
|
||||
abort(500, 'redis is not found trade no by stripe source id');
|
||||
}
|
||||
if (!$this->handle($trade_no, $source['id'])) {
|
||||
abort(500, 'fail');
|
||||
}
|
||||
Redis::del($source['id']);
|
||||
Cache::forget($source['id']);
|
||||
die('success');
|
||||
}
|
||||
break;
|
||||
@ -86,7 +89,8 @@ class OrderController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
public function bitpayXNotify (Request $request) {
|
||||
public function bitpayXNotify(Request $request)
|
||||
{
|
||||
$inputString = file_get_contents('php://input', 'r');
|
||||
Log::info('bitpayXNotifyData: ' . $inputString);
|
||||
$inputStripped = str_replace(array("\r", "\n", "\t", "\v"), '', $inputString);
|
||||
@ -94,46 +98,50 @@ class OrderController extends Controller
|
||||
|
||||
$bitpayX = new BitpayX(config('v2board.bitpayx_appsecret'));
|
||||
$params = [
|
||||
'status' => $inputJSON['status'],
|
||||
'order_id' => $inputJSON['order_id'],
|
||||
'merchant_order_id' => $inputJSON['merchant_order_id'],
|
||||
'price_amount' => $inputJSON['price_amount'],
|
||||
'price_currency' => $inputJSON['price_currency'],
|
||||
'pay_amount' => $inputJSON['pay_amount'],
|
||||
'pay_currency' => $inputJSON['pay_currency'],
|
||||
'created_at_t' => $inputJSON['created_at_t']
|
||||
'status' => $inputJSON['status'],
|
||||
'order_id' => $inputJSON['order_id'],
|
||||
'merchant_order_id' => $inputJSON['merchant_order_id'],
|
||||
'price_amount' => $inputJSON['price_amount'],
|
||||
'price_currency' => $inputJSON['price_currency'],
|
||||
'pay_amount' => $inputJSON['pay_amount'],
|
||||
'pay_currency' => $inputJSON['pay_currency'],
|
||||
'created_at_t' => $inputJSON['created_at_t']
|
||||
];
|
||||
$strToSign = $bitpayX->prepareSignId($inputJSON['merchant_order_id']);
|
||||
if (!$bitpayX->verify($strToSign, $inputJSON['token'])) {
|
||||
die([
|
||||
'status' => 400,
|
||||
'error' => 'sign error'
|
||||
]);
|
||||
abort(500, 'sign error');
|
||||
}
|
||||
if ($params['status'] !== 'PAID') {
|
||||
die([
|
||||
'status' => 400,
|
||||
'error' => 'order is not paid'
|
||||
]);
|
||||
abort(500, 'order is not paid');
|
||||
}
|
||||
if (!$this->handle($params['merchant_order_id'], $params['order_id'])) {
|
||||
die([
|
||||
'status' => 400,
|
||||
'error' => 'order process fail'
|
||||
]);
|
||||
abort(500, 'order process fail');
|
||||
}
|
||||
die([
|
||||
'status' => 200
|
||||
]);
|
||||
die('success');
|
||||
}
|
||||
|
||||
private function handle ($tradeNo, $callbackNo) {
|
||||
public function payTaroNotify(Request $request)
|
||||
{
|
||||
Log::info('payTaroNotify: ' . json_encode($request->input()));
|
||||
|
||||
$payTaro = new PayTaro(config('v2board.paytaro_app_id'), config('v2board.paytaro_app_secret'));
|
||||
if (!$payTaro->verify($request->input())) {
|
||||
abort(500, 'fail');
|
||||
}
|
||||
if (!$this->handle($request->input('out_trade_no'), $request->input('trade_no'))) {
|
||||
abort(500, 'fail');
|
||||
}
|
||||
die('success');
|
||||
}
|
||||
|
||||
private function handle($tradeNo, $callbackNo)
|
||||
{
|
||||
$order = Order::where('trade_no', $tradeNo)->first();
|
||||
if (!$order) {
|
||||
abort(500, 'order is not found');
|
||||
}
|
||||
if ($order->status !== 0) {
|
||||
abort(500, 'order is paid');
|
||||
return true;
|
||||
}
|
||||
$order->status = 1;
|
||||
$order->callback_no = $callbackNo;
|
||||
|
@ -8,7 +8,8 @@ use App\Models\Plan;
|
||||
|
||||
class PlanController extends Controller
|
||||
{
|
||||
public function fetch (Request $request) {
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
$plan = Plan::where('show', 1)->get();
|
||||
return response([
|
||||
'data' => $plan
|
||||
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Notice;
|
||||
use App\Utils\Helper;
|
||||
|
||||
class NoticeController extends Controller
|
||||
{
|
||||
public function fetch (Request $request) {
|
||||
return response([
|
||||
'data' => Notice::orderBy('created_at', 'DESC')->first()
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,303 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\OrderSave;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\Order;
|
||||
use App\Models\Plan;
|
||||
use App\Models\User;
|
||||
use App\Utils\Helper;
|
||||
use Omnipay\Omnipay;
|
||||
use Stripe\Stripe;
|
||||
use Stripe\Source;
|
||||
use Library\BitpayX;
|
||||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
public function fetch (Request $request) {
|
||||
$order = Order::where('user_id', $request->session()->get('id'))
|
||||
->orderBy('created_at', 'DESC')
|
||||
->get();
|
||||
$plan = Plan::get();
|
||||
for($i = 0; $i < count($order); $i++) {
|
||||
for($x = 0; $x < count($plan); $x++) {
|
||||
if ($order[$i]['plan_id'] === $plan[$x]['id']) {
|
||||
$order[$i]['plan'] = $plan[$x];
|
||||
}
|
||||
}
|
||||
}
|
||||
return response([
|
||||
'data' => $order
|
||||
]);
|
||||
}
|
||||
|
||||
public function details (Request $request) {
|
||||
$order = Order::where('user_id', $request->session()->get('id'))
|
||||
->where('trade_no', $request->input('trade_no'))
|
||||
->first();
|
||||
if (!$order) {
|
||||
abort(500, '订单不存在');
|
||||
}
|
||||
$order['plan'] = Plan::find($order->plan_id);
|
||||
$order['update_fee'] = config('v2board.plan_update_fee', 0.5);
|
||||
if (!$order['plan']) {
|
||||
abort(500, '订阅不存在');
|
||||
}
|
||||
return response([
|
||||
'data' => $order
|
||||
]);
|
||||
}
|
||||
|
||||
public function save (OrderSave $request) {
|
||||
$plan = Plan::find($request->input('plan_id'));
|
||||
$user = User::find($request->session()->get('id'));
|
||||
|
||||
if (!$plan) {
|
||||
abort(500, '该订阅不存在');
|
||||
}
|
||||
|
||||
if (!($plan->show || $user->plan_id == $plan->id)) {
|
||||
abort(500, '该订阅已售罄');
|
||||
}
|
||||
|
||||
if (!$plan->show && !$plan->renew) {
|
||||
abort(500, '该订阅无法续费,请更换其他订阅');
|
||||
}
|
||||
|
||||
if (!(int)$plan[$request->input('cycle')]) {
|
||||
abort(500, '该订阅周期无法进行购买,请选择其他周期');
|
||||
}
|
||||
|
||||
$order = new Order();
|
||||
$order->user_id = $request->session()->get('id');
|
||||
$order->plan_id = $plan->id;
|
||||
$order->cycle = $request->input('cycle');
|
||||
$order->trade_no = Helper::guid();
|
||||
$order->total_amount = $plan[$request->input('cycle')];
|
||||
if ($user->expired_at > time() && $order->plan_id !== $user->plan_id) {
|
||||
$order->type = 3;
|
||||
if (!(int)config('v2board.plan_is_update', 1)) abort(500, '目前不允许更改订阅,请联系管理员');
|
||||
$order->total_amount = $order->total_amount + (ceil(($user->expired_at - time()) / 86400) * config('v2board.plan_update_fee', 0.5) * 100);
|
||||
} else if ($user->expired_at > time() && $order->plan_id == $user->plan_id) {
|
||||
$order->type = 2;
|
||||
} else {
|
||||
$order->type = 1;
|
||||
}
|
||||
if ($user->invite_user_id) {
|
||||
$order->invite_user_id = $user->invite_user_id;
|
||||
$inviter = User::find($user->invite_user_id);
|
||||
if ($inviter && $inviter->commission_rate) {
|
||||
$order->commission_balance = $order->total_amount * ($inviter->commission_rate / 100);
|
||||
} else {
|
||||
$order->commission_balance = $order->total_amount * (config('v2board.invite_commission', 10) / 100);
|
||||
}
|
||||
}
|
||||
if (!$order->save()) {
|
||||
abort(500, '订单创建失败');
|
||||
}
|
||||
|
||||
return response([
|
||||
'data' => $order->trade_no
|
||||
]);
|
||||
}
|
||||
|
||||
public function checkout (Request $request) {
|
||||
$tradeNo = $request->input('trade_no');
|
||||
$method = $request->input('method');
|
||||
$order = Order::where('trade_no', $tradeNo)
|
||||
->where('user_id', $request->session()->get('id'))
|
||||
->where('status', 0)
|
||||
->first();
|
||||
if (!$order) {
|
||||
abort(500, '订单不存在或已支付');
|
||||
}
|
||||
switch ($method) {
|
||||
// return type => 0: QRCode / 1: URL
|
||||
case 0:
|
||||
// alipayF2F
|
||||
if (!(int)config('v2board.alipay_enable')) {
|
||||
abort(500, '支付方式不可用');
|
||||
}
|
||||
return response([
|
||||
'type' => 0,
|
||||
'data' => $this->alipayF2F($tradeNo, $order->total_amount)
|
||||
]);
|
||||
case 2:
|
||||
// stripeAlipay
|
||||
if (!(int)config('v2board.stripe_alipay_enable')) {
|
||||
abort(500, '支付方式不可用');
|
||||
}
|
||||
return response([
|
||||
'type' => 1,
|
||||
'data' => $this->stripeAlipay($order)
|
||||
]);
|
||||
case 3:
|
||||
// stripeWepay
|
||||
if (!(int)config('v2board.stripe_wepay_enable')) {
|
||||
abort(500, '支付方式不可用');
|
||||
}
|
||||
return response([
|
||||
'type' => 0,
|
||||
'data' => $this->stripeWepay($order)
|
||||
]);
|
||||
case 4:
|
||||
// bitpayX
|
||||
if (!(int)config('v2board.bitpayx_enable')) {
|
||||
abort(500, '支付方式不可用');
|
||||
}
|
||||
return response([
|
||||
'type' => 1,
|
||||
'data' => $this->bitpayX($order)
|
||||
]);
|
||||
default:
|
||||
abort(500, '支付方式不存在');
|
||||
}
|
||||
}
|
||||
|
||||
public function check (Request $request) {
|
||||
$tradeNo = $request->input('trade_no');
|
||||
$order = Order::where('trade_no', $tradeNo)
|
||||
->where('user_id', $request->session()->get('id'))
|
||||
->first();
|
||||
if (!$order) {
|
||||
abort(500, '订单不存在');
|
||||
}
|
||||
return response([
|
||||
'data' => $order->status
|
||||
]);
|
||||
}
|
||||
|
||||
public function getPaymentMethod () {
|
||||
$data = [];
|
||||
if ((int)config('v2board.alipay_enable')) {
|
||||
$alipayF2F = new \StdClass();
|
||||
$alipayF2F->name = '支付宝';
|
||||
$alipayF2F->method = 0;
|
||||
$alipayF2F->icon = 'alipay';
|
||||
array_push($data, $alipayF2F);
|
||||
}
|
||||
|
||||
if ((int)config('v2board.stripe_alipay_enable')) {
|
||||
$stripeAlipay = new \StdClass();
|
||||
$stripeAlipay->name = '支付宝';
|
||||
$stripeAlipay->method = 2;
|
||||
$stripeAlipay->icon = 'alipay';
|
||||
array_push($data, $stripeAlipay);
|
||||
}
|
||||
|
||||
if ((int)config('v2board.stripe_wepay_enable')) {
|
||||
$stripeWepay = new \StdClass();
|
||||
$stripeWepay->name = '微信';
|
||||
$stripeWepay->method = 3;
|
||||
$stripeWepay->icon = 'wechat';
|
||||
array_push($data, $stripeWepay);
|
||||
}
|
||||
|
||||
if ((int)config('v2board.bitpayx_enable')) {
|
||||
$bitpayX = new \StdClass();
|
||||
$bitpayX->name = '虚拟货币';
|
||||
$bitpayX->method = 4;
|
||||
$bitpayX->icon = 'bitcoin';
|
||||
array_push($data, $bitpayX);
|
||||
}
|
||||
|
||||
return response([
|
||||
'data' => $data
|
||||
]);
|
||||
}
|
||||
|
||||
private function alipayF2F ($tradeNo, $totalAmount) {
|
||||
$gateway = Omnipay::create('Alipay_AopF2F');
|
||||
$gateway->setSignType('RSA2'); //RSA/RSA2
|
||||
$gateway->setAppId(config('v2board.alipay_appid'));
|
||||
$gateway->setPrivateKey(config('v2board.alipay_privkey')); // 可以是路径,也可以是密钥内容
|
||||
$gateway->setAlipayPublicKey(config('v2board.alipay_pubkey')); // 可以是路径,也可以是密钥内容
|
||||
$gateway->setNotifyUrl(url('/api/v1/guest/order/alipayNotify'));
|
||||
$request = $gateway->purchase();
|
||||
$request->setBizContent([
|
||||
'subject' => config('v2board.app_name', 'V2Board') . ' - 订阅',
|
||||
'out_trade_no' => $tradeNo,
|
||||
'total_amount' => $totalAmount / 100
|
||||
]);
|
||||
/** @var \Omnipay\Alipay\Responses\AopTradePreCreateResponse $response */
|
||||
$response = $request->send();
|
||||
$result = $response->getAlipayResponse();
|
||||
if ($result['code'] !== '10000') {
|
||||
abort(500, $result['sub_msg']);
|
||||
}
|
||||
// 获取收款二维码内容
|
||||
return $response->getQrCode();
|
||||
}
|
||||
|
||||
private function stripeAlipay ($order) {
|
||||
$exchange = Helper::exchange('CNY', 'HKD');
|
||||
if (!$exchange) {
|
||||
abort(500, '货币转换超时,请稍后再试');
|
||||
}
|
||||
Stripe::setApiKey(config('v2board.stripe_sk_live'));
|
||||
$source = Source::create([
|
||||
'amount' => floor($order->total_amount * $exchange),
|
||||
'currency' => 'hkd',
|
||||
'type' => 'alipay',
|
||||
'redirect' => [
|
||||
'return_url' => config('v2board.app_url', env('APP_URL')) . '/#/order'
|
||||
]
|
||||
]);
|
||||
if (!$source['redirect']['url']) {
|
||||
abort(500, '支付网关请求失败');
|
||||
}
|
||||
|
||||
if (!Redis::set($source['id'], $order->trade_no)) {
|
||||
abort(500, '订单创建失败');
|
||||
}
|
||||
Redis::expire($source['id'], 3600);
|
||||
return $source['redirect']['url'];
|
||||
}
|
||||
|
||||
private function stripeWepay ($order) {
|
||||
$exchange = Helper::exchange('CNY', 'HKD');
|
||||
if (!$exchange) {
|
||||
abort(500, '货币转换超时,请稍后再试');
|
||||
}
|
||||
Stripe::setApiKey(config('v2board.stripe_sk_live'));
|
||||
$source = Source::create([
|
||||
'amount' => floor($order->total_amount * $exchange),
|
||||
'currency' => 'hkd',
|
||||
'type' => 'wechat',
|
||||
'redirect' => [
|
||||
'return_url' => config('v2board.app_url', env('APP_URL')) . '/#/order'
|
||||
]
|
||||
]);
|
||||
if (!$source['wechat']['qr_code_url']) {
|
||||
abort(500, '支付网关请求失败');
|
||||
}
|
||||
if (!Redis::set($source['id'], $order->trade_no)) {
|
||||
abort(500, '订单创建失败');
|
||||
}
|
||||
Redis::expire($source['id'], 3600);
|
||||
return $source['wechat']['qr_code_url'];
|
||||
}
|
||||
|
||||
private function bitpayX ($order) {
|
||||
$bitpayX = new BitpayX(config('v2board.bitpayx_appsecret'));
|
||||
$params = [
|
||||
'merchant_order_id' => 'V2Board_' . $order->trade_no,
|
||||
'price_amount' => $order->total_amount / 100,
|
||||
'price_currency' => 'CNY',
|
||||
'title' => '支付单号:' . $order->trade_no,
|
||||
'description' => '充值:' . $order->total_amount / 100 . ' 元',
|
||||
'callback_url' => url('/api/v1/guest/order/bitpayXNotify'),
|
||||
'success_url' => config('v2board.app_url', env('APP_URL')) . '/#/order',
|
||||
'cancel_url' => config('v2board.app_url', env('APP_URL')) . '/#/order'
|
||||
];
|
||||
$strToSign = $bitpayX->prepareSignId($params['merchant_order_id']);
|
||||
$params['token'] = $bitpayX->sign($strToSign);
|
||||
$result = $bitpayX->mprequest($params);
|
||||
Log::info('bitpayXSubmit: ' . json_encode($result));
|
||||
return isset($result['payment_url']) ? $result['payment_url'] : false;
|
||||
}
|
||||
}
|
211
app/Http/Controllers/Passport/AuthController.php
Normal file
211
app/Http/Controllers/Passport/AuthController.php
Normal file
@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Passport;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Passport\AuthRegister;
|
||||
use App\Http\Requests\Passport\AuthForget;
|
||||
use App\Http\Requests\Passport\AuthLogin;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Models\Plan;
|
||||
use App\Models\User;
|
||||
use App\Models\InviteCode;
|
||||
use App\Utils\Helper;
|
||||
use App\Utils\Dict;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
public function register(AuthRegister $request)
|
||||
{
|
||||
if ((int)config('v2board.email_whitelist_enable', 0)) {
|
||||
if (!Helper::emailSuffixVerify(
|
||||
$request->input('email'),
|
||||
config('v2board.email_whitelist_suffix', Dict::EMAIL_WHITELIST_SUFFIX_DEFAULT))
|
||||
) {
|
||||
abort(500, '邮箱后缀不处于白名单中');
|
||||
}
|
||||
}
|
||||
if ((int)config('v2board.stop_register', 0)) {
|
||||
abort(500, '本站已关闭注册');
|
||||
}
|
||||
if ((int)config('v2board.invite_force', 0)) {
|
||||
if (empty($request->input('invite_code'))) {
|
||||
abort(500, '必须使用邀请码才可以注册');
|
||||
}
|
||||
}
|
||||
if ((int)config('v2board.email_verify', 0)) {
|
||||
$redisKey = 'sendEmailVerify:' . $request->input('email');
|
||||
if (empty($request->input('email_code'))) {
|
||||
abort(500, '邮箱验证码不能为空');
|
||||
}
|
||||
if (Cache::get($redisKey) !== $request->input('email_code')) {
|
||||
abort(500, '邮箱验证码有误');
|
||||
}
|
||||
}
|
||||
$email = $request->input('email');
|
||||
$password = $request->input('password');
|
||||
$exist = User::where('email', $email)->first();
|
||||
if ($exist) {
|
||||
abort(500, '邮箱已存在系统中');
|
||||
}
|
||||
$user = new User();
|
||||
$user->email = $email;
|
||||
$user->password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$user->v2ray_uuid = Helper::guid(true);
|
||||
$user->token = Helper::guid();
|
||||
if ($request->input('invite_code')) {
|
||||
$inviteCode = InviteCode::where('code', $request->input('invite_code'))
|
||||
->where('status', 0)
|
||||
->first();
|
||||
if (!$inviteCode) {
|
||||
if ((int)config('v2board.invite_force', 0)) {
|
||||
abort(500, '邀请码无效');
|
||||
}
|
||||
} else {
|
||||
$user->invite_user_id = $inviteCode->user_id ? $inviteCode->user_id : null;
|
||||
if (!(int)config('v2board.invite_never_expire', env('V2BOARD_INVITE_NEVER_EXPIRE'))) {
|
||||
$inviteCode->status = 1;
|
||||
$inviteCode->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// try out
|
||||
if ((int)config('v2board.try_out_plan_id', 0)) {
|
||||
$plan = Plan::find(config('v2board.try_out_plan_id'));
|
||||
if ($plan) {
|
||||
$user->transfer_enable = $plan->transfer_enable * 1073741824;
|
||||
$user->plan_id = $plan->id;
|
||||
$user->group_id = $plan->group_id;
|
||||
$user->expired_at = time() + (config('v2board.try_out_hour', 1) * 3600);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$user->save()) {
|
||||
abort(500, '注册失败');
|
||||
}
|
||||
if ((int)config('v2board.email_verify', 0)) {
|
||||
Cache::forget($redisKey);
|
||||
}
|
||||
$request->session()->put('email', $user->email);
|
||||
$request->session()->put('id', $user->id);
|
||||
return response()->json([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
public function login(AuthLogin $request)
|
||||
{
|
||||
$email = $request->input('email');
|
||||
$password = $request->input('password');
|
||||
|
||||
$user = User::where('email', $email)->first();
|
||||
if (!$user) {
|
||||
abort(500, '用户名或密码错误');
|
||||
}
|
||||
if (!Helper::multiPasswordVerify(
|
||||
$user->password_algo,
|
||||
$password,
|
||||
$user->password)
|
||||
) {
|
||||
abort(500, '用户名或密码错误');
|
||||
}
|
||||
|
||||
if ($user->banned) {
|
||||
abort(500, '该账户已被停止使用');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'token' => $user->token
|
||||
];
|
||||
$request->session()->put('email', $user->email);
|
||||
$request->session()->put('id', $user->id);
|
||||
if ($user->is_admin) {
|
||||
$request->session()->put('is_admin', true);
|
||||
$data['is_admin'] = true;
|
||||
}
|
||||
return response([
|
||||
'data' => $data
|
||||
]);
|
||||
}
|
||||
|
||||
public function token2Login(Request $request)
|
||||
{
|
||||
if ($request->input('token')) {
|
||||
$user = User::where('token', $request->input('token'))->first();
|
||||
if (!$user) {
|
||||
return header('Location:' . config('v2board.app_url'));
|
||||
}
|
||||
$code = Helper::guid();
|
||||
$key = 'token2Login_' . $code;
|
||||
Cache::put($key, $user->id, 600);
|
||||
$redirect = '/#/login?verify=' . $code . '&redirect=' . ($request->input('redirect') ? $request->input('redirect') : 'dashboard');
|
||||
if (config('v2board.app_url')) {
|
||||
$location = config('v2board.app_url') . $redirect;
|
||||
} else {
|
||||
$location = url($redirect);
|
||||
}
|
||||
return header('Location:' . $location);
|
||||
}
|
||||
|
||||
if ($request->input('verify')) {
|
||||
$key = 'token2Login_' . $request->input('verify');
|
||||
$userId = Cache::get($key);
|
||||
if (!$userId) {
|
||||
abort(500, '令牌有误');
|
||||
}
|
||||
$user = User::find($userId);
|
||||
if (!$user) {
|
||||
abort(500, '用户不存在');
|
||||
}
|
||||
if ($user->banned) {
|
||||
abort(500, '该账户已被停止使用');
|
||||
}
|
||||
$request->session()->put('email', $user->email);
|
||||
$request->session()->put('id', $user->id);
|
||||
if ($user->is_admin) {
|
||||
$request->session()->put('is_admin', true);
|
||||
}
|
||||
Cache::forget($key);
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function check(Request $request)
|
||||
{
|
||||
$data = [
|
||||
'is_login' => $request->session()->get('id') ? true : false
|
||||
];
|
||||
if ($request->session()->get('is_admin')) {
|
||||
$data['is_admin'] = true;
|
||||
}
|
||||
return response([
|
||||
'data' => $data
|
||||
]);
|
||||
}
|
||||
|
||||
public function forget(AuthForget $request)
|
||||
{
|
||||
$redisKey = 'sendEmailVerify:' . $request->input('email');
|
||||
if (Cache::get($redisKey) !== $request->input('email_code')) {
|
||||
abort(500, '邮箱验证码有误');
|
||||
}
|
||||
$user = User::where('email', $request->input('email'))->first();
|
||||
if (!$user) {
|
||||
abort(500, '该邮箱不存在系统中');
|
||||
}
|
||||
$user->password = password_hash($request->input('password'), PASSWORD_DEFAULT);
|
||||
$user->password_algo = NULL;
|
||||
if (!$user->save()) {
|
||||
abort(500, '重置失败');
|
||||
}
|
||||
Cache::forget($redisKey);
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
@ -7,52 +7,80 @@ use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Exceptions\HttpResponseException;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use App\Utils\Helper;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Jobs\SendEmail;
|
||||
use App\Models\InviteCode;
|
||||
use App\Utils\Dict;
|
||||
|
||||
class CommController extends Controller
|
||||
{
|
||||
public function config () {
|
||||
public function config()
|
||||
{
|
||||
return response([
|
||||
'data' => [
|
||||
'isEmailVerify' => (int)config('v2board.email_verify', 0) ? 1 : 0,
|
||||
'isInviteForce' => (int)config('v2board.invite_force', 0) ? 1 : 0
|
||||
'isInviteForce' => (int)config('v2board.invite_force', 0) ? 1 : 0,
|
||||
'emailWhitelistSuffix' => (int)config('v2board.email_whitelist_enable', 0)
|
||||
? $this->getEmailSuffix()
|
||||
: 0
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
private function isEmailVerify () {
|
||||
private function isEmailVerify()
|
||||
{
|
||||
return response([
|
||||
'data' => (int)config('v2board.email_verify', 0) ? 1 : 0
|
||||
]);
|
||||
}
|
||||
|
||||
public function sendEmailVerify (CommSendEmailVerify $request) {
|
||||
public function sendEmailVerify(CommSendEmailVerify $request)
|
||||
{
|
||||
$email = $request->input('email');
|
||||
$redisKey = 'sendEmailVerify:' . $email;
|
||||
if (Redis::get($redisKey)) {
|
||||
abort(500, '验证码已发送,请过一会在请求');
|
||||
$cacheKey = 'sendEmailVerify:' . $email;
|
||||
if (Cache::get($cacheKey)) {
|
||||
abort(500, '验证码已发送,请过一会再请求');
|
||||
}
|
||||
$code = rand(100000, 999999);
|
||||
$code = Helper::randomChar(6);
|
||||
$subject = config('v2board.app_name', 'V2Board') . '邮箱验证码';
|
||||
Mail::send(
|
||||
'mail.sendEmailVerify',
|
||||
[
|
||||
'code' => $code,
|
||||
'name' => config('v2board.app_name', 'V2Board')
|
||||
],
|
||||
function ($message) use($email, $subject) {
|
||||
$message->to($email)->subject($subject);
|
||||
}
|
||||
);
|
||||
if (count(Mail::failures()) >= 1) {
|
||||
// 发送失败
|
||||
abort(500, '发送失败');
|
||||
}
|
||||
|
||||
Redis::set($redisKey, $code);
|
||||
Redis::expire($redisKey, 600);
|
||||
SendEmail::dispatch([
|
||||
'email' => $email,
|
||||
'subject' => $subject,
|
||||
'template_name' => 'mail.sendEmailVerify',
|
||||
'template_value' => [
|
||||
'name' => config('v2board.app_name', 'V2Board'),
|
||||
'code' => $code,
|
||||
'url' => config('v2board.app_url')
|
||||
]
|
||||
])->onQueue('verify_mail');
|
||||
|
||||
Cache::put($cacheKey, $code, 60);
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
public function pv(Request $request)
|
||||
{
|
||||
$inviteCode = InviteCode::where('code', $request->input('invite_code'))->first();
|
||||
if ($inviteCode) {
|
||||
$inviteCode->pv = $inviteCode->pv + 1;
|
||||
$inviteCode->save();
|
||||
}
|
||||
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
private function getEmailSuffix()
|
||||
{
|
||||
$suffix = config('v2board.email_whitelist_suffix', Dict::EMAIL_WHITELIST_SUFFIX_DEFAULT);
|
||||
if (!is_array($suffix)) {
|
||||
return preg_split('/,/', $suffix);
|
||||
}
|
||||
return $suffix;
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Passport;
|
||||
|
||||
use App\Http\Requests\Passport\ForgetIndex;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
|
||||
class ForgetController extends Controller
|
||||
{
|
||||
public function index (ForgetIndex $request) {
|
||||
$redisKey = 'sendEmailVerify:' . $request->input('email');
|
||||
if (Redis::get($redisKey) !== $request->input('email_code')) {
|
||||
abort(500, '邮箱验证码有误');
|
||||
}
|
||||
$user = User::where('email', $request->input('email'))->first();
|
||||
$user->password = password_hash($request->input('password'), PASSWORD_DEFAULT);
|
||||
if (!$user->save()) {
|
||||
abort(500, '重置失败');
|
||||
}
|
||||
Redis::del($redisKey);
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Passport;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Requests\Passport\LoginIndex;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
|
||||
class LoginController extends Controller
|
||||
{
|
||||
public function index (LoginIndex $request) {
|
||||
$email = $request->input('email');
|
||||
$password = $request->input('password');
|
||||
|
||||
$user = User::where('email', $email)->first();
|
||||
if (!$user) {
|
||||
abort(500, '用户名或密码错误');
|
||||
}
|
||||
if (!password_verify($password, $user->password)) {
|
||||
abort(500, '用户名或密码错误');
|
||||
}
|
||||
|
||||
$request->session()->put('email', $user->email);
|
||||
$request->session()->put('id', $user->id);
|
||||
if ($user->is_admin) {
|
||||
$request->session()->put('is_admin', true);
|
||||
}
|
||||
return response([
|
||||
'data' => [
|
||||
'is_admin' => $user->is_admin ? 2 : 1,
|
||||
'token' => $user->token
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function token2Login (Request $request) {
|
||||
if (empty($request->input('token'))) {
|
||||
abort(500, '参数错误');
|
||||
}
|
||||
$redirect = $request->input('redirect') ? $request->input('redirect') : 'dashboard';
|
||||
$user = User::where('token', $request->input('token'))->first();
|
||||
if ($user) {
|
||||
$request->session()->put('email', $user->email);
|
||||
$request->session()->put('id', $user->id);
|
||||
if ($user->is_admin) {
|
||||
$request->session()->put('is_admin', true);
|
||||
}
|
||||
}
|
||||
if (config('v2board.app_url')) {
|
||||
$location = config('v2board.app_url') . '/#/' . $redirect;
|
||||
} else {
|
||||
$location = url('/#/' . $redirect);
|
||||
}
|
||||
header('Location:' . $location);
|
||||
}
|
||||
|
||||
public function check (Request $request) {
|
||||
return response([
|
||||
'data' => $request->session()->get('id') ? true : false
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Passport;
|
||||
|
||||
use App\Http\Requests\Passport\RegisterIndex;
|
||||
use App\Http\Requests\Passport\RegisterSendEmailVerify;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Exceptions\HttpResponseException;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use App\Utils\Helper;
|
||||
use App\Models\InviteCode;
|
||||
|
||||
class RegisterController extends Controller
|
||||
{
|
||||
public function index (RegisterIndex $request) {
|
||||
if ((int)config('v2board.stop_register', 0)) {
|
||||
abort(500, '本站已关闭注册');
|
||||
}
|
||||
if ((int)config('v2board.invite_force', 0)) {
|
||||
if (empty($request->input('invite_code'))) {
|
||||
abort(500, '必须使用邀请码才可以注册');
|
||||
}
|
||||
}
|
||||
if ((int)config('v2board.email_verify', 0)) {
|
||||
$redisKey = 'sendEmailVerify:' . $request->input('email');
|
||||
if (empty($request->input('email_code'))) {
|
||||
abort(500, '邮箱验证码不能为空');
|
||||
}
|
||||
if (Redis::get($redisKey) !== $request->input('email_code')) {
|
||||
abort(500, '邮箱验证码有误');
|
||||
}
|
||||
}
|
||||
$email = $request->input('email');
|
||||
$password = $request->input('password');
|
||||
$exist = User::where('email', $email)->first();
|
||||
if ($exist) {
|
||||
abort(500, '邮箱已存在系统中');
|
||||
}
|
||||
$user = new User();
|
||||
$user->email = $email;
|
||||
$user->password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$user->v2ray_uuid = Helper::guid(true);
|
||||
$user->token = Helper::guid();
|
||||
if ($request->input('invite_code')) {
|
||||
$inviteCode = InviteCode::where('code', $request->input('invite_code'))
|
||||
->where('status', 0)
|
||||
->first();
|
||||
if (!$inviteCode) {
|
||||
if ((int)config('v2board.invite_force', 0)) {
|
||||
abort(500, '邀请码无效');
|
||||
}
|
||||
} else {
|
||||
$user->invite_user_id = $inviteCode->user_id ? $inviteCode->user_id : null;
|
||||
if (!(int)config('v2board.invite_never_expire', env('V2BOARD_INVITE_NEVER_EXPIRE'))) {
|
||||
$inviteCode->status = 1;
|
||||
$inviteCode->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$user->save()) {
|
||||
abort(500, '注册失败');
|
||||
}
|
||||
if ((int)config('v2board.email_verify', 0)) {
|
||||
Redis::del($redisKey);
|
||||
}
|
||||
return response()->json([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Plan;
|
||||
|
||||
class PlanController extends Controller
|
||||
{
|
||||
public function fetch (Request $request) {
|
||||
if (empty($request->input('plan_id'))) {
|
||||
abort(500, '参数错误');
|
||||
}
|
||||
$plan = Plan::find($request->input('plan_id'));
|
||||
if (!$plan) {
|
||||
abort(500, '该订阅不存在');
|
||||
}
|
||||
return response([
|
||||
'data' => $plan
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Server;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller as BaseController;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
public function __construct(Request $request) {
|
||||
$token = $request->input('token');
|
||||
if (empty($token)) {
|
||||
abort(500, 'token is null');
|
||||
}
|
||||
if ($token !== config('v2board.server_token')) {
|
||||
abort(500, 'token is error');
|
||||
}
|
||||
}
|
||||
}
|
@ -2,45 +2,46 @@
|
||||
|
||||
namespace App\Http\Controllers\Server;
|
||||
|
||||
use App\Services\ServerService;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Server\Controller;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use App\Models\Plan;
|
||||
use App\Models\Server;
|
||||
use App\Models\ServerLog;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class DeepbworkController extends Controller
|
||||
{
|
||||
CONST SERVER_CONFIG = '{"api":{"services":["HandlerService","StatsService"],"tag":"api"},"stats":{},"inbound":{"port":443,"protocol":"vmess","settings":{"clients":[]},"streamSettings":{"network":"tcp"},"tag":"proxy"},"inboundDetour":[{"listen":"0.0.0.0","port":23333,"protocol":"dokodemo-door","settings":{"address":"0.0.0.0"},"tag":"api"}],"log":{"loglevel":"debug","access":"access.log","error":"error.log"},"outbound":{"protocol":"freedom","settings":{}},"routing":{"settings":{"rules":[{"inboundTag":["api"],"outboundTag":"api","type":"field"}]},"strategy":"rules"},"policy":{"levels":{"0":{"handshake":4,"connIdle":300,"uplinkOnly":5,"downlinkOnly":30,"statsUserUplink":true,"statsUserDownlink":true}}}}';
|
||||
CONST SERVER_CONFIG = '{"api":{"services":["HandlerService","StatsService"],"tag":"api"},"stats":{},"inbound":{"port":443,"protocol":"vmess","settings":{"clients":[]},"sniffing":{"enabled": true,"destOverride": ["http","tls"]},"streamSettings":{"network":"tcp"},"tag":"proxy"},"inboundDetour":[{"listen":"0.0.0.0","port":23333,"protocol":"dokodemo-door","settings":{"address":"0.0.0.0"},"tag":"api"}],"log":{"loglevel":"debug","access":"access.log","error":"error.log"},"outbound":{"protocol":"freedom","settings":{}},"outboundDetour":[{"protocol":"blackhole","settings":{},"tag":"block"}],"routing":{"rules":[{"inboundTag":"api","outboundTag":"api","type":"field"}]},"policy":{"levels":{"0":{"handshake":4,"connIdle":300,"uplinkOnly":5,"downlinkOnly":30,"statsUserUplink":true,"statsUserDownlink":true}}}}';
|
||||
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$token = $request->input('token');
|
||||
if (empty($token)) {
|
||||
abort(500, 'token is null');
|
||||
}
|
||||
if ($token !== config('v2board.server_token')) {
|
||||
abort(500, 'token is error');
|
||||
}
|
||||
}
|
||||
|
||||
// 后端获取用户
|
||||
public function user (Request $request) {
|
||||
public function user(Request $request)
|
||||
{
|
||||
$nodeId = $request->input('node_id');
|
||||
$server = Server::find($nodeId);
|
||||
if (!$server) {
|
||||
abort(500, 'fail');
|
||||
}
|
||||
Redis::set('server_last_check_at_' . $server->id, time());
|
||||
$users = User::whereIn('group_id', json_decode($server->group_id))
|
||||
->select([
|
||||
'id',
|
||||
'email',
|
||||
't',
|
||||
'u',
|
||||
'd',
|
||||
'transfer_enable',
|
||||
'enable',
|
||||
'v2ray_uuid',
|
||||
'v2ray_alter_id',
|
||||
'v2ray_level'
|
||||
])
|
||||
->get();
|
||||
Cache::put('server_last_check_at_' . $server->id, time());
|
||||
$serverService = new ServerService();
|
||||
$users = $serverService->getAvailableUsers(json_decode($server->group_id));
|
||||
$result = [];
|
||||
foreach ($users as $user) {
|
||||
$user->v2ray_user = [
|
||||
"uuid" => $user->v2ray_uuid,
|
||||
"email" => sprintf("%s@v2panel.user", $user->v2ray_uuid),
|
||||
"email" => sprintf("%s@v2board.user", $user->v2ray_uuid),
|
||||
"alter_id" => $user->v2ray_alter_id,
|
||||
"level" => $user->v2ray_level,
|
||||
];
|
||||
@ -56,26 +57,27 @@ class DeepbworkController extends Controller
|
||||
}
|
||||
|
||||
// 后端提交数据
|
||||
public function submit (Request $request) {
|
||||
Log::info('serverSubmitData:' . $request->input('node_id') . ':' . file_get_contents('php://input'));
|
||||
public function submit(Request $request)
|
||||
{
|
||||
Log::info('serverSubmitData:' . $request->input('node_id') . ':' . file_get_contents('php://input'));
|
||||
$server = Server::find($request->input('node_id'));
|
||||
if (!$server) {
|
||||
return response([
|
||||
'ret' => 1,
|
||||
'msg' => 'ok'
|
||||
]);
|
||||
return response([
|
||||
'ret' => 1,
|
||||
'msg' => 'ok'
|
||||
]);
|
||||
}
|
||||
$data = file_get_contents('php://input');
|
||||
$data = json_decode($data, true);
|
||||
foreach ($data as $item) {
|
||||
$u = $item['u'] * $server->rate;
|
||||
$d = $item['d'] * $server->rate;
|
||||
$user = User::find($item['user_id']);
|
||||
$user->t = time();
|
||||
$user->u = $user->u + $u;
|
||||
$user->d = $user->d + $d;
|
||||
$u = $item['u'] * $server->rate;
|
||||
$d = $item['d'] * $server->rate;
|
||||
$user = User::find($item['user_id']);
|
||||
$user->t = time();
|
||||
$user->u = $user->u + $u;
|
||||
$user->d = $user->d + $d;
|
||||
$user->save();
|
||||
|
||||
|
||||
$serverLog = new ServerLog();
|
||||
$serverLog->user_id = $item['user_id'];
|
||||
$serverLog->server_id = $request->input('node_id');
|
||||
@ -84,23 +86,24 @@ class DeepbworkController extends Controller
|
||||
$serverLog->rate = $server->rate;
|
||||
$serverLog->save();
|
||||
}
|
||||
|
||||
return response([
|
||||
'ret' => 1,
|
||||
'msg' => 'ok'
|
||||
]);
|
||||
|
||||
return response([
|
||||
'ret' => 1,
|
||||
'msg' => 'ok'
|
||||
]);
|
||||
}
|
||||
|
||||
// 后端获取配置
|
||||
public function config (Request $request) {
|
||||
public function config(Request $request)
|
||||
{
|
||||
$nodeId = $request->input('node_id');
|
||||
$localPort = $request->input('local_port');
|
||||
if (empty($nodeId) || empty($localPort)) {
|
||||
abort(1000, '参数错误');
|
||||
abort(500, '参数错误');
|
||||
}
|
||||
$server = Server::find($nodeId);
|
||||
if (!$server) {
|
||||
abort(1001, '节点不存在');
|
||||
abort(500, '节点不存在');
|
||||
}
|
||||
$json = json_decode(self::SERVER_CONFIG);
|
||||
$json->inboundDetour[0]->port = (int)$localPort;
|
||||
@ -108,26 +111,57 @@ class DeepbworkController extends Controller
|
||||
$json->inbound->streamSettings->network = $server->network;
|
||||
if ($server->settings) {
|
||||
switch ($server->network) {
|
||||
case 'tcp': $json->inbound->streamSettings->tcpSettings = json_decode($server->settings);
|
||||
case 'tcp':
|
||||
$json->inbound->streamSettings->tcpSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'kcp': $json->inbound->streamSettings->kcpSettings = json_decode($server->settings);
|
||||
case 'kcp':
|
||||
$json->inbound->streamSettings->kcpSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'ws': $json->inbound->streamSettings->wsSettings = json_decode($server->settings);
|
||||
case 'ws':
|
||||
$json->inbound->streamSettings->wsSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'http': $json->inbound->streamSettings->httpSettings = json_decode($server->settings);
|
||||
case 'http':
|
||||
$json->inbound->streamSettings->httpSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'domainsocket': $json->inbound->streamSettings->dsSettings = json_decode($server->settings);
|
||||
case 'domainsocket':
|
||||
$json->inbound->streamSettings->dsSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'quic': $json->inbound->streamSettings->quicSettings = json_decode($server->settings);
|
||||
case 'quic':
|
||||
$json->inbound->streamSettings->quicSettings = json_decode($server->settings);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($server->rules) {
|
||||
$rules = json_decode($server->rules);
|
||||
// domain
|
||||
if (isset($rules->domain) && !empty($rules->domain)) {
|
||||
$domainObj = new \StdClass();
|
||||
$domainObj->type = 'field';
|
||||
$domainObj->domain = $rules->domain;
|
||||
$domainObj->outboundTag = 'block';
|
||||
array_push($json->routing->rules, $domainObj);
|
||||
}
|
||||
// protocol
|
||||
if (isset($rules->protocol) && !empty($rules->protocol)) {
|
||||
$protocolObj = new \StdClass();
|
||||
$protocolObj->type = 'field';
|
||||
$protocolObj->protocol = $rules->protocol;
|
||||
$protocolObj->outboundTag = 'block';
|
||||
array_push($json->routing->rules, $protocolObj);
|
||||
}
|
||||
}
|
||||
|
||||
if ((int)$server->tls) {
|
||||
$json->inbound->streamSettings->security = "tls";
|
||||
$tls = (object) array("certificateFile" => "/home/v2ray.crt", "keyFile" => "/home/v2ray.key");
|
||||
$json->inbound->streamSettings->security = 'tls';
|
||||
$tls = (object)[
|
||||
'certificateFile' => '/home/v2ray.crt',
|
||||
'keyFile' => '/home/v2ray.key'
|
||||
];
|
||||
$json->inbound->streamSettings->tlsSettings = new \StdClass();
|
||||
$json->inbound->streamSettings->tlsSettings->certificates[0] = $tls;
|
||||
}
|
||||
|
||||
|
||||
die(json_encode($json, JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
}
|
||||
|
183
app/Http/Controllers/Server/PoseidonController.php
Normal file
183
app/Http/Controllers/Server/PoseidonController.php
Normal file
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Server;
|
||||
|
||||
use App\Services\ServerService;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use App\Models\Plan;
|
||||
use App\Models\Server;
|
||||
use App\Models\ServerLog;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class PoseidonController extends Controller
|
||||
{
|
||||
CONST SERVER_CONFIG = '{"api":{"services":["HandlerService","StatsService"],"tag":"api"},"stats":{},"inbound":{"port":443,"protocol":"vmess","settings":{"clients":[]},"sniffing":{"enabled": true,"destOverride": ["http","tls"]},"streamSettings":{"network":"tcp"},"tag":"proxy"},"inboundDetour":[{"listen":"0.0.0.0","port":23333,"protocol":"dokodemo-door","settings":{"address":"0.0.0.0"},"tag":"api"}],"log":{"loglevel":"debug","access":"access.log","error":"error.log"},"outbound":{"protocol":"freedom","settings":{}},"outboundDetour":[{"protocol":"blackhole","settings":{},"tag":"block"}],"routing":{"rules":[{"inboundTag":"api","outboundTag":"api","type":"field"}]},"policy":{"levels":{"0":{"handshake":4,"connIdle":300,"uplinkOnly":5,"downlinkOnly":30,"statsUserUplink":true,"statsUserDownlink":true}}}}';
|
||||
|
||||
// 后端获取用户
|
||||
public function user(Request $request)
|
||||
{
|
||||
if ($r = $this->verifyToken($request)) { return $r; }
|
||||
|
||||
$nodeId = $request->input('node_id');
|
||||
$server = Server::find($nodeId);
|
||||
if (!$server) {
|
||||
return $this->error("server could not be found", 404);
|
||||
}
|
||||
Cache::put('server_last_check_at_' . $server->id, time());
|
||||
$serverService = new ServerService();
|
||||
$users = $serverService->getAvailableUsers(json_decode($server->group_id));
|
||||
$result = [];
|
||||
foreach ($users as $user) {
|
||||
$user->v2ray_user = [
|
||||
"uuid" => $user->v2ray_uuid,
|
||||
"email" => sprintf("%s@v2board.user", $user->v2ray_uuid),
|
||||
"alter_id" => $user->v2ray_alter_id,
|
||||
"level" => $user->v2ray_level,
|
||||
];
|
||||
unset($user['v2ray_uuid']);
|
||||
unset($user['v2ray_alter_id']);
|
||||
unset($user['v2ray_level']);
|
||||
array_push($result, $user);
|
||||
}
|
||||
|
||||
return $this->success($result);
|
||||
}
|
||||
|
||||
// 后端提交数据
|
||||
public function submit(Request $request)
|
||||
{
|
||||
if ($r = $this->verifyToken($request)) { return $r; }
|
||||
|
||||
Log::info('serverSubmitData:' . $request->input('node_id') . ':' . file_get_contents('php://input'));
|
||||
$server = Server::find($request->input('node_id'));
|
||||
if (!$server) {
|
||||
return $this->error("server could not be found", 404);
|
||||
}
|
||||
$data = file_get_contents('php://input');
|
||||
$data = json_decode($data, true);
|
||||
foreach ($data as $item) {
|
||||
$u = $item['u'] * $server->rate;
|
||||
$d = $item['d'] * $server->rate;
|
||||
$user = User::find($item['user_id']);
|
||||
$user->t = time();
|
||||
$user->u = $user->u + $u;
|
||||
$user->d = $user->d + $d;
|
||||
$user->save();
|
||||
|
||||
$serverLog = new ServerLog();
|
||||
$serverLog->user_id = $item['user_id'];
|
||||
$serverLog->server_id = $request->input('node_id');
|
||||
$serverLog->u = $item['u'];
|
||||
$serverLog->d = $item['d'];
|
||||
$serverLog->rate = $server->rate;
|
||||
$serverLog->save();
|
||||
}
|
||||
|
||||
return $this->success('');
|
||||
}
|
||||
|
||||
// 后端获取配置
|
||||
public function config(Request $request)
|
||||
{
|
||||
if ($r = $this->verifyToken($request)) { return $r; }
|
||||
|
||||
$nodeId = $request->input('node_id');
|
||||
$localPort = $request->input('local_port');
|
||||
if (empty($nodeId) || empty($localPort)) {
|
||||
return $this->error('invalid parameters', 400);
|
||||
}
|
||||
$server = Server::find($nodeId);
|
||||
if (!$server) {
|
||||
return $this->error("server could not be found", 404);
|
||||
}
|
||||
$json = json_decode(self::SERVER_CONFIG);
|
||||
$json->inboundDetour[0]->port = (int)$localPort;
|
||||
$json->inbound->port = (int)$server->server_port;
|
||||
$json->inbound->streamSettings->network = $server->network;
|
||||
if ($server->settings) {
|
||||
switch ($server->network) {
|
||||
case 'tcp':
|
||||
$json->inbound->streamSettings->tcpSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'kcp':
|
||||
$json->inbound->streamSettings->kcpSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'ws':
|
||||
$json->inbound->streamSettings->wsSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'http':
|
||||
$json->inbound->streamSettings->httpSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'domainsocket':
|
||||
$json->inbound->streamSettings->dsSettings = json_decode($server->settings);
|
||||
break;
|
||||
case 'quic':
|
||||
$json->inbound->streamSettings->quicSettings = json_decode($server->settings);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($server->rules) {
|
||||
$rules = json_decode($server->rules);
|
||||
// domain
|
||||
if (isset($rules->domain) && !empty($rules->domain)) {
|
||||
$domainObj = new \StdClass();
|
||||
$domainObj->type = 'field';
|
||||
$domainObj->domain = $rules->domain;
|
||||
$domainObj->outboundTag = 'block';
|
||||
array_push($json->routing->rules, $domainObj);
|
||||
}
|
||||
// protocol
|
||||
if (isset($rules->protocol) && !empty($rules->protocol)) {
|
||||
$protocolObj = new \StdClass();
|
||||
$protocolObj->type = 'field';
|
||||
$protocolObj->protocol = $rules->protocol;
|
||||
$protocolObj->outboundTag = 'block';
|
||||
array_push($json->routing->rules, $protocolObj);
|
||||
}
|
||||
}
|
||||
|
||||
if ((int)$server->tls) {
|
||||
$json->inbound->streamSettings->security = 'tls';
|
||||
$tls = (object)[
|
||||
'certificateFile' => '/home/v2ray.crt',
|
||||
'keyFile' => '/home/v2ray.key'
|
||||
];
|
||||
$json->inbound->streamSettings->tlsSettings = new \StdClass();
|
||||
$json->inbound->streamSettings->tlsSettings->certificates[0] = $tls;
|
||||
}
|
||||
|
||||
$json->poseidon = [
|
||||
'license_key' => (string)config('v2board.server_license'),
|
||||
];
|
||||
|
||||
return $this->success($json);
|
||||
}
|
||||
|
||||
protected function verifyToken(Request $request)
|
||||
{
|
||||
$token = $request->input('token');
|
||||
if (empty($token)) {
|
||||
return $this->error("token must be set");
|
||||
}
|
||||
if ($token !== config('v2board.server_token')) {
|
||||
return $this->error("invalid token");
|
||||
}
|
||||
}
|
||||
|
||||
protected function error($msg, int $status = 400) {
|
||||
return response([
|
||||
'msg' => $msg,
|
||||
], $status);
|
||||
}
|
||||
|
||||
protected function success($data) {
|
||||
return response([
|
||||
'msg' => 'ok',
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
|
||||
class TutorialController extends Controller
|
||||
{
|
||||
public function getSubscribeUrl (Request $request) {
|
||||
$user = User::find($request->session()->get('id'));
|
||||
return response([
|
||||
'data' => [
|
||||
'subscribe_url' => config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user['token']
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function getAppleID (Request $request) {
|
||||
$user = User::find($request->session()->get('id'));
|
||||
if ($user->expired_at < time()) {
|
||||
return response([
|
||||
'data' => [
|
||||
]
|
||||
]);
|
||||
}
|
||||
return response([
|
||||
'data' => [
|
||||
'apple_id' => config('v2board.apple_id'),
|
||||
'apple_id_password' => config('v2board.apple_id_password')
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
33
app/Http/Controllers/User/CouponController.php
Normal file
33
app/Http/Controllers/User/CouponController.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Coupon;
|
||||
|
||||
class CouponController extends Controller
|
||||
{
|
||||
public function check(Request $request)
|
||||
{
|
||||
if (empty($request->input('code'))) {
|
||||
abort(500, '优惠券码不能为空');
|
||||
}
|
||||
$coupon = Coupon::where('code', $request->input('code'))->first();
|
||||
if (!$coupon) {
|
||||
abort(500, '优惠券无效');
|
||||
}
|
||||
if ($coupon->limit_use <= 0 && $coupon->limit_use !== NULL) {
|
||||
abort(500, '优惠券已无可用次数');
|
||||
}
|
||||
if (time() < $coupon->started_at) {
|
||||
abort(500, '优惠券还未到可用时间');
|
||||
}
|
||||
if (time() > $coupon->ended_at) {
|
||||
abort(500, '优惠券已过期');
|
||||
}
|
||||
return response([
|
||||
'data' => $coupon
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\User;
|
||||
use App\Models\Order;
|
||||
use App\Models\InviteCode;
|
||||
@ -11,7 +11,8 @@ use App\Utils\Helper;
|
||||
|
||||
class InviteController extends Controller
|
||||
{
|
||||
public function save (Request $request) {
|
||||
public function save(Request $request)
|
||||
{
|
||||
if (InviteCode::where('user_id', $request->session()->get('id'))->where('status', 0)->count() >= config('v2board.invite_gen_limit', 5)) {
|
||||
abort(500, '已达到创建数量上限');
|
||||
}
|
||||
@ -23,7 +24,8 @@ class InviteController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function details (Request $request) {
|
||||
public function details(Request $request)
|
||||
{
|
||||
return response([
|
||||
'data' => Order::where('invite_user_id', $request->session()->get('id'))
|
||||
->where('status', 3)
|
||||
@ -38,7 +40,8 @@ class InviteController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function fetch (Request $request) {
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
$codes = InviteCode::where('user_id', $request->session()->get('id'))
|
||||
->where('status', 0)
|
||||
->get();
|
||||
@ -52,7 +55,7 @@ class InviteController extends Controller
|
||||
(int)User::where('invite_user_id', $request->session()->get('id'))->count(),
|
||||
//有效的佣金
|
||||
(int)Order::where('status', 3)
|
||||
->where('commission_status', 1)
|
||||
->where('commission_status', 2)
|
||||
->where('invite_user_id', $request->session()->get('id'))
|
||||
->sum('commission_balance'),
|
||||
//确认中的佣金
|
||||
@ -61,7 +64,9 @@ class InviteController extends Controller
|
||||
->where('invite_user_id', $request->session()->get('id'))
|
||||
->sum('commission_balance'),
|
||||
//佣金比例
|
||||
(int)$commission_rate
|
||||
(int)$commission_rate,
|
||||
//可用佣金
|
||||
(int)$user->commission_balance
|
||||
];
|
||||
return response([
|
||||
'data' => [
|
25
app/Http/Controllers/User/NoticeController.php
Normal file
25
app/Http/Controllers/User/NoticeController.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Notice;
|
||||
use App\Utils\Helper;
|
||||
|
||||
class NoticeController extends Controller
|
||||
{
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
$current = $request->input('current') ? $request->input('current') : 1;
|
||||
$pageSize = 5;
|
||||
$model = Notice::orderBy('created_at', 'DESC');
|
||||
$total = $model->count();
|
||||
$res = $model->forPage($current, $pageSize)
|
||||
->get();
|
||||
return response([
|
||||
'data' => $res,
|
||||
'total' => $total
|
||||
]);
|
||||
}
|
||||
}
|
490
app/Http/Controllers/User/OrderController.php
Executable file
490
app/Http/Controllers/User/OrderController.php
Executable file
@ -0,0 +1,490 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\User\OrderSave;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Models\Order;
|
||||
use App\Models\Plan;
|
||||
use App\Models\User;
|
||||
use App\Models\Coupon;
|
||||
use App\Utils\Helper;
|
||||
use Omnipay\Omnipay;
|
||||
use Stripe\Stripe;
|
||||
use Stripe\Source;
|
||||
use Library\BitpayX;
|
||||
use Library\PayTaro;
|
||||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
$model = Order::where('user_id', $request->session()->get('id'))
|
||||
->orderBy('created_at', 'DESC');
|
||||
if ($request->input('status') !== null) {
|
||||
$model->where('status', $request->input('status'));
|
||||
}
|
||||
$order = $model->get();
|
||||
$plan = Plan::get();
|
||||
for ($i = 0; $i < count($order); $i++) {
|
||||
for ($x = 0; $x < count($plan); $x++) {
|
||||
if ($order[$i]['plan_id'] === $plan[$x]['id']) {
|
||||
$order[$i]['plan'] = $plan[$x];
|
||||
}
|
||||
}
|
||||
}
|
||||
return response([
|
||||
'data' => $order
|
||||
]);
|
||||
}
|
||||
|
||||
public function details(Request $request)
|
||||
{
|
||||
$order = Order::where('user_id', $request->session()->get('id'))
|
||||
->where('trade_no', $request->input('trade_no'))
|
||||
->first();
|
||||
if (!$order) {
|
||||
abort(500, '订单不存在');
|
||||
}
|
||||
$order['plan'] = Plan::find($order->plan_id);
|
||||
$order['try_out_plan_id'] = (int)config('v2board.try_out_plan_id');
|
||||
if (!$order['plan']) {
|
||||
abort(500, '订阅不存在');
|
||||
}
|
||||
return response([
|
||||
'data' => $order
|
||||
]);
|
||||
}
|
||||
|
||||
private function isNotCompleteOrderByUserId($userId)
|
||||
{
|
||||
$order = Order::whereIn('status', [0, 1])
|
||||
->where('user_id', $userId)
|
||||
->first();
|
||||
if (!$order) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// surplus value
|
||||
private function getSurplusValue(User $user)
|
||||
{
|
||||
$plan = Plan::find($user->plan_id);
|
||||
switch ($plan->type) {
|
||||
case 0: return $this->getSurplusValueByCycle($user, $plan);
|
||||
case 1: return $this->getSurplusValueByOneTime($user, $plan);
|
||||
}
|
||||
}
|
||||
|
||||
private function getSurplusValueByOneTime(User $user, Plan $plan)
|
||||
{
|
||||
$trafficUnitPrice = 0;
|
||||
$trafficUnitPrice = $plan->onetime_price / $plan->transfer_enable;
|
||||
if ($user->discount && $trafficUnitPrice) {
|
||||
$trafficUnitPrice = $trafficUnitPrice - ($trafficUnitPrice * $user->discount / 100);
|
||||
}
|
||||
$notUsedTrafficPrice = $plan->transfer_enable - (($user->u + $user->d) / 1073741824);
|
||||
$result = $trafficUnitPrice * $notUsedTrafficPrice;
|
||||
return $result > 0 ? $result : 0;
|
||||
}
|
||||
|
||||
private function getSurplusValueByCycle(User $user, Plan $plan)
|
||||
{
|
||||
$dayPrice = 0;
|
||||
if ($plan->month_price) {
|
||||
$dayPrice = $plan->month_price / 2592000;
|
||||
} else if ($plan->quarter_price) {
|
||||
$dayPrice = $plan->quarter_price / 7862400;
|
||||
} else if ($plan->half_year_price) {
|
||||
$dayPrice = $plan->half_year_price / 15811200;
|
||||
} else if ($plan->year_price) {
|
||||
$dayPrice = $plan->year_price / 31536000;
|
||||
}
|
||||
// exclude discount
|
||||
if ($user->discount && $dayPrice) {
|
||||
$dayPrice = $dayPrice - ($dayPrice * $user->discount / 100);
|
||||
}
|
||||
$remainingDay = $user->expired_at - time();
|
||||
$result = $remainingDay * $dayPrice;
|
||||
return $result > 0 ? $result : 0;
|
||||
}
|
||||
|
||||
public function save(OrderSave $request)
|
||||
{
|
||||
if ($this->isNotCompleteOrderByUserId($request->session()->get('id'))) {
|
||||
abort(500, '存在未付款订单,请取消后再试');
|
||||
}
|
||||
|
||||
$plan = Plan::find($request->input('plan_id'));
|
||||
$user = User::find($request->session()->get('id'));
|
||||
|
||||
if (!$plan) {
|
||||
abort(500, '该订阅不存在');
|
||||
}
|
||||
|
||||
if ((!$plan->show && !$plan->renew) || (!$plan->show && $user->plan_id !== $plan->id)) {
|
||||
abort(500, '该订阅已售罄');
|
||||
}
|
||||
|
||||
if (!$plan->renew && $user->plan_id == $plan->id) {
|
||||
abort(500, '该订阅无法续费,请更换其他订阅');
|
||||
}
|
||||
|
||||
if ($plan[$request->input('cycle')] === NULL) {
|
||||
abort(500, '该订阅周期无法进行购买,请选择其他周期');
|
||||
}
|
||||
|
||||
if ($request->input('coupon_code')) {
|
||||
$coupon = Coupon::where('code', $request->input('coupon_code'))->first();
|
||||
if (!$coupon) {
|
||||
abort(500, '优惠券无效');
|
||||
}
|
||||
if ($coupon->limit_use <= 0 && $coupon->limit_use !== NULL) {
|
||||
abort(500, '优惠券已无可用次数');
|
||||
}
|
||||
if (time() < $coupon->started_at) {
|
||||
abort(500, '优惠券还未到可用时间');
|
||||
}
|
||||
if (time() > $coupon->ended_at) {
|
||||
abort(500, '优惠券已过期');
|
||||
}
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
$order = new Order();
|
||||
$order->user_id = $request->session()->get('id');
|
||||
$order->plan_id = $plan->id;
|
||||
$order->cycle = $request->input('cycle');
|
||||
$order->trade_no = Helper::guid();
|
||||
$order->total_amount = $plan[$request->input('cycle')];
|
||||
// discount start
|
||||
// coupon
|
||||
if (isset($coupon)) {
|
||||
switch ($coupon->type) {
|
||||
case 1:
|
||||
$order->discount_amount = $coupon->value;
|
||||
break;
|
||||
case 2:
|
||||
$order->discount_amount = $order->total_amount * ($coupon->value / 100);
|
||||
break;
|
||||
}
|
||||
if ($coupon->limit_use !== NULL) {
|
||||
$coupon->limit_use = $coupon->limit_use - 1;
|
||||
if (!$coupon->save()) {
|
||||
DB::rollback();
|
||||
abort(500, '优惠券使用失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
// user
|
||||
if ($user->discount) {
|
||||
$order->discount_amount = $order->discount_amount + ($order->total_amount * ($user->discount / 100));
|
||||
}
|
||||
// discount complete
|
||||
$order->total_amount = $order->total_amount - $order->discount_amount;
|
||||
// discount end
|
||||
// renew and change subscribe process
|
||||
if ($user->plan_id !== NULL && $order->plan_id !== $user->plan_id) {
|
||||
if (!(int)config('v2board.plan_change_enable', 1)) abort(500, '目前不允许更改订阅,请联系客服或提交工单');
|
||||
$order->type = 3;
|
||||
$order->surplus_amount = $this->getSurplusValue($user);
|
||||
if ($order->surplus_amount >= $order->total_amount) {
|
||||
$order->refund_amount = $order->surplus_amount - $order->total_amount;
|
||||
$order->total_amount = 0;
|
||||
} else {
|
||||
$order->total_amount = $order->total_amount - $order->surplus_amount;
|
||||
}
|
||||
} else if ($user->expired_at > time() && $order->plan_id == $user->plan_id) {
|
||||
$order->type = 2;
|
||||
} else {
|
||||
$order->type = 1;
|
||||
}
|
||||
// invite process
|
||||
if ($user->invite_user_id && $order->total_amount > 0) {
|
||||
$order->invite_user_id = $user->invite_user_id;
|
||||
$inviter = User::find($user->invite_user_id);
|
||||
if ($inviter && $inviter->commission_rate) {
|
||||
$order->commission_balance = $order->total_amount * ($inviter->commission_rate / 100);
|
||||
} else {
|
||||
$order->commission_balance = $order->total_amount * (config('v2board.invite_commission', 10) / 100);
|
||||
}
|
||||
}
|
||||
if (!$order->save()) {
|
||||
DB::rollback();
|
||||
abort(500, '订单创建失败');
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response([
|
||||
'data' => $order->trade_no
|
||||
]);
|
||||
}
|
||||
|
||||
public function checkout(Request $request)
|
||||
{
|
||||
$tradeNo = $request->input('trade_no');
|
||||
$method = $request->input('method');
|
||||
$order = Order::where('trade_no', $tradeNo)
|
||||
->where('user_id', $request->session()->get('id'))
|
||||
->where('status', 0)
|
||||
->first();
|
||||
if (!$order) {
|
||||
abort(500, '订单不存在或已支付');
|
||||
}
|
||||
// free process
|
||||
if ($order->total_amount <= 0) {
|
||||
$order->total_amount = 0;
|
||||
$order->status = 1;
|
||||
$order->save();
|
||||
exit();
|
||||
}
|
||||
switch ($method) {
|
||||
// return type => 0: QRCode / 1: URL
|
||||
case 0:
|
||||
// alipayF2F
|
||||
if (!(int)config('v2board.alipay_enable')) {
|
||||
abort(500, '支付方式不可用');
|
||||
}
|
||||
return response([
|
||||
'type' => 0,
|
||||
'data' => $this->alipayF2F($tradeNo, $order->total_amount)
|
||||
]);
|
||||
case 2:
|
||||
// stripeAlipay
|
||||
if (!(int)config('v2board.stripe_alipay_enable')) {
|
||||
abort(500, '支付方式不可用');
|
||||
}
|
||||
return response([
|
||||
'type' => 1,
|
||||
'data' => $this->stripeAlipay($order)
|
||||
]);
|
||||
case 3:
|
||||
// stripeWepay
|
||||
if (!(int)config('v2board.stripe_wepay_enable')) {
|
||||
abort(500, '支付方式不可用');
|
||||
}
|
||||
return response([
|
||||
'type' => 0,
|
||||
'data' => $this->stripeWepay($order)
|
||||
]);
|
||||
case 4:
|
||||
// bitpayX
|
||||
if (!(int)config('v2board.bitpayx_enable')) {
|
||||
abort(500, '支付方式不可用');
|
||||
}
|
||||
return response([
|
||||
'type' => 1,
|
||||
'data' => $this->bitpayX($order)
|
||||
]);
|
||||
case 5:
|
||||
if (!(int)config('v2board.paytaro_enable')) {
|
||||
abort(500, '支付方式不可用');
|
||||
}
|
||||
return response([
|
||||
'type' => 1,
|
||||
'data' => $this->payTaro($order)
|
||||
]);
|
||||
default:
|
||||
abort(500, '支付方式不存在');
|
||||
}
|
||||
}
|
||||
|
||||
public function check(Request $request)
|
||||
{
|
||||
$tradeNo = $request->input('trade_no');
|
||||
$order = Order::where('trade_no', $tradeNo)
|
||||
->where('user_id', $request->session()->get('id'))
|
||||
->first();
|
||||
if (!$order) {
|
||||
abort(500, '订单不存在');
|
||||
}
|
||||
return response([
|
||||
'data' => $order->status
|
||||
]);
|
||||
}
|
||||
|
||||
public function getPaymentMethod()
|
||||
{
|
||||
$data = [];
|
||||
if ((int)config('v2board.alipay_enable')) {
|
||||
$alipayF2F = new \StdClass();
|
||||
$alipayF2F->name = '支付宝';
|
||||
$alipayF2F->method = 0;
|
||||
$alipayF2F->icon = 'alipay';
|
||||
array_push($data, $alipayF2F);
|
||||
}
|
||||
|
||||
if ((int)config('v2board.stripe_alipay_enable')) {
|
||||
$stripeAlipay = new \StdClass();
|
||||
$stripeAlipay->name = '支付宝';
|
||||
$stripeAlipay->method = 2;
|
||||
$stripeAlipay->icon = 'alipay';
|
||||
array_push($data, $stripeAlipay);
|
||||
}
|
||||
|
||||
if ((int)config('v2board.stripe_wepay_enable')) {
|
||||
$stripeWepay = new \StdClass();
|
||||
$stripeWepay->name = '微信';
|
||||
$stripeWepay->method = 3;
|
||||
$stripeWepay->icon = 'wechat';
|
||||
array_push($data, $stripeWepay);
|
||||
}
|
||||
|
||||
if ((int)config('v2board.bitpayx_enable')) {
|
||||
$bitpayX = new \StdClass();
|
||||
$bitpayX->name = '聚合支付';
|
||||
$bitpayX->method = 4;
|
||||
$bitpayX->icon = 'wallet';
|
||||
array_push($data, $bitpayX);
|
||||
}
|
||||
|
||||
if ((int)config('v2board.paytaro_enable')) {
|
||||
$obj = new \StdClass();
|
||||
$obj->name = '聚合支付';
|
||||
$obj->method = 5;
|
||||
$obj->icon = 'wallet';
|
||||
array_push($data, $obj);
|
||||
}
|
||||
|
||||
return response([
|
||||
'data' => $data
|
||||
]);
|
||||
}
|
||||
|
||||
public function cancel(Request $request)
|
||||
{
|
||||
if (empty($request->input('trade_no'))) {
|
||||
abort(500, '参数有误');
|
||||
}
|
||||
$order = Order::where('trade_no', $request->input('trade_no'))
|
||||
->where('user_id', $request->session()->get('id'))
|
||||
->first();
|
||||
if (!$order) {
|
||||
abort(500, '订单不存在');
|
||||
}
|
||||
if ($order->status !== 0) {
|
||||
abort(500, '只可以取消待支付订单');
|
||||
}
|
||||
$order->status = 2;
|
||||
if (!$order->save()) {
|
||||
abort(500, '取消失败');
|
||||
}
|
||||
return response([
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
private function alipayF2F($tradeNo, $totalAmount)
|
||||
{
|
||||
$gateway = Omnipay::create('Alipay_AopF2F');
|
||||
$gateway->setSignType('RSA2'); //RSA/RSA2
|
||||
$gateway->setAppId(config('v2board.alipay_appid'));
|
||||
$gateway->setPrivateKey(config('v2board.alipay_privkey')); // 可以是路径,也可以是密钥内容
|
||||
$gateway->setAlipayPublicKey(config('v2board.alipay_pubkey')); // 可以是路径,也可以是密钥内容
|
||||
$gateway->setNotifyUrl(url('/api/v1/guest/order/alipayNotify'));
|
||||
$request = $gateway->purchase();
|
||||
$request->setBizContent([
|
||||
'subject' => config('v2board.app_name', 'V2Board') . ' - 订阅',
|
||||
'out_trade_no' => $tradeNo,
|
||||
'total_amount' => $totalAmount / 100
|
||||
]);
|
||||
/** @var \Omnipay\Alipay\Responses\AopTradePreCreateResponse $response */
|
||||
$response = $request->send();
|
||||
$result = $response->getAlipayResponse();
|
||||
if ($result['code'] !== '10000') {
|
||||
abort(500, $result['sub_msg']);
|
||||
}
|
||||
// 获取收款二维码内容
|
||||
return $response->getQrCode();
|
||||
}
|
||||
|
||||
private function stripeAlipay($order)
|
||||
{
|
||||
$currency = config('stripe_currency', 'hkd');
|
||||
$exchange = Helper::exchange('CNY', strtoupper($currency));
|
||||
if (!$exchange) {
|
||||
abort(500, '货币转换超时,请稍后再试');
|
||||
}
|
||||
Stripe::setApiKey(config('v2board.stripe_sk_live'));
|
||||
$source = Source::create([
|
||||
'amount' => floor($order->total_amount * $exchange),
|
||||
'currency' => $currency,
|
||||
'type' => 'alipay',
|
||||
'redirect' => [
|
||||
'return_url' => config('v2board.app_url', env('APP_URL')) . '/#/order'
|
||||
]
|
||||
]);
|
||||
if (!$source['redirect']['url']) {
|
||||
abort(500, '支付网关请求失败');
|
||||
}
|
||||
|
||||
if (!Cache::put($source['id'], $order->trade_no, 3600)) {
|
||||
abort(500, '订单创建失败');
|
||||
}
|
||||
return $source['redirect']['url'];
|
||||
}
|
||||
|
||||
private function stripeWepay($order)
|
||||
{
|
||||
$currency = config('stripe_currency', 'hkd');
|
||||
$exchange = Helper::exchange('CNY', strtoupper($currency));
|
||||
if (!$exchange) {
|
||||
abort(500, '货币转换超时,请稍后再试');
|
||||
}
|
||||
Stripe::setApiKey(config('v2board.stripe_sk_live'));
|
||||
$source = Source::create([
|
||||
'amount' => floor($order->total_amount * $exchange),
|
||||
'currency' => $currency,
|
||||
'type' => 'wechat',
|
||||
'redirect' => [
|
||||
'return_url' => config('v2board.app_url', env('APP_URL')) . '/#/order'
|
||||
]
|
||||
]);
|
||||
if (!$source['wechat']['qr_code_url']) {
|
||||
abort(500, '支付网关请求失败');
|
||||
}
|
||||
if (!Cache::put($source['id'], $order->trade_no, 3600)) {
|
||||
abort(500, '订单创建失败');
|
||||
}
|
||||
return $source['wechat']['qr_code_url'];
|
||||
}
|
||||
|
||||
private function bitpayX($order)
|
||||
{
|
||||
$bitpayX = new BitpayX(config('v2board.bitpayx_appsecret'));
|
||||
$params = [
|
||||
'merchant_order_id' => $order->trade_no,
|
||||
'price_amount' => $order->total_amount / 100,
|
||||
'price_currency' => 'CNY',
|
||||
'title' => '支付单号:' . $order->trade_no,
|
||||
'description' => '充值:' . $order->total_amount / 100 . ' 元',
|
||||
'callback_url' => url('/api/v1/guest/order/bitpayXNotify'),
|
||||
'success_url' => config('v2board.app_url', env('APP_URL')) . '/#/order',
|
||||
'cancel_url' => config('v2board.app_url', env('APP_URL')) . '/#/order'
|
||||
];
|
||||
$strToSign = $bitpayX->prepareSignId($params['merchant_order_id']);
|
||||
$params['token'] = $bitpayX->sign($strToSign);
|
||||
$result = $bitpayX->mprequest($params);
|
||||
Log::info('bitpayXSubmit: ' . json_encode($result));
|
||||
return isset($result['payment_url']) ? $result['payment_url'] : false;
|
||||
}
|
||||
|
||||
private function payTaro($order)
|
||||
{
|
||||
$payTaro = new PayTaro(config('v2board.paytaro_app_id'), config('v2board.paytaro_app_secret'));
|
||||
$result = $payTaro->pay([
|
||||
'app_id' => config('v2board.paytaro_app_id'),
|
||||
'out_trade_no' => $order->trade_no,
|
||||
'total_amount' => $order->total_amount,
|
||||
'notify_url' => url('/api/v1/guest/order/payTaroNotify'),
|
||||
'return_url' => config('v2board.app_url', env('APP_URL')) . '/#/order'
|
||||
]);
|
||||
return $result;
|
||||
}
|
||||
}
|
29
app/Http/Controllers/User/PlanController.php
Executable file
29
app/Http/Controllers/User/PlanController.php
Executable file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Plan;
|
||||
|
||||
class PlanController extends Controller
|
||||
{
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
if ($request->input('id')) {
|
||||
$plan = Plan::where('id', $request->input('id'))
|
||||
->first();
|
||||
if (!$plan) {
|
||||
abort(500, '该订阅不存在');
|
||||
}
|
||||
return response([
|
||||
'data' => $plan
|
||||
]);
|
||||
}
|
||||
$plan = Plan::where('show', 1)
|
||||
->get();
|
||||
return response([
|
||||
'data' => $plan
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,21 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\UserService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Models\Server;
|
||||
use App\Models\ServerLog;
|
||||
use App\Models\User;
|
||||
|
||||
use App\Utils\Helper;
|
||||
|
||||
class ServerController extends Controller {
|
||||
public function fetch (Request $request) {
|
||||
class ServerController extends Controller
|
||||
{
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
$user = User::find($request->session()->get('id'));
|
||||
$server = [];
|
||||
if ($user->expired_at > time()) {
|
||||
$userService = new UserService();
|
||||
if ($userService->isAvailable($user)) {
|
||||
$servers = Server::where('show', 1)
|
||||
->orderBy('name')
|
||||
->get();
|
||||
@ -28,30 +32,38 @@ class ServerController extends Controller {
|
||||
}
|
||||
for ($i = 0; $i < count($server); $i++) {
|
||||
$server[$i]['link'] = Helper::buildVmessLink($server[$i], $user);
|
||||
$server[$i]['last_check_at'] = Redis::get('server_last_check_at_' . $server[$i]['id']);
|
||||
if ($server[$i]['parent_id']) {
|
||||
$server[$i]['last_check_at'] = Cache::get('server_last_check_at_' . $server[$i]['parent_id']);
|
||||
} else {
|
||||
$server[$i]['last_check_at'] = Cache::get('server_last_check_at_' . $server[$i]['id']);
|
||||
}
|
||||
}
|
||||
return response([
|
||||
'data' => $server
|
||||
]);
|
||||
}
|
||||
|
||||
public function logFetch (Request $request) {
|
||||
$type = $request->input('type') ? $request->input('type') : 0;
|
||||
public function logFetch(Request $request)
|
||||
{
|
||||
$type = $request->input('type') ? $request->input('type') : 0;
|
||||
$current = $request->input('current') ? $request->input('current') : 1;
|
||||
$pageSize = $request->input('pageSize') >= 10 ? $request->input('pageSize') : 10;
|
||||
$serverLogModel = ServerLog::where('user_id', $request->session()->get('id'))
|
||||
->orderBy('created_at', 'DESC');
|
||||
switch ($type) {
|
||||
case 0: $serverLogModel->where('created_at', '>=', strtotime(date('Y-m-d')));
|
||||
break;
|
||||
case 1: $serverLogModel->where('created_at', '>=', strtotime(date('Y-m-d')) - 604800);
|
||||
break;
|
||||
case 2: $serverLogModel->where('created_at', '>=', strtotime(date('Y-m-1')));
|
||||
}
|
||||
$sum = [
|
||||
'u' => $serverLogModel->sum('u'),
|
||||
'd' => $serverLogModel->sum('d')
|
||||
];
|
||||
switch ($type) {
|
||||
case 0:
|
||||
$serverLogModel->where('created_at', '>=', strtotime(date('Y-m-d')));
|
||||
break;
|
||||
case 1:
|
||||
$serverLogModel->where('created_at', '>=', strtotime(date('Y-m-d')) - 604800);
|
||||
break;
|
||||
case 2:
|
||||
$serverLogModel->where('created_at', '>=', strtotime(date('Y-m-1')));
|
||||
}
|
||||
$sum = [
|
||||
'u' => $serverLogModel->sum('u'),
|
||||
'd' => $serverLogModel->sum('d')
|
||||
];
|
||||
$total = $serverLogModel->count();
|
||||
$res = $serverLogModel->forPage($current, $pageSize)
|
||||
->get();
|
||||
@ -61,4 +73,4 @@ class ServerController extends Controller {
|
||||
'sum' => $sum
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use App\Http\Requests\TicketSave;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\User\TicketSave;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\TicketMessage;
|
||||
use App\Utils\Helper;
|
||||
@ -12,7 +12,8 @@ use Illuminate\Support\Facades\DB;
|
||||
|
||||
class TicketController extends Controller
|
||||
{
|
||||
public function fetch (Request $request) {
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
if ($request->input('id')) {
|
||||
$ticket = Ticket::where('id', $request->input('id'))
|
||||
->where('user_id', $request->session()->get('id'))
|
||||
@ -47,7 +48,8 @@ class TicketController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function save (TicketSave $request) {
|
||||
public function save(TicketSave $request)
|
||||
{
|
||||
DB::beginTransaction();
|
||||
$ticket = Ticket::create(array_merge($request->only([
|
||||
'subject',
|
||||
@ -75,7 +77,8 @@ class TicketController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function reply (Request $request) {
|
||||
public function reply(Request $request)
|
||||
{
|
||||
if (empty($request->input('id'))) {
|
||||
abort(500, '参数错误');
|
||||
}
|
||||
@ -112,7 +115,8 @@ class TicketController extends Controller
|
||||
}
|
||||
|
||||
|
||||
public function close (Request $request) {
|
||||
public function close(Request $request)
|
||||
{
|
||||
if (empty($request->input('id'))) {
|
||||
abort(500, '参数错误');
|
||||
}
|
||||
@ -131,7 +135,8 @@ class TicketController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
private function getLastMessage ($ticketId) {
|
||||
private function getLastMessage($ticketId)
|
||||
{
|
||||
return TicketMessage::where('ticket_id', $ticketId)
|
||||
->orderBy('id', 'DESC')
|
||||
->first();
|
77
app/Http/Controllers/User/TutorialController.php
Normal file
77
app/Http/Controllers/User/TutorialController.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\User;
|
||||
use App\Models\Tutorial;
|
||||
|
||||
class TutorialController extends Controller
|
||||
{
|
||||
public function getSubscribeUrl(Request $request)
|
||||
{
|
||||
$user = User::find($request->session()->get('id'));
|
||||
return response([
|
||||
'data' => [
|
||||
'subscribe_url' => config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user['token']
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function getAppleID(Request $request)
|
||||
{
|
||||
$user = User::find($request->session()->get('id'));
|
||||
if ($user->expired_at < time()) {
|
||||
return response([
|
||||
'data' => [
|
||||
]
|
||||
]);
|
||||
}
|
||||
return response([
|
||||
'data' => [
|
||||
'apple_id' => config('v2board.apple_id'),
|
||||
'apple_id_password' => config('v2board.apple_id_password')
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
if ($request->input('id')) {
|
||||
$tutorial = Tutorial::where('show', 1)
|
||||
->where('id', $request->input('id'))
|
||||
->first();
|
||||
if (!$tutorial) {
|
||||
abort(500, '教程不存在');
|
||||
}
|
||||
return response([
|
||||
'data' => $tutorial
|
||||
]);
|
||||
}
|
||||
$tutorial = Tutorial::select(['id', 'category_id', 'title', 'icon'])
|
||||
->where('show', 1)
|
||||
->get()
|
||||
->groupBy('category_id');
|
||||
$user = User::find($request->session()->get('id'));
|
||||
$response = [
|
||||
'data' => [
|
||||
'tutorials' => $tutorial,
|
||||
'safe_area_var' => [
|
||||
'subscribe_url' => config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user['token'],
|
||||
'app_name' => config('v2board.app_name', 'V2board'),
|
||||
'apple_id' => $user->expired_at > time() || $user->expired_at === NULL ? config('v2board.apple_id', '本站暂无提供AppleID信息') : '账号过期或未订阅',
|
||||
'apple_id_password' => $user->expired_at > time() || $user->expired_at === NULL ? config('v2board.apple_id_password', '本站暂无提供AppleID信息') : '账号过期或未订阅'
|
||||
]
|
||||
]
|
||||
];
|
||||
// fuck support shadowrocket urlsafeb64 subscribe
|
||||
$response['data']['safe_area_var']['b64_subscribe_url'] = str_replace(
|
||||
array('+', '/', '='),
|
||||
array('-', '_', ''),
|
||||
base64_encode($response['data']['safe_area_var']['subscribe_url'])
|
||||
);
|
||||
// end
|
||||
return response($response);
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use App\Http\Requests\UserUpdate;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\User\UserUpdate;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\User;
|
||||
use App\Models\Plan;
|
||||
use App\Models\Server;
|
||||
@ -15,13 +15,16 @@ use App\Models\ServerLog;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function logout (Request $request) {
|
||||
public function logout(Request $request)
|
||||
{
|
||||
$request->session()->flush();
|
||||
return response([
|
||||
'data' => $request->session()->flush()
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
public function changePassword (Request $request) {
|
||||
public function changePassword(Request $request)
|
||||
{
|
||||
if (empty($request->input('old_password'))) {
|
||||
abort(500, '旧密码不能为空');
|
||||
}
|
||||
@ -29,10 +32,15 @@ class UserController extends Controller
|
||||
abort(500, '新密码不能为空');
|
||||
}
|
||||
$user = User::find($request->session()->get('id'));
|
||||
if (!password_verify($request->input('old_password'), $user->password)) {
|
||||
if (!Helper::multiPasswordVerify(
|
||||
$user->password_algo,
|
||||
$request->input('old_password'),
|
||||
$user->password)
|
||||
) {
|
||||
abort(500, '旧密码有误');
|
||||
}
|
||||
$user->password = password_hash($request->input('new_password'), PASSWORD_DEFAULT);
|
||||
$user->password_algo = NULL;
|
||||
if (!$user->save()) {
|
||||
abort(500, '保存失败');
|
||||
}
|
||||
@ -41,20 +49,25 @@ class UserController extends Controller
|
||||
'data' => true
|
||||
]);
|
||||
}
|
||||
|
||||
public function info (Request $request) {
|
||||
|
||||
public function info(Request $request)
|
||||
{
|
||||
$user = User::where('id', $request->session()->get('id'))
|
||||
->select([
|
||||
'email',
|
||||
'transfer_enable',
|
||||
'last_login_at',
|
||||
'created_at',
|
||||
'enable',
|
||||
'banned',
|
||||
'is_admin',
|
||||
'remind_expire',
|
||||
'remind_traffic',
|
||||
'expired_at',
|
||||
'balance',
|
||||
'commission_balance'
|
||||
'commission_balance',
|
||||
'plan_id',
|
||||
'discount',
|
||||
'commission_rate'
|
||||
])
|
||||
->first();
|
||||
$user['avatar_url'] = 'https://cdn.v2ex.com/gravatar/' . md5($user->email) . '?s=64&d=identicon';
|
||||
@ -63,7 +76,8 @@ class UserController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function getStat (Request $request) {
|
||||
public function getStat(Request $request)
|
||||
{
|
||||
$stat = [
|
||||
Order::where('status', 0)
|
||||
->where('user_id', $request->session()->get('id'))
|
||||
@ -79,7 +93,8 @@ class UserController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function getSubscribe (Request $request) {
|
||||
public function getSubscribe(Request $request)
|
||||
{
|
||||
$user = User::find($request->session()->get('id'));
|
||||
if ($user->plan_id) {
|
||||
$user['plan'] = Plan::find($user->plan_id);
|
||||
@ -92,8 +107,9 @@ class UserController extends Controller
|
||||
'data' => $user
|
||||
]);
|
||||
}
|
||||
|
||||
public function resetSecurity (Request $request) {
|
||||
|
||||
public function resetSecurity(Request $request)
|
||||
{
|
||||
$user = User::find($request->session()->get('id'));
|
||||
$user->v2ray_uuid = Helper::guid(true);
|
||||
$user->token = Helper::guid();
|
||||
@ -101,16 +117,17 @@ class UserController extends Controller
|
||||
abort(500, '重置失败');
|
||||
}
|
||||
return response([
|
||||
'data' => true
|
||||
'data' => config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user->token
|
||||
]);
|
||||
}
|
||||
|
||||
public function update (UserUpdate $request) {
|
||||
public function update(UserUpdate $request)
|
||||
{
|
||||
$updateData = $request->only([
|
||||
'remind_expire',
|
||||
'remind_traffic'
|
||||
]);
|
||||
|
||||
|
||||
$user = User::find($request->session()->get('id'));
|
||||
if (!$user) {
|
||||
abort(500, '该用户不存在');
|
@ -43,7 +43,7 @@ class Kernel extends HttpKernel
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\App\Http\Middleware\ForceJson::class,
|
||||
\App\Http\Middleware\CORS::class,
|
||||
'throttle:60,1',
|
||||
'throttle:120,1',
|
||||
'bindings',
|
||||
],
|
||||
];
|
||||
|
@ -9,8 +9,8 @@ class Admin
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
|
@ -9,12 +9,12 @@ class Authenticate extends Middleware
|
||||
/**
|
||||
* Get the path the user should be redirected to when they are not authenticated.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return string
|
||||
*/
|
||||
protected function redirectTo($request)
|
||||
{
|
||||
if (! $request->expectsJson()) {
|
||||
if (!$request->expectsJson()) {
|
||||
return route('login');
|
||||
}
|
||||
}
|
||||
|
@ -9,9 +9,9 @@ class CORS
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$origin = $request->header('origin');
|
||||
if(empty($origin)){
|
||||
if (empty($origin)) {
|
||||
$referer = $request->header('referer');
|
||||
if(!empty($referer)&&preg_match("/^((https|http):\/\/)?([^\/]+)/i", $referer, $matches)){
|
||||
if (!empty($referer) && preg_match("/^((https|http):\/\/)?([^\/]+)/i", $referer, $matches)) {
|
||||
$origin = $matches[0];
|
||||
}
|
||||
}
|
||||
@ -21,7 +21,7 @@ class CORS
|
||||
$response->header('Access-Control-Allow-Headers', 'Content-Type,X-Requested-With');
|
||||
$response->header('Access-Control-Allow-Credentials', 'true');
|
||||
$response->header('Access-Control-Max-Age', 10080);
|
||||
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,8 @@ class Client
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
|
@ -9,9 +9,9 @@ class ForceJson
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next, $guard = null)
|
||||
|
@ -10,9 +10,9 @@ class RedirectIfAuthenticated
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next, $guard = null)
|
||||
|
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use App\Models\User;
|
||||
|
||||
class Server
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$token = $request->input('token');
|
||||
if (empty($token)) {
|
||||
abort(500, 'token is null');
|
||||
}
|
||||
if ($token !== config('v2board.server_token')) {
|
||||
abort(500, 'token is error');
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
@ -9,12 +9,19 @@ class User
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if ($request->input('access_token')) {
|
||||
$user = \App\Models\User::where('token', $request->input('access_token'))->first();
|
||||
if ($user) {
|
||||
$request->session()->put('email', $user->email);
|
||||
$request->session()->put('id', $user->id);
|
||||
}
|
||||
}
|
||||
if (!$request->session()->get('id')) {
|
||||
abort(403, '未登录或登陆已过期');
|
||||
}
|
||||
|
@ -6,40 +6,59 @@ use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ConfigSave extends FormRequest
|
||||
{
|
||||
public static function filter() {
|
||||
return [
|
||||
'invite_force',
|
||||
'invite_commission',
|
||||
'invite_gen_limit',
|
||||
'invite_never_expire',
|
||||
'stop_register',
|
||||
'email_verify',
|
||||
'app_name',
|
||||
'app_url',
|
||||
'subscribe_url',
|
||||
'plan_update_fee',
|
||||
'plan_is_update',
|
||||
// server
|
||||
'server_token',
|
||||
// alipay
|
||||
'alipay_enable',
|
||||
'alipay_appid',
|
||||
'alipay_pubkey',
|
||||
'alipay_privkey',
|
||||
// stripe
|
||||
'stripe_sk_live',
|
||||
'stripe_pk_live',
|
||||
'stripe_alipay_enable',
|
||||
'stripe_wepay_enable',
|
||||
'stripe_webhook_key',
|
||||
// bitpayx,
|
||||
'bitpayx_enable',
|
||||
'bitpayx_appsecret',
|
||||
// tutorial
|
||||
'apple_id',
|
||||
'apple_id_password'
|
||||
];
|
||||
}
|
||||
CONST RULES = [
|
||||
'safe_mode_enable' => 'in:0,1',
|
||||
'invite_force' => 'in:0,1',
|
||||
'invite_commission' => 'integer',
|
||||
'invite_gen_limit' => 'integer',
|
||||
'invite_never_expire' => 'in:0,1',
|
||||
'stop_register' => 'in:0,1',
|
||||
'email_verify' => 'in:0,1',
|
||||
'app_name' => '',
|
||||
'app_description' => '',
|
||||
'app_url' => 'nullable|url',
|
||||
'subscribe_url' => 'nullable|url',
|
||||
'try_out_enable' => 'in:0,1',
|
||||
'try_out_plan_id' => 'integer',
|
||||
'try_out_hour' => 'numeric',
|
||||
'email_whitelist_enable' => 'in:0,1',
|
||||
'email_whitelist_suffix' => '',
|
||||
// subscribe
|
||||
'plan_change_enable' => 'in:0,1',
|
||||
'reset_traffic_method' => 'in:0,1',
|
||||
'renew_reset_traffic_enable' => 'in:0,1',
|
||||
// server
|
||||
'server_token' => 'nullable|min:16',
|
||||
'server_license' => 'nullable',
|
||||
// alipay
|
||||
'alipay_enable' => 'in:0,1',
|
||||
'alipay_appid' => 'nullable|integer|min:16',
|
||||
'alipay_pubkey' => 'max:2048',
|
||||
'alipay_privkey' => 'max:2048',
|
||||
// stripe
|
||||
'stripe_alipay_enable' => 'in:0,1',
|
||||
'stripe_wepay_enable' => 'in:0,1',
|
||||
'stripe_sk_live' => '',
|
||||
'stripe_pk_live' => '',
|
||||
'stripe_webhook_key' => '',
|
||||
'stripe_currency' => 'in:hkd,usd,sgd',
|
||||
// bitpayx
|
||||
'bitpayx_enable' => 'in:0,1',
|
||||
'bitpayx_appsecret' => '',
|
||||
// paytaro
|
||||
'paytaro_enable' => 'in:0,1',
|
||||
'paytaro_app_id' => '',
|
||||
'paytaro_app_secret' => '',
|
||||
// frontend
|
||||
'frontend_theme_sidebar' => 'in:dark,light',
|
||||
'frontend_theme_header' => 'in:dark,light',
|
||||
'frontend_theme_color' => 'in:default,darkblue,black',
|
||||
'frontend_background_url' => 'nullable|url',
|
||||
// tutorial
|
||||
'apple_id' => 'email',
|
||||
'apple_id_password' => ''
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
@ -47,37 +66,15 @@ class ConfigSave extends FormRequest
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'invite_force' => 'in:0,1',
|
||||
'invite_commission' => 'integer',
|
||||
'invite_gen_limit' => 'integer',
|
||||
'invite_never_expire' => 'in:0,1',
|
||||
'stop_register' => 'in:0,1',
|
||||
'email_verify' => 'in:0,1',
|
||||
'app_url' => 'url',
|
||||
'subscribe_url' => 'url',
|
||||
'plan_update_fee' => 'numeric',
|
||||
'plan_is_update' => 'in:0,1',
|
||||
// server
|
||||
'server_token' => 'min:16',
|
||||
// alipay
|
||||
'alipay_enable' => 'in:0,1',
|
||||
'alipay_appid' => 'integer|min:16',
|
||||
'alipay_pubkey' => 'max:2048',
|
||||
'alipay_privkey' => 'max:2048',
|
||||
// stripe
|
||||
'stripe_alipay_enable' => 'in:0,1',
|
||||
'stripe_wepay_enable' => 'in:0,1',
|
||||
// bitpayx
|
||||
'bitpayx_enable' => 'in:0,1',
|
||||
// tutorial
|
||||
'apple_id' => 'email'
|
||||
];
|
||||
return self::RULES;
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
// illiteracy prompt
|
||||
return [
|
||||
'app_url.url' => '站点URL格式不正确,必须携带http(s)://',
|
||||
'subscribe_url.url' => '订阅URL格式不正确,必须携带http(s)://'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
41
app/Http/Requests/Admin/CouponSave.php
Normal file
41
app/Http/Requests/Admin/CouponSave.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Admin;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class CouponSave extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'required',
|
||||
'type' => 'required|in:1,2',
|
||||
'value' => 'required|integer',
|
||||
'started_at' => 'required|integer',
|
||||
'ended_at' => 'required|integer',
|
||||
'limit_use' => 'nullable|integer'
|
||||
];
|
||||
}
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'name.required' => '名称不能为空',
|
||||
'type.required' => '类型不能为空',
|
||||
'type.in' => '类型格式有误',
|
||||
'value.required' => '金额或比例不能为空',
|
||||
'value.integer' => '金额或比例格式有误',
|
||||
'started_at.required' => '开始时间不能为空',
|
||||
'started_at.integer' => '开始时间格式有误',
|
||||
'ended_at.required' => '结束时间不能为空',
|
||||
'ended_at.integer' => '结束时间格式有误',
|
||||
'limit_use.integer' => '使用次数格式有误'
|
||||
];
|
||||
}
|
||||
}
|
34
app/Http/Requests/Admin/MailSend.php
Normal file
34
app/Http/Requests/Admin/MailSend.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Admin;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class MailSend extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'type' => 'required|in:1,2,3,4',
|
||||
'subject' => 'required',
|
||||
'content' => 'required',
|
||||
'receiver' => 'array'
|
||||
];
|
||||
}
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'type.required' => '发送类型不能为空',
|
||||
'type.in' => '发送类型格式有误',
|
||||
'subject.required' => '主题不能为空',
|
||||
'content.required' => '内容不能为空',
|
||||
'receiver.array' => '收件人格式有误'
|
||||
];
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ class NoticeSave extends FormRequest
|
||||
'img_url' => 'url'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
|
@ -15,15 +15,15 @@ class OrderUpdate extends FormRequest
|
||||
{
|
||||
return [
|
||||
'status' => 'in:0,1,2,3',
|
||||
'commission_status' => 'in:0,1'
|
||||
'commission_status' => 'in:0,1,2'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'status.in' => '销售状态格式不正确',
|
||||
'commission_status.in' => '续费状态格式不正确'
|
||||
'commission_status.in' => '佣金状态格式不正确'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,17 @@ use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class PlanSave extends FormRequest
|
||||
{
|
||||
CONST RULES = [
|
||||
'name' => 'required',
|
||||
'content' => '',
|
||||
'group_id' => 'required',
|
||||
'transfer_enable' => 'required',
|
||||
'month_price' => 'nullable|integer',
|
||||
'quarter_price' => 'nullable|integer',
|
||||
'half_year_price' => 'nullable|integer',
|
||||
'year_price' => 'nullable|integer',
|
||||
'onetime_price' => 'nullable|integer'
|
||||
];
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
@ -13,27 +24,22 @@ class PlanSave extends FormRequest
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'required',
|
||||
'group_id' => 'required',
|
||||
'transfer_enable' => 'required',
|
||||
'month_price' => 'required|numeric',
|
||||
'quarter_price' => 'required|numeric',
|
||||
'half_year_price' => 'required|numeric',
|
||||
'year_price' => 'required|numeric'
|
||||
];
|
||||
return self::RULES;
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'name.required' => '套餐名称不能为空',
|
||||
'type.required' => '套餐类型不能为空',
|
||||
'type.in' => '套餐类型格式有误',
|
||||
'group_id.required' => '权限组不能为空',
|
||||
'transfer_enable.required' => '流量不能为空',
|
||||
'month_price.required' => '月付金额不能为空',
|
||||
'quarter_price.required' => '季付金额不能为空',
|
||||
'half_year_price.required' => '半年付金额不能为空',
|
||||
'year_price.required' => '年付金额不能为空'
|
||||
'month_price.integer' => '月付金额格式有误',
|
||||
'quarter_price.integer' => '季付金额格式有误',
|
||||
'half_year_price.integer' => '半年付金额格式有误',
|
||||
'year_price.integer' => '年付金额格式有误',
|
||||
'onetime_price.integer' => '一次性金额有误'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ class PlanUpdate extends FormRequest
|
||||
'renew' => 'in:0,1'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
|
@ -6,6 +6,21 @@ use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ServerSave extends FormRequest
|
||||
{
|
||||
CONST RULES = [
|
||||
'rules' => '',
|
||||
'show' => '',
|
||||
'name' => 'required',
|
||||
'group_id' => 'required|array',
|
||||
'parent_id' => 'nullable|integer',
|
||||
'host' => 'required',
|
||||
'port' => 'required',
|
||||
'server_port' => 'required',
|
||||
'tls' => 'required',
|
||||
'tags' => 'array',
|
||||
'rate' => 'required|numeric',
|
||||
'network' => 'required|in:tcp,kcp,ws,http,domainsocket,quic',
|
||||
'settings' => ''
|
||||
];
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
@ -13,25 +28,16 @@ class ServerSave extends FormRequest
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'required',
|
||||
'group_id' => 'required|array',
|
||||
'host' => 'required',
|
||||
'port' => 'required',
|
||||
'server_port' => 'required',
|
||||
'tls' => 'required',
|
||||
'tags' => 'array',
|
||||
'rate' => 'required|numeric',
|
||||
'network' => 'required|in:tcp,kcp,ws,http,domainsocket,quic'
|
||||
];
|
||||
return self::RULES;
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'name.required' => '节点名称不能为空',
|
||||
'group_id.required' => '权限组不能为空',
|
||||
'group_id.required' => '权限组不能为空',
|
||||
'group_id.array' => '权限组格式不正确',
|
||||
'parent_id.integer' => '父ID格式不正确',
|
||||
'host.required' => '节点地址不能为空',
|
||||
'port.required' => '连接端口不能为空',
|
||||
'server_port.required' => '后端服务端口不能为空',
|
||||
|
@ -11,14 +11,14 @@ class ServerUpdate extends FormRequest
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'show' => 'in:0,1'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
|
36
app/Http/Requests/Admin/TutorialSave.php
Normal file
36
app/Http/Requests/Admin/TutorialSave.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Admin;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class TutorialSave extends FormRequest
|
||||
{
|
||||
CONST RULES = [
|
||||
'title' => 'required',
|
||||
// 1:windows 2:macos 3:ios 4:android 5:linux 6:router
|
||||
'category_id' => 'required|in:1,2,3,4,5,6',
|
||||
'icon' => 'required',
|
||||
'steps' => 'required'
|
||||
];
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return self::RULES;
|
||||
}
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'title.required' => '标题不能为空',
|
||||
'category_id.required' => '分类不能为空',
|
||||
'category_id.in' => '分类格式不正确',
|
||||
'icon.required' => '图标不能为空',
|
||||
'steps.required' => '教程步骤不能为空'
|
||||
];
|
||||
}
|
||||
}
|
@ -6,6 +6,21 @@ use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UserUpdate extends FormRequest
|
||||
{
|
||||
CONST RULES = [
|
||||
'email' => 'required|email',
|
||||
'password' => 'nullable',
|
||||
'transfer_enable' => 'numeric',
|
||||
'expired_at' => 'nullable|integer',
|
||||
'banned' => 'required|in:0,1',
|
||||
'plan_id' => 'nullable|integer',
|
||||
'commission_rate' => 'nullable|integer|min:0|max:100',
|
||||
'discount' => 'nullable|integer|min:0|max:100',
|
||||
'is_admin' => 'required|in:0,1',
|
||||
'u' => 'integer',
|
||||
'd' => 'integer',
|
||||
'balance' => 'integer',
|
||||
'commission_balance' => 'integer'
|
||||
];
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
@ -13,17 +28,9 @@ class UserUpdate extends FormRequest
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'email' => 'required|email',
|
||||
'transfer_enable' => 'numeric',
|
||||
'expired_at' => 'integer',
|
||||
'banned' => 'required|in:0,1',
|
||||
'is_admin' => 'required|in:0,1',
|
||||
'plan_id' => 'integer',
|
||||
'commission_rate' => 'nullable|integer|min:0|max:100'
|
||||
];
|
||||
return self::RULES;
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
@ -39,7 +46,15 @@ class UserUpdate extends FormRequest
|
||||
'commission_rate.integer' => '推荐返利比例格式不正确',
|
||||
'commission_rate.nullable' => '推荐返利比例格式不正确',
|
||||
'commission_rate.min' => '推荐返利比例最小为0',
|
||||
'commission_rate.max' => '推荐返利比例最大为100'
|
||||
'commission_rate.max' => '推荐返利比例最大为100',
|
||||
'discount.integer' => '专属折扣比例格式不正确',
|
||||
'discount.nullable' => '专属折扣比例格式不正确',
|
||||
'discount.min' => '专属折扣比例最小为0',
|
||||
'discount.max' => '专属折扣比例最大为100',
|
||||
'u.integer' => '上行流量格式不正确',
|
||||
'd.integer' => '下行流量格式不正确',
|
||||
'balance.integer' => '余额格式不正确',
|
||||
'commission_balance.integer' => '佣金格式不正确'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ namespace App\Http\Requests\Passport;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ForgetIndex extends FormRequest
|
||||
class AuthForget extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
@ -19,12 +19,12 @@ class ForgetIndex extends FormRequest
|
||||
'email_code' => 'required'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'email.required' => '邮箱不能为空',
|
||||
'email.email' => '邮箱格式不正确',
|
||||
'email.email' => '邮箱格式不正确',
|
||||
'password.required' => '密码不能为空',
|
||||
'password.min' => '密码必须大于8位数',
|
||||
'email_code.required' => '邮箱验证码不能为空'
|
@ -4,7 +4,7 @@ namespace App\Http\Requests\Passport;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class LoginIndex extends FormRequest
|
||||
class AuthLogin extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
@ -18,12 +18,12 @@ class LoginIndex extends FormRequest
|
||||
'password' => 'required|min:8'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'email.required' => '邮箱不能为空',
|
||||
'email.email' => '邮箱格式不正确',
|
||||
'email.email' => '邮箱格式不正确',
|
||||
'password.required' => '密码不能为空',
|
||||
'password.min' => '密码必须大于8位数'
|
||||
];
|
@ -4,7 +4,7 @@ namespace App\Http\Requests\Passport;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class RegisterIndex extends FormRequest
|
||||
class AuthRegister extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
@ -18,12 +18,12 @@ class RegisterIndex extends FormRequest
|
||||
'password' => 'required|min:8'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'email.required' => '邮箱不能为空',
|
||||
'email.email' => '邮箱格式不正确',
|
||||
'email.email' => '邮箱格式不正确',
|
||||
'password.required' => '密码不能为空',
|
||||
'password.min' => '密码必须大于8位数'
|
||||
];
|
@ -17,12 +17,12 @@ class CommSendEmailVerify extends FormRequest
|
||||
'email' => 'required|email'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'email.required' => '邮箱不能为空',
|
||||
'email.email' => '邮箱格式不正确'
|
||||
'email.email' => '邮箱格式不正确'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
namespace App\Http\Requests\User;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
@ -15,10 +15,10 @@ class OrderSave extends FormRequest
|
||||
{
|
||||
return [
|
||||
'plan_id' => 'required',
|
||||
'cycle' => 'required|in:month_price,quarter_price,half_year_price,year_price'
|
||||
'cycle' => 'required|in:month_price,quarter_price,half_year_price,year_price,onetime_price'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
namespace App\Http\Requests\User;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
@ -19,7 +19,7 @@ class TicketSave extends FormRequest
|
||||
'message' => 'required'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
namespace App\Http\Requests\User;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
@ -18,7 +18,7 @@ class UserUpdate extends FormRequest
|
||||
'remind_traffic' => 'in:0,1'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
62
app/Http/Routes/AdminRoute.php
Normal file
62
app/Http/Routes/AdminRoute.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
namespace App\Http\Routes;
|
||||
|
||||
use Illuminate\Contracts\Routing\Registrar;
|
||||
|
||||
class AdminRoute
|
||||
{
|
||||
public function map(Registrar $router)
|
||||
{
|
||||
$router->group([
|
||||
'prefix' => 'admin',
|
||||
'middleware' => 'admin'
|
||||
], function ($router) {
|
||||
// Config
|
||||
$router->get ('/config/fetch', 'Admin\\ConfigController@fetch');
|
||||
$router->post('/config/save', 'Admin\\ConfigController@save');
|
||||
// Plan
|
||||
$router->get ('/plan/fetch', 'Admin\\PlanController@fetch');
|
||||
$router->post('/plan/save', 'Admin\\PlanController@save');
|
||||
$router->post('/plan/drop', 'Admin\\PlanController@drop');
|
||||
$router->post('/plan/update', 'Admin\\PlanController@update');
|
||||
// Server
|
||||
$router->get ('/server/fetch', 'Admin\\ServerController@fetch');
|
||||
$router->post('/server/save', 'Admin\\ServerController@save');
|
||||
$router->get ('/server/group/fetch', 'Admin\\ServerController@groupFetch');
|
||||
$router->post('/server/group/save', 'Admin\\ServerController@groupSave');
|
||||
$router->post('/server/group/drop', 'Admin\\ServerController@groupDrop');
|
||||
$router->post('/server/drop', 'Admin\\ServerController@drop');
|
||||
$router->post('/server/update', 'Admin\\ServerController@update');
|
||||
// Order
|
||||
$router->get ('/order/fetch', 'Admin\\OrderController@fetch');
|
||||
$router->post('/order/repair', 'Admin\\OrderController@repair');
|
||||
$router->post('/order/update', 'Admin\\OrderController@update');
|
||||
// User
|
||||
$router->get ('/user/fetch', 'Admin\\UserController@fetch');
|
||||
$router->post('/user/update', 'Admin\\UserController@update');
|
||||
$router->get ('/user/getUserInfoById', 'Admin\\UserController@getUserInfoById');
|
||||
// Stat
|
||||
$router->get ('/stat/getOverride', 'Admin\\StatController@getOverride');
|
||||
// Notice
|
||||
$router->get ('/notice/fetch', 'Admin\\NoticeController@fetch');
|
||||
$router->post('/notice/save', 'Admin\\NoticeController@save');
|
||||
$router->post('/notice/update', 'Admin\\NoticeController@update');
|
||||
$router->post('/notice/drop', 'Admin\\NoticeController@drop');
|
||||
// Ticket
|
||||
$router->get ('/ticket/fetch', 'Admin\\TicketController@fetch');
|
||||
$router->post('/ticket/reply', 'Admin\\TicketController@reply');
|
||||
$router->post('/ticket/close', 'Admin\\TicketController@close');
|
||||
// Mail
|
||||
$router->post('/mail/send', 'Admin\\MailController@send');
|
||||
// Coupon
|
||||
$router->get ('/coupon/fetch', 'Admin\\CouponController@fetch');
|
||||
$router->post('/coupon/save', 'Admin\\CouponController@save');
|
||||
$router->post('/coupon/drop', 'Admin\\CouponController@drop');
|
||||
// Tutorial
|
||||
$router->get ('/tutorial/fetch', 'Admin\\TutorialController@fetch');
|
||||
$router->post('/tutorial/save', 'Admin\\TutorialController@save');
|
||||
$router->post('/tutorial/show', 'Admin\\TutorialController@show');
|
||||
$router->post('/tutorial/drop', 'Admin\\TutorialController@drop');
|
||||
});
|
||||
}
|
||||
}
|
21
app/Http/Routes/ClientRoute.php
Normal file
21
app/Http/Routes/ClientRoute.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace App\Http\Routes;
|
||||
|
||||
use Illuminate\Contracts\Routing\Registrar;
|
||||
|
||||
class ClientRoute
|
||||
{
|
||||
public function map(Registrar $router)
|
||||
{
|
||||
$router->group([
|
||||
'prefix' => 'client',
|
||||
'middleware' => 'client'
|
||||
], function ($router) {
|
||||
// Client
|
||||
$router->get('/subscribe', 'Client\\ClientController@subscribe');
|
||||
// App
|
||||
$router->get('/app/data', 'Client\\AppController@data');
|
||||
$router->get('/app/config', 'Client\\AppController@config');
|
||||
});
|
||||
}
|
||||
}
|
22
app/Http/Routes/GuestRoute.php
Normal file
22
app/Http/Routes/GuestRoute.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace App\Http\Routes;
|
||||
|
||||
use Illuminate\Contracts\Routing\Registrar;
|
||||
|
||||
class GuestRoute
|
||||
{
|
||||
public function map(Registrar $router)
|
||||
{
|
||||
$router->group([
|
||||
'prefix' => 'guest'
|
||||
], function ($router) {
|
||||
// Plan
|
||||
$router->get ('/plan/fetch', 'Guest\\PlanController@fetch');
|
||||
// Order
|
||||
$router->post('/order/alipayNotify', 'Guest\\OrderController@alipayNotify');
|
||||
$router->post('/order/stripeNotify', 'Guest\\OrderController@stripeNotify');
|
||||
$router->post('/order/bitpayXNotify', 'Guest\\OrderController@bitpayXNotify');
|
||||
$router->post('/order/payTaroNotify', 'Guest\\OrderController@payTaroNotify');
|
||||
});
|
||||
}
|
||||
}
|
27
app/Http/Routes/PassportRoute.php
Normal file
27
app/Http/Routes/PassportRoute.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace App\Http\Routes;
|
||||
|
||||
use Illuminate\Contracts\Routing\Registrar;
|
||||
|
||||
class PassportRoute
|
||||
{
|
||||
public function map(Registrar $router)
|
||||
{
|
||||
$router->group([
|
||||
'prefix' => 'passport'
|
||||
], function ($router) {
|
||||
// TODO: 1.1.1 abolish
|
||||
$router->post('/login', 'Passport\\AuthController@login');
|
||||
// Auth
|
||||
$router->post('/auth/register', 'Passport\\AuthController@register');
|
||||
$router->post('/auth/login', 'Passport\\AuthController@login');
|
||||
$router->get ('/auth/token2Login', 'Passport\\AuthController@token2Login');
|
||||
$router->get ('/auth/check', 'Passport\\AuthController@check');
|
||||
$router->post('/auth/forget', 'Passport\\AuthController@forget');
|
||||
// Comm
|
||||
$router->get ('/comm/config', 'Passport\\CommController@config');
|
||||
$router->post('/comm/sendEmailVerify', 'Passport\\CommController@sendEmailVerify');
|
||||
$router->post('/comm/pv', 'Passport\\CommController@pv');
|
||||
});
|
||||
}
|
||||
}
|
19
app/Http/Routes/ServerRoute.php
Normal file
19
app/Http/Routes/ServerRoute.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
namespace App\Http\Routes;
|
||||
|
||||
use Illuminate\Contracts\Routing\Registrar;
|
||||
|
||||
class ServerRoute
|
||||
{
|
||||
public function map(Registrar $router)
|
||||
{
|
||||
$router->group([
|
||||
'prefix' => 'server'
|
||||
], function ($router) {
|
||||
$router->any('/{class}/{action}', function($class, $action) {
|
||||
$ctrl = \App::make("\\App\\Http\\Controllers\\Server\\" . ucfirst($class) . "Controller");
|
||||
return \App::call([$ctrl, $action]);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
54
app/Http/Routes/UserRoute.php
Normal file
54
app/Http/Routes/UserRoute.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
namespace App\Http\Routes;
|
||||
|
||||
use Illuminate\Contracts\Routing\Registrar;
|
||||
|
||||
class UserRoute
|
||||
{
|
||||
public function map(Registrar $router)
|
||||
{
|
||||
$router->group([
|
||||
'prefix' => 'user',
|
||||
'middleware' => 'user'
|
||||
], function ($router) {
|
||||
// User
|
||||
$router->get ('/resetSecurity', 'User\\UserController@resetSecurity');
|
||||
$router->get ('/logout', 'User\\UserController@logout');
|
||||
$router->get ('/info', 'User\\UserController@info');
|
||||
$router->post('/changePassword', 'User\\UserController@changePassword');
|
||||
$router->post('/update', 'User\\UserController@update');
|
||||
$router->get ('/getSubscribe', 'User\\UserController@getSubscribe');
|
||||
$router->get ('/getStat', 'User\\UserController@getStat');
|
||||
// Order
|
||||
$router->post('/order/save', 'User\\OrderController@save');
|
||||
$router->post('/order/checkout', 'User\\OrderController@checkout');
|
||||
$router->get ('/order/check', 'User\\OrderController@check');
|
||||
$router->get ('/order/details', 'User\\OrderController@details');
|
||||
$router->get ('/order/fetch', 'User\\OrderController@fetch');
|
||||
$router->get ('/order/getPaymentMethod', 'User\\OrderController@getPaymentMethod');
|
||||
$router->post('/order/cancel', 'User\\OrderController@cancel');
|
||||
// Plan
|
||||
$router->get ('/plan/fetch', 'User\\PlanController@fetch');
|
||||
// Invite
|
||||
$router->get ('/invite/save', 'User\\InviteController@save');
|
||||
$router->get ('/invite/fetch', 'User\\InviteController@fetch');
|
||||
$router->get ('/invite/details', 'User\\InviteController@details');
|
||||
// Tutorial
|
||||
$router->get ('/tutorial/getSubscribeUrl', 'User\\TutorialController@getSubscribeUrl');
|
||||
$router->get ('/tutorial/getAppleID', 'User\\TutorialController@getAppleID');
|
||||
$router->get ('/tutorial/fetch', 'User\\TutorialController@fetch');
|
||||
// Notice
|
||||
$router->get ('/notice/fetch', 'User\\NoticeController@fetch');
|
||||
// Ticket
|
||||
$router->post('/ticket/reply', 'User\\TicketController@reply');
|
||||
$router->post('/ticket/close', 'User\\TicketController@close');
|
||||
$router->post('/ticket/save', 'User\\TicketController@save');
|
||||
$router->get ('/ticket/fetch', 'User\\TicketController@fetch');
|
||||
// Server
|
||||
$router->get ('/server/fetch', 'User\\ServerController@fetch');
|
||||
$router->get ('/server/log/fetch', 'User\\ServerController@logFetch');
|
||||
// Coupon
|
||||
$router->post('/coupon/check', 'User\\CouponController@check');
|
||||
});
|
||||
}
|
||||
}
|
@ -8,11 +8,13 @@ use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use App\Models\MailLog;
|
||||
|
||||
class SendEmail implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
protected $params;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
@ -33,12 +35,23 @@ class SendEmail implements ShouldQueue
|
||||
$params = $this->params;
|
||||
$email = $params['email'];
|
||||
$subject = $params['subject'];
|
||||
Mail::send(
|
||||
$params['template_name'],
|
||||
$params['template_value'],
|
||||
function ($message) use($email, $subject) {
|
||||
$message->to($email)->subject($subject);
|
||||
}
|
||||
);
|
||||
try {
|
||||
Mail::send(
|
||||
$params['template_name'],
|
||||
$params['template_value'],
|
||||
function ($message) use ($email, $subject) {
|
||||
$message->to($email)->subject($subject);
|
||||
}
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
$error = $e->getMessage();
|
||||
}
|
||||
|
||||
MailLog::create([
|
||||
'email' => $params['email'],
|
||||
'subject' => $params['subject'],
|
||||
'template_name' => $params['template_name'],
|
||||
'error' => isset($error) ? $error : NULL
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
12
app/Models/Coupon.php
Normal file
12
app/Models/Coupon.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Coupon extends Model
|
||||
{
|
||||
protected $table = 'v2_coupon';
|
||||
protected $dateFormat = 'U';
|
||||
protected $guarded = ['id'];
|
||||
}
|
12
app/Models/MailLog.php
Normal file
12
app/Models/MailLog.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class MailLog extends Model
|
||||
{
|
||||
protected $table = 'v2_mail_log';
|
||||
protected $dateFormat = 'U';
|
||||
protected $guarded = ['id'];
|
||||
}
|
12
app/Models/Tutorial.php
Normal file
12
app/Models/Tutorial.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Tutorial extends Model
|
||||
{
|
||||
protected $table = 'v2_tutorial';
|
||||
protected $dateFormat = 'U';
|
||||
protected $guarded = ['id'];
|
||||
}
|
@ -36,7 +36,6 @@ class RouteServiceProvider extends ServiceProvider
|
||||
public function map()
|
||||
{
|
||||
$this->mapApiRoutes();
|
||||
|
||||
$this->mapWebRoutes();
|
||||
|
||||
//
|
||||
@ -52,8 +51,8 @@ class RouteServiceProvider extends ServiceProvider
|
||||
protected function mapWebRoutes()
|
||||
{
|
||||
Route::middleware('web')
|
||||
->namespace($this->namespace)
|
||||
->group(base_path('routes/web.php'));
|
||||
->namespace($this->namespace)
|
||||
->group(base_path('routes/web.php'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,9 +64,14 @@ class RouteServiceProvider extends ServiceProvider
|
||||
*/
|
||||
protected function mapApiRoutes()
|
||||
{
|
||||
Route::prefix('api')
|
||||
->middleware('api')
|
||||
->namespace($this->namespace)
|
||||
->group(base_path('routes/api.php'));
|
||||
Route::group([
|
||||
'prefix' => '/api/v1',
|
||||
'middleware' => 'api',
|
||||
'namespace' => $this->namespace
|
||||
], function ($router) {
|
||||
foreach (glob(app_path('Http//Routes') . '/*.php') as $file) {
|
||||
$this->app->make('App\\Http\\Routes\\' . basename($file, '.php'))->map($router);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
31
app/Services/ServerService.php
Normal file
31
app/Services/ServerService.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
class ServerService
|
||||
{
|
||||
public function getAvailableUsers($groupId)
|
||||
{
|
||||
return User::whereIn('group_id', $groupId)
|
||||
->whereRaw('u + d < transfer_enable')
|
||||
->where(function ($query) {
|
||||
$query->where('expired_at', '>=', time())
|
||||
->orWhere('expired_at', NULL);
|
||||
})
|
||||
->where('banned', 0)
|
||||
->select([
|
||||
'id',
|
||||
'email',
|
||||
't',
|
||||
'u',
|
||||
'd',
|
||||
'transfer_enable',
|
||||
'v2ray_uuid',
|
||||
'v2ray_alter_id',
|
||||
'v2ray_level'
|
||||
])
|
||||
->get();
|
||||
}
|
||||
}
|
50
app/Services/UserService.php
Normal file
50
app/Services/UserService.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
class UserService
|
||||
{
|
||||
public function isAvailable(User $user)
|
||||
{
|
||||
if (!$user->banned && $user->transfer_enable && ($user->expired_at > time() || $user->expired_at === NULL)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getAvailableUsers()
|
||||
{
|
||||
return User::whereRaw('u + d < transfer_enable')
|
||||
->where(function ($query) {
|
||||
$query->where('expired_at', '>=', time())
|
||||
->orWhere('expired_at', NULL);
|
||||
})
|
||||
->where('banned', 0)
|
||||
->get();
|
||||
}
|
||||
|
||||
public function getUnAvailbaleUsers()
|
||||
{
|
||||
return User::where(function ($query) {
|
||||
$query->where('expired_at', '<', time())
|
||||
->orWhere('expired_at', 0);
|
||||
})
|
||||
->where(function ($query) {
|
||||
$query->where('plan_id', NULL)
|
||||
->orWhere('transfer_enable', 0);
|
||||
})
|
||||
->get();
|
||||
}
|
||||
|
||||
public function getUsersByIds($ids)
|
||||
{
|
||||
return User::whereIn('id', $ids)->get();
|
||||
}
|
||||
|
||||
public function getAllUsers()
|
||||
{
|
||||
return User::all();
|
||||
}
|
||||
}
|
8
app/Utils/CacheKey.php
Normal file
8
app/Utils/CacheKey.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Utils;
|
||||
|
||||
class CacheKey
|
||||
{
|
||||
|
||||
}
|
18
app/Utils/Dict.php
Normal file
18
app/Utils/Dict.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Utils;
|
||||
|
||||
class Dict
|
||||
{
|
||||
CONST EMAIL_WHITELIST_SUFFIX_DEFAULT = [
|
||||
'gmail.com',
|
||||
'qq.com',
|
||||
'163.com',
|
||||
'yahoo.com',
|
||||
'sina.com',
|
||||
'126.com',
|
||||
'outlook.com',
|
||||
'yeah.net',
|
||||
'foxmail.com'
|
||||
];
|
||||
}
|
@ -4,7 +4,8 @@ namespace App\Utils;
|
||||
|
||||
class Helper
|
||||
{
|
||||
public static function guid ($format = false) {
|
||||
public static function guid($format = false)
|
||||
{
|
||||
if (function_exists('com_create_guid') === true) {
|
||||
return md5(trim(com_create_guid(), '{}'));
|
||||
}
|
||||
@ -14,16 +15,18 @@ class Helper
|
||||
if ($format) {
|
||||
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
|
||||
}
|
||||
return md5(vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)).'-'.time());
|
||||
return md5(vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)) . '-' . time());
|
||||
}
|
||||
|
||||
public static function exchange ($from, $to) {
|
||||
public static function exchange($from, $to)
|
||||
{
|
||||
$result = file_get_contents('https://api.exchangeratesapi.io/latest?symbols=' . $to . '&base=' . $from);
|
||||
$result = json_decode($result, true);
|
||||
return $result['rates'][$to];
|
||||
}
|
||||
|
||||
public static function randomChar($len, $special=false){
|
||||
public static function randomChar($len, $special = false)
|
||||
{
|
||||
$chars = array(
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
|
||||
"l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
|
||||
@ -32,40 +35,64 @@ class Helper
|
||||
"S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
|
||||
"3", "4", "5", "6", "7", "8", "9"
|
||||
);
|
||||
|
||||
if($special){
|
||||
|
||||
if ($special) {
|
||||
$chars = array_merge($chars, array(
|
||||
"!", "@", "#", "$", "?", "|", "{", "/", ":", ";",
|
||||
"%", "^", "&", "*", "(", ")", "-", "_", "[", "]",
|
||||
"}", "<", ">", "~", "+", "=", ",", "."
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
$charsLen = count($chars) - 1;
|
||||
shuffle($chars);
|
||||
$str = '';
|
||||
for($i=0; $i<$len; $i++){
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$str .= $chars[mt_rand(0, $charsLen)];
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
public static function buildVmessLink($item, $user) {
|
||||
public static function buildVmessLink($item, $user)
|
||||
{
|
||||
$config = [
|
||||
"v" => "2",
|
||||
"ps" => $item->name,
|
||||
"add" => $item->host,
|
||||
"port" => $item->port,
|
||||
"id" => $user->v2ray_uuid,
|
||||
"aid" => "2",
|
||||
"net" => $item->network,
|
||||
"type" => "chacha20-poly1305",
|
||||
"type" => "none",
|
||||
"host" => "",
|
||||
"tls" => $item->tls?"tls":"",
|
||||
"path" => "",
|
||||
"tls" => $item->tls ? "tls" : ""
|
||||
];
|
||||
if ($item->network == 'ws') {
|
||||
$wsSettings = json_decode($item->settings);
|
||||
if ($wsSettings->path) $config['path'] = $wsSettings->path;
|
||||
if (isset($wsSettings->path)) $config['path'] = $wsSettings->path;
|
||||
if (isset($wsSettings->headers->Host)) $config['host'] = $wsSettings->headers->Host;
|
||||
}
|
||||
return "vmess://".base64_encode(json_encode($config))."\r\n";
|
||||
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
||||
}
|
||||
|
||||
public static function multiPasswordVerify($algo, $password, $hash)
|
||||
{
|
||||
switch($algo) {
|
||||
case 'md5': return md5($password) === $hash;
|
||||
case 'sha256': return hash('sha256', $password) === $hash;
|
||||
default: return password_verify($password, $hash);
|
||||
}
|
||||
}
|
||||
|
||||
public static function emailSuffixVerify($email, $suffixs)
|
||||
{
|
||||
$suffix = preg_split('/@/', $email)[1];
|
||||
if (!$suffix) return false;
|
||||
if (!is_array($suffixs)) {
|
||||
$suffixs = preg_split('/,/', $suffixs);
|
||||
}
|
||||
if (!in_array($suffix, $suffixs)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
"laravel/framework": "^6.0",
|
||||
"laravel/tinker": "^1.0",
|
||||
"lokielse/omnipay-alipay": "^3.0",
|
||||
"php-curl-class/php-curl-class": "^8.6",
|
||||
"stripe/stripe-php": "^7.5",
|
||||
"symfony/yaml": "^4.3"
|
||||
},
|
||||
|
@ -228,4 +228,13 @@ return [
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| V2board version
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The only modification by laravel config
|
||||
|
|
||||
*/
|
||||
'version' => '1.2'
|
||||
];
|
||||
|
@ -98,6 +98,6 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'),
|
||||
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_') . '_cache'),
|
||||
|
||||
];
|
||||
|
@ -123,7 +123,7 @@ return [
|
||||
|
||||
'options' => [
|
||||
'cluster' => env('REDIS_CLUSTER', 'redis'),
|
||||
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
|
||||
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_') . '_database_'),
|
||||
],
|
||||
|
||||
'default' => [
|
||||
|
@ -51,7 +51,7 @@ return [
|
||||
'public' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app/public'),
|
||||
'url' => env('APP_URL').'/storage',
|
||||
'url' => env('APP_URL') . '/storage',
|
||||
'visibility' => 'public',
|
||||
],
|
||||
|
||||
|
@ -126,7 +126,7 @@ return [
|
||||
|
||||
'cookie' => env(
|
||||
'SESSION_COOKIE',
|
||||
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
|
||||
Str::slug(env('APP_NAME', 'laravel'), '_') . '_session'
|
||||
),
|
||||
|
||||
/*
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user