Articles: finish admin refactor, uploads hardening, and attachment sorting (0.262)
This commit is contained in:
@@ -4,6 +4,10 @@ namespace admin\Controllers;
|
||||
use Domain\Article\ArticleRepository;
|
||||
use Domain\Languages\LanguagesRepository;
|
||||
use Domain\Layouts\LayoutsRepository;
|
||||
use admin\ViewModels\Forms\FormAction;
|
||||
use admin\ViewModels\Forms\FormEditViewModel;
|
||||
use admin\ViewModels\Forms\FormField;
|
||||
use admin\ViewModels\Forms\FormTab;
|
||||
|
||||
class ArticlesController
|
||||
{
|
||||
@@ -61,12 +65,21 @@ class ArticlesController
|
||||
$listRequest['perPage']
|
||||
);
|
||||
|
||||
$articleIds = [];
|
||||
foreach ($result['items'] as $item) {
|
||||
$id = (int)($item['id'] ?? 0);
|
||||
if ($id > 0) {
|
||||
$articleIds[] = $id;
|
||||
}
|
||||
}
|
||||
$pagesSummary = $this->repository->pagesSummaryForArticles($articleIds);
|
||||
|
||||
$rows = [];
|
||||
$lp = ($listRequest['page'] - 1) * $listRequest['perPage'] + 1;
|
||||
foreach ($result['items'] as $item) {
|
||||
$id = (int)$item['id'];
|
||||
$title = (string)($item['title'] ?? '');
|
||||
$pages = (string)\admin\factory\Articles::article_pages($id);
|
||||
$pages = (string)($pagesSummary[$id] ?? '');
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
@@ -146,6 +159,18 @@ class ArticlesController
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zapis kolejnosci zalacznikow (AJAX)
|
||||
*/
|
||||
public function filesOrderSave(): void
|
||||
{
|
||||
if ($this->repository->saveFilesOrder((int)\S::get('article_id'), (string)\S::get('order'))) {
|
||||
echo json_encode(['status' => 'ok', 'msg' => 'Artykul zostal zapisany.']);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zapis artykulu (AJAX)
|
||||
*/
|
||||
@@ -153,11 +178,72 @@ class ArticlesController
|
||||
{
|
||||
global $user;
|
||||
|
||||
$values = json_decode(\S::get('values'), true);
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania artykulu wystapil blad. Prosze sprobowac ponownie.'];
|
||||
$values = $this->resolveSavePayload();
|
||||
$articleId = (int)($values['id'] ?? \S::get('id') ?? 0);
|
||||
$id = $this->repository->save($articleId, $values, (int)$user['id']);
|
||||
|
||||
if ($id = $this->repository->save((int)($values['id'] ?? 0), $values, (int)$user['id'])) {
|
||||
$response = ['status' => 'ok', 'msg' => 'Artykul zostal zapisany.', 'id' => $id];
|
||||
if ($id) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'status' => 'ok',
|
||||
'message' => 'Artykul zostal zapisany.',
|
||||
'msg' => 'Artykul zostal zapisany.',
|
||||
'id' => (int)$id,
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'status' => 'error',
|
||||
'message' => 'Podczas zapisywania artykulu wystapil blad. Prosze sprobowac ponownie.',
|
||||
'msg' => 'Podczas zapisywania artykulu wystapil blad. Prosze sprobowac ponownie.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function imageAltChange(): void
|
||||
{
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zmiany atrybutu alt zdjecia wystapil blad. Prosze sprobowac ponownie.'];
|
||||
|
||||
if ($this->repository->updateImageAlt((int)\S::get('image_id'), (string)\S::get('image_alt'))) {
|
||||
$response = ['status' => 'ok'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function fileNameChange(): void
|
||||
{
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zmiany nazwy zalacznika wystapil blad. Prosze sprobowac ponownie.'];
|
||||
|
||||
if ($this->repository->updateFileName((int)\S::get('file_id'), (string)\S::get('file_name'))) {
|
||||
$response = ['status' => 'ok'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function imageDelete(): void
|
||||
{
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas usuwania zdjecia wystapil blad. Prosze sprobowac ponownie.'];
|
||||
|
||||
if ($this->repository->markImageToDelete((int)\S::get('image_id'))) {
|
||||
$response = ['status' => 'ok'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function fileDelete(): void
|
||||
{
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas usuwania zalacznika wystapil blad. Prosze sprobowac ponownie.'];
|
||||
|
||||
if ($this->repository->markFileToDelete((int)\S::get('file_id'))) {
|
||||
$response = ['status' => 'ok'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
@@ -192,12 +278,226 @@ class ArticlesController
|
||||
$this->repository->deleteNonassignedImages();
|
||||
$this->repository->deleteNonassignedFiles();
|
||||
|
||||
$article = $this->repository->find((int)\S::get('id')) ?: ['id' => 0, 'languages' => [], 'images' => [], 'files' => [], 'pages' => []];
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
$menus = \admin\factory\Pages::menus_list();
|
||||
$layouts = $this->layoutsRepository->listAll();
|
||||
|
||||
$viewModel = $this->buildFormViewModel($article, $languages, $menus, $layouts);
|
||||
|
||||
return \Tpl::view('articles/article-edit', [
|
||||
'article' => $this->repository->find((int)\S::get('id')),
|
||||
'menus' => \admin\factory\Pages::menus_list(),
|
||||
'languages' => $this->languagesRepository->languagesList(),
|
||||
'layouts' => $this->layoutsRepository->listAll(),
|
||||
'user' => $user
|
||||
'form' => $viewModel,
|
||||
'article' => $article,
|
||||
'user' => $user,
|
||||
]);
|
||||
}
|
||||
|
||||
private function resolveSavePayload(): array
|
||||
{
|
||||
$legacyValuesRaw = \S::get('values');
|
||||
if ($legacyValuesRaw !== null && $legacyValuesRaw !== '') {
|
||||
$legacyValues = json_decode((string)$legacyValuesRaw, true);
|
||||
if (is_array($legacyValues)) {
|
||||
return $legacyValues;
|
||||
}
|
||||
}
|
||||
|
||||
$payload = $_POST;
|
||||
unset($payload['_form_id']);
|
||||
|
||||
return is_array($payload) ? $payload : [];
|
||||
}
|
||||
|
||||
private function buildFormViewModel(array $article, array $languages, array $menus, array $layouts): FormEditViewModel
|
||||
{
|
||||
$articleId = (int)($article['id'] ?? 0);
|
||||
$defaultLanguageId = (string)($this->languagesRepository->defaultLanguageId() ?? 'pl');
|
||||
$title = $articleId > 0
|
||||
? 'Edycja artykulu: <u>' . $this->escapeHtml((string)($article['languages'][$defaultLanguageId]['title'] ?? '')) . '</u>'
|
||||
: 'Edycja artykulu';
|
||||
|
||||
$layoutOptions = ['' => '---- szablon domyslny ----'];
|
||||
foreach ($layouts as $layout) {
|
||||
$layoutOptions[(string)$layout['id']] = (string)$layout['name'];
|
||||
}
|
||||
|
||||
$copyFromOptions = ['' => '---- wersja jezykowa ----'];
|
||||
foreach ($languages as $language) {
|
||||
if (!empty($language['id'])) {
|
||||
$copyFromOptions[(string)$language['id']] = (string)$language['name'];
|
||||
}
|
||||
}
|
||||
|
||||
$tabs = [
|
||||
new FormTab('content', 'Tresc', 'fa-file'),
|
||||
new FormTab('settings', 'Ustawienia', 'fa-wrench'),
|
||||
new FormTab('seo', 'SEO', 'fa-globe'),
|
||||
new FormTab('display', 'Wyswietlanie', 'fa-share-alt'),
|
||||
new FormTab('gallery', 'Galeria', 'fa-file-image-o'),
|
||||
new FormTab('files', 'Zalaczniki', 'fa-file-archive-o'),
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::hidden('id', $articleId),
|
||||
FormField::langSection('article_content', 'content', [
|
||||
FormField::select('copy_from', [
|
||||
'label' => 'Wyswietlaj tresc z wersji',
|
||||
'options' => $copyFromOptions,
|
||||
]),
|
||||
FormField::text('title', [
|
||||
'label' => 'Tytul',
|
||||
'required' => true,
|
||||
'attributes' => ['id' => 'title'],
|
||||
]),
|
||||
FormField::image('main_image', [
|
||||
'label' => 'Zdjecie tytulowe',
|
||||
'filemanager' => true,
|
||||
'attributes' => ['id' => 'main_image'],
|
||||
]),
|
||||
FormField::editor('entry', [
|
||||
'label' => 'Wstep',
|
||||
'toolbar' => 'MyToolbar',
|
||||
'height' => 250,
|
||||
'attributes' => ['id' => 'entry'],
|
||||
]),
|
||||
FormField::editor('text', [
|
||||
'label' => 'Tresc',
|
||||
'toolbar' => 'MyToolbar',
|
||||
'height' => 250,
|
||||
'attributes' => ['id' => 'text'],
|
||||
]),
|
||||
FormField::editor('table_of_contents', [
|
||||
'label' => 'Spis tresci',
|
||||
'toolbar' => 'MyToolbar',
|
||||
'height' => 250,
|
||||
'attributes' => ['id' => 'table_of_contents'],
|
||||
]),
|
||||
]),
|
||||
FormField::switch('status', ['label' => 'Opublikowany', 'tab' => 'settings', 'value' => ((int)($article['status'] ?? 0) === 1) || $articleId === 0]),
|
||||
FormField::switch('show_title', ['label' => 'Pokaz tytul', 'tab' => 'settings', 'value' => (int)($article['show_title'] ?? 0) === 1]),
|
||||
FormField::switch('show_table_of_contents', ['label' => 'Pokaz spis tresci', 'tab' => 'settings', 'value' => (int)($article['show_table_of_contents'] ?? 0) === 1]),
|
||||
FormField::switch('show_date_add', ['label' => 'Pokaz date dodania', 'tab' => 'settings', 'value' => (int)($article['show_date_add'] ?? 0) === 1]),
|
||||
FormField::switch('show_date_modify', ['label' => 'Pokaz date modyfikacji', 'tab' => 'settings', 'value' => (int)($article['show_date_modify'] ?? 0) === 1]),
|
||||
FormField::switch('repeat_entry', ['label' => 'Powtorz wprowadzenie', 'tab' => 'settings', 'value' => (int)($article['repeat_entry'] ?? 0) === 1]),
|
||||
FormField::switch('social_icons', ['label' => 'Linki do portali spolecznosciowych', 'tab' => 'settings', 'value' => (int)($article['social_icons'] ?? 0) === 1]),
|
||||
FormField::langSection('article_seo', 'seo', [
|
||||
FormField::text('seo_link', ['label' => 'Link SEO', 'attributes' => ['id' => 'seo_link']]),
|
||||
FormField::text('meta_title', ['label' => 'Meta title']),
|
||||
FormField::textarea('meta_description', ['label' => 'Meta description', 'rows' => 4]),
|
||||
FormField::textarea('meta_keywords', ['label' => 'Meta keywords', 'rows' => 4]),
|
||||
FormField::switch('noindex', ['label' => 'Blokuj indeksacje']),
|
||||
FormField::switch('block_direct_access', ['label' => 'Blokuj bezposredni dostep']),
|
||||
]),
|
||||
FormField::select('layout_id', [
|
||||
'label' => 'Szablon',
|
||||
'tab' => 'display',
|
||||
'options' => $layoutOptions,
|
||||
'value' => $article['layout_id'] ?? '',
|
||||
]),
|
||||
FormField::custom('pages_tree', $this->renderPagesTree($menus, $article), ['tab' => 'display']),
|
||||
FormField::custom('images_box', $this->renderImagesBox($article), ['tab' => 'gallery']),
|
||||
FormField::custom('files_box', $this->renderFilesBox($article), ['tab' => 'files']),
|
||||
];
|
||||
|
||||
$actions = [
|
||||
FormAction::save('/admin/articles/article_save/' . ($articleId > 0 ? 'id=' . $articleId : ''), '/admin/articles/view_list/'),
|
||||
FormAction::cancel('/admin/articles/view_list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
'article-edit',
|
||||
$title,
|
||||
$article,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
'/admin/articles/article_save/' . ($articleId > 0 ? 'id=' . $articleId : ''),
|
||||
'/admin/articles/view_list/',
|
||||
true,
|
||||
['id' => $articleId],
|
||||
$languages
|
||||
);
|
||||
}
|
||||
|
||||
private function renderPagesTree(array $menus, array $article): string
|
||||
{
|
||||
$html = '<div class="form-group row">';
|
||||
$html .= '<label class="col-lg-4 control-label">Wyswietlaj na:</label>';
|
||||
$html .= '<div class="col-lg-8">';
|
||||
|
||||
foreach ($menus as $menu) {
|
||||
$menuId = (int)($menu['id'] ?? 0);
|
||||
$menuName = $this->escapeHtml((string)($menu['name'] ?? ''));
|
||||
$menuStatus = (int)($menu['status'] ?? 0);
|
||||
$menuPages = \admin\factory\Pages::menu_pages($menuId);
|
||||
|
||||
$html .= '<div class="menu_sortable">';
|
||||
$html .= '<ol class="sortable" id="sortable_' . $menuId . '">';
|
||||
$html .= '<li id="list_' . $menuId . '" class="menu_' . $menuId . '" menu="' . $menuId . '">';
|
||||
$html .= '<div class="context_0 content content_menu"' . ($menuStatus ? '' : ' style="color: #cc0000;"') . '>';
|
||||
$html .= '<span class="disclose"><span></span></span>Menu: <b>' . $menuName . '</b>';
|
||||
$html .= '</div>';
|
||||
$html .= \Tpl::view('articles/subpages-list', [
|
||||
'pages' => $menuPages,
|
||||
'article_pages' => $article['pages'] ?? [],
|
||||
'parent_id' => $menuId,
|
||||
'step' => 1,
|
||||
]);
|
||||
$html .= '</li></ol></div>';
|
||||
}
|
||||
|
||||
$html .= '</div><div class="clear"></div></div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function renderImagesBox(array $article): string
|
||||
{
|
||||
$html = '<ul id="images-list">';
|
||||
$images = is_array($article['images'] ?? null) ? $article['images'] : [];
|
||||
foreach ($images as $img) {
|
||||
$id = (int)($img['id'] ?? 0);
|
||||
$src = $this->escapeHtml((string)($img['src'] ?? ''));
|
||||
$alt = $this->escapeHtml((string)($img['alt'] ?? ''));
|
||||
|
||||
$html .= '<li id="image-' . $id . '">';
|
||||
$html .= '<img class="article-image lozad" data-src="/libraries/thumb.php?img=' . $src . '&w=300&h=300">';
|
||||
$html .= '<a href="#" class="input-group-addon btn btn-danger article_image_delete" image-id="' . $id . '"><i class="fa fa-trash"></i></a>';
|
||||
$html .= '<input type="text" class="form-control image-alt" value="' . $alt . '" image-id="' . $id . '" placeholder="atrybut alt...">';
|
||||
$html .= '</li>';
|
||||
}
|
||||
$html .= '</ul><div id="images-uploader">You browser doesn\'t have Flash installed.</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function renderFilesBox(array $article): string
|
||||
{
|
||||
$html = '<ul id="files-list">';
|
||||
$files = is_array($article['files'] ?? null) ? $article['files'] : [];
|
||||
foreach ($files as $file) {
|
||||
$id = (int)($file['id'] ?? 0);
|
||||
$src = (string)($file['src'] ?? '');
|
||||
$name = trim((string)($file['name'] ?? ''));
|
||||
if ($name === '') {
|
||||
$parts = explode('/', $src);
|
||||
$name = (string)end($parts);
|
||||
}
|
||||
$name = $this->escapeHtml($name);
|
||||
|
||||
$html .= '<li id="file-' . $id . '"><div class="input-group">';
|
||||
$html .= '<input type="text" class="article_file_edit form-control" file_id="' . $id . '" value="' . $name . '" />';
|
||||
$html .= '<a href="#" class="input-group-addon btn btn-info article_file_delete" file_id="' . $id . '"><i class="fa fa-trash"></i></a>';
|
||||
$html .= '</div></li>';
|
||||
}
|
||||
$html .= '</ul><div id="files-uploader">You browser doesn\'t have Flash installed.</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function escapeHtml(string $value): string
|
||||
{
|
||||
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user