Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions formwork/src/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,6 @@ public function run(): Response

$response->send();

if ($this->config()->get('system.statistics.enabled') && $this->site()->currentPage() !== null && !$this->site()->currentPage()->isErrorPage()) {
$this->container->get(Statistics::class)->trackVisit();
}

return $response;
}

Expand Down
7 changes: 6 additions & 1 deletion formwork/src/Controllers/PageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Formwork\Pages\Site;
use Formwork\Router\RouteParams;
use Formwork\Router\Router;
use Formwork\Statistics\Statistics;
use Formwork\Utils\FileSystem;
use Formwork\View\ViewFactory;

Expand All @@ -23,7 +24,7 @@ public function __construct(protected App $app, protected Config $config, protec
parent::__construct();
}

public function load(RouteParams $routeParams, ViewFactory $viewFactory): Response
public function load(RouteParams $routeParams, ViewFactory $viewFactory, Statistics $statistics): Response
{
if ($this->site->get('maintenance.enabled') && !$this->app->panel()?->isLoggedIn()) {
if ($this->site->get('maintenance.page') !== null) {
Expand Down Expand Up @@ -68,6 +69,10 @@ public function load(RouteParams $routeParams, ViewFactory $viewFactory): Respon
}
}

if ($this->config->get('system.statistics.enabled')) {
$statistics->trackVisit();
}

if ($page->isPublished() && $page->routable()) {
return $this->getPageResponse($page);
}
Expand Down
68 changes: 68 additions & 0 deletions formwork/src/Panel/ContentHistory/ContentHistory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace Formwork\Panel\ContentHistory;

use Formwork\Parsers\Json;
use Formwork\Utils\Arr;
use Formwork\Utils\FileSystem;

class ContentHistory
{
public const HISTORY_FILENAME = '.history';

public const HISTORY_DEFAULT_LIMIT = 1;

protected ContentHistoryItemCollection $items;

public function __construct(
protected string $path,
protected int $limit = self::HISTORY_DEFAULT_LIMIT
) {
}

public function path(): string
{
return $this->path;
}

public function exists(): bool
{
return FileSystem::exists(FileSystem::joinPaths($this->path, self::HISTORY_FILENAME));
}

public function items(): ContentHistoryItemCollection
{
if (isset($this->items)) {
return $this->items;
}
if (!$this->exists()) {
return $this->items = new ContentHistoryItemCollection();
}
$items = Json::parse(FileSystem::read(FileSystem::joinPaths($this->path, self::HISTORY_FILENAME)));
return $this->items = new ContentHistoryItemCollection(Arr::map($items, fn ($item) => ContentHistoryItem::fromArray($item)));
}

public function lastItem(): ?ContentHistoryItem
{
return $this->items()->last();
}

public function isJustCreated(): bool
{
return $this->lastItem()?->event() === ContentHistoryEvent::Created;
}

public function update(ContentHistoryEvent $contentHistoryEvent, string $user, int $timestamp): void
{
$this->items()->add(new ContentHistoryItem($contentHistoryEvent, $user, $timestamp));
if ($this->items()->count() > $this->limit) {
$this->items = $this->items()->slice(-$this->limit);
}
}

public function save(): void
{
$data = $this->items()->map(fn ($item) => $item->toArray())->toArray();
FileSystem::write(FileSystem::joinPaths($this->path, self::HISTORY_FILENAME), Json::encode($data));
}
}
9 changes: 9 additions & 0 deletions formwork/src/Panel/ContentHistory/ContentHistoryEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Formwork\Panel\ContentHistory;

enum ContentHistoryEvent: string
{
case Created = 'created';
case Edited = 'edited';
}
54 changes: 54 additions & 0 deletions formwork/src/Panel/ContentHistory/ContentHistoryItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Formwork\Panel\ContentHistory;

use Formwork\Data\Contracts\ArraySerializable;

class ContentHistoryItem implements ArraySerializable
{
final public function __construct(
protected ContentHistoryEvent $contentHistoryEvent,
protected string $user,
protected int $time
) {
}

public function event(): ContentHistoryEvent
{
return $this->contentHistoryEvent;
}

public function user(): string
{
return $this->user;
}

public function time(): int
{
return $this->time;
}

/**
* @return array{event: string, user: string, time: int}
*/
public function toArray(): array
{
return [
'event' => $this->contentHistoryEvent->value,
'user' => $this->user,
'time' => $this->time,
];
}

/**
* @param array{event: string, user: string, time: int} $data
*/
public static function fromArray(array $data): static
{
return new static(
ContentHistoryEvent::from($data['event']),
$data['user'],
$data['time']
);
}
}
14 changes: 14 additions & 0 deletions formwork/src/Panel/ContentHistory/ContentHistoryItemCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Formwork\Panel\ContentHistory;

use Formwork\Data\AbstractCollection;

class ContentHistoryItemCollection extends AbstractCollection
{
protected bool $associative = false;

protected ?string $dataType = ContentHistoryItem::class;

protected bool $mutable = true;
}
67 changes: 63 additions & 4 deletions formwork/src/Panel/Controllers/PagesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
use Formwork\Images\Image;
use Formwork\Pages\Page;
use Formwork\Pages\Site;
use Formwork\Panel\ContentHistory\ContentHistory;
use Formwork\Panel\ContentHistory\ContentHistoryEvent;
use Formwork\Parsers\Yaml;
use Formwork\Router\RouteParams;
use Formwork\Schemes\Schemes;
use Formwork\Utils\Arr;
use Formwork\Utils\Constraint;
use Formwork\Utils\Date;
use Formwork\Utils\FileSystem;
use Formwork\Utils\MimeType;
Expand Down Expand Up @@ -169,13 +172,22 @@ public function edit(RouteParams $routeParams): Response
$data = $this->request->input();

// Validate fields against data
$fields->setValues($data, null)->validate();
$fields->setValues($data, null);

$forceUpdate = false;

if ($this->request->query()->has('publish')) {
$fields->setValues(['published' => Constraint::isTruthy($this->request->query()->get('publish'))]);
$forceUpdate = true;
}

$fields->validate();

$error = false;

// Update the page
try {
$page = $this->updatePage($page, $data, $fields);
$page = $this->updatePage($page, $data, $fields, force: $forceUpdate);
} catch (TranslatedException $e) {
$error = true;
$this->panel()->notify($e->getTranslatedMessage(), 'error');
Expand Down Expand Up @@ -218,16 +230,53 @@ public function edit(RouteParams $routeParams): Response

$this->modal('renameFile');

$contentHistory = $page->path()
? new ContentHistory($page->path())
: null;

return new Response($this->view('pages.editor', [
'title' => $this->translate('panel.pages.editPage', $page->title()),
'page' => $page,
'fields' => $page->fields(),
'templates' => $this->site()->templates()->keys(),
'parents' => $this->site()->descendants()->sortBy('relativePath'),
'currentLanguage' => $routeParams->get('language', $page->language()?->code()),
'history' => $contentHistory,
]));
}

/**
* Pages@preview action
*/
public function preview(RouteParams $routeParams): Response
{
$page = $this->site()->findPage($routeParams->get('page'));

if ($page === null) {
$this->panel()->notify($this->translate('panel.pages.page.cannotPreview.pageNotFound'), 'error');
return $this->redirectToReferer(default: '/pages/');
}

$this->site()->setCurrentPage($page);

// Load data from POST variables
$requestData = $this->request->input();

// Validate fields against data
$page->fields()->setValues($requestData)->validate();

if ($page->template()->name() !== ($template = $requestData->get('template'))) {
$page->reload(['template' => $this->site()->templates()->get($template)]);
}

if ($page->parent() !== ($parent = $this->resolveParent($requestData->get('parent')))) {
$this->panel()->notify($this->translate('panel.pages.page.cannotPreview.parentChanged'), 'error');
return $this->redirectToReferer(default: '/pages/');
}

return new Response($page->render(), $page->responseStatus(), $page->headers());
}

/**
* Pages@reorder action
*/
Expand Down Expand Up @@ -547,13 +596,18 @@ protected function createPage(FieldCollection $fieldCollection): Page

FileSystem::write($path . $filename, $fileContent);

$contentHistory = new ContentHistory($path);

$contentHistory->update(ContentHistoryEvent::Created, $this->user()->username(), time());
$contentHistory->save();

return $this->site()->retrievePage($path);
}

