login notify + bonus log

This commit is contained in:
xiaomlove
2023-01-31 16:38:21 +08:00
parent 3edb283b62
commit 9c0f458920
26 changed files with 552 additions and 7 deletions
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace App\Console\Commands;
use App\Jobs\GenerateTemporaryInvite;
use App\Jobs\SendLoginNotify;
use Illuminate\Console\Command;
class UserLoginNotify extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'user:login_notify {--this_id=} {--last_id=}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send login notify, option: --this_id, --last_id';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$thisId = $this->option('this_id');
$lastId = $this->option('last_id');
$this->info("thisId: $thisId, lastId: $lastId");
SendLoginNotify::dispatch($thisId, $lastId);
return Command::SUCCESS;
}
}
@@ -0,0 +1,104 @@
<?php
namespace App\Filament\Resources\User;
use App\Filament\Resources\User\BonusLogResource\Pages;
use App\Filament\Resources\User\BonusLogResource\RelationManagers;
use App\Models\BonusLogs;
use Filament\Forms;
use Filament\Resources\Form;
use Filament\Resources\Resource;
use Filament\Resources\Table;
use Filament\Tables;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class BonusLogResource extends Resource
{
protected static ?string $model = BonusLogs::class;
protected static ?string $navigationIcon = 'heroicon-o-collection';
protected static ?string $navigationGroup = 'User';
protected static ?int $navigationSort = 10;
protected static function getNavigationLabel(): string
{
return __('admin.sidebar.bonus_log');
}
public static function getBreadcrumb(): string
{
return self::getNavigationLabel();
}
public static function form(Form $form): Form
{
return $form
->schema([
//
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')->sortable(),
Tables\Columns\TextColumn::make('uid')
->formatStateUsing(fn ($state) => username_for_admin($state))
->label(__('label.username'))
,
Tables\Columns\TextColumn::make('business_type_text')
->label(__('bonus-log.fields.business_type'))
,
Tables\Columns\TextColumn::make('old_total_value')
->label(__('bonus-log.fields.old_total_value'))
,
Tables\Columns\TextColumn::make('value')
->label(__('bonus-log.fields.value'))
,
Tables\Columns\TextColumn::make('new_total_value')
->label(__('bonus-log.fields.new_total_value'))
,
Tables\Columns\TextColumn::make('comment')
->label(__('label.comment'))
,
Tables\Columns\TextColumn::make('created_at')
->label(__('label.created_at'))
,
])
->defaultSort('id', 'desc')
->filters([
Tables\Filters\Filter::make('uid')
->form([
Forms\Components\TextInput::make('uid')
->label(__('label.username'))
->placeholder('UID')
,
])->query(function (Builder $query, array $data) {
return $query->when($data['uid'], fn (Builder $query, $value) => $query->where("uid", $value));
})
,
Tables\Filters\SelectFilter::make('business_type')
->options(BonusLogs::listStaticProps(BonusLogs::$businessTypes, 'bonus-log.business_types', true))
->label(__('bonus-log.fields.business_type'))
,
])
->actions([
// Tables\Actions\EditAction::make(),
// Tables\Actions\DeleteAction::make(),
])
->bulkActions([
// Tables\Actions\DeleteBulkAction::make(),
]);
}
public static function getPages(): array
{
return [
'index' => Pages\ManageBonusLogs::route('/'),
];
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Filament\Resources\User\BonusLogResource\Pages;
use App\Filament\PageListSingle;
use App\Filament\Resources\User\BonusLogResource;
use Filament\Pages\Actions;
use Filament\Resources\Pages\ManageRecords;
class ManageBonusLogs extends PageListSingle
{
protected static string $resource = BonusLogResource::class;
protected function getActions(): array
{
return [
// Actions\CreateAction::make(),
];
}
}
@@ -0,0 +1,87 @@
<?php
namespace App\Filament\Resources\User;
use App\Filament\Resources\User\LoginLogResource\Pages;
use App\Filament\Resources\User\LoginLogResource\RelationManagers;
use App\Models\LoginLog;
use Filament\Forms;
use Filament\Resources\Form;
use Filament\Resources\Resource;
use Filament\Resources\Table;
use Filament\Tables;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class LoginLogResource extends Resource
{
protected static ?string $model = LoginLog::class;
protected static ?string $navigationIcon = 'heroicon-o-collection';
protected static ?string $navigationGroup = 'User';
protected static ?int $navigationSort = 9;
protected static function getNavigationLabel(): string
{
return __('admin.sidebar.login_log');
}
public static function getBreadcrumb(): string
{
return self::getNavigationLabel();
}
public static function form(Form $form): Form
{
return $form
->schema([
//
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')->sortable(),
Tables\Columns\TextColumn::make('uid')
->formatStateUsing(fn ($state) => username_for_admin($state))
->label(__('label.username'))
,
Tables\Columns\TextColumn::make('ip')->searchable(),
Tables\Columns\TextColumn::make('country')->label(__('label.country'))->searchable(),
Tables\Columns\TextColumn::make('city')->label(__('label.city'))->searchable(),
Tables\Columns\TextColumn::make('client')->label(__('label.client')),
Tables\Columns\TextColumn::make('created_at')->label(__('label.created_at')),
])
->defaultSort('id', 'desc')
->filters([
Tables\Filters\Filter::make('uid')
->form([
Forms\Components\TextInput::make('uid')
->label(__('label.username'))
->placeholder('UID')
,
])->query(function (Builder $query, array $data) {
return $query->when($data['uid'], fn (Builder $query, $value) => $query->where("uid", $value));
})
,
])
->actions([
// Tables\Actions\EditAction::make(),
// Tables\Actions\DeleteAction::make(),
])
->bulkActions([
// Tables\Actions\DeleteBulkAction::make(),
]);
}
public static function getPages(): array
{
return [
'index' => Pages\ManageLoginLogs::route('/'),
];
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Filament\Resources\User\LoginLogResource\Pages;
use App\Filament\PageListSingle;
use App\Filament\Resources\User\LoginLogResource;
use Filament\Pages\Actions;
use Filament\Resources\Pages\ManageRecords;
class ManageLoginLogs extends PageListSingle
{
protected static string $resource = LoginLogResource::class;
protected function getActions(): array
{
return [
// Actions\CreateAction::make(),
];
}
}
+60
View File
@@ -0,0 +1,60 @@
<?php
namespace App\Jobs;
use App\Models\LoginLog;
use App\Models\Setting;
use App\Models\User;
use App\Repositories\ToolRepository;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class SendLoginNotify implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private int $thisLoginLogId;
private int $lastLoginLogId;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(int $thisLoginLogId, int $lastLoginLogId)
{
$this->thisLoginLogId = $thisLoginLogId;
$this->lastLoginLogId = $lastLoginLogId;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$thisLoginLog = LoginLog::query()->findOrFail($this->thisLoginLogId);
$lastLoginLog = LoginLog::query()->findOrFail($this->lastLoginLogId);
$user = User::query()->findOrFail($thisLoginLog->uid, User::$commonFields);
$locale = $user->locale;
$toolRep = new ToolRepository();
$subject = nexus_trans('message.login_notify.subject', ['site_name' => Setting::get('basic.SITENAME')], $locale);
$body = nexus_trans('message.login_notify.body', [
'this_login_time' => $thisLoginLog->created_at,
'this_ip' => $thisLoginLog->ip,
'this_location' => sprintf('%s·%s', $thisLoginLog->city, $thisLoginLog->country),
'last_login_time' => $lastLoginLog->created_at,
'last_ip' => $lastLoginLog->ip,
'last_location' => sprintf('%s·%s', $lastLoginLog->city, $lastLoginLog->country),
], $locale);
$result = $toolRep->sendMail($user->email, $subject, $body);
do_log(sprintf('user: %s login notify result: %s', $user->username, var_export($result, true)));
}
}
+5
View File
@@ -55,6 +55,11 @@ class BonusLogs extends NexusModel
self::BUSINESS_TYPE_GIFT_MEDAL => ['text' => 'Gift medal to someone'], self::BUSINESS_TYPE_GIFT_MEDAL => ['text' => 'Gift medal to someone'],
]; ];
public function getBusinessTypeTextAttribute()
{
return nexus_trans('bonus-log.business_types.' . $this->business_type);
}
public static function getBonusForCancelHitAndRun() public static function getBonusForCancelHitAndRun()
{ {
$result = Setting::get('bonus.cancel_hr'); $result = Setting::get('bonus.cancel_hr');
+14
View File
@@ -0,0 +1,14 @@
<?php
namespace App\Models;
class LoginLog extends NexusModel
{
public $timestamps = true;
protected $fillable = [
'uid', 'ip', 'country', 'city', 'client'
];
}
+1 -1
View File
@@ -222,7 +222,7 @@ class User extends Authenticatable implements FilamentUser, HasName
'id', 'username', 'email', 'class', 'status', 'added', 'avatar', 'id', 'username', 'email', 'class', 'status', 'added', 'avatar',
'uploaded', 'downloaded', 'seedbonus', 'seedtime', 'leechtime', 'uploaded', 'downloaded', 'seedbonus', 'seedtime', 'leechtime',
'invited_by', 'enabled', 'seed_points', 'last_access', 'invites', 'invited_by', 'enabled', 'seed_points', 'last_access', 'invites',
'lang', 'attendance_card', 'privacy', 'noad', 'downloadpos', 'donoruntil', 'donor' 'lang', 'attendance_card', 'privacy', 'noad', 'downloadpos', 'donoruntil', 'donor', 'language'
]; ];
public static function getDefaultUserAttributes(): array public static function getDefaultUserAttributes(): array
@@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('login_logs', function (Blueprint $table) {
$table->id();
$table->integer('uid')->index();
$table->string('ip', 128)->index();
$table->string('country')->nullable(true)->index();
$table->string('city')->nullable(true)->index();
$table->string('client')->nullable(true)->index();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('login_logs');
}
};
+1 -1
View File
@@ -1,6 +1,6 @@
<?php <?php
defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.8.0'); defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.8.0');
defined('RELEASE_DATE') || define('RELEASE_DATE', '2023-01-29'); defined('RELEASE_DATE') || define('RELEASE_DATE', '2023-01-31');
defined('IN_TRACKER') || define('IN_TRACKER', false); defined('IN_TRACKER') || define('IN_TRACKER', false);
defined('PROJECTNAME') || define("PROJECTNAME","NexusPHP"); defined('PROJECTNAME') || define("PROJECTNAME","NexusPHP");
defined('NEXUSPHPURL') || define("NEXUSPHPURL","https://nexusphp.org"); defined('NEXUSPHPURL') || define("NEXUSPHPURL","https://nexusphp.org");
+8
View File
@@ -5831,6 +5831,8 @@ function get_ip_location_from_geoip($ip): bool|array
'version' => '', 'version' => '',
'country' => '', 'country' => '',
'city' => '', 'city' => '',
'country_en' => '',
'city_en' => '',
]; ];
try { try {
$record = $reader->city($ip); $record = $reader->city($ip);
@@ -5842,7 +5844,10 @@ function get_ip_location_from_geoip($ip): bool|array
$info['version'] = 6; $info['version'] = 6;
} }
$info['country'] = $countryName; $info['country'] = $countryName;
$info['country_en'] = $record->country->names['en'] ?? '';
$info['city'] = $cityName; $info['city'] = $cityName;
$info['city_en'] = $record->city->names['en'] ?? '';
} catch (\Exception $exception) { } catch (\Exception $exception) {
do_log($exception->getMessage() . $exception->getTraceAsString(), 'error'); do_log($exception->getMessage() . $exception->getTraceAsString(), 'error');
} }
@@ -5857,6 +5862,9 @@ function get_ip_location_from_geoip($ip): bool|array
'flagpic' => '', 'flagpic' => '',
'start_ip' => $ip, 'start_ip' => $ip,
'end_ip' => $ip, 'end_ip' => $ip,
'ip_version' => $locationInfo['version'],
'country_en' => $locationInfo['country_en'],
'city_en' => $locationInfo['city_en'],
]; ];
} }
+8 -2
View File
@@ -1113,18 +1113,24 @@ function get_passkey_by_authkey($authkey)
}); });
} }
function executeCommand($command, $format = 'string'): string|array function executeCommand($command, $format = 'string', $artisan = false, $exception = true): string|array
{ {
$append = " 2>&1"; $append = " 2>&1";
if (!str_ends_with($command, $append)) { if (!str_ends_with($command, $append)) {
$command .= $append; $command .= $append;
} }
if ($artisan) {
$phpPath = nexus_env('PHP_PATH', 'php');
$webRoot = rtrim(ROOT_PATH, '/');
$command = "$phpPath $webRoot/artisan $command";
}
do_log("command: $command"); do_log("command: $command");
$result = exec($command, $output, $result_code); $result = exec($command, $output, $result_code);
$outputString = implode("\n", $output); $outputString = implode("\n", $output);
do_log(sprintf('result_code: %s, result: %s, output: %s', $result_code, $result, $outputString)); do_log(sprintf('result_code: %s, result: %s, output: %s', $result_code, $result, $outputString));
if ($result_code != 0) { if ($exception && $result_code != 0) {
throw new \RuntimeException($outputString); throw new \RuntimeException($outputString);
} }
return $format == 'string' ? $outputString : $output; return $format == 'string' ? $outputString : $output;
} }
+21 -3
View File
@@ -34,9 +34,27 @@ if (!empty($row['two_step_secret'])) {
} }
} }
$log = "user: {$row['id']}, ip: $ip"; $log = "user: {$row['id']}, ip: $ip";
if ($row["passhash"] != md5($row["secret"] . $password . $row["secret"])) if ($row["passhash"] != md5($row["secret"] . $password . $row["secret"])) {
login_failedlogins(); login_failedlogins();
}
$locationInfo = get_ip_location_from_geoip($ip);
$thisLoginLog = \App\Models\LoginLog::query()->create([
'ip' => $ip,
'uid' => $row['id'],
'country' => $locationInfo['country_en'],
'city' => $locationInfo['city_en'],
'client' => 'Web',
]);
$lastLoginLog = \App\Models\LoginLog::query()->where('uid', $row['id'])->orderBy('id', 'desc')->first();
if (
$lastLoginLog && $lastLoginLog->country && $lastLoginLog->city
&& $locationInfo['country_en'] && $locationInfo['city_en']
&& ($lastLoginLog->country != $locationInfo['country_en'] || $lastLoginLog->city != $locationInfo['city_en'])
) {
$command = sprintf("user:login_notify --this_id=%s --last_id=%s", $thisLoginLog->id, $lastLoginLog->id);
do_log("[LOGIN_NOTIFY], user: {$row['id']}, $command");
// executeCommand($command, "string", true, false);
}
if ($row["enabled"] == "no") if ($row["enabled"] == "no")
bark($lang_takelogin['std_account_disabled']); bark($lang_takelogin['std_account_disabled']);
+2
View File
@@ -34,6 +34,8 @@ return [
'torrent_operation_log' => 'Torrent operation logs', 'torrent_operation_log' => 'Torrent operation logs',
'invite' => 'Invites', 'invite' => 'Invites',
'user_props' => 'User props', 'user_props' => 'User props',
'login_log' => 'Login logs',
'bonus_log' => 'Bonus logs',
], ],
'resources' => [ 'resources' => [
'agent_allow' => [ 'agent_allow' => [
+30
View File
@@ -0,0 +1,30 @@
<?php
return [
'business_types' => [
\App\Models\BonusLogs::BUSINESS_TYPE_CANCEL_HIT_AND_RUN => 'Cancel H&R',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_MEDAL => 'Buy medal',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_ATTENDANCE_CARD => 'Buy attendance card',
\App\Models\BonusLogs::BUSINESS_TYPE_STICKY_PROMOTION => 'Sticky promotion',
\App\Models\BonusLogs::BUSINESS_TYPE_POST_REWARD => 'Post reward',
\App\Models\BonusLogs::BUSINESS_TYPE_EXCHANGE_UPLOAD => 'Exchange uploaded',
\App\Models\BonusLogs::BUSINESS_TYPE_EXCHANGE_INVITE => 'Buy invite',
\App\Models\BonusLogs::BUSINESS_TYPE_CUSTOM_TITLE => 'Custom title',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_VIP => 'Buy VIP',
\App\Models\BonusLogs::BUSINESS_TYPE_GIFT_TO_SOMEONE => 'Gift to someone',
\App\Models\BonusLogs::BUSINESS_TYPE_NO_AD => 'Cancel ad',
\App\Models\BonusLogs::BUSINESS_TYPE_GIFT_TO_LOW_SHARE_RATIO => 'Gift to low share ratio',
\App\Models\BonusLogs::BUSINESS_TYPE_LUCKY_DRAW => 'Lucky draw',
\App\Models\BonusLogs::BUSINESS_TYPE_EXCHANGE_DOWNLOAD => 'Exchange downloaded',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_TEMPORARY_INVITE => 'Buy temporary invite',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_RAINBOW_ID => 'Buy rainbow ID',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_CHANGE_USERNAME_CARD => 'Buy change username card',
\App\Models\BonusLogs::BUSINESS_TYPE_GIFT_MEDAL => 'Gift medal',
],
'fields' => [
'business_type' => 'Business type',
'old_total_value' => 'Pre-trade value',
'value' => 'Trade value',
'new_total_value' => 'Post-trade value',
],
];
+3
View File
@@ -36,6 +36,9 @@ return [
'anonymous' => 'Anonymous', 'anonymous' => 'Anonymous',
'infinite' => 'Infinite', 'infinite' => 'Infinite',
'save' => 'Save', 'save' => 'Save',
'country' => 'Country',
'city' => 'City',
'client' => 'Client',
'setting' => [ 'setting' => [
'nav_text' => 'Setting', 'nav_text' => 'Setting',
'backup' => [ 'backup' => [
+8
View File
@@ -31,4 +31,12 @@ return [
'subject' => 'Receive gift medal', 'subject' => 'Receive gift medal',
'body' => "User :username purchased a medal [:medal_name] at a cost of :cost_bonus and gave it to you. The medal is worth :price, the fee is :gift_fee_total(factor: :gift_fee_factor), you will have this medal until: :expire_at, and the medal's bonus addition factor is: :bonus_addition_factor.", 'body' => "User :username purchased a medal [:medal_name] at a cost of :cost_bonus and gave it to you. The medal is worth :price, the fee is :gift_fee_total(factor: :gift_fee_factor), you will have this medal until: :expire_at, and the medal's bonus addition factor is: :bonus_addition_factor.",
], ],
'login_notify' => [
'subject' => ':site_name Offsite login alert',
'body' => <<<BODY
You logged in at :this_login_time, IP::this_ip, location::this_location.
Last login time::last_login_time, IP::last_ip, location::last_location.
If it is not your own operation, the account password may have been leaked, please change it in time!
BODY,
],
]; ];
+2
View File
@@ -32,6 +32,8 @@ return [
'torrent_operation_log' => '种子操作记录', 'torrent_operation_log' => '种子操作记录',
'invite' => '用户邀请', 'invite' => '用户邀请',
'user_props' => '用户道具', 'user_props' => '用户道具',
'login_log' => '登录记录',
'bonus_log' => '魔力记录',
], ],
'resources' => [ 'resources' => [
'agent_allow' => [ 'agent_allow' => [
+30
View File
@@ -0,0 +1,30 @@
<?php
return [
'business_types' => [
\App\Models\BonusLogs::BUSINESS_TYPE_CANCEL_HIT_AND_RUN => '消除 H&R',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_MEDAL => '购买勋章',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_ATTENDANCE_CARD => '购买补签卡',
\App\Models\BonusLogs::BUSINESS_TYPE_STICKY_PROMOTION => '置顶促销',
\App\Models\BonusLogs::BUSINESS_TYPE_POST_REWARD => '帖子奖励',
\App\Models\BonusLogs::BUSINESS_TYPE_EXCHANGE_UPLOAD => '兑换上传量',
\App\Models\BonusLogs::BUSINESS_TYPE_EXCHANGE_INVITE => '购买邀请',
\App\Models\BonusLogs::BUSINESS_TYPE_CUSTOM_TITLE => '自定义头衔',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_VIP => '购买 VIP',
\App\Models\BonusLogs::BUSINESS_TYPE_GIFT_TO_SOMEONE => '捐赠给某人',
\App\Models\BonusLogs::BUSINESS_TYPE_NO_AD => '消除广告',
\App\Models\BonusLogs::BUSINESS_TYPE_GIFT_TO_LOW_SHARE_RATIO => '捐赠给低分享率者',
\App\Models\BonusLogs::BUSINESS_TYPE_LUCKY_DRAW => '幸运大转盘',
\App\Models\BonusLogs::BUSINESS_TYPE_EXCHANGE_DOWNLOAD => '兑换下载量',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_TEMPORARY_INVITE => '购买临时邀请',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_RAINBOW_ID => '购买彩虹 ID',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_CHANGE_USERNAME_CARD => '购买改名卡',
\App\Models\BonusLogs::BUSINESS_TYPE_GIFT_MEDAL => '赠送勋章',
],
'fields' => [
'business_type' => '业务类型',
'old_total_value' => '交易前值',
'value' => '交易值',
'new_total_value' => '交易后值',
],
];
+3
View File
@@ -36,6 +36,9 @@ return [
'anonymous' => '匿名', 'anonymous' => '匿名',
'infinite' => '无限', 'infinite' => '无限',
'save' => '保存', 'save' => '保存',
'country' => '国家',
'city' => '城市',
'client' => '客户端',
'setting' => [ 'setting' => [
'nav_text' => '设置', 'nav_text' => '设置',
'backup' => [ 'backup' => [
+8
View File
@@ -31,4 +31,12 @@ return [
'subject' => '收到赠送勋章', 'subject' => '收到赠送勋章',
'body' => '用户 :username 花费魔力 :cost_bonus 购买了勋章[:medal_name]并赠送与你。此勋章价值 :price,手续费 :gift_fee_total(系数::gift_fee_factor),你将拥有此勋章有效期至: :expire_at,勋章的魔力加成系数为: :bonus_addition_factor。', 'body' => '用户 :username 花费魔力 :cost_bonus 购买了勋章[:medal_name]并赠送与你。此勋章价值 :price,手续费 :gift_fee_total(系数::gift_fee_factor),你将拥有此勋章有效期至: :expire_at,勋章的魔力加成系数为: :bonus_addition_factor。',
], ],
'login_notify' => [
'subject' => ':site_name 异地登录提醒',
'body' => <<<BODY
你于 :this_login_time 进行了登录操作,IP:this_ip,位置::this_location。
上次登录时间::last_login_timeIP:last_ip,位置::last_location。
若不是你本人操作,账号密码可能已经泄露,请及时修改!
BODY,
],
]; ];
+2
View File
@@ -34,6 +34,8 @@ return [
'torrent_operation_log' => '種子操作記錄', 'torrent_operation_log' => '種子操作記錄',
'invite' => '用戶邀請', 'invite' => '用戶邀請',
'user_props' => '用戶道具', 'user_props' => '用戶道具',
'login_log' => '登錄記錄',
'bonus_log' => '魔力記錄',
], ],
'resources' => [ 'resources' => [
'agent_allow' => [ 'agent_allow' => [
+30
View File
@@ -0,0 +1,30 @@
<?php
return [
'business_types' => [
\App\Models\BonusLogs::BUSINESS_TYPE_CANCEL_HIT_AND_RUN => '消除 H&R',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_MEDAL => '購買勛章',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_ATTENDANCE_CARD => '購買補簽卡',
\App\Models\BonusLogs::BUSINESS_TYPE_STICKY_PROMOTION => '置頂促銷',
\App\Models\BonusLogs::BUSINESS_TYPE_POST_REWARD => '帖子獎勵',
\App\Models\BonusLogs::BUSINESS_TYPE_EXCHANGE_UPLOAD => '兌換上傳量',
\App\Models\BonusLogs::BUSINESS_TYPE_EXCHANGE_INVITE => '購買邀請',
\App\Models\BonusLogs::BUSINESS_TYPE_CUSTOM_TITLE => '自定義頭銜',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_VIP => '購買 VIP',
\App\Models\BonusLogs::BUSINESS_TYPE_GIFT_TO_SOMEONE => '捐贈給某人',
\App\Models\BonusLogs::BUSINESS_TYPE_NO_AD => '消除廣告',
\App\Models\BonusLogs::BUSINESS_TYPE_GIFT_TO_LOW_SHARE_RATIO => '捐贈給低分享率者',
\App\Models\BonusLogs::BUSINESS_TYPE_LUCKY_DRAW => '幸運大轉盤',
\App\Models\BonusLogs::BUSINESS_TYPE_EXCHANGE_DOWNLOAD => '兌換下載量',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_TEMPORARY_INVITE => '購買臨時邀請',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_RAINBOW_ID => '購買彩虹 ID',
\App\Models\BonusLogs::BUSINESS_TYPE_BUY_CHANGE_USERNAME_CARD => '購買改名卡',
\App\Models\BonusLogs::BUSINESS_TYPE_GIFT_MEDAL => '贈送勛章',
],
'fields' => [
'business_type' => '業務類型',
'old_total_value' => '交易前值',
'value' => '交易值',
'new_total_value' => '交易後值',
],
];
+3
View File
@@ -36,6 +36,9 @@ return [
'anonymous' => '匿名', 'anonymous' => '匿名',
'infinite' => '無限', 'infinite' => '無限',
'save' => '保存', 'save' => '保存',
'country' => '國家',
'city' => '城市',
'client' => '客戶端',
'setting' => [ 'setting' => [
'nav_text' => '設置', 'nav_text' => '設置',
'backup' => [ 'backup' => [
+8
View File
@@ -30,4 +30,12 @@ return [
'subject' => '收到贈送勛章', 'subject' => '收到贈送勛章',
'body' => '用戶 :username 花費魔力 :cost_bonus 購買了勛章[:medal_name]並贈送與你。此勛章價值 :price,手續費 :gift_fee_total(系數::gift_fee_factor),你將擁有此勛章有效期至: :expire_at,勛章的魔力加成系數為: :bonus_addition_factor。', 'body' => '用戶 :username 花費魔力 :cost_bonus 購買了勛章[:medal_name]並贈送與你。此勛章價值 :price,手續費 :gift_fee_total(系數::gift_fee_factor),你將擁有此勛章有效期至: :expire_at,勛章的魔力加成系數為: :bonus_addition_factor。',
], ],
'login_notify' => [
'subject' => ':site_name 異地登錄提醒',
'body' => <<<BODY
你於 :this_login_time 進行了登錄操作,IP:this_ip,位置::this_location。
上次登錄時間::last_login_timeIP:last_ip,位置::last_location。
若不是你本人操作,賬號密碼可能已經泄露,請及時修改!
BODY,
]
]; ];