Skip to content

Commit

Permalink
Merge pull request #953 from CatoTH/noref-fix-comment-caching
Browse files Browse the repository at this point in the history
Noref fix comment caching
  • Loading branch information
CatoTH authored Oct 12, 2024
2 parents c3f6591 + 7ac4b2a commit 231e2d6
Show file tree
Hide file tree
Showing 12 changed files with 157 additions and 79 deletions.
17 changes: 8 additions & 9 deletions controllers/ConsultationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -312,20 +312,15 @@ public function actionIndex(): ResponseInterface
$this->consultationSidebar($this->consultation);

$myself = User::getCurrentUser();
if ($myself) {
$myMotions = $myself->getMySupportedMotionsByConsultation($this->consultation);
$myAmendments = $myself->getMySupportedAmendmentsByConsultation($this->consultation);
} else {
$myMotions = null;
$myAmendments = null;
}

return new HtmlResponse($this->render('index', [
'cache' => $cache,
'consultation' => $this->consultation,
'myself' => $myself,
'myMotions' => $myMotions,
'myAmendments' => $myAmendments,
'myMotions' => $myself?->getMySupportedMotionsByConsultation($this->consultation),
'myAmendments' => $myself?->getMySupportedAmendmentsByConsultation($this->consultation),
'myMotionComments' => MotionComment::getPrivatelyCommentedByConsultation($myself, $this->consultation),
'myAmendmentComments' => AmendmentComment::getPrivatelyCommentedByConsultation($myself, $this->consultation),
]));
}

Expand Down Expand Up @@ -593,10 +588,14 @@ private function tagMotionResolutionList(int $tagId, bool $isResolutionList): Re
return new HtmlErrorResponse(404, 'Tag not found');
}

$myself = User::getCurrentUser();

return new HtmlResponse($this->render('tag_motion_list', [
'tag' => $tag,
'cache' => LayoutHelper::getTagMotionListCache($this->consultation, $tag, $isResolutionList),
'isResolutionList' => $isResolutionList,
'myMotionComments' => MotionComment::getPrivatelyCommentedByConsultation($myself, $this->consultation),
'myAmendmentComments' => AmendmentComment::getPrivatelyCommentedByConsultation($myself, $this->consultation),
]));
}

Expand Down
45 changes: 17 additions & 28 deletions models/db/AmendmentComment.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,43 +121,32 @@ public static function getNewestByConsultation(Consultation $consultation, int $
}));
}

private static array $cachedComments = [];

/**
* @return AmendmentComment[][]
* @return AmendmentComment[]
*/
public static function getAllForUserAndConsultationByMotion(Consultation $consultation, ?User $user, int $status): array
public static function getPrivatelyCommentedByConsultation(?User $user, Consultation $consultation): array
{
if (!$user) {
return [];
}

$key = $user->id . '.' . $status;
if (isset(self::$cachedComments[$key])) {
return self::$cachedComments[$key];
}

$invisibleStatuses = array_map('intval', $consultation->getStatuses()->getInvisibleMotionStatuses());
/** @var AmendmentComment[] $allComments */
$allComments = static::find()->joinWith('amendment', true)->joinWith('amendment.motionJoin', true)
->where('amendmentComment.status = ' . intval($status))
->andWhere('amendmentComment.userId = ' . intval($user->id))
->andWhere('amendment.status NOT IN (' . implode(', ', $invisibleStatuses) . ')')
->andWhere('motion.status NOT IN (' . implode(', ', $invisibleStatuses) . ')')
->andWhere('motion.consultationId = ' . intval($consultation->id))
->orderBy('amendmentComment.paragraph')
->all();
$query = AmendmentComment::find();
$query->innerJoin(
'amendment',
'amendmentComment.amendmentId = amendment.id'
);
$query->innerJoin('motion', 'motion.id = amendment.motionId');
$query->where('motion.status != ' . IntVal(Motion::STATUS_DELETED));
$query->andWhere('amendment.status != ' . IntVal(Motion::STATUS_DELETED));
$query->andWhere('motion.consultationId = ' . IntVal($consultation->id));
$query->andWhere('amendmentComment.userId = ' . IntVal($user->id));
$query->andWhere('amendmentComment.status = ' . AmendmentComment::STATUS_PRIVATE);
$query->orderBy('motion.titlePrefix ASC, amendment.titlePrefix ASC, amendment.dateCreation DESC, amendmentComment.paragraph ASC');

$byAmendment = [];
foreach ($allComments as $comment) {
if (!isset($byAmendment[$comment->amendmentId])) {
$byAmendment[$comment->amendmentId] = [];
}
$byAmendment[$comment->amendmentId][] = $comment;
}
/** @var AmendmentComment[] $comments */
$comments = $query->all();

self::$cachedComments[$key] = $byAmendment;
return $byAmendment;
return $comments;
}

