setup complete

This commit is contained in:
2024-09-06 23:30:12 +03:00
parent a73ee21568
commit 6fc0a65b6f
22 changed files with 351 additions and 330 deletions
+1 -1
View File
@@ -24,7 +24,7 @@
setContext("user", user);
</script>
<div style="text-align: center;background: var(--p20);padding: 20px;color: var(--p90)">
<h1><a class="text-decoration-none" href="{channel.lucentUrl}">{channel.name}</a></h1>
<h1><a class="text-decoration-none" href="{channel.lucentUrl}">{channel.name ?? "Lucent Setup"}</a></h1>
</div>
<div>
<svelte:component this={components[view]} {title} {...data}/>
+11 -3
View File
@@ -1,12 +1,20 @@
<script>
import Step from "./Step.svelte"
export let steps;
export let allSuccess = false;
console.log(steps);
</script>
<div class="wrapper-tiny">
{#each steps as step}
<Step {step}></Step>
{/each}
{#each steps as step}
<Step {step}></Step>
{/each}
<div style="text-align: center;margin-top: 30px;">
{#if allSuccess}
<a href="/lucent/register" class="bt">Create the first user</a>
{/if}
</div>
</div>
+43
View File
@@ -0,0 +1,43 @@
.flatpickr-wrapper {
display: block !important;
}
.editor-field {
.flatpickr-calendar {
border-radius: 12px !important;
}
.flatpickr-months .flatpickr-month {
background: var(--p30);
color: var(--text);
font-size: 12px;
}
.flatpickr-current-month .flatpickr-monthDropdown-months {
background: var(--p30);
}
.flatpickr-weekdays{
background: var(--p30);
color: var(--text);
}
.flatpickr-weekdaycontainer .flatpickr-weekday{
background: var(--p30);
color: var(--text);
}
.flatpickr-days{
background: var(--p10);
color: var(--text);
}
.flatpickr-time{
background: var(--p10);
color: var(--text);
}
}
+2 -2
View File
@@ -15,7 +15,7 @@ body:has(dialog[open]) {
dialog {
margin: 2vh auto;
background-color: #fff;
background-color: var(--p10);
padding: 34px;
border: none;
border-radius: 12px;
@@ -49,6 +49,6 @@ dialog::backdrop {
position: sticky;
top: -34px;
z-index: 999;
background: #fff;
background-color: var(--p10);
padding: 10px 0;
}
+1 -4
View File
@@ -70,6 +70,7 @@
@import "./reference-tags";
@import "./members";
@import "./revisions";
@import "./datepicker";
body {
background-color: var(--p10);
@@ -104,7 +105,3 @@ a {
.lucent-component {
position: relative;
}
.flatpickr-wrapper {
display: block!important;
}
+105
View File
@@ -0,0 +1,105 @@
<?php
namespace Lucent\Commands;
use Illuminate\Console\Command;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class SetupDatabase extends Command
{
protected $signature = 'lucent:setup-db';
protected $description = 'Run to setup a new database';
public function handle()
{
$this->tableUsers();
$this->tableRecords();
$this->tableRevisions();
$this->tableSessions();
$this->tableCommandLogs();
$this->info("Lucent Database Setup Completed");
}
private function tableUsers(): void
{
Schema::create('users', function (Blueprint $table) {
$table->uuid("id")->primary();
$table->string('name')->nullable();
$table->string('email')->unique();
$table->jsonb('roles');
$table->string('createdAt');
$table->string('updatedAt');
$table->string('loggedInAt');
$table->string('mailToken')->nullable();
});
}
private function tableSessions(): void
{
Schema::create('sessions', function (Blueprint $table) {
$table->string('id')->primary();
$table->foreignId('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->longText('payload');
$table->integer('last_activity')->index();
});
}
private function tableRecords(): void
{
Schema::create('records', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('schema');
$table->string('status');
$table->jsonb('data');
$table->jsonb('_sys');
$table->jsonb('_file');
$table->text('search')->default("");
$table->index(['schema', '_sys->updatedAt', 'status']);
$table->index('search');
});
Schema::create('edges', function (Blueprint $table) {
$table->uuid('source');
$table->uuid('target');
$table->string('sourceSchema');
$table->string('targetSchema');
$table->string('field');
$table->string('rank');
$table->unique(['source', 'target', "field"]);
});
}
private function tableRevisions(): void
{
Schema::create('revisions', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->uuid('recordId');
$table->string('schema');
$table->jsonb('data');
$table->jsonb('_sys');
$table->jsonb('_file');
$table->jsonb('_edges');
});
}
private function tableCommandLogs(): void
{
Schema::create('command_logs', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('signature');
$table->integer('pid')->nullable();
$table->text('logs');
});
}
}
@@ -1,40 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
protected $connection = 'lucentdb';
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->uuid("id")->primary();
$table->string('name')->nullable();
$table->string('email')->unique();
$table->jsonb('roles');
$table->string('createdAt');
$table->string('updatedAt');
$table->string('loggedInAt');
$table->string('mailToken')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
};
@@ -1,37 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
protected $connection = 'lucentdb';
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('sessions', function (Blueprint $table) {
$table->string('id')->primary();
$table->foreignId('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->longText('payload');
$table->integer('last_activity')->index();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('sessions');
}
};
-50
View File
@@ -1,50 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
protected $connection = 'lucentdb';
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('records', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('schema');
$table->string('status');
$table->jsonb('data');
$table->jsonb('_sys');
$table->jsonb('_file');
$table->index(['schema', 'status']);
});
Schema::create('edges', function (Blueprint $table) {
$table->uuid('source');
$table->uuid('target');
$table->string('sourceSchema');
$table->string('targetSchema');
$table->string('field');
$table->string('rank');
$table->unique(['source', 'target', "field"]);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('records');
Schema::dropIfExists('edges');
}
};
@@ -1,37 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
protected $connection = 'lucentdb';
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('revisions', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->uuid('recordId');
$table->string('schema');
$table->jsonb('data');
$table->jsonb('_sys');
$table->jsonb('_file');
$table->jsonb('_edges');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('revisions');
}
};
@@ -1,38 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
protected $connection = 'lucentdb';
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('records', function (Blueprint $table) {
$table->text('search')->default("");
$table->index('search');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('records', function (Blueprint $table) {
$table->dropColumn('search');
$table->dropIndex('search');
});
}
};
@@ -1,37 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
protected $connection = 'lucentdb';
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('records', function (Blueprint $table) {
$table->dropIndex(['schema', 'status']);
$table->index(['schema', '_sys->updatedAt', 'status']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('records', function (Blueprint $table) {
$table->dropIndex(['schema', '_sys->updatedAt', 'status']);
$table->index(['schema', 'status']);
});
}
};
@@ -1,35 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
protected $connection = 'lucentdb';
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('command_logs', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('signature');
$table->integer('pid')->nullable();
$table->text('logs');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('command_logs');
}
};
+22 -28
View File
@@ -3,7 +3,6 @@
namespace Lucent\Http\Controller;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Session\Session;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
@@ -12,10 +11,15 @@ use Lucent\Account\AccountService;
use Lucent\Channel\ChannelService;
use Lucent\LucentException;
use Lucent\Setup\Data\SetupStep;
use Lucent\Setup\Data\SetupStepStatus;
use Lucent\Setup\Setup;
use Lucent\Setup\Step\ComposerStep;
use Lucent\Setup\Step\DatabaseSetupStep;
use Lucent\Setup\Step\IStep;
use Lucent\Setup\Step\LaravelEnvStep;
use Lucent\Setup\Step\LucentConfigStep;
use Lucent\Setup\Step\StorageLinkSetupStep;
use Lucent\Setup\Step\StorageSetupStep;
use Lucent\Svelte\Svelte;
use function Lucent\Response\fail;
use function Lucent\Response\ok;
@@ -27,7 +31,6 @@ class SetupController
private readonly AccountService $accountService,
private readonly ChannelService $channelService,
private readonly Svelte $svelte,
private readonly Setup $setup,
)
{
@@ -35,44 +38,35 @@ class SetupController
public function setup(Request $request): View|RedirectResponse
{
if ($this->accountService->countUsers() > 0) {
return redirect($this->channelService->channel->lucentUrl . "/login");
}
$steps = array_reduce([
new ComposerStep,
new LucentConfigStep,
],fn(array $carry, IStep $setupStep)=> array_merge($carry,[$setupStep()]) ,[]);
new ComposerStep,
new LucentConfigStep,
new LaravelEnvStep,
new StorageSetupStep,
new StorageLinkSetupStep,
new DatabaseSetupStep,
], fn(array $carry, IStep $setupStep) => array_merge($carry, [$setupStep()]), []);
$allSuccess = array_reduce($steps, fn(bool $carry, SetupStep $step) => !$carry ? false : $step->status === SetupStepStatus::SUCCESS, true);
if($allSuccess){
if ($this->accountService->countUsers() > 0) {
return redirect($this->channelService->channel->lucentUrl . "/login");
}
}
return $this->svelte->render(
layout: "account",
view: "setup",
title: "Setup Lucent",
data: [
"steps" => $steps
"steps" => $steps,
"allSuccess" => $allSuccess,
]
);
}
public function postRegister(Request $request): Response
{
if ($this->accountService->countUsers() > 0) {
abort(400);
}
try {
$this->authService->registerAdmin(
name: $request->input("name"),
email: $request->input("email"),
);
} catch (LucentException $th) {
return fail($th);
}
return ok();
}
}
+5 -1
View File
@@ -13,14 +13,18 @@ use Lucent\Http\Controller\RevisionController;
use Lucent\Http\Controller\SetupController;
Route::get('/lucent/setup', [SetupController::class, 'setup']);
Route::group([
'middleware' => ['web'],
'prefix' => "lucent"
], function () {
Route::middleware(['lucent.guest'])->group(function () {
Route::get('/', [AuthController::class, 'login']);
Route::get('/setup', [SetupController::class, 'setup']);
Route::get('/register', [AuthController::class, 'register']);
Route::post('/register', [AuthController::class, 'postRegister']);
Route::get('/login', [AuthController::class, 'login']);
+2 -2
View File
@@ -12,6 +12,7 @@ use Lucent\Commands\CompileSchemas;
use Lucent\Commands\LiveLink;
use Lucent\Commands\RebuildThumbnails;
use Lucent\Commands\RemoveOrphanEdges;
use Lucent\Commands\SetupDatabase;
use Lucent\File\FileService;
use Lucent\File\ImageService;
use Lucent\Query\DatabaseGraph\DatabaseGraph;
@@ -67,14 +68,13 @@ class LucentServiceProvider extends ServiceProvider
$this->loadRoutesFrom(__DIR__ . '/Http/web.php');
$this->loadRoutesFrom(__DIR__ . '/Http/api.php');
$this->loadMigrationsFrom(__DIR__ . '/Database/migrations');
if ($this->app->runningInConsole()) {
$this->commands([
CompileSchemas::class,
RebuildThumbnails::class,
LiveLink::class,
RemoveOrphanEdges::class,
SetupDatabase::class,
]);
}
-13
View File
@@ -1,13 +0,0 @@
<?php
namespace Lucent\Setup;
use Lucent\Setup\Data\SetupStep;
class Setup
{
}
+53
View File
@@ -0,0 +1,53 @@
<?php
namespace Lucent\Setup\Step;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
use Lucent\Setup\Data\SetupStep;
class DatabaseSetupStep implements IStep
{
public function __invoke(): SetupStep
{
$name = "Database Connection";
$databaseConfig = config('database.connections.lucentdb');
if(empty($databaseConfig)) {
$instructions = <<<EOD
# You need to setup a database connection for lucentdb in database.php config. You can choose either sqlite or pgsql
# example:
'connections' => [
'lucentdb' => [
'driver' => 'sqlite',
'url' => env('LUCENT_DATABASE_URL'),
'database' => env('LUCENT_DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
],
EOD;
return SetupStep::makeFail($name, $instructions);
}
try {
DB::connection("lucentdb")->table("records")->get();
}catch (QueryException $e) {
$instructions = <<<EOD
# Make sure you run:
php artisan lucent:setup-db
EOD;
return SetupStep::makeFail($name, $instructions);
}
return SetupStep::makeSuccess($name, "Database Connection successfully created");
}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace Lucent\Setup\Step;
use Lucent\Setup\Data\SetupStep;
class LaravelEnvStep implements IStep
{
public function __invoke(): SetupStep
{
$name = "Laravel ENV";
$instructions = <<<EOD
# Make sure in your env that you APP_URL is the same as the one in your browser right now. Or the other way round.
EOD;
return match (config("lucent.url") === request()->getSchemeAndHttpHost()) {
true => SetupStep::makeSuccess($name, $instructions),
false => SetupStep::makeFail($name, $instructions),
};
}
}
+2 -2
View File
@@ -10,14 +10,14 @@ class LucentConfigStep implements IStep
public function __invoke(): SetupStep
{
$lucentConfig = config("lucent.schemasPath");
$lucentConfig = config("lucent.schemas_path");
$name = "Generate Lucent config";
$instructions = <<<EOD
# Run the following command to generate the configuration file:
php8.3 artisan vendor:publish --tag=lucent-config
php artisan vendor:publish --tag=lucent-config
# A lucent.php file will be created in your config folder
+39
View File
@@ -0,0 +1,39 @@
<?php
namespace Lucent\Setup\Step;
use Lucent\Setup\Data\SetupStep;
class StorageLinkSetupStep implements IStep
{
public function __invoke(): SetupStep
{
$storageDriver = config("filesystems.disks.lucent.driver");
$name = "Storage Link";
$instructions = <<<EOD
# If you have chosen to store your file locally then you have to generate a link to the public folder
# run:
php artisan storage:link
EOD;
if($storageDriver !== "local"){
return SetupStep::makeSuccess($name, $instructions);
}
$storageLinks = config("filesystems.links");
$allLinksExist = array_reduce(array_keys($storageLinks),fn(bool $carry, string $link) => !$carry ? false : is_link($link) , true);
return match ($allLinksExist) {
true => SetupStep::makeSuccess($name, $instructions),
false => SetupStep::makeFail($name, $instructions),
};
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace Lucent\Setup\Step;
use Lucent\Setup\Data\SetupStep;
class StorageSetupStep implements IStep
{
public function __invoke(): SetupStep
{
$storage = config("filesystems.disks.lucent");
$name = "Storage setup";
$instructions = <<<EOD
# You can use your local filesystem or s3 compatible storage. Lucent expects you to have a valid configuration inside config/filesystems.php
# example:
return [
'disks' => [
'lucent' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
'throw' => true,
],
],
];
EOD;
return match (!empty($storage)) {
true => SetupStep::makeSuccess($name, $instructions),
false => SetupStep::makeFail($name, $instructions),
};
}
}