Add login and Laravel Pulse
This commit is contained in:
@@ -21,3 +21,4 @@ yarn-error.log
|
||||
/.nova
|
||||
/.vscode
|
||||
/.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",
|
||||
"dedoc/scramble": "^0.12.15",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/pulse": "^1.4",
|
||||
"laravel/sanctum": "^4.0",
|
||||
"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',
|
||||
'provider' => 'users',
|
||||
],
|
||||
'monitoring' => [
|
||||
'driver' => 'session',
|
||||
'provider' => 'admins',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
@@ -64,6 +68,10 @@ return [
|
||||
'driver' => 'eloquent',
|
||||
'model' => env('AUTH_MODEL', App\Models\User::class),
|
||||
],
|
||||
'admins' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => env('AUTH_ADMIN_MODEL', App\Models\Admin::class),
|
||||
],
|
||||
|
||||
// 'users' => [
|
||||
// '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;
|
||||
|
||||
use App\Models\User;
|
||||
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Seed the application's database.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
User::factory()->create([
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
'password' => bcrypt('password')
|
||||
// Run User Seeder
|
||||
$this->call([
|
||||
UserSeeder::class,
|
||||
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('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)
|
||||
Route::get('/file/{id}', [FileViewController::class, 'show'])
|
||||
->name('file.view')
|
||||
|
||||
+12
-2
@@ -1,7 +1,17 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\AdminMonitoringController;
|
||||
use Illuminate\Auth\Middleware\Authorize;
|
||||
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