|
25 | 25 | use craft\helpers\ElementHelper;
|
26 | 26 | use craft\helpers\Html;
|
27 | 27 | use craft\helpers\UrlHelper;
|
| 28 | +use craft\models\ElementActivity; |
28 | 29 | use craft\models\FieldLayoutForm;
|
29 | 30 | use craft\services\Elements;
|
30 | 31 | use craft\web\Controller;
|
@@ -425,6 +426,8 @@ public function actionEdit(?ElementInterface $element, ?int $elementId = null):
|
425 | 426 | 'siteStatuses' => $siteStatuses,
|
426 | 427 | 'siteToken' => (!Craft::$app->getIsLive() || !$element->getSite()->enabled) ? $security->hashData((string)$element->siteId) : null,
|
427 | 428 | 'visibleLayoutElements' => $form ? $form->getVisibleElements() : [],
|
| 429 | + 'updatedTimestamp' => $element->dateUpdated->getTimestamp(), |
| 430 | + 'canonicalUpdatedTimestamp' => $canonical->dateUpdated->getTimestamp(), |
428 | 431 | ]
|
429 | 432 | )
|
430 | 433 | );
|
@@ -695,7 +698,11 @@ private function _additionalButtons(
|
695 | 698 | bool $isUnpublishedDraft,
|
696 | 699 | bool $isDraft,
|
697 | 700 | ): string {
|
698 |
| - $components = []; |
| 701 | + $components = [ |
| 702 | + Html::tag('div', options: [ |
| 703 | + 'class' => ['activity-container'], |
| 704 | + ]), |
| 705 | + ]; |
699 | 706 |
|
700 | 707 | // Preview (View will be added later by JS)
|
701 | 708 | if ($canSave && $previewTargets) {
|
@@ -966,6 +973,8 @@ public function actionSave(): ?Response
|
966 | 973 | ]));
|
967 | 974 | }
|
968 | 975 |
|
| 976 | + $elementsService->trackActivity($element, ElementActivity::TYPE_SAVE); |
| 977 | + |
969 | 978 | // See if the user happens to have a provisional element. If so delete it.
|
970 | 979 | $provisional = $element::find()
|
971 | 980 | ->provisionalDrafts()
|
@@ -1203,6 +1212,8 @@ public function actionSaveDraft(): ?Response
|
1203 | 1212 | ]));
|
1204 | 1213 | }
|
1205 | 1214 |
|
| 1215 | + $elementsService->trackActivity($element, ElementActivity::TYPE_SAVE); |
| 1216 | + |
1206 | 1217 | $creator = $element->getCreator();
|
1207 | 1218 |
|
1208 | 1219 | $data = [
|
@@ -1275,6 +1286,8 @@ public function actionSaveDraft(): ?Response
|
1275 | 1286 | 'initialDeltaValues' => $view->getInitialDeltaValues(),
|
1276 | 1287 | 'headHtml' => $view->getHeadHtml(),
|
1277 | 1288 | 'bodyHtml' => $view->getBodyHtml(),
|
| 1289 | + 'updatedTimestamp' => $element->dateUpdated->getTimestamp(), |
| 1290 | + 'canonicalUpdatedTimestamp' => $element->getCanonical()->dateUpdated->getTimestamp(), |
1278 | 1291 | ];
|
1279 | 1292 | }
|
1280 | 1293 |
|
@@ -1354,6 +1367,8 @@ public function actionApplyDraft(): ?Response
|
1354 | 1367 | }
|
1355 | 1368 | }
|
1356 | 1369 |
|
| 1370 | + $elementsService->trackActivity($canonical, ElementActivity::TYPE_SAVE); |
| 1371 | + |
1357 | 1372 | if (!$this->request->getAcceptsJson()) {
|
1358 | 1373 | // Tell all browser windows about the element save
|
1359 | 1374 | $session = Craft::$app->getSession();
|
@@ -1484,6 +1499,7 @@ public function actionRevert(): Response
|
1484 | 1499 | }
|
1485 | 1500 |
|
1486 | 1501 | $canonical = Craft::$app->getRevisions()->revertToRevision($element, $user->id);
|
| 1502 | + Craft::$app->getElements()->trackActivity($canonical, ElementActivity::TYPE_SAVE); |
1487 | 1503 |
|
1488 | 1504 | return $this->_asSuccess(Craft::t('app', '{type} reverted to past revision.', [
|
1489 | 1505 | 'type' => $element::displayName(),
|
@@ -1522,6 +1538,63 @@ public function actionGetElementHtml(): Response
|
1522 | 1538 | return $this->asJson(compact('html', 'headHtml'));
|
1523 | 1539 | }
|
1524 | 1540 |
|
| 1541 | + /** |
| 1542 | + * Returns any recent activity for an element, and records that the user is viewing the element. |
| 1543 | + * |
| 1544 | + * @return Response |
| 1545 | + * @since 4.5.0 |
| 1546 | + */ |
| 1547 | + public function actionRecentActivity(): Response |
| 1548 | + { |
| 1549 | + $element = $this->_element(); |
| 1550 | + |
| 1551 | + if (!$element || $element->getIsRevision()) { |
| 1552 | + throw new BadRequestHttpException('No element was identified by the request.'); |
| 1553 | + } |
| 1554 | + |
| 1555 | + $elementsService = Craft::$app->getElements(); |
| 1556 | + $currentUser = Craft::$app->getUser()->getIdentity(); |
| 1557 | + $activity = $elementsService->getRecentActivity($element, $currentUser->id); |
| 1558 | + $elementsService->trackActivity($element, ElementActivity::TYPE_VIEW, $currentUser); |
| 1559 | + |
| 1560 | + return $this->asJson([ |
| 1561 | + 'activity' => array_map(function(ElementActivity $record) use ($element) { |
| 1562 | + $recordIsCanonical = $record->element->getIsCanonical() || $record->element->isProvisionalDraft; |
| 1563 | + $recordIsCanonicalAndPublished = $recordIsCanonical && !$record->element->getIsUnpublishedDraft(); |
| 1564 | + $isSameOrUpstream = $element->id === $record->element->id || $recordIsCanonical; |
| 1565 | + |
| 1566 | + if ($isSameOrUpstream) { |
| 1567 | + $messageParams = [ |
| 1568 | + 'user' => $record->user->getName(), |
| 1569 | + 'type' => $recordIsCanonicalAndPublished ? $element::lowerDisplayName() : Craft::t('app', 'draft'), |
| 1570 | + ]; |
| 1571 | + $message = match ($record->type) { |
| 1572 | + ElementActivity::TYPE_VIEW => Craft::t('app', '{user} is viewing this {type}.', $messageParams), |
| 1573 | + ElementActivity::TYPE_EDIT, ElementActivity::TYPE_SAVE => Craft::t('app', '{user} is editing this {type}.', $messageParams), |
| 1574 | + }; |
| 1575 | + } else { |
| 1576 | + $messageParams = [ |
| 1577 | + 'user' => $record->user->getName(), |
| 1578 | + 'type' => $element::lowerDisplayName(), |
| 1579 | + ]; |
| 1580 | + $message = match ($record->type) { |
| 1581 | + ElementActivity::TYPE_VIEW => Craft::t('app', '{user} is viewing a draft of this {type}.', $messageParams), |
| 1582 | + ElementActivity::TYPE_EDIT, ElementActivity::TYPE_SAVE => Craft::t('app', '{user} is editing a draft of this {type}.', $messageParams), |
| 1583 | + }; |
| 1584 | + } |
| 1585 | + |
| 1586 | + return [ |
| 1587 | + 'userId' => $record->user->id, |
| 1588 | + 'userName' => $record->user->getName(), |
| 1589 | + 'userThumb' => $record->user->getThumbHtml(26), |
| 1590 | + 'message' => $message, |
| 1591 | + ]; |
| 1592 | + }, $activity), |
| 1593 | + 'updatedTimestamp' => $element->dateUpdated->getTimestamp(), |
| 1594 | + 'canonicalUpdatedTimestamp' => $element->getCanonical()->dateUpdated->getTimestamp(), |
| 1595 | + ]); |
| 1596 | + } |
| 1597 | + |
1525 | 1598 | /**
|
1526 | 1599 | * Returns the requested element, populated with any posted attributes.
|
1527 | 1600 | *
|
|
0 commit comments