Initialer Laravel Commit für BetiX
This commit is contained in:
136
app/Http/Controllers/Settings/KycController.php
Normal file
136
app/Http/Controllers/Settings/KycController.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Settings;
|
||||
|
||||
use App\Http\Controllers\Concerns\ProxiesBackend;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\BackendHttpClient;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
class KycController extends Controller
|
||||
{
|
||||
use ProxiesBackend;
|
||||
|
||||
public function __construct(private readonly BackendHttpClient $client)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Show KYC center page with user's documents (from upstream)
|
||||
*/
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
$docs = [];
|
||||
try {
|
||||
$res = $this->client->get($request, '/kyc/documents', [], retry: true);
|
||||
if ($res->successful()) {
|
||||
$j = $res->json() ?: [];
|
||||
$docs = $j['data'] ?? $j['documents'] ?? $j;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// ignore; page can still render and show empty state
|
||||
}
|
||||
|
||||
return Inertia::render('settings/Kyc', [
|
||||
'documents' => $docs,
|
||||
'accepted' => [
|
||||
'identity' => ['passport','driver_license','id_card','other'],
|
||||
'address' => ['bank_statement','utility_bill','other'],
|
||||
'payment' => ['online_banking','other'],
|
||||
],
|
||||
'maxUploadMb' => 15,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a new KYC document via upstream (multipart)
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'category' => ['required', Rule::in(['identity','address','payment'])],
|
||||
'type' => ['required', Rule::in(['passport','driver_license','id_card','bank_statement','utility_bill','online_banking','other'])],
|
||||
'file' => ['required','file','max:15360', 'mimetypes:image/jpeg,image/png,image/webp,application/pdf'],
|
||||
]);
|
||||
|
||||
try {
|
||||
$res = $this->client->postMultipart($request, '/kyc/documents', [
|
||||
'category' => $validated['category'],
|
||||
'type' => $validated['type'],
|
||||
], $request->file('file'), 'file');
|
||||
|
||||
if ($res->successful()) {
|
||||
return back()->with('status', 'Document uploaded');
|
||||
}
|
||||
if ($res->clientError()) {
|
||||
$msg = data_get($res->json(), 'message', 'Invalid request');
|
||||
return back()->withErrors(['kyc' => $msg]);
|
||||
}
|
||||
if ($res->serverError()) {
|
||||
return back()->withErrors(['kyc' => 'Service temporarily unavailable']);
|
||||
}
|
||||
return back()->withErrors(['kyc' => 'API server not reachable']);
|
||||
} catch (\Throwable $e) {
|
||||
return back()->withErrors(['kyc' => 'API server not reachable']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a KYC document via upstream
|
||||
*/
|
||||
public function destroy(Request $request, int $docId)
|
||||
{
|
||||
try {
|
||||
$res = $this->client->delete($request, "/kyc/documents/{$docId}");
|
||||
if ($res->successful()) {
|
||||
return back()->with('status', 'Document deleted');
|
||||
}
|
||||
if ($res->clientError()) {
|
||||
$msg = data_get($res->json(), 'message', 'Invalid request');
|
||||
return back()->withErrors(['kyc' => $msg]);
|
||||
}
|
||||
if ($res->serverError()) {
|
||||
return back()->withErrors(['kyc' => 'Service temporarily unavailable']);
|
||||
}
|
||||
return back()->withErrors(['kyc' => 'API server not reachable']);
|
||||
} catch (\Throwable $e) {
|
||||
return back()->withErrors(['kyc' => 'API server not reachable']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a document via upstream: prefer redirect to signed URL if provided
|
||||
*/
|
||||
public function download(Request $request, int $docId)
|
||||
{
|
||||
try {
|
||||
$res = $this->client->get($request, "/kyc/documents/{$docId}/download", [], retry: false);
|
||||
if ($res->successful()) {
|
||||
$j = $res->json();
|
||||
$url = $j['url'] ?? null;
|
||||
if ($url) {
|
||||
return redirect()->away($url);
|
||||
}
|
||||
// If upstream responds with binary directly, just passthrough headers/body
|
||||
$content = $res->body();
|
||||
$headers = [
|
||||
'Content-Type' => $res->header('Content-Type', 'application/octet-stream'),
|
||||
];
|
||||
return response($content, 200, $headers);
|
||||
}
|
||||
if ($res->clientError()) {
|
||||
$msg = data_get($res->json(), 'message', 'Invalid request');
|
||||
return back()->withErrors(['kyc' => $msg]);
|
||||
}
|
||||
if ($res->serverError()) {
|
||||
return back()->withErrors(['kyc' => 'Service temporarily unavailable']);
|
||||
}
|
||||
return back()->withErrors(['kyc' => 'API server not reachable']);
|
||||
} catch (\Throwable $e) {
|
||||
return back()->withErrors(['kyc' => 'API server not reachable']);
|
||||
}
|
||||
}
|
||||
}
|
||||
32
app/Http/Controllers/Settings/PasswordController.php
Normal file
32
app/Http/Controllers/Settings/PasswordController.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Settings;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Settings\PasswordUpdateRequest;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
class PasswordController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show the user's password settings page.
|
||||
*/
|
||||
public function edit(): Response
|
||||
{
|
||||
return Inertia::render('settings/Password');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user's password.
|
||||
*/
|
||||
public function update(PasswordUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$request->user()->update([
|
||||
'password' => $request->password,
|
||||
]);
|
||||
|
||||
return back();
|
||||
}
|
||||
}
|
||||
60
app/Http/Controllers/Settings/ProfileController.php
Normal file
60
app/Http/Controllers/Settings/ProfileController.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Settings;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Settings\ProfileDeleteRequest;
|
||||
use App\Http\Requests\Settings\ProfileUpdateRequest;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
class ProfileController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show the user's profile settings page.
|
||||
*/
|
||||
public function edit(Request $request): Response
|
||||
{
|
||||
return Inertia::render('settings/Profile', [
|
||||
'mustVerifyEmail' => $request->user() instanceof MustVerifyEmail,
|
||||
'status' => $request->session()->get('status'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user's profile information.
|
||||
*/
|
||||
public function update(ProfileUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$request->user()->fill($request->validated());
|
||||
|
||||
if ($request->user()->isDirty('email')) {
|
||||
$request->user()->email_verified_at = null;
|
||||
}
|
||||
|
||||
$request->user()->save();
|
||||
|
||||
return to_route('profile.edit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the user's profile.
|
||||
*/
|
||||
public function destroy(ProfileDeleteRequest $request): RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
Auth::logout();
|
||||
|
||||
$user->delete();
|
||||
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
return redirect('/');
|
||||
}
|
||||
}
|
||||
70
app/Http/Controllers/Settings/SecurityController.php
Normal file
70
app/Http/Controllers/Settings/SecurityController.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Settings;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
class SecurityController extends Controller
|
||||
{
|
||||
/**
|
||||
* Render the Security center page.
|
||||
*/
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
// Provide a light payload; sessions loaded via separate endpoint
|
||||
return Inertia::render('settings/Security', [
|
||||
'twoFactorEnabled' => (bool) optional($request->user())->hasEnabledTwoFactorAuthentication(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* List active sessions for the current user (from database sessions table).
|
||||
*/
|
||||
public function sessions(Request $request)
|
||||
{
|
||||
$userId = Auth::id();
|
||||
$rows = DB::table('sessions')
|
||||
->where('user_id', $userId)
|
||||
->orderByDesc('last_activity')
|
||||
->limit(100)
|
||||
->get(['id', 'ip_address', 'user_agent', 'last_activity']);
|
||||
|
||||
// Format response
|
||||
$data = $rows->map(function ($r) use ($request) {
|
||||
$isCurrent = $request->session()->getId() === $r->id;
|
||||
return [
|
||||
'id' => $r->id,
|
||||
'ip' => $r->ip_address,
|
||||
'user_agent' => $r->user_agent,
|
||||
'last_activity' => $r->last_activity,
|
||||
'current' => $isCurrent,
|
||||
];
|
||||
})->values();
|
||||
|
||||
return response()->json(['data' => $data]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke a specific session by ID (current user's session only)
|
||||
*/
|
||||
public function revoke(Request $request, string $id)
|
||||
{
|
||||
$userId = Auth::id();
|
||||
$session = DB::table('sessions')->where('id', $id)->first();
|
||||
if (! $session || $session->user_id != $userId) {
|
||||
abort(404);
|
||||
}
|
||||
// Prevent revoking current session via this endpoint to avoid lockouts
|
||||
if ($request->session()->getId() === $id) {
|
||||
return response()->json(['message' => 'Cannot revoke current session via API.'], 422);
|
||||
}
|
||||
DB::table('sessions')->where('id', $id)->delete();
|
||||
return response()->json(['message' => 'Session revoked']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Settings;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Settings\TwoFactorAuthenticationRequest;
|
||||
use Illuminate\Routing\Controllers\HasMiddleware;
|
||||
use Illuminate\Routing\Controllers\Middleware;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
use Laravel\Fortify\Features;
|
||||
|
||||
class TwoFactorAuthenticationController extends Controller implements HasMiddleware
|
||||
{
|
||||
/**
|
||||
* Get the middleware that should be assigned to the controller.
|
||||
*/
|
||||
public static function middleware(): array
|
||||
{
|
||||
return Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword')
|
||||
? [new Middleware('password.confirm', only: ['show'])]
|
||||
: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the user's two-factor authentication settings page.
|
||||
*/
|
||||
public function show(TwoFactorAuthenticationRequest $request): Response
|
||||
{
|
||||
$request->ensureStateIsValid();
|
||||
|
||||
return Inertia::render('settings/TwoFactor', [
|
||||
'twoFactorEnabled' => $request->user()->hasEnabledTwoFactorAuthentication(),
|
||||
'requiresConfirmation' => Features::optionEnabled(Features::twoFactorAuthentication(), 'confirm'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user