Skip to content

Commit

Permalink
feat: export cms (#169)
Browse files Browse the repository at this point in the history
* feat: import export

* feat: use file instead of database

* feat: move import/export to model

* fix: export from tableitem

* feat: move export to Trait

* style: formatting

* style: formatting

* fix: never use file as source of truth

* style: formatting

* chore: cleanup

* fix: use export to file

* feat: comment things that no longer work

* feat: add  meta data

* feat: list filenames

* feat: cleaner export

* feat: remove UI for import/export

* style: formatting

* feat: add import command

* feat: import from files

* feat: remove import UI

* feat: prevent editing tables with changes on disk

* feat: do not use id's in export for tables

* feat: optionally export ids

* feat: import ids when available

---------

Co-authored-by: Rene <[email protected]>
  • Loading branch information
keeama13 and 64knl authored Dec 15, 2023
1 parent f5489c9 commit 0848dee
Show file tree
Hide file tree
Showing 11 changed files with 378 additions and 145 deletions.
11 changes: 11 additions & 0 deletions config/siteboss.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,15 @@

'frontend_api_prefix' => env('SB_FRONTEND_API_PREFIX', 'api'),

/*
|--------------------------------------------------------------------------
| CMS importer
|--------------------------------------------------------------------------
|
| Do you want to retain the database id's for tables and table items.
|
*/

'export_retain_ids' => env('SB_EXPORT_RETAIN_IDS', false),

];
4 changes: 3 additions & 1 deletion routes/cms/editor.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

Route::get('', [CmsEditorController::class, 'index']);

// import/export
Route::post('table-export', [CmsEditorImportExportController::class, 'exportAllTables']);