public function getMotionTitle(): string
Expand Down
42 changes: 15 additions & 27 deletions models/db/MotionComment.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,42 +126,30 @@ public static function getNewestByConsultation(Consultation $consultation, int $
}));
}

private static array $cachedComments = [];

/**
* @return MotionComment[][]
* @return MotionComment[]
*/
public static function getAllForUserAndConsultationByMotion(Consultation $consultation, ?User $user, int $status): array
public static function getPrivatelyCommentedByConsultation(?User $user, Consultation $consultation): array
{
if (!$user) {
return [];
}

$key = $user->id . '.' . $status;
if (isset(self::$cachedComments[$key])) {
return self::$cachedComments[$key];
}

$invisibleStatuses = array_map('intval', $consultation->getStatuses()->getInvisibleMotionStatuses());
/** @var MotionComment[] $allComments */
$allComments = static::find()->joinWith('motion', true)
->where('motionComment.status = ' . intval($status))
->andWhere('motionComment.userId = ' . intval($user->id))
->andWhere('motion.status NOT IN (' . implode(', ', $invisibleStatuses) . ')')
->andWhere('motion.consultationId = ' . intval($consultation->id))
->orderBy('motionComment.paragraph')
->all();
$query = MotionComment::find();
$query->innerJoin(
'motion',
'motionComment.motionId = motion.id'
);
$query->where('motion.status != ' . intval(Motion::STATUS_DELETED));
$query->andWhere('motion.consultationId = ' . intval($consultation->id));
$query->andWhere('motionComment.userId = ' . intval($user->id));
$query->andWhere('motionComment.status = ' . MotionComment::STATUS_PRIVATE);
$query->orderBy('motion.titlePrefix ASC, motion.dateCreation DESC, motion.id DESC, motionComment.paragraph ASC');

$byMotion = [];
foreach ($allComments as $comment) {
if (!isset($byMotion[$comment->motionId])) {
$byMotion[$comment->motionId] = [];
}
$byMotion[$comment->motionId][] = $comment;
}
/** @var MotionComment[] $comments */
$comments = $query->all();

self::$cachedComments[$key] = $byMotion;
return $byMotion;
return $comments;
}

public function getConsultation(): ?Consultation
Expand Down
1 change: 0 additions & 1 deletion models/db/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,6 @@ public function getMySupportedAmendmentsByConsultation(Consultation $consultatio
return $supporters;
}


