From ec66dca3581c5a2c7025482d8661fe83216d60ab Mon Sep 17 00:00:00 2001
From: xiaomlove <1939737565@qq.com>
Date: Tue, 21 Oct 2025 03:22:55 +0700
Subject: [PATCH] IP Search
---
app/Filament/Pages/IpSearch.php | 159 ++++++++++++++++++
app/Policies/IpLogPolicy.php | 76 +++++++++
resources/lang/en/ip-search.php | 12 ++
resources/lang/zh_CN/ip-search.php | 12 ++
resources/lang/zh_TW/ip-search.php | 12 ++
.../views/filament/pages/ip-search.blade.php | 3 +
6 files changed, 274 insertions(+)
create mode 100644 app/Filament/Pages/IpSearch.php
create mode 100644 app/Policies/IpLogPolicy.php
create mode 100644 resources/lang/en/ip-search.php
create mode 100644 resources/lang/zh_CN/ip-search.php
create mode 100644 resources/lang/zh_TW/ip-search.php
create mode 100644 resources/views/filament/pages/ip-search.blade.php
diff --git a/app/Filament/Pages/IpSearch.php b/app/Filament/Pages/IpSearch.php
new file mode 100644
index 00000000..4d4b2d12
--- /dev/null
+++ b/app/Filament/Pages/IpSearch.php
@@ -0,0 +1,159 @@
+records(fn (array $filters, int $page, int $recordsPerPage): LengthAwarePaginator => self::getRecords($filters, $page, $recordsPerPage))
+ ->columns([
+ TextColumn::make('userid')
+ ->label(__('label.username'))
+ ->state(fn (array $record) => username_for_admin($record['userid']))
+ ,
+ TextColumn::make('last_access_ip')
+ ->label(__('ip-search.last_access_ip'))
+ ,
+ TextColumn::make('last_access')
+ ->label(__('ip-search.last_access'))
+ ,
+ TextColumn::make('ip_count')
+ ->label(__('ip-search.ip_count'))
+ ->state(function (array $record) {
+ return new HtmlString(sprintf(
+ '%s',
+ IpLogResource::getUrl('index', ['filters[uid][uid]' => $record['userid']]), $record['ip_count']
+ ));
+ })
+ ,
+ TextColumn::make('ip_last_access')
+ ->label(__('ip-search.ip_last_access'))
+ ,
+ TextColumn::make('user_added')
+ ->label(__('ip-search.user_added'))
+ ,
+ TextColumn::make('invited_by')
+ ->state(fn (array $record) => $record['invited_by'] > 0 ? username_for_admin($record['invited_by']) : '')
+ ->label(__('ip-search.invited_by'))
+ ,
+ ])
+ ->filters([
+ Filter::make('ip')
+ ->schema([
+ TextInput::make('ip')
+ ->label(__('ip-search.label'))
+ ->placeholder(__('ip-search.placeholder'))
+ ,
+ ])
+ ])
+ ->recordActions([
+// ViewAction::make(),
+// EditAction::make(),
+// DeleteAction::make(),
+ ])
+// ->toolbarActions([
+// BulkActionGroup::make([
+//// DeleteBulkAction::make(),
+// ]),
+// ]);
+ ;
+ }
+
+ private static function getRecords(array $filters, int $page, int $recordsPerPage): LengthAwarePaginator
+ {
+ $total = 0;
+ $results = [];
+ if (!empty($filters['ip']['ip'])) {
+ $query = DB::table('iplog')
+ ->leftJoin('users', 'users.id', '=', 'iplog.userid')
+ ->select([
+ 'iplog.userid',
+ 'users.username',
+ 'users.last_access',
+ DB::raw('users.added as user_added'),
+ 'users.invited_by',
+ 'users.ip AS last_access_ip',
+ DB::raw('MAX(iplog.access) AS ip_last_access'),
+ DB::raw('0 AS ip_count'),
+ ])
+ ->whereRaw("iplog.ip = '{$filters['ip']['ip']}'")
+ ;
+ $total = $query->clone()->distinct()->count('iplog.userid');
+ $records = $query->groupBy('iplog.userid')
+ ->orderByDesc('ip_last_access')
+ ->forPage($page, $recordsPerPage)
+ ->get()
+ ;
+
+ if ($records->isNotEmpty()) {
+ $userIdArr = $records->pluck('userid')->toArray();
+ $ipCountResult = IpLog::query()
+ ->whereIn('userid', $userIdArr)
+ ->selectRaw('userid, COUNT(distinct ip) AS count')
+ ->groupBy('userid')
+ ->get()
+ ->pluck('count', 'userid')
+ ->toArray();
+ ;
+ foreach ($records as $record) {
+ $item = json_decode(json_encode($record), true);
+ $item['ip_count'] = $ipCountResult[$item['userid']] ?? 0;
+ $results[] = $item;
+ }
+ }
+ }
+ return new LengthAwarePaginator(
+ $results,
+ total: $total,
+ perPage: $recordsPerPage,
+ currentPage: $page,
+ );
+ }
+}
diff --git a/app/Policies/IpLogPolicy.php b/app/Policies/IpLogPolicy.php
new file mode 100644
index 00000000..1deac624
--- /dev/null
+++ b/app/Policies/IpLogPolicy.php
@@ -0,0 +1,76 @@
+can($user);
+ }
+
+ /**
+ * Determine whether the user can view the model.
+ */
+ public function view(User $user, IpLog $ipLog): bool
+ {
+ return $this->can($user);
+ }
+
+ /**
+ * Determine whether the user can create models.
+ */
+ public function create(User $user): bool
+ {
+ return false;
+ }
+
+ /**
+ * Determine whether the user can update the model.
+ */
+ public function update(User $user, IpLog $ipLog): bool
+ {
+ return false;
+ }
+
+ /**
+ * Determine whether the user can delete the model.
+ */
+ public function delete(User $user, IpLog $ipLog): bool
+ {
+ return $this->can($user);
+ }
+
+ /**
+ * Determine whether the user can restore the model.
+ */
+ public function restore(User $user, IpLog $ipLog): bool
+ {
+ return false;
+ }
+
+ /**
+ * Determine whether the user can permanently delete the model.
+ */
+ public function forceDelete(User $user, IpLog $ipLog): bool
+ {
+ return $this->can($user);
+ }
+
+ private function can(User $user)
+ {
+ if ($user->class >= User::CLASS_SYSOP) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/resources/lang/en/ip-search.php b/resources/lang/en/ip-search.php
new file mode 100644
index 00000000..81d6e962
--- /dev/null
+++ b/resources/lang/en/ip-search.php
@@ -0,0 +1,12 @@
+ 'IP Search',
+ 'placeholder' => 'Enter the IP to search; otherwise results will be empty',
+ 'last_access_ip' => 'Latest IP',
+ 'last_access' => 'Last access',
+ 'ip_count' => 'IP count',
+ 'ip_last_access' => 'This IP last accessed',
+ 'user_added' => 'Join time',
+ 'invited_by' => 'Invited by',
+];
diff --git a/resources/lang/zh_CN/ip-search.php b/resources/lang/zh_CN/ip-search.php
new file mode 100644
index 00000000..d48033a9
--- /dev/null
+++ b/resources/lang/zh_CN/ip-search.php
@@ -0,0 +1,12 @@
+ 'IP 搜索',
+ 'placeholder' => '输入要搜索的 IP,否则结果为空',
+ 'last_access_ip' => '最近 IP',
+ 'last_access' => '最近访问',
+ 'ip_count' => 'IP 数',
+ 'ip_last_access' => '此 IP 最近访问',
+ 'user_added' => '加入时间',
+ 'invited_by' => '邀请者',
+];
diff --git a/resources/lang/zh_TW/ip-search.php b/resources/lang/zh_TW/ip-search.php
new file mode 100644
index 00000000..5a415641
--- /dev/null
+++ b/resources/lang/zh_TW/ip-search.php
@@ -0,0 +1,12 @@
+ 'IP 搜索',
+ 'placeholder' => '輸入要搜索的 IP,否則結果爲空',
+ 'last_access_ip' => '最近 IP',
+ 'last_access' => '最近訪問',
+ 'ip_count' => 'IP 數',
+ 'ip_last_access' => '此 IP 最近訪問',
+ 'user_added' => '加入時間',
+ 'invited_by' => '邀請者',
+];
diff --git a/resources/views/filament/pages/ip-search.blade.php b/resources/views/filament/pages/ip-search.blade.php
new file mode 100644
index 00000000..ce096a2d
--- /dev/null
+++ b/resources/views/filament/pages/ip-search.blade.php
@@ -0,0 +1,3 @@
+
+ {{ $this->table }}
+