/**
* Update a page
*/
protected function updatePage(Page $page, RequestData $requestData, FieldCollection $fieldCollection): Page
protected function updatePage(Page $page, RequestData $requestData, FieldCollection $fieldCollection, bool $force = false): Page
{
if ($page->contentFile() === null) {
throw new RuntimeException('Unexpected missing content file');
Expand Down Expand Up @@ -597,7 +651,7 @@ protected function updatePage(Page $page, RequestData $requestData, FieldCollect

$differ = $frontmatter !== $page->contentFile()->frontmatter() || $content !== $page->data()['content'] || $language !== $page->language();

if ($differ) {
if ($force || $differ) {
$filename = $requestData->get('template');
$filename .= empty($language) ? '' : '.' . $language;
$filename .= $this->config->get('system.content.extension');
Expand All @@ -615,6 +669,11 @@ protected function updatePage(Page $page, RequestData $requestData, FieldCollect
FileSystem::write($page->path() . $filename, $fileContent);
FileSystem::touch($this->site()->path());

$contentHistory = new ContentHistory($page->path());

$contentHistory->update(ContentHistoryEvent::Edited, $this->user()->username(), time());
$contentHistory->save();

// Update page with the new data
$page->reload();

Expand Down
2 changes: 1 addition & 1 deletion panel/assets/css/panel-dark.min.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion panel/assets/css/panel.min.css

Large diffs are not rendered by default.

Loading