transition
This commit is contained in:
@@ -119,24 +119,20 @@ readonly class AuthService
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws LucentException
|
||||
*/
|
||||
public
|
||||
function sendLoginEmail(string $email): void
|
||||
|
||||
public function sendLoginEmail(string $email): void
|
||||
{
|
||||
$emailAddress = (new Email($email));
|
||||
$user = $this->userRepo->findByEmail($emailAddress);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
throw new LucentException("User not found");
|
||||
return;
|
||||
}
|
||||
|
||||
if ($user->get()->isRemoved()) {
|
||||
throw new LucentException("Cannot reset email if the user is not active");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$newToken = $this->userRepo->updateLoginToken($user->get()->id);
|
||||
|
||||
Mail::to($email)->send(
|
||||
|
||||
@@ -13,11 +13,13 @@ use Lucent\Account\AuthService;
|
||||
use Lucent\Channel\ChannelService;
|
||||
use Lucent\LucentException;
|
||||
use Lucent\Svelte\Svelte;
|
||||
use Lucent\Util\Form\FormException;
|
||||
use Lucent\Util\Form\ResponseFormError;
|
||||
use function Lucent\Response\fail;
|
||||
use function Lucent\Response\ok;
|
||||
|
||||
|
||||
class AuthController extends Controller
|
||||
class AuthController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AuthService $authService,
|
||||
@@ -65,52 +67,39 @@ class AuthController extends Controller
|
||||
return ok();
|
||||
}
|
||||
|
||||
public function login(): View|RedirectResponse
|
||||
public function login()
|
||||
{
|
||||
|
||||
if ($this->accountService->countUsers() == 0) {
|
||||
return redirect($this->channelService->channel->lucentUrl . "/register");
|
||||
}
|
||||
|
||||
return $this->svelte->render(
|
||||
layout: "account",
|
||||
view: "login",
|
||||
title: "Log in"
|
||||
);
|
||||
return view("lucent::auth.login");
|
||||
}
|
||||
|
||||
public function postLogin(Request $request): Response
|
||||
public function postLogin(Request $request)
|
||||
{
|
||||
try {
|
||||
$this->authService->sendLoginEmail($request->input("email"));
|
||||
} catch (LucentException $th) {
|
||||
return fail($th);
|
||||
}
|
||||
$this->authService->sendLoginEmail($request->input("email"));
|
||||
|
||||
return ok();
|
||||
return view("lucent::auth.login-success");
|
||||
}
|
||||
|
||||
public function verify(Request $request): View
|
||||
{
|
||||
return $this->svelte->render(
|
||||
layout: "account",
|
||||
view: "verify",
|
||||
title: "Verify and enter",
|
||||
data: [
|
||||
"email" => $request->input("email"),
|
||||
"token" => $request->input("token"),
|
||||
]
|
||||
);
|
||||
return view("lucent::auth.verify", [
|
||||
"email" => $request->input("email"),
|
||||
"token" => $request->input("token"),
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
public function postVerify(Request $request): Response
|
||||
public function postVerify(Request $request)
|
||||
{
|
||||
try {
|
||||
$this->authService->login($request->input("email"), $request->input("token"));
|
||||
} catch (LucentException $th) {
|
||||
return fail($th);
|
||||
return ResponseFormError::fromException($th);
|
||||
}
|
||||
return ok();
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,14 +21,36 @@ class HomeController extends Controller
|
||||
{
|
||||
}
|
||||
|
||||
public function home(): View
|
||||
public function home(Request $request): View
|
||||
{
|
||||
$urlParams = $request->all();
|
||||
$users = $this->accountService->all();
|
||||
|
||||
$sort = data_get($urlParams, "sort") ?? "-_sys.updatedAt";
|
||||
$filter = data_get($urlParams, "filter") ?? [];
|
||||
$arguments = array_merge([
|
||||
"schema_in" => $this->accountService->currentReadableSchemas(),
|
||||
"status_in" => ["draft", "published"]
|
||||
], $filter);
|
||||
|
||||
$limit = 10;
|
||||
|
||||
$graph = $this->query
|
||||
->filter($arguments)
|
||||
->limit($limit)
|
||||
->childrenDepth(1)
|
||||
->parentsDepth(0)
|
||||
->sort($sort)
|
||||
->run();
|
||||
|
||||
|
||||
return view("lucent::home", [
|
||||
"users" => $users,
|
||||
"records" => $graph->getRootRecords(),
|
||||
"graph" => toArray($graph),
|
||||
"modalUrl" => $request->fullUrl(),
|
||||
]);
|
||||
|
||||
return $this->svelte->render(
|
||||
layout: "channel",
|
||||
view: "homeIndex",
|
||||
title: "Records",
|
||||
);
|
||||
}
|
||||
|
||||
public function records(Request $request): Response
|
||||
|
||||
@@ -4,15 +4,19 @@ namespace Lucent\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Lucent\Account\AccountService;
|
||||
use Lucent\Account\AuthService;
|
||||
use Lucent\Channel\ChannelService;
|
||||
use Lucent\ViewModel\ViewModel;
|
||||
|
||||
readonly class AuthMiddleware
|
||||
{
|
||||
public function __construct(
|
||||
private AuthService $authService,
|
||||
private ChannelService $channelService
|
||||
private AccountService $accountService,
|
||||
private ChannelService $channelService,
|
||||
private ViewModel $viewModel
|
||||
)
|
||||
{
|
||||
}
|
||||
@@ -22,9 +26,11 @@ readonly class AuthMiddleware
|
||||
if (!$this->authService->isLoggedIn()) {
|
||||
return redirect($this->channelService->channel->lucentUrl . "/login");
|
||||
}
|
||||
|
||||
$this->authService->refreshSession();
|
||||
|
||||
View::share("channel",$this->channelService->channel);
|
||||
View::share("user",session("user"));
|
||||
View::share("schemas",$this->channelService->channel->schemas->whereIn("name",$this->accountService->currentReadableSchemas())->values());
|
||||
View::share("viewModel",$this->viewModel);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Lucent;
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Intervention\Image\ImageManager;
|
||||
@@ -58,7 +59,7 @@ class LucentServiceProvider extends ServiceProvider
|
||||
$router->aliasMiddleware('lucent.auth', \Lucent\Http\Middleware\AuthMiddleware::class);
|
||||
$router->aliasMiddleware('lucent.guest', \Lucent\Http\Middleware\GuestMiddleware::class);
|
||||
|
||||
$this->loadViewsFrom(__DIR__ . '/Views', 'lucent');
|
||||
$this->loadViewsFrom(__DIR__ . '/../front/views', 'lucent');
|
||||
$this->loadRoutesFrom(__DIR__ . '/Http/web.php');
|
||||
$this->loadRoutesFrom(__DIR__ . '/Http/api.php');
|
||||
|
||||
@@ -76,6 +77,7 @@ class LucentServiceProvider extends ServiceProvider
|
||||
View::share('manifest', $manifest);
|
||||
View::share('image', app()->make(ImageService::class));
|
||||
View::share('file', app()->make(FileService::class));
|
||||
Blade::anonymousComponentPath(__DIR__.'../front/views/components',"lucent");
|
||||
|
||||
$this->publishes([
|
||||
__DIR__ . '/Config/main.php' => config_path('lucent.php'),
|
||||
@@ -83,6 +85,7 @@ class LucentServiceProvider extends ServiceProvider
|
||||
|
||||
$this->publishes([
|
||||
__DIR__ . '/../front/dist' => public_path('vendor/lucent/dist'),
|
||||
__DIR__ . '/../front/public' => public_path('vendor/lucent/public'),
|
||||
], 'lucent');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\Util\Form;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
|
||||
final class FormException extends Exception
|
||||
{
|
||||
// Redefine the exception so message isn't optional
|
||||
public function __construct(string $message, int $code = 0, Exception $previous = null)
|
||||
{
|
||||
// make sure everything is assigned properly
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\Util\Form;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Contracts\Routing\ResponseFactory;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Validation\Validator;
|
||||
use Lucent\LucentException;
|
||||
|
||||
class ResponseFormError
|
||||
{
|
||||
/**
|
||||
* @param $errors list<string>
|
||||
*/
|
||||
public static function render(array $errors): ResponseFactory|Application|Response
|
||||
{
|
||||
return response(view("lucent::forms.errors", ["errors" => $errors])->render(), 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Validator $validator
|
||||
* @return ResponseFactory|Application|Response
|
||||
*/
|
||||
public static function fromValidator(Validator $validator): ResponseFactory|Application|Response
|
||||
{
|
||||
|
||||
return self::render($validator->errors()->all());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $errors
|
||||
* @return ResponseFactory|Application|Response
|
||||
*/
|
||||
public static function fromArray(array $errors): ResponseFactory|Application|Response
|
||||
{
|
||||
return self::render($errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $errorString
|
||||
* @return ResponseFactory|Application|Response
|
||||
*/
|
||||
public static function fromMessage(string $errorString): ResponseFactory|Application|Response
|
||||
{
|
||||
return self::render([$errorString]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LucentException|FormException $exception
|
||||
* @return ResponseFactory|Application|Response
|
||||
*/
|
||||
public static function fromException(LucentException|FormException $exception): ResponseFactory|Application|Response
|
||||
{
|
||||
return self::render([$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\ViewModel;
|
||||
|
||||
use Lucent\Channel\ChannelService;
|
||||
use Lucent\Record\QueryRecord;
|
||||
use Lucent\Record\Status;
|
||||
use Lucent\Schema\CollectionSchema;
|
||||
use Lucent\Schema\FieldInterface;
|
||||
use Lucent\Schema\FilesSchema;
|
||||
use Mustache_Engine;
|
||||
|
||||
class ViewModel
|
||||
{
|
||||
public function __construct(
|
||||
public ChannelService $channelService
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public function getRecordName(QueryRecord $record): string
|
||||
{
|
||||
$schema = $this->channelService->getSchema($record->schema)->get();
|
||||
if (empty($schema->titleTemplate)) {
|
||||
$title = match (get_class($schema)) {
|
||||
CollectionSchema::class => $record->data[$schema->fields->filter(fn(FieldInterface $f) => $f->info->name === "text")->first()->name],
|
||||
FilesSchema::class => $record->_file->path,
|
||||
};
|
||||
|
||||
if (empty(trim($title))) {
|
||||
return "~Untitled~";
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
$m = new Mustache_Engine(array('entity_flags' => ENT_QUOTES));
|
||||
return $m->render($schema->titleTemplate, $record->data);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
Login to your Lucent account!
|
||||
|
||||
If you were not the one making this request, please ignore this email.
|
||||
|
||||
{{ $url }}/verify?email={{ $email }}&token={{ $token }}
|
||||
@@ -1,35 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<title>@yield('title') - Lucent Data Platform</title>
|
||||
|
||||
@if(config("lucent.env") == "production")
|
||||
<!-- if production -->
|
||||
<link rel="stylesheet" href="/vendor/lucent/dist/{{ $manifest['main.css']["file"] }}"/>
|
||||
<script type="module" src="/vendor/lucent/dist/{{ $manifest['main.js']["file"] }}"></script>
|
||||
@else
|
||||
<!-- if development -->
|
||||
@php
|
||||
echo '<script type="module" crossorigin src="http://127.0.0.1:5173/@vite/client"></script>';
|
||||
@endphp
|
||||
<script type="module" crossorigin src="http://127.0.0.1:5173/main.js"></script>
|
||||
@endif
|
||||
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||
|
||||
</head>
|
||||
|
||||
<body class="view-{{ $view }}">
|
||||
<div class="mt-5">
|
||||
@yield('content')
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,30 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<title>@yield('title') - Lucent Data Platform</title>
|
||||
@if(config("lucent.env") == "production")
|
||||
<!-- if production -->
|
||||
<link rel="stylesheet" href="/vendor/lucent/dist/{{ $manifest['main.css']["file"] }}"/>
|
||||
<script type="module" src="/vendor/lucent/dist/{{ $manifest['main.js']["file"] }}"></script>
|
||||
@else
|
||||
<!-- if development -->
|
||||
@php
|
||||
echo '<script type="module" crossorigin src="http://127.0.0.1:5173/@vite/client"></script>';
|
||||
@endphp
|
||||
<script type="module" crossorigin src="http://127.0.0.1:5173/main.js"></script>
|
||||
@endif
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||
|
||||
</head>
|
||||
|
||||
<body class="view-{{ $view }}">
|
||||
@yield('content')
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{$title}}</title>
|
||||
<meta http-equiv="refresh" content="0; url='{{$to}}'"/>
|
||||
</head>
|
||||
<body>
|
||||
<p>{{$message}}</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,7 +0,0 @@
|
||||
@extends('lucent::layouts.'.$layout)
|
||||
@section('title')
|
||||
{{ $title }}
|
||||
@endsection
|
||||
@section('content')
|
||||
{!! $svelte !!}
|
||||
@endsection
|
||||
Reference in New Issue
Block a user