Add login and Laravel Pulse
This commit is contained in:
@@ -21,3 +21,4 @@ yarn-error.log
|
|||||||
/.nova
|
/.nova
|
||||||
/.vscode
|
/.vscode
|
||||||
/.zed
|
/.zed
|
||||||
|
/public
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Models\AcceptanceLetter;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
|
|
||||||
class AcceptanceLetterController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Menampilkan semua data Acceptance Letter (GET /acceptance_letters).
|
|
||||||
*/
|
|
||||||
public function index()
|
|
||||||
{
|
|
||||||
$letters = AcceptanceLetter::all();
|
|
||||||
return response()->json($letters);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Menyimpan data baru (POST /acceptance_letters).
|
|
||||||
*/
|
|
||||||
public function store(Request $request)
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
'nomor_surat' => 'required',
|
|
||||||
'nama_mahasiswa' => 'required',
|
|
||||||
'nomor_induk_mahasiswa' => 'required',
|
|
||||||
'program_studi_mahasiswa' => 'required',
|
|
||||||
'tahun_ajaran' => 'required',
|
|
||||||
'start_date' => 'required|date',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$letter = AcceptanceLetter::create($request->all());
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'message' => 'Acceptance Letter berhasil disimpan.',
|
|
||||||
'data' => $letter
|
|
||||||
], 201);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Menampilkan detail data (GET /acceptance_letters/{id}).
|
|
||||||
*/
|
|
||||||
public function show($id)
|
|
||||||
{
|
|
||||||
$letter = AcceptanceLetter::findOrFail($id);
|
|
||||||
return response()->json($letter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mengupdate data (PUT/PATCH /acceptance_letters/{id}).
|
|
||||||
*/
|
|
||||||
public function update(Request $request, $id)
|
|
||||||
{
|
|
||||||
$letter = AcceptanceLetter::findOrFail($id);
|
|
||||||
|
|
||||||
$request->validate([
|
|
||||||
'nomor_surat' => 'required',
|
|
||||||
'nama_mahasiswa' => 'required',
|
|
||||||
'nomor_induk_mahasiswa' => 'required',
|
|
||||||
'program_studi_mahasiswa' => 'required',
|
|
||||||
'tahun_ajaran' => 'required',
|
|
||||||
'start_date' => 'required|date',
|
|
||||||
'lampiran' => 'nullable'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$letter->update($request->all());
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'message' => 'Acceptance Letter berhasil diupdate.',
|
|
||||||
'data' => $letter
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Menghapus data (DELETE /acceptance_letters/{id}).
|
|
||||||
*/
|
|
||||||
public function destroy($id)
|
|
||||||
{
|
|
||||||
$letter = AcceptanceLetter::findOrFail($id);
|
|
||||||
$letter->delete();
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'message' => 'Acceptance Letter berhasil dihapus.'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class AdminMonitoringController extends Controller
|
||||||
|
{
|
||||||
|
public function showLoginForm()
|
||||||
|
{
|
||||||
|
return view('monitoring.login');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function login(Request $request)
|
||||||
|
{
|
||||||
|
$credentials = $request->validate([
|
||||||
|
'email' => ['required', 'email'],
|
||||||
|
'password' => ['required'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Ubah dari 'monitor' ke 'monitoring' sesuai config/auth.php
|
||||||
|
if (Auth::guard('monitoring')->attempt($credentials, $request->filled('remember'))) {
|
||||||
|
$request->session()->regenerate();
|
||||||
|
|
||||||
|
return redirect()->intended('/pulse');
|
||||||
|
}
|
||||||
|
|
||||||
|
return back()->withErrors([
|
||||||
|
'email' => 'Email atau password salah.',
|
||||||
|
])->onlyInput('email');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logout(Request $request)
|
||||||
|
{
|
||||||
|
// Ubah dari 'monitor' ke 'monitoring'
|
||||||
|
Auth::guard('monitoring')->logout();
|
||||||
|
|
||||||
|
$request->session()->invalidate();
|
||||||
|
$request->session()->regenerateToken();
|
||||||
|
|
||||||
|
return redirect('/monitoring/login');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Models\CompletionLetter;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
|
|
||||||
class CompletionLetterController extends Controller
|
|
||||||
{
|
|
||||||
public function index()
|
|
||||||
{
|
|
||||||
$letters = CompletionLetter::all();
|
|
||||||
return response()->json($letters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function store(Request $request)
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
'nomor_surat' => 'required',
|
|
||||||
'nama_mahasiswa' => 'required',
|
|
||||||
'nomor_induk_mahasiswa' => 'required',
|
|
||||||
'program_studi_mahasiswa' => 'required',
|
|
||||||
'tahun_ajaran' => 'required',
|
|
||||||
'completion_date' => 'required|date',
|
|
||||||
'lampiran' => 'nullable'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$letter = CompletionLetter::create($request->all());
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'message' => 'Completion Letter berhasil disimpan.',
|
|
||||||
'data' => $letter
|
|
||||||
], 201);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function show($id)
|
|
||||||
{
|
|
||||||
$letter = CompletionLetter::findOrFail($id);
|
|
||||||
return response()->json($letter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function update(Request $request, $id)
|
|
||||||
{
|
|
||||||
$letter = CompletionLetter::findOrFail($id);
|
|
||||||
$letter->update($request->all());
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'message' => 'Completion Letter berhasil diupdate.',
|
|
||||||
'data' => $letter
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function destroy($id)
|
|
||||||
{
|
|
||||||
$letter = CompletionLetter::findOrFail($id);
|
|
||||||
$letter->delete();
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'message' => 'Completion Letter berhasil dihapus.'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class AcceptanceLetter extends Model
|
|
||||||
{
|
|
||||||
use HasFactory;
|
|
||||||
|
|
||||||
protected $table = 'acceptance_letters';
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'nomor_surat',
|
|
||||||
'nama_mahasiswa',
|
|
||||||
'nomor_induk_mahasiswa',
|
|
||||||
'program_studi_mahasiswa',
|
|
||||||
'tahun_ajaran',
|
|
||||||
'start_date',
|
|
||||||
'lampiran'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||||
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class Admin extends Authenticatable
|
||||||
|
{
|
||||||
|
use Notifiable, HasUuids;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'email',
|
||||||
|
'password',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $hidden = [
|
||||||
|
'password',
|
||||||
|
'remember_token',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'email_verified_at' => 'datetime',
|
||||||
|
'password' => 'hashed',
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class CompletionLetter extends Model
|
|
||||||
{
|
|
||||||
use HasFactory;
|
|
||||||
|
|
||||||
protected $table = 'completion_letters';
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'nomor_surat',
|
|
||||||
'nama_mahasiswa',
|
|
||||||
'nomor_induk_mahasiswa',
|
|
||||||
'program_studi_mahasiswa',
|
|
||||||
'tahun_ajaran',
|
|
||||||
'completion_date',
|
|
||||||
'lampiran'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
"dedoc/scramble": "^0.12.15",
|
"dedoc/scramble": "^0.12.15",
|
||||||
"laravel/framework": "^12.0",
|
"laravel/framework": "^12.0",
|
||||||
|
"laravel/pulse": "^1.4",
|
||||||
"laravel/sanctum": "^4.0",
|
"laravel/sanctum": "^4.0",
|
||||||
"laravel/tinker": "^2.10.1"
|
"laravel/tinker": "^2.10.1"
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
+400
-180
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,10 @@ return [
|
|||||||
'driver' => 'session',
|
'driver' => 'session',
|
||||||
'provider' => 'users',
|
'provider' => 'users',
|
||||||
],
|
],
|
||||||
|
'monitoring' => [
|
||||||
|
'driver' => 'session',
|
||||||
|
'provider' => 'admins',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -64,6 +68,10 @@ return [
|
|||||||
'driver' => 'eloquent',
|
'driver' => 'eloquent',
|
||||||
'model' => env('AUTH_MODEL', App\Models\User::class),
|
'model' => env('AUTH_MODEL', App\Models\User::class),
|
||||||
],
|
],
|
||||||
|
'admins' => [
|
||||||
|
'driver' => 'eloquent',
|
||||||
|
'model' => env('AUTH_ADMIN_MODEL', App\Models\Admin::class),
|
||||||
|
],
|
||||||
|
|
||||||
// 'users' => [
|
// 'users' => [
|
||||||
// 'driver' => 'database',
|
// 'driver' => 'database',
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cross-Origin Resource Sharing (CORS) Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may configure your settings for cross-origin resource sharing
|
||||||
|
| or "CORS". This determines what cross-origin operations may execute
|
||||||
|
| in web browsers. You are free to adjust these settings as needed.
|
||||||
|
|
|
||||||
|
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'paths' => ['api/*', 'sanctum/csrf-cookie'],
|
||||||
|
|
||||||
|
'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||||
|
|
||||||
|
'allowed_origins' => [
|
||||||
|
'https://cetaksuratkp.humicprototyping.com', // domain frontend kamu
|
||||||
|
'http://localhost:3000', // kalau develop lokal, bisa dihapus kalau udah produksi
|
||||||
|
],
|
||||||
|
|
||||||
|
'allowed_origins_patterns' => [],
|
||||||
|
|
||||||
|
'allowed_headers' => ['*'],
|
||||||
|
|
||||||
|
'exposed_headers' => [],
|
||||||
|
|
||||||
|
'max_age' => 0,
|
||||||
|
|
||||||
|
'supports_credentials' => true,
|
||||||
|
];
|
||||||
@@ -0,0 +1,236 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Laravel\Pulse\Http\Middleware\Authorize;
|
||||||
|
use Laravel\Pulse\Pulse;
|
||||||
|
use Laravel\Pulse\Recorders;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Domain
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the subdomain which the Pulse dashboard will be accessible from.
|
||||||
|
| When set to null, the dashboard will reside under the same domain as
|
||||||
|
| the application. Remember to configure your DNS entries correctly.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'domain' => env('PULSE_DOMAIN'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Path
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the path which the Pulse dashboard will be accessible from. Feel
|
||||||
|
| free to change this path to anything you'd like. Note that this won't
|
||||||
|
| affect the path of the internal API that is never exposed to users.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'path' => env('PULSE_PATH', 'pulse'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Master Switch
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This configuration option may be used to completely disable all Pulse
|
||||||
|
| data recorders regardless of their individual configurations. This
|
||||||
|
| provides a single option to quickly disable all Pulse recording.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'enabled' => env('PULSE_ENABLED', true),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Storage Driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This configuration option determines which storage driver will be used
|
||||||
|
| while storing entries from Pulse's recorders. In addition, you also
|
||||||
|
| may provide any options to configure the selected storage driver.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'storage' => [
|
||||||
|
'driver' => env('PULSE_STORAGE_DRIVER', 'database'),
|
||||||
|
|
||||||
|
'trim' => [
|
||||||
|
'keep' => env('PULSE_STORAGE_KEEP', '7 days'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'database' => [
|
||||||
|
'connection' => env('PULSE_DB_CONNECTION'),
|
||||||
|
'chunk' => 1000,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Ingest Driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This configuration options determines the ingest driver that will be used
|
||||||
|
| to capture entries from Pulse's recorders. Ingest drivers are great to
|
||||||
|
| free up your request workers quickly by offloading the data storage.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'ingest' => [
|
||||||
|
'driver' => env('PULSE_INGEST_DRIVER', 'storage'),
|
||||||
|
|
||||||
|
'buffer' => env('PULSE_INGEST_BUFFER', 5_000),
|
||||||
|
|
||||||
|
'trim' => [
|
||||||
|
'lottery' => [1, 1_000],
|
||||||
|
'keep' => env('PULSE_INGEST_KEEP', '7 days'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'redis' => [
|
||||||
|
'connection' => env('PULSE_REDIS_CONNECTION'),
|
||||||
|
'chunk' => 1000,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Cache Driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This configuration option determines the cache driver that will be used
|
||||||
|
| for various tasks, including caching dashboard results, establishing
|
||||||
|
| locks for events that should only occur on one server and signals.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'cache' => env('PULSE_CACHE_DRIVER'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Route Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These middleware will be assigned to every Pulse route, giving you the
|
||||||
|
| chance to add your own middleware to this list or change any of the
|
||||||
|
| existing middleware. Of course, reasonable defaults are provided.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'middleware' => [
|
||||||
|
'web',
|
||||||
|
Authorize::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Recorders
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The following array lists the "recorders" that will be registered with
|
||||||
|
| Pulse, along with their configuration. Recorders gather application
|
||||||
|
| event data from requests and tasks to pass to your ingest driver.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'recorders' => [
|
||||||
|
Recorders\CacheInteractions::class => [
|
||||||
|
'enabled' => env('PULSE_CACHE_INTERACTIONS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_CACHE_INTERACTIONS_SAMPLE_RATE', 1),
|
||||||
|
'ignore' => [
|
||||||
|
...Pulse::defaultVendorCacheKeys(),
|
||||||
|
],
|
||||||
|
'groups' => [
|
||||||
|
'/^job-exceptions:.*/' => 'job-exceptions:*',
|
||||||
|
// '/:\d+/' => ':*',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\Exceptions::class => [
|
||||||
|
'enabled' => env('PULSE_EXCEPTIONS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_EXCEPTIONS_SAMPLE_RATE', 1),
|
||||||
|
'location' => env('PULSE_EXCEPTIONS_LOCATION', true),
|
||||||
|
'ignore' => [
|
||||||
|
// '/^Package\\\\Exceptions\\\\/',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\Queues::class => [
|
||||||
|
'enabled' => env('PULSE_QUEUES_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_QUEUES_SAMPLE_RATE', 1),
|
||||||
|
'ignore' => [
|
||||||
|
// '/^Package\\\\Jobs\\\\/',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\Servers::class => [
|
||||||
|
'server_name' => env('PULSE_SERVER_NAME', gethostname()),
|
||||||
|
'directories' => explode(':', env('PULSE_SERVER_DIRECTORIES', '/')),
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\SlowJobs::class => [
|
||||||
|
'enabled' => env('PULSE_SLOW_JOBS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_SLOW_JOBS_SAMPLE_RATE', 1),
|
||||||
|
'threshold' => env('PULSE_SLOW_JOBS_THRESHOLD', 1000),
|
||||||
|
'ignore' => [
|
||||||
|
// '/^Package\\\\Jobs\\\\/',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\SlowOutgoingRequests::class => [
|
||||||
|
'enabled' => env('PULSE_SLOW_OUTGOING_REQUESTS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_SLOW_OUTGOING_REQUESTS_SAMPLE_RATE', 1),
|
||||||
|
'threshold' => env('PULSE_SLOW_OUTGOING_REQUESTS_THRESHOLD', 1000),
|
||||||
|
'ignore' => [
|
||||||
|
// '#^http://127\.0\.0\.1:13714#', // Inertia SSR...
|
||||||
|
],
|
||||||
|
'groups' => [
|
||||||
|
// '#^https://api\.github\.com/repos/.*$#' => 'api.github.com/repos/*',
|
||||||
|
// '#^https?://([^/]*).*$#' => '\1',
|
||||||
|
// '#/\d+#' => '/*',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\SlowQueries::class => [
|
||||||
|
'enabled' => env('PULSE_SLOW_QUERIES_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_SLOW_QUERIES_SAMPLE_RATE', 1),
|
||||||
|
'threshold' => env('PULSE_SLOW_QUERIES_THRESHOLD', 1000),
|
||||||
|
'location' => env('PULSE_SLOW_QUERIES_LOCATION', true),
|
||||||
|
'max_query_length' => env('PULSE_SLOW_QUERIES_MAX_QUERY_LENGTH'),
|
||||||
|
'ignore' => [
|
||||||
|
'/(["`])pulse_[\w]+?\1/', // Pulse tables...
|
||||||
|
'/(["`])telescope_[\w]+?\1/', // Telescope tables...
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\SlowRequests::class => [
|
||||||
|
'enabled' => env('PULSE_SLOW_REQUESTS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_SLOW_REQUESTS_SAMPLE_RATE', 1),
|
||||||
|
'threshold' => env('PULSE_SLOW_REQUESTS_THRESHOLD', 1000),
|
||||||
|
'ignore' => [
|
||||||
|
'#^/'.env('PULSE_PATH', 'pulse').'$#', // Pulse dashboard...
|
||||||
|
'#^/telescope#', // Telescope dashboard...
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\UserJobs::class => [
|
||||||
|
'enabled' => env('PULSE_USER_JOBS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_USER_JOBS_SAMPLE_RATE', 1),
|
||||||
|
'ignore' => [
|
||||||
|
// '/^Package\\\\Jobs\\\\/',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\UserRequests::class => [
|
||||||
|
'enabled' => env('PULSE_USER_REQUESTS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_USER_REQUESTS_SAMPLE_RATE', 1),
|
||||||
|
'ignore' => [
|
||||||
|
'#^/'.env('PULSE_PATH', 'pulse').'$#', // Pulse dashboard...
|
||||||
|
'#^/telescope#', // Telescope dashboard...
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Laravel\Pulse\Support\PulseMigration;
|
||||||
|
|
||||||
|
return new class extends PulseMigration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
if (! $this->shouldRun()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema::create('pulse_values', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedInteger('timestamp');
|
||||||
|
$table->string('type');
|
||||||
|
$table->mediumText('key');
|
||||||
|
match ($this->driver()) {
|
||||||
|
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
|
||||||
|
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
|
||||||
|
'sqlite' => $table->string('key_hash'),
|
||||||
|
};
|
||||||
|
$table->mediumText('value');
|
||||||
|
|
||||||
|
$table->index('timestamp'); // For trimming...
|
||||||
|
$table->index('type'); // For fast lookups and purging...
|
||||||
|
$table->unique(['type', 'key_hash']); // For data integrity and upserts...
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('pulse_entries', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedInteger('timestamp');
|
||||||
|
$table->string('type');
|
||||||
|
$table->mediumText('key');
|
||||||
|
match ($this->driver()) {
|
||||||
|
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
|
||||||
|
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
|
||||||
|
'sqlite' => $table->string('key_hash'),
|
||||||
|
};
|
||||||
|
$table->bigInteger('value')->nullable();
|
||||||
|
|
||||||
|
$table->index('timestamp'); // For trimming...
|
||||||
|
$table->index('type'); // For purging...
|
||||||
|
$table->index('key_hash'); // For mapping...
|
||||||
|
$table->index(['timestamp', 'type', 'key_hash', 'value']); // For aggregate queries...
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('pulse_aggregates', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedInteger('bucket');
|
||||||
|
$table->unsignedMediumInteger('period');
|
||||||
|
$table->string('type');
|
||||||
|
$table->mediumText('key');
|
||||||
|
match ($this->driver()) {
|
||||||
|
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
|
||||||
|
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
|
||||||
|
'sqlite' => $table->string('key_hash'),
|
||||||
|
};
|
||||||
|
$table->string('aggregate');
|
||||||
|
$table->decimal('value', 20, 2);
|
||||||
|
$table->unsignedInteger('count')->nullable();
|
||||||
|
|
||||||
|
$table->unique(['bucket', 'period', 'type', 'aggregate', 'key_hash']); // Force "on duplicate update"...
|
||||||
|
$table->index(['period', 'bucket']); // For trimming...
|
||||||
|
$table->index('type'); // For purging...
|
||||||
|
$table->index(['period', 'type', 'aggregate', 'bucket']); // For aggregate queries...
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('pulse_values');
|
||||||
|
Schema::dropIfExists('pulse_entries');
|
||||||
|
Schema::dropIfExists('pulse_aggregates');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('admins', function (Blueprint $table) {
|
||||||
|
$table->uuid('id')->primary();
|
||||||
|
$table->string('name');
|
||||||
|
$table->string('email')->unique();
|
||||||
|
$table->timestamp('email_verified_at')->nullable();
|
||||||
|
$table->string('password');
|
||||||
|
$table->rememberToken();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('admins');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\Admin;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class AdminSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
Admin::create([
|
||||||
|
'id' => Str::uuid()->toString(),
|
||||||
|
'name' => 'Admin Monitoring',
|
||||||
|
'email' => 'admin@monitoring.com',
|
||||||
|
'password' => bcrypt('monitoring123'),
|
||||||
|
'email_verified_at' => now(),
|
||||||
|
'remember_token' => Str::random(10),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,21 +2,16 @@
|
|||||||
|
|
||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
class DatabaseSeeder extends Seeder
|
class DatabaseSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Seed the application's database.
|
|
||||||
*/
|
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
User::factory()->create([
|
// Run User Seeder
|
||||||
'name' => 'Test User',
|
$this->call([
|
||||||
'email' => 'test@example.com',
|
UserSeeder::class,
|
||||||
'password' => bcrypt('password')
|
AdminSeeder::class
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class UserSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
User::create([
|
||||||
|
'id' => Str::uuid()->toString(),
|
||||||
|
'name' => 'Test User',
|
||||||
|
'email' => 'test@example.com',
|
||||||
|
'password' => bcrypt('password'),
|
||||||
|
'email_verified_at' => now(),
|
||||||
|
'remember_token' => Str::random(10),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Monitoring Login</title>
|
||||||
|
<!-- Tailwind CSS CDN -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
</head>
|
||||||
|
<body class="min-h-screen bg-gray-100 flex items-center justify-center">
|
||||||
|
<div class="max-w-md w-full bg-white shadow-md rounded-lg p-8">
|
||||||
|
<div class="mb-6 text-center">
|
||||||
|
<a href="{{ url('/') }}">
|
||||||
|
{{-- <x-application-logo class="w-20 h-20 mx-auto text-gray-500" /> --}}
|
||||||
|
</a>
|
||||||
|
<h2 class="mt-4 text-2xl font-semibold text-gray-700">Monitoring Login</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('monitoring.login.submit') }}">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<!-- Email Address -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="block text-gray-700 text-sm font-bold mb-2" for="email">
|
||||||
|
Email
|
||||||
|
</label>
|
||||||
|
<input class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||||
|
id="email"
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
required
|
||||||
|
autofocus>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Password -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<label class="block text-gray-700 text-sm font-bold mb-2" for="password">
|
||||||
|
Password
|
||||||
|
</label>
|
||||||
|
<input class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline"
|
||||||
|
id="password"
|
||||||
|
type="password"
|
||||||
|
name="password"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if ($errors->any())
|
||||||
|
<div class="mb-4 text-red-500 text-sm">
|
||||||
|
{{ $errors->first() }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Submit Button -->
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
|
||||||
|
type="submit">
|
||||||
|
Sign In
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<x-pulse>
|
||||||
|
<!-- Konten Pulse lainnya -->
|
||||||
|
<livewire:pulse.servers cols="full" />
|
||||||
|
<livewire:pulse.usage cols="4" rows="2" />
|
||||||
|
<livewire:pulse.queues cols="4" />
|
||||||
|
<livewire:pulse.cache cols="4" />
|
||||||
|
<livewire:pulse.slow-queries cols="8" />
|
||||||
|
<livewire:pulse.exceptions cols="6" />
|
||||||
|
<livewire:pulse.slow-requests cols="6" />
|
||||||
|
<livewire:pulse.slow-jobs cols="6" />
|
||||||
|
<livewire:pulse.slow-outgoing-requests cols="6" />
|
||||||
|
|
||||||
|
<!-- Tombol Logout -->
|
||||||
|
<div class="mt-4 text-right">
|
||||||
|
<form action="{{ route('monitoring.logout') }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<button type="submit" class="px-4 py-2 text-white bg-red-600 hover:bg-red-700 rounded-md">
|
||||||
|
Logout
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</x-pulse>
|
||||||
@@ -40,10 +40,6 @@ Route::middleware('auth:sanctum')->group(function () {
|
|||||||
Route::apiResource('completion_templates', CompletionTemplateController::class);
|
Route::apiResource('completion_templates', CompletionTemplateController::class);
|
||||||
Route::apiResource('acceptance_templates', AcceptanceTemplateController::class);
|
Route::apiResource('acceptance_templates', AcceptanceTemplateController::class);
|
||||||
|
|
||||||
// Letter Type Routes
|
|
||||||
Route::apiResource('acceptance_letters', AcceptanceLetterController::class);
|
|
||||||
Route::apiResource('completion_letters', CompletionLetterController::class);
|
|
||||||
|
|
||||||
// File Viewer Route (Internal use for signed URLs)
|
// File Viewer Route (Internal use for signed URLs)
|
||||||
Route::get('/file/{id}', [FileViewController::class, 'show'])
|
Route::get('/file/{id}', [FileViewController::class, 'show'])
|
||||||
->name('file.view')
|
->name('file.view')
|
||||||
|
|||||||
+12
-2
@@ -1,7 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Http\Controllers\AdminMonitoringController;
|
||||||
|
use Illuminate\Auth\Middleware\Authorize;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::get('/', function () {
|
|
||||||
return view('welcome');
|
Route::get('/monitoring/login', [AdminMonitoringController::class, 'showLoginForm'])
|
||||||
|
->name('monitoring.login');
|
||||||
|
|
||||||
|
Route::post('/monitoring/login', [AdminMonitoringController::class, 'login'])
|
||||||
|
->name('monitoring.login.submit');
|
||||||
|
|
||||||
|
Route::middleware('auth:monitoring')->group(function () {
|
||||||
|
Route::post('/monitoring/logout', [AdminMonitoringController::class, 'logout'])
|
||||||
|
->name('monitoring.logout');
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user