public function getNotificationUnsubscribeCode(): string
{
return $this->id . '-' . $this->createConfirmationCode('unsubscribe');
Expand Down
7 changes: 2 additions & 5 deletions views/consultation/LayoutHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,7 @@ public static function flushViewCaches(Consultation $consultation): void
private static function getMotionLineContent(Motion $motion, Consultation $consultation): string
{
$return = '<p class="title">' . "\n";

$privateMotionComments = MotionComment::getAllForUserAndConsultationByMotion($consultation, User::getCurrentUser(), MotionComment::STATUS_PRIVATE);
$return .= LayoutHelper::getPrivateCommentIndicator($motion, $privateMotionComments, []);
$return .= '<span class="privateCommentHolder"></span>';

$motionUrl = UrlHelper::createMotionUrl($motion);
$return .= '<a href="' . Html::encode($motionUrl) . '" class="motionLink' . $motion->id . '">';
Expand Down Expand Up @@ -157,8 +155,7 @@ private static function getAmendmentLineContent(Amendment $amendment): string
$return = '';

$consultation = $amendment->getMyConsultation();
$privateAmendmentComments = AmendmentComment::getAllForUserAndConsultationByMotion($consultation, User::getCurrentUser(), AmendmentComment::STATUS_PRIVATE);
$return .= LayoutHelper::getPrivateCommentIndicator($amendment, [], $privateAmendmentComments);
$return .= '<span class="privateCommentHolder"></span>';

$title = ($amendment->showTitlePrefix() ? $amendment->getFormattedTitlePrefix() : \Yii::t('amend', 'amendment'));
$return .= '<a href="' . Html::encode(UrlHelper::createAmendmentUrl($amendment)) . '" ' .
Expand Down
61 changes: 61 additions & 0 deletions views/consultation/_index_private_comment_list.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

use app\models\db\{AmendmentComment, MotionComment};
use yii\helpers\Html;

/**
* @var MotionComment[] $myMotionComments
* @var AmendmentComment[] $myAmendmentComments
*/

if (count($myMotionComments) === 0 && count($myAmendmentComments) === 0) {
return;
}

$motionComments = [];
foreach ($myMotionComments as $comment) {
if (!isset($motionComments[$comment->motionId])) {
$motionComments[$comment->motionId] = [];
}
if ($comment->paragraph === -1) {
$motionComments[$comment->motionId][] = $comment->text;
} else {
$motionComments[$comment->motionId][] = str_replace('%NO%', (string) $comment->paragraph, Yii::t('motion', 'private_notes_para')) .
': ' . $comment->text;
}
}

$amendmentComments = [];
foreach ($myAmendmentComments as $comment) {
if (!isset($amendmentComments[$comment->amendmentId])) {
$amendmentComments[$comment->amendmentId] = [];
}
if ($comment->paragraph === -1) {
$amendmentComments[$comment->amendmentId][] = $comment->text;
} else {
$amendmentComments[$comment->amendmentId][] = str_replace('%NO%', (string) $comment->paragraph, Yii::t('motion', 'private_notes_para')) .
': ' . $comment->text;
}
}

echo '<div class="hidden privateCommentList" data-antragsgruen-widget="frontend/MotionListPrivateComments">';
foreach ($motionComments as $motionId => $commentTexts) {
$tooltip = Html::encode(implode(" - ", $commentTexts));

echo '<a href="#" class="privateCommentsIndicator" data-target-type="motion" data-target-id="' . $motionId . '">';
echo '<span class="glyphicon glyphicon-pushpin" data-toggle="tooltip" data-placement="right" ' .
'aria-label="' . Html::encode(Yii::t('base', 'aria_tooltip')) . ': ' . $tooltip . '" ' .
'data-original-title="' . $tooltip . '"></span>';
echo '</a>';
}

foreach ($amendmentComments as $amendmentId => $commentTexts) {
$tooltip = Html::encode(implode(" - ", $commentTexts));

echo '<a href="#" class="privateCommentsIndicator" data-target-type="amendment" data-target-id="' . $amendmentId . '">';
echo '<span class="glyphicon glyphicon-pushpin" data-toggle="tooltip" data-placement="right" ' .
'aria-label="' . Html::encode(Yii::t('base', 'aria_tooltip')) . ': ' . $tooltip . '" ' .
'data-original-title="' . $tooltip . '"></span>';
echo '</a>';
}
echo '</div>';
9 changes: 8 additions & 1 deletion views/consultation/index.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

use app\models\db\{Amendment, AmendmentSupporter, Consultation, Motion, MotionSupporter, User};
use app\models\db\{Amendment, AmendmentComment, AmendmentSupporter, Consultation, Motion, MotionComment, MotionSupporter, User};
use app\components\{HashedStaticCache, MotionSorter, UrlHelper};
use app\models\settings\{Privileges, Consultation as ConsultationSettings};
use yii\helpers\Html;
Expand All @@ -12,6 +12,8 @@
* @var User|null $myself
* @var MotionSupporter[] $myMotions
* @var AmendmentSupporter[] $myAmendments
* @var MotionComment[] $myMotionComments
* @var AmendmentComment[] $myAmendmentComments
* @var HashedStaticCache $cache
*/

Expand Down Expand Up @@ -170,3 +172,8 @@
}
return $output;
});

echo $this->render('_index_private_comment_list', [
'myMotionComments' => $myMotionComments,
'myAmendmentComments' => $myAmendmentComments,
]);
14 changes: 7 additions & 7 deletions views/consultation/index_layout_tags.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@
/** @var int[] $tagIds */
$tagIds = [];
$hasNoTagMotions = false;
$privateMotionComments = MotionComment::getAllForUserAndConsultationByMotion($consultation, User::getCurrentUser(), MotionComment::STATUS_PRIVATE);
$privateAmendmentComments = AmendmentComment::getAllForUserAndConsultationByMotion($consultation, User::getCurrentUser(), AmendmentComment::STATUS_PRIVATE);

