create user login activity

This commit is contained in:
Geriano
2022-07-29 20:45:43 +07:00
parent 8585428659
commit 15e3431a06
7 changed files with 167 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\DataTableRequest;
use App\Models\Login;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Inertia\Inertia;
class ActivityController extends Controller
{
/**
* @return \Illuminate\Http\Response
*/
public function login()
{
return Inertia::render('Superuser/Activity/Login');
}
/**
* @param \App\Http\Requests\DataTableRequest $request
* @return \Illuminate\Http\Response
*/
public function logins(DataTableRequest $request)
{
$request->validated();
return Login::join('users', 'login_activities.user_id', '=', 'users.id')
->where(function (Builder $query) use ($request) {
$search = '%' . $request->search . '%';
$query->where('users.name', 'like', $search)
->orWhere('users.username', 'like', $search)
->orWhere('login_activities.ip_address', 'like', $search)
->orWhere('login_activities.browser', 'like', $search)
->orWhere('login_activities.platform', 'like', $search)
->orWhere('login_activities.created_at', 'like', $search);
})
->select(['users.*', 'login_activities.*'])
->orderBy($request->input('order.key') ?: 'created_at', $request->input('order.dir') ?: 'asc')
->paginate($request->per_page ?: 10);
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class DataTableRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'search' => 'nullable|string',
'per_page' => 'nullable|integer|min:0|max:10',
'order.key' => 'nullable|string',
'order.dir' => 'nullable|in:asc,desc',
];
}
}

View File

@@ -23,4 +23,12 @@ class Login extends Model
'browser',
'platform',
];
/**
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function user()
{
return $this->hasOne(User::class, 'id', 'user_id');
}
}

View File

@@ -98,5 +98,23 @@ class MenuSeeder extends Seeder
'create menu', 'read menu', 'update menu', 'delete menu',
])->get(['id'])
);
$activities = Menu::create([
'name' => 'activities',
'icon' => 'address-card',
'position' => 3,
'deleteable' => false,
]);
$activities->childs()->create([
'name' => 'login',
'route_or_url' => 'superuser.activity.login',
'icon' => 'user-clock',
'position' => 1,
'deleteable' => false,
'actives' => [
'superuser.activity.login',
],
]);
}
}

View File

@@ -0,0 +1,62 @@
<script setup>
import { getCurrentInstance, ref, onMounted } from 'vue';
import DashboardLayout from '@/Layouts/DashboardLayout.vue';
import Card from '@/Components/Card.vue';
import Icon from '@/Components/Icon.vue';
import Builder from '@/Components/DataTable/Builder.vue';
import Th from '@/Components/DataTable/Th.vue';
const self = getCurrentInstance()
</script>
<template>
<DashboardLayout title="Login Activity">
<Card class="bg-white dark:bg-gray-700 dark:text-gray-200">
<template #header>
<div class="flex items-center space-x-2 bg-gray-200 dark:bg-gray-800 p-2">
<p class="lowercase first-letter:capitalize font-semibold">login activities</p>
</div>
</template>
<template #body>
<Builder :url="route('api.v1.superuser.activity.login')">
<template #thead="table">
<tr class="bg-gray-200 dark:bg-gray-800 border-gray-300 dark:border-gray-900">
<Th class="border px-3 py-2 text-center" :table="table" :sort="false">no</Th>
<Th class="border px-3 py-2 text-center whitespace-nowrap" :table="table" :sort="true" name="users.name">name</Th>
<Th class="border px-3 py-2 text-center whitespace-nowrap" :table="table" :sort="true" name="users.username">username</Th>
<Th class="border px-3 py-2 text-center whitespace-nowrap" :table="table" :sort="true" name="login_activities.ip_address">ip address</Th>
<Th class="border px-3 py-2 text-center whitespace-nowrap" :table="table" :sort="true" name="login_activities.browser">browser</Th>
<Th class="border px-3 py-2 text-center whitespace-nowrap" :table="table" :sort="true" name="login_activities.platform">platform</Th>
<Th class="border px-3 py-2 text-center whitespace-nowrap" :table="table" :sort="true" name="login_activities.created_at">at</Th>
</tr>
</template>
<template #tfoot="table">
<tr class="bg-gray-200 dark:bg-gray-800 border-gray-300 dark:border-gray-900">
<Th class="border px-3 py-2 text-center" :table="table" :sort="false">no</Th>
<Th class="border px-3 py-2 text-center whitespace-nowrap" :table="table" :sort="false">name</Th>
<Th class="border px-3 py-2 text-center whitespace-nowrap" :table="table" :sort="false">username</Th>
<Th class="border px-3 py-2 text-center whitespace-nowrap" :table="table" :sort="false">ip address</Th>
<Th class="border px-3 py-2 text-center whitespace-nowrap" :table="table" :sort="false">browser</Th>
<Th class="border px-3 py-2 text-center whitespace-nowrap" :table="table" :sort="false">platform</Th>
<Th class="border px-3 py-2 text-center whitespace-nowrap" :table="table" :sort="false">at</Th>
</tr>
</template>
<template #tbody="{ data }">
<tr v-for="(activity, i) in data" :key="i" class="dark:hover:bg-gray-600 dark:border-gray-800 transition-all">
<td class="px-2 py-1 border border-inherit text-center">{{ i + 1 }}</td>
<td class="px-2 py-1 border border-inherit uppercase">{{ activity.name }}</td>
<td class="px-2 py-1 border border-inherit uppercase">{{ activity.username }}</td>
<td class="px-2 py-1 border border-inherit uppercase">{{ activity.ip_address }}</td>
<td class="px-2 py-1 border border-inherit uppercase">{{ activity.browser }}</td>
<td class="px-2 py-1 border border-inherit uppercase">{{ activity.platform }}</td>
<td class="px-2 py-1 border border-inherit uppercase">{{ new Date(activity.created_at).toLocaleString('id') }}</td>
</tr>
</template>
</Builder>
</template>
</Card>
</DashboardLayout>
</template>

View File

@@ -22,6 +22,7 @@ Route::prefix('/v1')->name('api.v1.')->group(function () {
Route::get('/superuser/role', [App\Http\Controllers\Superuser\RoleController::class, 'get'])->name('role');
Route::post('/superuser/role/paginate', [App\Http\Controllers\Superuser\RoleController::class, 'paginate'])->name('role.paginate');
Route::post('/superuser/user/paginate', [App\Http\Controllers\Superuser\UserController::class, 'paginate'])->name('user.paginate');
Route::post('/superuser/activity/login', [App\Http\Controllers\ActivityController::class, 'logins'])->name('activity.login');
Route::get('/superuser/menu', [App\Http\Controllers\Superuser\MenuController::class, 'get'])->name('menu');
});
});

View File

@@ -45,5 +45,6 @@ Route::middleware(['auth:sanctum', config('jetstream.auth_session'), 'verified']
'index', 'store', 'update', 'destroy',
]);
Route::get('/activity/login', [App\Http\Controllers\ActivityController::class, 'login'])->name('activity.login');
});
});