mirror of
https://git.imnavajas.es/jjimenez/safekat.git
synced 2025-07-25 22:52:08 +00:00
wiki
This commit is contained in:
@ -5,4 +5,13 @@ use CodeIgniter\Router\RouteCollection;
|
||||
|
||||
$routes->group('wiki', ['namespace' => 'App\Controllers\Wiki'], function ($routes) {
|
||||
$routes->get('','WikiController::index',["as" => "wikiIndex"]);
|
||||
$routes->get('view/(:segment)','WikiController::show_page/$1',["as" => "showWikiPage"]);
|
||||
$routes->get('section/(:num)','WikiController::get_section/$1',["as" => "getWikiSection"]);
|
||||
$routes->post('section','WikiController::store_section/$1',["as" => "storeWikiSection"]);
|
||||
$routes->post('save/(:num)','WikiController::store_save_page/$1',["as" => "storeWikiSavePage"]);
|
||||
$routes->post('publish/(:num)','WikiController::store_publish_page/$1',["as" => "storeWikiPublishPage"]);
|
||||
$routes->post('file/upload/(:num)','WikiController::wiki_file_upload/$1',["as" => "storeWikiFileUpload"]);
|
||||
$routes->get('file/(:num)','WikiController::get_wiki_file/$1',["as" => "getWikiFile"]);
|
||||
|
||||
|
||||
});
|
||||
@ -3,12 +3,111 @@
|
||||
namespace App\Controllers\Wiki;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\Wiki\WikiContentModel;
|
||||
use App\Models\Wiki\WikiFileModel;
|
||||
use App\Models\Wiki\WikiPageModel;
|
||||
use App\Models\Wiki\WikiSectionModel;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class WikiController extends BaseController
|
||||
{
|
||||
protected WikiSectionModel $wikiSectionModel;
|
||||
protected WikiContentModel $wikiContentModel;
|
||||
protected WikiPageModel $wikiPageModel;
|
||||
protected WikiFileModel $wikiFileModel;
|
||||
|
||||
protected string $locale;
|
||||
protected array $viewData;
|
||||
|
||||
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
|
||||
{
|
||||
$this->wikiSectionModel = model(WikiSectionModel::class);
|
||||
$this->wikiPageModel = model(WikiPageModel::class);
|
||||
$this->wikiContentModel = model(WikiContentModel::class);
|
||||
$this->wikiFileModel = model(WikiFileModel::class);
|
||||
|
||||
$sections = $this->wikiSectionModel->sections();
|
||||
$this->locale = session()->get('lang');
|
||||
|
||||
$this->viewData['wiki_sections'] = $sections;
|
||||
parent::initController($request, $response, $logger);
|
||||
}
|
||||
public function index()
|
||||
{
|
||||
return view('themes/vuexy/wiki/pages/home');
|
||||
return view('themes/vuexy/wiki/pages/render', $this->viewData);
|
||||
}
|
||||
public function show_page(string $slug)
|
||||
{
|
||||
$section = $this->wikiSectionModel->where('slug', $slug)->first();
|
||||
$this->viewData['slug'] = $slug;
|
||||
$this->viewData['section'] = $section->withAll($this->locale);
|
||||
|
||||
return view('themes/vuexy/wiki/pages/render', $this->viewData);
|
||||
}
|
||||
public function get_section(int $section_id)
|
||||
{
|
||||
$section = $this->wikiSectionModel->find($section_id)->withAll($this->locale);
|
||||
return $this->response->setJSON(["data" => $section, "message" => lang("App.global_alert_fetch_success")]);
|
||||
}
|
||||
public function store_save_page(int $section_id)
|
||||
{
|
||||
$bodyData = $this->request->getPost();
|
||||
$wikiSectionPage = $this->wikiSectionModel->find($section_id)->page();
|
||||
if ($wikiSectionPage) {
|
||||
$wikiPageId = $wikiSectionPage->id;
|
||||
} else {
|
||||
$wikiPageId = $this->wikiPageModel->insert(['section_id' => $section_id]);
|
||||
}
|
||||
$content = $this->wikiContentModel->where('locale', $this->locale)->where('page_id', $wikiPageId)->countAllResults();
|
||||
if ($content > 0) {
|
||||
$this->wikiContentModel->where('locale', $this->locale)->where('page_id', $wikiPageId)->delete();
|
||||
}
|
||||
|
||||
$this->wikiContentModel->insert([
|
||||
"locale" => $this->locale,
|
||||
"page_id" => $wikiPageId,
|
||||
"editor_data" => json_encode($bodyData)
|
||||
]);
|
||||
return $this->response->setJSON(["data" => [], "message" => lang("App.global_alert_save_success")]);
|
||||
}
|
||||
public function wiki_file_upload(int $section_id)
|
||||
{
|
||||
try {
|
||||
$file = $this->request->getFile('image');
|
||||
$section = $this->wikiSectionModel->find($section_id);
|
||||
$content = $section->content();
|
||||
$r = null;
|
||||
$fullpath = null;
|
||||
if ($file->isValid() && !$file->hasMoved()) {
|
||||
$fullpath = $file->store('wiki_images/' . $section->slug);
|
||||
$r = $this->wikiFileModel->insert(["content_id" => $content->id, "path" => $fullpath]);
|
||||
return $this->response->setJSON(["success" => 1, "file" => [
|
||||
"url" => '/wiki/file/'.$r
|
||||
]]);
|
||||
}else{
|
||||
return $this->response->setJSON(["success" => 0, "file" => [
|
||||
"url" => null
|
||||
]]);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
|
||||
return $this->response->setJSON(["success" => 0, "error" => $th->getMessage()])->setStatusCode($th->getCode());
|
||||
}
|
||||
}
|
||||
public function get_wiki_file(int $wiki_file_id)
|
||||
{
|
||||
$wikiFile = $this->wikiFileModel->find($wiki_file_id);
|
||||
if ($wikiFile->path) {
|
||||
$filePath = WRITEPATH . 'uploads/' . $wikiFile->path;
|
||||
$mimeType = mime_content_type($filePath);
|
||||
return $this->response
|
||||
->setHeader('Content-Type', $mimeType)
|
||||
->setHeader('Content-Length', filesize($filePath))
|
||||
->setBody(file_get_contents($filePath));
|
||||
} else {
|
||||
return $this->response->setJSON(["message" => "Portada error", "error" => "No hay portada"])->setStatusCode(400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
use CodeIgniter\Database\RawSql;
|
||||
|
||||
class WikiSectionsMigration extends Migration
|
||||
{
|
||||
protected array $COLUMNS = [
|
||||
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
],
|
||||
'slug' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
],
|
||||
'role' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'default' => 'admin'
|
||||
],
|
||||
'parent_section_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField($this->COLUMNS);
|
||||
$currenttime = new RawSql('CURRENT_TIMESTAMP');
|
||||
$this->forge->addField([
|
||||
'created_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'default' => $currenttime,
|
||||
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'null' => true,
|
||||
|
||||
],
|
||||
'deleted_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'null' => true,
|
||||
|
||||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey('id');
|
||||
$this->forge->addForeignKey('parent_section_id','wiki_sections','id');
|
||||
$this->forge->createTable("wiki_sections");
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable("wiki_sections");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
use CodeIgniter\Database\RawSql;
|
||||
|
||||
class WikiPagesMigration extends Migration
|
||||
{
|
||||
protected array $COLUMNS = [
|
||||
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'section_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
],
|
||||
];
|
||||
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField($this->COLUMNS);
|
||||
$currenttime = new RawSql('CURRENT_TIMESTAMP');
|
||||
$this->forge->addField([
|
||||
'created_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'default' => $currenttime,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'null' => true,
|
||||
],
|
||||
'deleted_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'null' => true,
|
||||
|
||||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey('id');
|
||||
$this->forge->addForeignKey('section_id','wiki_sections','id');
|
||||
$this->forge->createTable("wiki_pages");
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable("wiki_pages");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
use CodeIgniter\Database\RawSql;
|
||||
|
||||
class WikiContentsMigration extends Migration
|
||||
{
|
||||
protected array $COLUMNS = [
|
||||
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'locale' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'default' => 'es',
|
||||
],
|
||||
'page_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
],
|
||||
'editor_data' => [
|
||||
'type' => 'LONGTEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'published_data' => [
|
||||
'type' => 'LONGTEXT',
|
||||
'null' => true,
|
||||
],
|
||||
];
|
||||
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField($this->COLUMNS);
|
||||
$currenttime = new RawSql('CURRENT_TIMESTAMP');
|
||||
$this->forge->addField([
|
||||
'created_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'default' => $currenttime,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'null' => true,
|
||||
],
|
||||
'deleted_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'null' => true,
|
||||
|
||||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey('id');
|
||||
$this->forge->addForeignKey('page_id','wiki_pages','id');
|
||||
$this->forge->createTable("wiki_contents");
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable("wiki_contents");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
use CodeIgniter\Database\RawSql;
|
||||
|
||||
class WikiFilesMigration extends Migration
|
||||
{
|
||||
protected array $COLUMNS = [
|
||||
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'content_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
],
|
||||
'path' => [
|
||||
'type' => 'LONGTEXT',
|
||||
'null' => true,
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField($this->COLUMNS);
|
||||
$currenttime = new RawSql('CURRENT_TIMESTAMP');
|
||||
$this->forge->addField([
|
||||
'created_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'default' => $currenttime,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'null' => true,
|
||||
],
|
||||
'deleted_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'null' => true,
|
||||
|
||||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey('id');
|
||||
$this->forge->addForeignKey('content_id','wiki_contents','id');
|
||||
$this->forge->createTable("wiki_files");
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable("wiki_files");
|
||||
}
|
||||
}
|
||||
21
ci4/app/Entities/Wiki/WikiContentEntity.php
Normal file
21
ci4/app/Entities/Wiki/WikiContentEntity.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace App\Entities\Wiki;
|
||||
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
class WikiContentEntity extends Entity
|
||||
{
|
||||
protected $attributes = [
|
||||
"locale" => null,
|
||||
"page_id" => null,
|
||||
"editor_data" => null,
|
||||
"published_data" => null,
|
||||
];
|
||||
protected $casts = [
|
||||
"locale" => "string",
|
||||
"page_id" => "int",
|
||||
"editor_data" => "string",
|
||||
"published_data" => "string",
|
||||
];
|
||||
|
||||
}
|
||||
17
ci4/app/Entities/Wiki/WikiFileEntity.php
Normal file
17
ci4/app/Entities/Wiki/WikiFileEntity.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
namespace App\Entities\Wiki;
|
||||
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
class WikiFileEntity extends Entity
|
||||
{
|
||||
protected $attributes = [
|
||||
"content_id" => null,
|
||||
"path" => null,
|
||||
];
|
||||
protected $casts = [
|
||||
"content_id" => "int",
|
||||
"path" => "string",
|
||||
];
|
||||
|
||||
}
|
||||
15
ci4/app/Entities/Wiki/WikiPageEntity.php
Normal file
15
ci4/app/Entities/Wiki/WikiPageEntity.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
namespace App\Entities\Wiki;
|
||||
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
class WikiPageEntity extends Entity
|
||||
{
|
||||
protected $attributes = [
|
||||
"section_id" => null,
|
||||
];
|
||||
protected $casts = [
|
||||
"section_id" => "int",
|
||||
];
|
||||
|
||||
}
|
||||
59
ci4/app/Entities/Wiki/WikiSectionEntity.php
Normal file
59
ci4/app/Entities/Wiki/WikiSectionEntity.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
namespace App\Entities\Wiki;
|
||||
|
||||
use App\Models\Wiki\WikiContentModel;
|
||||
use App\Models\Wiki\WikiPageModel;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
class WikiSectionEntity extends Entity
|
||||
{
|
||||
protected $attributes = [
|
||||
"name" => null,
|
||||
"slug" => null,
|
||||
"role" => null,
|
||||
"parent_id" => null
|
||||
];
|
||||
protected $casts = [
|
||||
"name" => "string",
|
||||
"slug" => "string",
|
||||
"role" => "string",
|
||||
"parent_id" => "int"
|
||||
];
|
||||
|
||||
public function withPage(): self
|
||||
{
|
||||
$this->attributes['pages'] = $this->page();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withContents(string $locale = "es"): self
|
||||
{
|
||||
$m = model(WikiContentModel::class);
|
||||
$this->attributes['contents'] = $this->content($locale);
|
||||
return $this;
|
||||
}
|
||||
public function withAll(string $locale = "es") : self
|
||||
{
|
||||
$this->withPage();
|
||||
$this->withContents($locale);
|
||||
return $this;
|
||||
|
||||
}
|
||||
public function page(): ?WikiPageEntity
|
||||
{
|
||||
$m = model(WikiPageModel::class);
|
||||
return $m->where('section_id',$this->attributes['id'])->first();
|
||||
}
|
||||
public function content(string $locale = "es"): ?WikiContentEntity
|
||||
{
|
||||
$page = $this->page();
|
||||
$content = null;
|
||||
$m = model(WikiContentModel::class);
|
||||
if($page){
|
||||
$content = $m->where('page_id',$page->id)
|
||||
->where('locale',$locale)
|
||||
->first();
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
@ -19,6 +19,7 @@ return [
|
||||
"global_come_back" => "Volver",
|
||||
"global_save" => "Guardar",
|
||||
"global_alert_save_success" => "¡Guardado exitosamente!",
|
||||
"global_alert_fetch_success" => "Obtenido exitosamente!",
|
||||
"global_alert_save_error" => "¡Error al guardar!",
|
||||
"global_activate" => "Activar",
|
||||
"global_disable" => "Desactivar",
|
||||
|
||||
53
ci4/app/Models/Wiki/WikiContentModel.php
Normal file
53
ci4/app/Models/Wiki/WikiContentModel.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Wiki;
|
||||
|
||||
use App\Entities\Wiki\WikiContentEntity;
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class WikiContentModel extends Model
|
||||
{
|
||||
protected $table = 'wiki_contents';
|
||||
protected $primaryKey = 'id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = WikiContentEntity::class;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $protectFields = true;
|
||||
protected $allowedFields = [
|
||||
"locale",
|
||||
"page_id",
|
||||
"editor_data",
|
||||
"published_data"
|
||||
|
||||
];
|
||||
|
||||
protected bool $allowEmptyInserts = false;
|
||||
protected bool $updateOnlyChanged = true;
|
||||
|
||||
protected array $casts = [];
|
||||
protected array $castHandlers = [];
|
||||
|
||||
// Dates
|
||||
protected $useTimestamps = true;
|
||||
protected $dateFormat = 'datetime';
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
protected $deletedField = 'deleted_at';
|
||||
|
||||
// Validation
|
||||
protected $validationRules = [];
|
||||
protected $validationMessages = [];
|
||||
protected $skipValidation = false;
|
||||
protected $cleanValidationRules = true;
|
||||
|
||||
// Callbacks
|
||||
protected $allowCallbacks = true;
|
||||
protected $beforeInsert = [];
|
||||
protected $afterInsert = [];
|
||||
protected $beforeUpdate = [];
|
||||
protected $afterUpdate = [];
|
||||
protected $beforeFind = [];
|
||||
protected $afterFind = [];
|
||||
protected $beforeDelete = [];
|
||||
protected $afterDelete = [];
|
||||
}
|
||||
51
ci4/app/Models/Wiki/WikiFileModel.php
Normal file
51
ci4/app/Models/Wiki/WikiFileModel.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Wiki;
|
||||
|
||||
use App\Entities\Wiki\WikiFileEntity;
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class WikiFileModel extends Model
|
||||
{
|
||||
protected $table = 'wiki_files';
|
||||
protected $primaryKey = 'id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = WikiFileEntity::class;
|
||||
protected $useSoftDeletes = false;
|
||||
protected $protectFields = true;
|
||||
protected $allowedFields = [
|
||||
"content_id",
|
||||
"path"
|
||||
|
||||
];
|
||||
|
||||
protected bool $allowEmptyInserts = false;
|
||||
protected bool $updateOnlyChanged = true;
|
||||
|
||||
protected array $casts = [];
|
||||
protected array $castHandlers = [];
|
||||
|
||||
// Dates
|
||||
protected $useTimestamps = true;
|
||||
protected $dateFormat = 'datetime';
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
protected $deletedField = 'deleted_at';
|
||||
|
||||
// Validation
|
||||
protected $validationRules = [];
|
||||
protected $validationMessages = [];
|
||||
protected $skipValidation = false;
|
||||
protected $cleanValidationRules = true;
|
||||
|
||||
// Callbacks
|
||||
protected $allowCallbacks = true;
|
||||
protected $beforeInsert = [];
|
||||
protected $afterInsert = [];
|
||||
protected $beforeUpdate = [];
|
||||
protected $afterUpdate = [];
|
||||
protected $beforeFind = [];
|
||||
protected $afterFind = [];
|
||||
protected $beforeDelete = [];
|
||||
protected $afterDelete = [];
|
||||
}
|
||||
49
ci4/app/Models/Wiki/WikiPageModel.php
Normal file
49
ci4/app/Models/Wiki/WikiPageModel.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Wiki;
|
||||
|
||||
use App\Entities\Wiki\WikiPageEntity;
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class WikiPageModel extends Model
|
||||
{
|
||||
protected $table = 'wiki_pages';
|
||||
protected $primaryKey = 'id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = WikiPageEntity::class;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $protectFields = true;
|
||||
protected $allowedFields = [
|
||||
"section_id",
|
||||
];
|
||||
|
||||
protected bool $allowEmptyInserts = false;
|
||||
protected bool $updateOnlyChanged = true;
|
||||
|
||||
protected array $casts = [];
|
||||
protected array $castHandlers = [];
|
||||
|
||||
// Dates
|
||||
protected $useTimestamps = true;
|
||||
protected $dateFormat = 'datetime';
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
protected $deletedField = 'deleted_at';
|
||||
|
||||
// Validation
|
||||
protected $validationRules = [];
|
||||
protected $validationMessages = [];
|
||||
protected $skipValidation = false;
|
||||
protected $cleanValidationRules = true;
|
||||
|
||||
// Callbacks
|
||||
protected $allowCallbacks = true;
|
||||
protected $beforeInsert = [];
|
||||
protected $afterInsert = [];
|
||||
protected $beforeUpdate = [];
|
||||
protected $afterUpdate = [];
|
||||
protected $beforeFind = [];
|
||||
protected $afterFind = [];
|
||||
protected $beforeDelete = [];
|
||||
protected $afterDelete = [];
|
||||
}
|
||||
62
ci4/app/Models/Wiki/WikiSectionModel.php
Normal file
62
ci4/app/Models/Wiki/WikiSectionModel.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Wiki;
|
||||
|
||||
use App\Entities\Wiki\WikiSectionEntity;
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class WikiSectionModel extends Model
|
||||
{
|
||||
protected $table = 'wiki_sections';
|
||||
protected $primaryKey = 'id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = WikiSectionEntity::class;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $protectFields = true;
|
||||
protected $allowedFields = [
|
||||
"name",
|
||||
"slug",
|
||||
"role",
|
||||
"parent_id"
|
||||
];
|
||||
|
||||
protected bool $allowEmptyInserts = false;
|
||||
protected bool $updateOnlyChanged = true;
|
||||
|
||||
protected array $casts = [];
|
||||
protected array $castHandlers = [];
|
||||
|
||||
// Dates
|
||||
protected $useTimestamps = true;
|
||||
protected $dateFormat = 'datetime';
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
protected $deletedField = 'deleted_at';
|
||||
|
||||
// Validation
|
||||
protected $validationRules = [];
|
||||
protected $validationMessages = [];
|
||||
protected $skipValidation = false;
|
||||
protected $cleanValidationRules = true;
|
||||
|
||||
// Callbacks
|
||||
protected $allowCallbacks = true;
|
||||
protected $beforeInsert = [];
|
||||
protected $afterInsert = [];
|
||||
protected $beforeUpdate = [];
|
||||
protected $afterUpdate = [];
|
||||
protected $beforeFind = [];
|
||||
protected $afterFind = [];
|
||||
protected $beforeDelete = [];
|
||||
protected $afterDelete = [];
|
||||
|
||||
/**
|
||||
* Get wiki sections
|
||||
*
|
||||
* @return array<WikiSectionEntity>
|
||||
*/
|
||||
public function sections() : array
|
||||
{
|
||||
return $this->where('role','admin')->findAll();
|
||||
}
|
||||
}
|
||||
@ -90,7 +90,38 @@ $picture = "/assets/img/default-user.png";
|
||||
<!-- Layout wrapper -->
|
||||
<div class="layout-wrapper layout-content-navbar">
|
||||
<div class="layout-container">
|
||||
<?php include "sidebar.php" ?>
|
||||
<aside id="layout-menu" class="layout-menu menu-vertical menu bg-menu-theme">
|
||||
<div class="app-brand">
|
||||
<a href="<?= site_url('home') ?>" class="app-brand-link">
|
||||
<span class="app-brand-logo">
|
||||
<img src="<?= site_url('themes/vuexy/img/safekat/logos/sk-logo.png') ?>" width="150px">
|
||||
</span>
|
||||
</a>
|
||||
<a href="javascript:void(0);" class="layout-menu-toggle menu-link text-large ms-auto">
|
||||
<i class="ti menu-toggle-icon d-none d-xl-block ti-sm align-middle"></i>
|
||||
<i class="ti ti-x d-block d-xl-none ti-sm align-middle"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="menu-inner-shadow"></div>
|
||||
|
||||
<ul class="menu-inner py-1">
|
||||
|
||||
<li class="menu-item">
|
||||
<!-- Iterate throught sections -->
|
||||
<?php foreach ($wiki_sections as $key => $value) : ?>
|
||||
<!-- Check if user can view the section link -->
|
||||
<?php if (auth()->user()->inGroup($value->role)): ?>
|
||||
<a href="<?= site_url("wiki/render/".$value->slug) ?>" class="menu-link">
|
||||
<i class="menu-icon tf-icons ti ti-book"></i>
|
||||
<?= $value->name ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</aside>
|
||||
|
||||
<!-- Layout container -->
|
||||
<div class="layout-page">
|
||||
@ -236,7 +267,7 @@ $picture = "/assets/img/default-user.png";
|
||||
<script src="<?= site_url('themes/vuexy/vendor/libs/perfect-scrollbar/perfect-scrollbar.js') ?>"></script>
|
||||
<script src="<?= site_url('themes/vuexy/vendor/libs/hammer/hammer.js') ?>"></script>
|
||||
<script src="<?= site_url('themes/vuexy/vendor/js/menu.js') ?>"></script>
|
||||
|
||||
|
||||
<script type="module" src="<?= site_url('assets/js/safekat/pages/layout.js') ?>"></script>
|
||||
<!-- Helpers -->
|
||||
<script src="<?= site_url('themes/vuexy/vendor/js/helpers.js') ?>"></script>
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<?= $this->include('themes/_commonPartialsBs/select2bs5') ?>
|
||||
<?= $this->include('themes/_commonPartialsBs/datatables') ?>
|
||||
<?= $this->include('themes/_commonPartialsBs/_confirm2delete') ?>
|
||||
<?= $this->include("themes/_commonPartialsBs/sweetalert") ?>
|
||||
<?= $this->extend('themes/vuexy/wiki/layout') ?>
|
||||
|
||||
<?= $this->section('content'); ?>
|
||||
@ -13,7 +14,12 @@
|
||||
</div><!--//.card-header -->
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
|
||||
<form action="POST" id="form-wiki">
|
||||
<input type="hidden" name="slug" id="section-slug">
|
||||
<input type="hidden" name="wiki_page_id" id="wiki-section-id" value="<?=$section->id?>">
|
||||
<input type="hidden" name="wiki_page_id" id="wiki-page-id">
|
||||
<input type="hidden" name="wiki_page_id" id="wiki-content-id">
|
||||
</form>
|
||||
<?php if (auth()->user()->inGroup('admin')): ?>
|
||||
<div class="col-md-10">
|
||||
<div id="editorjs"></div>
|
||||
@ -27,6 +33,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
|
||||
<div class="col-md-12">
|
||||
<div id="editorjs"></div>
|
||||
</div>
|
||||
@ -40,7 +47,15 @@
|
||||
</div><!--//.card -->
|
||||
</div><!--//.col -->
|
||||
</div><!--//.row -->
|
||||
<?= $this->section("additionalExternalJs") ?>
|
||||
<script type="module" src="<?= site_url('assets/js/safekat/pages/wiki/home.js') ?>"></script>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('css') ?>
|
||||
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/sweetalert2/sweetalert2.css') ?>" />
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section("additionalExternalJs") ?>
|
||||
|
||||
<script src="<?= site_url('themes/vuexy/vendor/libs/sweetalert2/sweetalert2.js') ?>"></script>
|
||||
<script type="module" src="<?= site_url('assets/js/safekat/pages/wiki/home.js') ?>"></script>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@ -17,17 +17,12 @@
|
||||
<ul class="menu-inner py-1">
|
||||
|
||||
<li class="menu-item">
|
||||
<a href="javascript:void(0);" class="menu-link menu-toggle">
|
||||
<?php foreach ($wiki_sections as $key => $value) :?>
|
||||
<a href="<?= site_url("wiki/presupuesto")?>" class="menu-link menu-toggle">
|
||||
<i class="menu-icon tf-icons ti ti-book"></i>
|
||||
<?= lang("App.menu_presupuestos") ?>
|
||||
</a>
|
||||
<ul class="menu-sub">
|
||||
<li class="menu-item">
|
||||
<a href="<?= site_url("wiki/presupuesto") ?>" class="menu-link">
|
||||
<?= lang("App.menu_presupuestos") ?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<?php endforeach;?>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
|
||||
|
||||
|
||||
export const alertConfirmationDelete = (title, type = "primary") => {
|
||||
return Swal.fire({
|
||||
title: '¿Está seguro?',
|
||||
@ -63,4 +62,54 @@ export const toastPresupuestoSummary = (value, target = 'body') => {
|
||||
timerProgressBar: false,
|
||||
stopKeydownPropagation: false,
|
||||
})
|
||||
}
|
||||
export const alertSuccess = (value, target = 'body') => {
|
||||
return Swal.mixin({
|
||||
toast: true,
|
||||
position: 'bottom-end',
|
||||
html: `
|
||||
<span class="badge badge-label-primary fs-big">${value}</span>`,
|
||||
customClass: {
|
||||
popup: 'bg-success text-white',
|
||||
},
|
||||
icon : 'success',
|
||||
iconColor: 'white',
|
||||
target: target,
|
||||
showConfirmButton: false,
|
||||
timer: 2000,
|
||||
timerProgressBar: true,
|
||||
})
|
||||
}
|
||||
export const alertError = (value, target = 'body') => {
|
||||
return Swal.mixin({
|
||||
toast: true,
|
||||
position: 'bottom-end',
|
||||
html: `<span class="badge badge-label-error fs-big">${value}</span>`,
|
||||
customClass: {
|
||||
popup: 'bg-error text-white',
|
||||
},
|
||||
icon : 'error',
|
||||
iconColor: 'white',
|
||||
target: target,
|
||||
showConfirmButton: false,
|
||||
timer: 2000,
|
||||
timerProgressBar: true,
|
||||
})
|
||||
}
|
||||
export const alertWarning = (value, target = 'body') => {
|
||||
return Swal.mixin({
|
||||
toast: true,
|
||||
position: 'bottom-end',
|
||||
html: `
|
||||
<span class="badge badge-label-warning fs-big">${value}</span>`,
|
||||
customClass: {
|
||||
popup: 'bg-warning text-white',
|
||||
},
|
||||
icon : 'warning',
|
||||
iconColor: 'white',
|
||||
target: target,
|
||||
showConfirmButton: false,
|
||||
timer: 2000,
|
||||
timerProgressBar: true,
|
||||
})
|
||||
}
|
||||
170
httpdocs/assets/js/safekat/components/editorjs/WikiEditor.js
Normal file
170
httpdocs/assets/js/safekat/components/editorjs/WikiEditor.js
Normal file
@ -0,0 +1,170 @@
|
||||
|
||||
import { es } from './lang/es.js';
|
||||
import EditorJS from '../../../../../themes/vuexy/js/editorjs.mjs';
|
||||
import '../../../../../../themes/vuexy/js/editorjs/header.js';
|
||||
import '../../../../../themes/vuexy/js/editorjs/list.js';
|
||||
import '../../../../../../themes/vuexy/js/editorjs/alert.js';
|
||||
import '../../../../../../themes/vuexy/js/editorjs/drag-drop.js';
|
||||
import '../../../../../../themes/vuexy/js/editorjs/image.js';
|
||||
import '../../../../../themes/vuexy/js/editorjs/table.js';
|
||||
import '../../../../../themes/vuexy/js/editorjs/tune.js';
|
||||
|
||||
|
||||
import Ajax from '../ajax.js'
|
||||
import { alertError, alertSuccess, alertWarning } from '../alerts/sweetAlert.js';
|
||||
|
||||
class WikiEditor {
|
||||
constructor() {
|
||||
this.sectionId = $("#wiki-section-id").val();
|
||||
this.editor = new EditorJS({
|
||||
holder: 'editorjs',
|
||||
i18n: es,
|
||||
autofocus: true,
|
||||
placeholder: 'Empieza a diseñar aquí',
|
||||
readOnly: true,
|
||||
tunes: {
|
||||
alignment: {
|
||||
class: AlignmentBlockTune,
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
|
||||
header: {
|
||||
class: Header,
|
||||
tunes : ['alignment'],
|
||||
config: {
|
||||
placeholder: 'Introduce un encabezado ...',
|
||||
levels: [1, 2, 3, 4],
|
||||
defaultLevel: 3
|
||||
},
|
||||
},
|
||||
nestedchecklist: {
|
||||
class: editorjsNestedChecklist ,
|
||||
config : {
|
||||
maxLevel : 1,
|
||||
}
|
||||
},
|
||||
alert: {
|
||||
class: Alert,
|
||||
inlineToolbar: true,
|
||||
tunes : ['alignment'],
|
||||
shortcut: 'CMD+SHIFT+W',
|
||||
config: {
|
||||
alertTypes: ['primary', 'secondary', 'info', 'success', 'warning', 'danger', 'light', 'dark'],
|
||||
defaultType: 'primary',
|
||||
messagePlaceholder: 'Introduzca texto',
|
||||
},
|
||||
},
|
||||
image: {
|
||||
class: ImageTool,
|
||||
tunes : ['alignment'],
|
||||
config: {
|
||||
features: {
|
||||
border: false,
|
||||
caption: 'optional',
|
||||
stretch: false
|
||||
},
|
||||
endpoints: {
|
||||
byFile: `/wiki/file/upload/${this.sectionId}`, // Your backend file uploader endpoint
|
||||
byUrl: 'fetchUrl', // Your endpoint that provides uploading by Url
|
||||
}
|
||||
}
|
||||
},
|
||||
table: {
|
||||
class: Table,
|
||||
tunes : ['alignment'],
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
rows: 2,
|
||||
cols: 3,
|
||||
maxRows: 5,
|
||||
maxCols: 5,
|
||||
},
|
||||
},
|
||||
alignment: {
|
||||
class:AlignmentBlockTune,
|
||||
config:{
|
||||
default: "left",
|
||||
blocks: {
|
||||
header: 'left',
|
||||
list: 'left'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
})
|
||||
}
|
||||
async init() {
|
||||
try {
|
||||
await this.editor.isReady;
|
||||
new DragDrop(this.editor);
|
||||
/** Do anything you need after editor initialization */
|
||||
$('#save-editor').on('click', () => {
|
||||
this.editor.save().then(outputData => {
|
||||
console.log("Data saved", outputData)
|
||||
this.handleSaveContent(outputData)
|
||||
})
|
||||
})
|
||||
$('#preview-editor').on('click', () => {
|
||||
this.editor.readOnly.toggle()
|
||||
$('#edit-editor').removeClass('d-none')
|
||||
$('#preview-editor').addClass('d-none')
|
||||
})
|
||||
$('#edit-editor').on('click', () => {
|
||||
$('#edit-editor').addClass('d-none')
|
||||
$('#preview-editor').removeClass('d-none')
|
||||
this.editor.readOnly.toggle()
|
||||
})
|
||||
this.handleGetData();
|
||||
} catch (reason) {
|
||||
console.log(`Editor.js initialization failed because of ${reason}`)
|
||||
}
|
||||
}
|
||||
|
||||
handleGetData() {
|
||||
const ajax = new Ajax(`/wiki/section/${this.sectionId}`,
|
||||
null,
|
||||
null,
|
||||
this.handleGetDataSuccess.bind(this),
|
||||
this.handleGetDataError.bind(this))
|
||||
ajax.get()
|
||||
}
|
||||
handleGetDataSuccess(response) {
|
||||
if (response.data.contents) {
|
||||
alertSuccess(response.message).fire()
|
||||
this.renderContent(response.data.contents.editor_data)
|
||||
} else {
|
||||
alertWarning('No hay contenido').fire()
|
||||
|
||||
}
|
||||
}
|
||||
handleGetDataError(error) {
|
||||
console.log(error)
|
||||
}
|
||||
renderContent(content) {
|
||||
try {
|
||||
let parsedContent = JSON.parse(content)
|
||||
this.editor.render(parsedContent)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
handleSaveContent(data) {
|
||||
|
||||
const ajax = new Ajax(`/wiki/save/${this.sectionId}`,
|
||||
data,
|
||||
null,
|
||||
this.handleSaveContentSuccess.bind(this),
|
||||
this.handleSaveContentError.bind(this))
|
||||
ajax.post()
|
||||
}
|
||||
handleSaveContentSuccess(response) {
|
||||
this.handleGetData()
|
||||
// alertSuccess(response.message).fire()
|
||||
}
|
||||
handleSaveContentError(response) { }
|
||||
|
||||
}
|
||||
export default WikiEditor
|
||||
@ -1,76 +1,13 @@
|
||||
import { es } from './lang/es.js';
|
||||
import '../../../../../themes/vuexy/js/editorjs/list.js';
|
||||
import '../../../../../themes/vuexy/js/editorjs/header.js';
|
||||
import EditorJS from '../../../../../themes/vuexy/js/editorjs.mjs';
|
||||
import '../../../../../themes/vuexy/js/editorjs/alert.js';
|
||||
import '../../../../../themes/vuexy/js/editorjs/drag-drop.js';
|
||||
import '../../../../../themes/vuexy/js/editorjs/image.js';
|
||||
import { dataExample } from './demo.js';
|
||||
import WikiEditor from "../../components/editorjs/WikiEditor.js"
|
||||
|
||||
|
||||
const editor = new EditorJS({
|
||||
holder : 'editorjs',
|
||||
i18n : es,
|
||||
autofocus: true,
|
||||
placeholder : 'Empieza a diseñar aquí',
|
||||
readOnly : true,
|
||||
tools: {
|
||||
header: {
|
||||
class: Header,
|
||||
config: {
|
||||
placeholder: 'Introduce un encabezado ...',
|
||||
levels: [1,2, 3,4],
|
||||
defaultLevel: 3
|
||||
},
|
||||
},
|
||||
list: {
|
||||
class: EditorjsList,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
defaultStyle: 'unordered'
|
||||
},
|
||||
},
|
||||
alert: {
|
||||
class: Alert ,
|
||||
inlineToolbar: true,
|
||||
shortcut: 'CMD+SHIFT+W',
|
||||
config: {
|
||||
alertTypes: ['primary', 'secondary', 'info', 'success', 'warning', 'danger', 'light', 'dark'],
|
||||
defaultType: 'primary',
|
||||
messagePlaceholder: 'Introduzca texto',
|
||||
},
|
||||
},
|
||||
image: {
|
||||
class: ImageTool,
|
||||
config: {
|
||||
endpoints: {
|
||||
byFile: 'http://localhost:8008/uploadFile', // Your backend file uploader endpoint
|
||||
byUrl: 'http://localhost:8008/fetchUrl', // Your endpoint that provides uploading by Url
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
try {
|
||||
await editor.isReady;
|
||||
new DragDrop(editor);
|
||||
editor.render(dataExample)
|
||||
/** Do anything you need after editor initialization */
|
||||
$('#save-editor').on('click',() => {
|
||||
editor.save().then(outputData => {
|
||||
console.log("Data saved",outputData)
|
||||
})
|
||||
})
|
||||
$('#preview-editor').on('click',() => {
|
||||
editor.readOnly.toggle()
|
||||
$('#edit-editor').removeClass('d-none')
|
||||
$('#preview-editor').addClass('d-none')
|
||||
})
|
||||
$('#edit-editor').on('click',() => {
|
||||
$('#edit-editor').addClass('d-none')
|
||||
$('#preview-editor').removeClass('d-none')
|
||||
editor.readOnly.toggle()
|
||||
})
|
||||
} catch (reason) {
|
||||
console.log(`Editor.js initialization failed because of ${reason}`)
|
||||
}
|
||||
|
||||
$(async() => {
|
||||
|
||||
try {
|
||||
const editor = new WikiEditor()
|
||||
await editor.init()
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
})
|
||||
8
httpdocs/themes/vuexy/js/editorjs/columns.js
Normal file
8
httpdocs/themes/vuexy/js/editorjs/columns.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
8
httpdocs/themes/vuexy/js/editorjs/table.js
Normal file
8
httpdocs/themes/vuexy/js/editorjs/table.js
Normal file
File diff suppressed because one or more lines are too long
1
httpdocs/themes/vuexy/js/editorjs/tune.js
Normal file
1
httpdocs/themes/vuexy/js/editorjs/tune.js
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user