File: /home/accemeff/vendor/craftcms/cms/src/controllers/EntryRevisionsController.php
<?php
/**
* @link https://craftcms.com/
* @copyright Copyright (c) Pixel & Tonic, Inc.
* @license https://craftcms.github.io/license/
*/
namespace craft\controllers;
use Craft;
use craft\helpers\DateTimeHelper;
use craft\models\EntryDraft;
use craft\models\Section;
use yii\web\NotFoundHttpException;
use yii\web\Response;
use yii\web\ServerErrorHttpException;
/**
* The EntryRevisionsController class is a controller that handles various entry version and draft related tasks such as
* retrieving, saving, deleting, publishing and reverting entry drafts and versions.
* Note that all actions in the controller require an authenticated Craft session via [[allowAnonymous]].
*
* @author Pixel & Tonic, Inc. <support@pixelandtonic.com>
* @since 3.0
*/
class EntryRevisionsController extends BaseEntriesController
{
// Public Methods
// =========================================================================
/**
* Saves a draft, or creates a new one.
*
* @return Response|null
* @throws NotFoundHttpException if the requested entry draft cannot be found
*/
public function actionSaveDraft()
{
$this->requirePostRequest();
$draftId = Craft::$app->getRequest()->getBodyParam('draftId');
if ($draftId) {
$draft = Craft::$app->getEntryRevisions()->getDraftById($draftId);
if (!$draft) {
throw new NotFoundHttpException('Entry draft not found');
}
} else {
$draft = new EntryDraft([
'id' => Craft::$app->getRequest()->getBodyParam('entryId'),
'sectionId' => Craft::$app->getRequest()->getRequiredBodyParam('sectionId'),
'creatorId' => Craft::$app->getUser()->getIdentity()->id,
'siteId' => Craft::$app->getRequest()->getBodyParam('siteId') ?: Craft::$app->getSites()->getPrimarySite()->id,
]);
}
// Make sure they have permission to be editing this
$this->enforceEditEntryPermissions($draft);
$this->_setDraftAttributesFromPost($draft);
$fieldsLocation = Craft::$app->getRequest()->getParam('fieldsLocation', 'fields');
$draft->setFieldValuesFromRequest($fieldsLocation);
$draft->updateTitle();
// Manually validate 'title' since the Elements service will just give it a title automatically.
if (!$draft->id && $draft->validate(['title'])) {
// Don't save brand new entries as enabled
$enabled = $draft->enabled;
$draft->enabled = false;
Craft::$app->getElements()->saveElement($draft, false);
$draft->enabled = $enabled;
}
if (!$draft->id || !Craft::$app->getEntryRevisions()->saveDraft($draft)) {
Craft::$app->getSession()->setError(Craft::t('app', 'Couldn’t save draft.'));
// Send the draft back to the template
Craft::$app->getUrlManager()->setRouteParams([
'entry' => $draft
]);
return null;
}
Craft::$app->getSession()->setNotice(Craft::t('app', 'Draft saved.'));
return $this->redirectToPostedUrl($draft);
}
/**
* Renames a draft.
*
* @return Response
* @throws NotFoundHttpException if the requested entry draft cannot be found
*/
public function actionUpdateDraftMeta(): Response
{
$this->requirePostRequest();
$this->requireAcceptsJson();
$draftId = Craft::$app->getRequest()->getRequiredBodyParam('draftId');
$name = Craft::$app->getRequest()->getRequiredBodyParam('name');
$draft = Craft::$app->getEntryRevisions()->getDraftById($draftId);
if (!$draft) {
throw new NotFoundHttpException('Entry draft not found');
}
if (!$draft->creatorId || $draft->creatorId != Craft::$app->getUser()->getIdentity()->id) {
// Make sure they have permission to be doing this
$this->requirePermission('editPeerEntryDrafts:' . $draft->getSection()->uid);
}
$draft->name = $name;
$draft->revisionNotes = Craft::$app->getRequest()->getBodyParam('notes');
if (Craft::$app->getEntryRevisions()->saveDraft($draft)) {
return $this->asJson(['success' => true]);
}
return $this->asErrorJson($draft->getFirstError('name'));
}
/**
* Deletes a draft.
*
* @return Response
* @throws NotFoundHttpException if the requested entry draft cannot be found
*/
public function actionDeleteDraft(): Response
{
$this->requirePostRequest();
$draftId = Craft::$app->getRequest()->getBodyParam('draftId');
$draft = Craft::$app->getEntryRevisions()->getDraftById($draftId);
if (!$draft) {
throw new NotFoundHttpException('Entry draft not found');
}
if (!$draft->creatorId || $draft->creatorId != Craft::$app->getUser()->getIdentity()->id) {
$this->requirePermission('deletePeerEntryDrafts:' . $draft->getSection()->uid);
}
Craft::$app->getEntryRevisions()->deleteDraft($draft);
return $this->redirectToPostedUrl();
}
/**
* Publish a draft.
*
* @return Response|null
* @throws NotFoundHttpException if the requested entry draft cannot be found
* @throws ServerErrorHttpException if the entry draft is missing its entry
*/
public function actionPublishDraft()
{
$this->requirePostRequest();
$draftId = Craft::$app->getRequest()->getBodyParam('draftId');
$draft = Craft::$app->getEntryRevisions()->getDraftById($draftId);
$userId = Craft::$app->getUser()->getIdentity()->id;
if (!$draft) {
throw new NotFoundHttpException('Entry draft not found');
}
// Permission enforcement
$entry = Craft::$app->getEntries()->getEntryById($draft->id, $draft->siteId);
if (!$entry) {
throw new ServerErrorHttpException('Entry draft is missing its entry');
}
$this->enforceEditEntryPermissions($entry);
$userSession = Craft::$app->getUser();
// Is this another user's entry (and it's not a Single)?
if (
$entry->authorId != $userSession->getIdentity()->id &&
$entry->getSection()->type != Section::TYPE_SINGLE &&
$entry->enabled
) {
// Make sure they have permission to make live changes to those
$this->requirePermission('publishPeerEntries:' . $entry->getSection()->uid);
}
// Is this another user's draft?
if (!$draft->creatorId || $draft->creatorId != $userId) {
$this->requirePermission('publishPeerEntryDrafts:' . $entry->getSection()->uid);
}
// Populate the main draft attributes
$this->_setDraftAttributesFromPost($draft);
// Even more permission enforcement
if ($draft->enabled) {
$this->requirePermission('publishEntries:' . $entry->getSection()->uid);
}
// Populate the field content
$fieldsLocation = Craft::$app->getRequest()->getParam('fieldsLocation', 'fields');
$draft->setFieldValuesFromRequest($fieldsLocation);
$draft->updateTitle();
// Publish the draft (finally!)
if (!Craft::$app->getEntryRevisions()->publishDraft($draft)) {
Craft::$app->getSession()->setError(Craft::t('app', 'Couldn’t publish draft.'));
// Send the draft back to the template
Craft::$app->getUrlManager()->setRouteParams([
'entry' => $draft
]);
return null;
}
Craft::$app->getSession()->setNotice(Craft::t('app', 'Draft published.'));
return $this->redirectToPostedUrl($draft);
}
/**
* Reverts an entry to a version.
*
* @return Response|null
* @throws NotFoundHttpException if the requested entry version cannot be found
* @throws ServerErrorHttpException if the entry version is missing its entry
*/
public function actionRevertEntryToVersion()
{
$this->requirePostRequest();
$versionId = Craft::$app->getRequest()->getBodyParam('versionId');
$version = Craft::$app->getEntryRevisions()->getVersionById($versionId);
if (!$version) {
throw new NotFoundHttpException('Entry version not found');
}
// Permission enforcement
$entry = Craft::$app->getEntries()->getEntryById($version->id, $version->siteId);
if (!$entry) {
throw new ServerErrorHttpException('Entry version is missing its entry');
}
$this->enforceEditEntryPermissions($entry);
$userSession = Craft::$app->getUser();
// Is this another user's entry (and it's not a Single)?
if (
$entry->authorId != $userSession->getIdentity()->id &&
$entry->getSection()->type !== Section::TYPE_SINGLE &&
$entry->enabled
) {
// Make sure they have permission to make live changes to those
$this->requirePermission('publishPeerEntries:' . $entry->getSection()->uid);
}
if ($entry->enabled) {
$this->requirePermission('publishEntries:' . $entry->getSection()->uid);
}
// Revert to the version
$revisionsService = Craft::$app->getEntryRevisions();
if (!$revisionsService->revertEntryToVersion($version)) {
Craft::$app->getSession()->setError(Craft::t('app', 'Couldn’t revert entry to past version.'));
// Send the version back to the template
Craft::$app->getUrlManager()->setRouteParams([
'entry' => $version
]);
return null;
}
// Should we save a new version?
if ($version->getSection()->enableVersioning) {
$revisionsService->saveVersion($version);
}
Craft::$app->getSession()->setNotice(Craft::t('app', 'Entry reverted to past version.'));
return $this->redirectToPostedUrl($version);
}
// Private Methods
// =========================================================================
/**
* Sets a draft's attributes from the post data.
*
* @param EntryDraft $draft
*/
private function _setDraftAttributesFromPost(EntryDraft $draft)
{
$draft->typeId = Craft::$app->getRequest()->getBodyParam('typeId');
$draft->slug = Craft::$app->getRequest()->getBodyParam('slug');
if (($postDate = Craft::$app->getRequest()->getBodyParam('postDate')) !== null) {
$draft->postDate = DateTimeHelper::toDateTime($postDate) ?: null;
}
if (($expiryDate = Craft::$app->getRequest()->getBodyParam('expiryDate')) !== null) {
$draft->expiryDate = DateTimeHelper::toDateTime($expiryDate) ?: null;
}
$draft->enabled = (bool)Craft::$app->getRequest()->getBodyParam('enabled');
$draft->title = Craft::$app->getRequest()->getBodyParam('title');
if (!$draft->typeId) {
// Default to the section's first entry type
$draft->typeId = $draft->getSection()->getEntryTypes()[0]->id;
}
// Author
$authorId = Craft::$app->getRequest()->getBodyParam('author', ($draft->authorId ?: Craft::$app->getUser()->getIdentity()->id));
if (is_array($authorId)) {
$authorId = $authorId[0] ?? null;
}
$draft->authorId = $authorId;
// Parent
$parentId = Craft::$app->getRequest()->getBodyParam('parentId');
if (is_array($parentId)) {
$parentId = $parentId[0] ?? null;
}
$draft->newParentId = $parentId ?: null;
}
}