$layout->addOnLoadJS('$(\'[data-toggle="tooltip"]\').tooltip();');

Expand Down Expand Up @@ -163,8 +161,11 @@
}
echo '</tr></thead>';
foreach ($sortedIMotions as $imotion) {
/** @var IMotion $imotion */
$classes = ['motion'];
if (is_a($imotion, Motion::class)) {
$classes = ['motion', 'motionRow' . $imotion->id];
} else {
$classes = ['motion', 'amendmentRow' . $imotion->id];
}
if ($imotion->getMyMotionType()->getSettingsObj()->cssIcon) {
$classes[] = $imotion->getMyMotionType()->getSettingsObj()->cssIcon;
}
Expand All @@ -177,14 +178,13 @@
if ($imotion->isInScreeningProcess()) {
$classes[] = 'unscreened';
}
$privateComment = LayoutHelper::getPrivateCommentIndicator($imotion, $privateMotionComments, $privateAmendmentComments);
echo '<tr class="' . implode(' ', $classes) . '">';
if (!$consultation->getSettings()->hideTitlePrefix) {
echo '<td class="prefixCol">' . $privateComment . Html::encode($imotion->getFormattedTitlePrefix(LayoutHooks::CONTEXT_MOTION_LIST)) . '</td>';
echo '<td class="prefixCol"><span class="privateCommentHolder"></span>' . Html::encode($imotion->getFormattedTitlePrefix(LayoutHooks::CONTEXT_MOTION_LIST)) . '</td>';
}
echo '<td class="titleCol">';
if ($consultation->getSettings()->hideTitlePrefix) {
echo $privateComment;
echo '<span class="privateCommentHolder"></span>';
}
echo '<div class="titleLink">';
if (is_a($imotion, Amendment::class)) {
Expand Down
9 changes: 8 additions & 1 deletion views/consultation/tag_motion_list.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

use app\models\db\{ConsultationSettingsTag, IMotion};
use app\models\db\{AmendmentComment, ConsultationSettingsTag, IMotion, MotionComment};
use app\components\{MotionSorter, UrlHelper};
use yii\helpers\Html;
use app\models\settings\{Consultation as ConsultationSettings};
Expand All @@ -10,6 +10,8 @@
* @var ConsultationSettingsTag $tag
* @var \app\components\HashedStaticCache $cache
* @var bool $isResolutionList
* @var MotionComment[] $myMotionComments
* @var AmendmentComment[] $myAmendmentComments
*/

/** @var \app\controllers\Base $controller */
Expand Down Expand Up @@ -80,3 +82,8 @@
}
return $output;
});

echo $this->render('_index_private_comment_list', [
'myMotionComments' => $myMotionComments,
'myAmendmentComments' => $myAmendmentComments,
]);
2 changes: 2 additions & 0 deletions web/js/build/frontend/MotionListPrivateComments.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions web/js/build/frontend/MotionListPrivateComments.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions web/typescript/frontend/MotionListPrivateComments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export class MotionListPrivateComments {
constructor(private $element: JQuery) {
const holder = $element[0];
holder.childNodes.forEach(comment => {
if (comment.nodeType !== Node.ELEMENT_NODE) {
return;
}
const commentNode = comment as HTMLElement;
const selector = '.' + commentNode.attributes['data-target-type'].value + 'Row' + commentNode.attributes['data-target-id'].value;
document.querySelectorAll(selector).forEach(motionRow => {
const commentHolder = motionRow.querySelector('.privateCommentHolder');
if (!commentHolder) {
return;
}
const clonedComment = comment.cloneNode(true) as HTMLElement;
const link = motionRow.querySelector('.titleLink a');
if (link) {
clonedComment.setAttribute('href', link.getAttribute('href'));
}

commentHolder.parentNode.insertBefore(clonedComment, commentHolder);
commentHolder.parentNode.removeChild(commentHolder);

$(clonedComment).find("[data-toggle=\"tooltip\"]").tooltip();
});
});
}
}

0 comments on commit 231e2d6

Please sign in to comment.