// table
Route::prefix('table')->group(function () {
Route::get('', [CmsEditorTableController::class, 'index']);
Expand All @@ -20,7 +23,6 @@
Route::prefix('{table}')->group(function () {
Route::get('', [CmsEditorTableController::class, 'readOne']);
Route::post('', [CmsEditorTableController::class, 'update']);
Route::post('import', [CmsEditorImportExportController::class, 'importTable']);

Route::put('move', [CmsEditorTableController::class, 'updatePosition']);
Route::post('add-field', [CmsEditorTableController::class, 'addField']);
Expand Down
9 changes: 9 additions & 0 deletions routes/console.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use NotFound\Framework\Helpers\CmsImportHelper;
use NotFound\Framework\Services\Indexer\IndexBuilderService;

Artisan::command('siteboss:index-site {--debug : Whether debug messages should be displayed} {--clean : Truncate search table}', function ($debug, $clean) {
Expand All @@ -11,3 +12,11 @@

return Command::SUCCESS;
})->purpose('Index site for local search');

Artisan::command('siteboss:cms-import {--debug : Whether debug messages should be displayed} {--dry : Dry Run}', function ($debug, $dry) {

$indexer = new CmsImportHelper($debug, $dry);
$indexer->import();

return Command::SUCCESS;
})->purpose('Import CMS changes to the database');
172 changes: 172 additions & 0 deletions src/Helpers/CmsImportHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
<?php

namespace NotFound\Framework\Helpers;

use File;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use NotFound\Framework\Models\Table;
use NotFound\Framework\Models\TableItem;

class CmsImportHelper
{
public function __construct(
private bool $debug = false,
private bool $dryRun = false
) {
}

public function import(): void
{
$this->debug('Starting CMS Import');
if ($this->dryRun) {
$this->debug('Dry Run: true', force: true);
}

$this->importTables('cms_users');
$this->debug('DONE');
}

public function hasChanges(Table $table): bool
{
$path = resource_path('siteboss/tables/'.$table->table.'.json');
if (! File::exists($path)) {
return false;
}
$data = $table->exportToObject();
$fileData = json_decode(file_get_contents($path));

return $data != $fileData;
}

private function importTables(string $tableName): object
{
$path = resource_path('siteboss/tables');
if (! File::exists($path)) {
$this->debug('No export files found in '.$path);

return (object) [];
}

// Create temp table to import into
$this->createImportTables();

$fileSources = [];
$files = File::files($path);
foreach ($files as $file) {
$index = str_replace('.json', '', $file->getFilename());
$fileSources[$index] = json_decode(file_get_contents($file->getPathname()));
}
$this->debug('== Read '.count($fileSources).' files from '.$path);

$order = 1;
foreach ($fileSources as $tableName => $fileSource) {
if ($this->dryRun) {
$this->debug('CREATE TABLE '.$tableName);
} else {

$table = new Table();
if (isset($fileSource->id)) {
$table->id = $fileSource->id;
}
$table->name = $fileSource->name;
$table->url = $fileSource->url;
$table->rights = $fileSource->rights;

$table->comments = $fileSource->comments;
$table->allow_create = $fileSource->allow_create;
$table->allow_delete = $fileSource->allow_delete;
$table->allow_sort = $fileSource->allow_sort;
$table->properties = $fileSource->properties;
$table->order = $order++;
$table->enabled = $fileSource->enabled;
$table->table = $tableName;
$table->save();

$tableId = $table->id;
}
$itemOrder = 1;
foreach ($fileSource->items as $item) {
if ($this->dryRun) {
$this->debug(' [x] '.$item->name);

continue;
}
$tableItem = new TableItem();
if (isset($item->id)) {
$tableItem->id = $item->id;
}
$tableItem->table_id = $tableId;
$tableItem->name = $item->name;
$tableItem->type = $item->type;
$tableItem->internal = $item->internal;
$tableItem->description = $item->description;
$tableItem->properties = $item->properties;
$tableItem->server_properties = $item->server_properties;
$tableItem->order = $itemOrder++;
$tableItem->enabled = $item->enabled;
$tableItem->rights = $item->rights;

$tableItem->save();

}

}

return (object) [];
}

private function debug($text, $force = false)
{
if ($this->debug || $force) {
printf("\n - %s", $text);
}
}

private function createImportTables(): void
{
if ($this->dryRun) {
$this->debug('Dry run: skipping table creation');

return;
}
$this->debug('Creating import tables');
Schema::dropIfExists('cms_table_backup');
Schema::rename('cms_table', 'cms_table_backup');
Schema::create('cms_table', function (Blueprint $table) {
$table->id();
$table->string('name', 128)->nullable();
$table->string('table', 128)->nullable();
$table->string('url', 128)->nullable();
$table->string('rights', 128)->nullable();
$table->text('comments')->nullable();
$table->boolean('allow_create')->default(true);
$table->boolean('allow_delete')->default(true);
$table->boolean('allow_sort')->default(true);
$table->json('properties')->nullable();
$table->integer('order')->nullable();
$table->tinyInteger('enabled')->default(1);
$table->softDeletes();
$table->timestamps();
});

Schema::dropIfExists('cms_tableitem_backup');
Schema::rename('cms_tableitem', 'cms_tableitem_backup');
Schema::create('cms_tableitem', function (Blueprint $table) {
$table->id();
$table->string('rights', 128)->default('');
$table->foreignIdFor(Table::class, 'table_id')->nullable();
$table->string('type', 64)->nullable();
$table->string('internal', 64)->nullable();
$table->string('name', 128)->nullable();
$table->text('description')->nullable();
$table->json('properties')->nullable();
$table->json('server_properties')->nullable();
$table->integer('order')->nullable(); //TODO: FIX
$table->tinyInteger('enabled')->nullable()->default(1);
$table->softDeletes();
$table->timestamps();
});

}
}
93 changes: 10 additions & 83 deletions src/Http/Controllers/CmsEditor/CmsEditorImportExportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,99 +2,26 @@

namespace NotFound\Framework\Http\Controllers\CmsEditor;

use NotFound\Framework\Http\Requests\FormDataRequest;
use NotFound\Framework\Models\AssetModel;
use NotFound\Framework\Http\Controllers\Controller;
use NotFound\Framework\Models\Table;
use NotFound\Framework\Models\Template;
use NotFound\Layout\Elements\LayoutButton;
use NotFound\Layout\Elements\LayoutForm;
use NotFound\Layout\Elements\LayoutText;
use NotFound\Layout\Elements\LayoutWidget;
use NotFound\Layout\Inputs\LayoutInputTextArea;
use NotFound\Layout\LayoutResponse;
use NotFound\Layout\Responses\Toast;

class CmsEditorImportExportController extends \NotFound\Framework\Http\Controllers\Controller
class CmsEditorImportExportController extends Controller
{
public static function getImport($table_id, $type)
{
$importWidget = new LayoutWidget('Import', 1);
$importForm = new LayoutForm('/app/editor/'.$type.'/'.$table_id.'/import');
$importForm->addInput(new LayoutInputTextArea('import'));
$importForm->addButton(new LayoutButton('Import'));
$importWidget->addForm($importForm);

return $importWidget;
}

public static function getExport($tables)
{
$exportData = [];

foreach ($tables as $tableItem) {
$exportData[] = (object) [
'rights' => $tableItem->rights,
'internal' => $tableItem->internal,
'type' => $tableItem->type,
'name' => $tableItem->name,
'description' => $tableItem->description,
'properties' => $tableItem->properties,
'enabled' => $tableItem->enabled,
'global' => $tableItem->global ?? 0,
'server_properties' => $tableItem->server_properties,
];
}

$exportWidget = new LayoutWidget('Export', 1);
$exportForm = new LayoutForm('');
$exportForm->addText(new LayoutText(json_encode($exportData)));
$exportWidget->addForm($exportForm);

return $exportWidget;
}

public function importTemplate(FormDataRequest $request, Template $table)
{
return $this->import($request, $table);
}

public function importTable(FormDataRequest $request, Table $table)
{
return $this->import($request, $table);
}

private function import(FormDataRequest $request, AssetModel $table)
public function exportAllTables()
{
$response = new LayoutResponse();
$data = json_decode($request->import);
if (! $data || $data == '') {
$response->addAction(new Toast('Foutieve JSON data', 'error'));
$tables = Table::all();

return $response->build();
foreach ($tables as $table) {
// TODO: catch exceptions
$table->exportToFile();
}
$max = $table->items()->max('order');

try {
foreach ($data as $tableItem) {
$table->items()->create(
[
'rights' => $tableItem->rights,
'internal' => $tableItem->internal,
'type' => $tableItem->type,
'name' => $tableItem->name,
'description' => $tableItem->description,
'properties' => $tableItem->properties,
'order' => ++$max,
'global' => $tableItem->global ?? 0,
'enabled' => $tableItem->enabled,
'server_properties' => $tableItem->server_properties,
]
);
}
$response->addAction(new Toast('Succesvol geimporteerd (Refresh om de wijzigingen te zien)'));
} catch (\Exception $e) {
$response->addAction(new Toast('Fout bij uploaden. '.$e->getMessage(), 'error'));
}
$response->addAction(
new Toast($tables->count().' tables exported successfully')
);

return $response->build();
}
Expand Down
Loading

0 comments on commit 0848dee

Please sign in to comment.