Use log_search to track already sent thanks

We currently use client-side storage to keep track of what revisions and
posts have already been thanked for. This is problematic because client-
side storage is not permanent, making it easy to send duplicate thanks
if you have logged out and in, or switched computers.

This starts storing new thanks in the log_search table, which is
designed for efficient querying of metadata associated with a specific
log entry. With this, we can easily check to see if a user has already
sent thanks for a specific revision.

The UX is a bit weird right now, we only check log_search when actually
sending thanks again, in which case the user thinks they have sent
thanks again, but no duplicate thanks is actually sent.

Bug: T88820
Bug: T53303
Change-Id: Iaf8cbe0776081dc69e82883d8727ba1cfe20e3e1
This commit is contained in:
Kunal Mehta 2015-06-15 17:53:40 -07:00
parent 679e5518ce
commit 956a476005
3 changed files with 54 additions and 14 deletions

View file

@ -119,7 +119,13 @@ class ApiFlowThank extends ApiThank {
private function sendThanks( User $user, User $recipient, UUID $postId, UUID $workflowId,
$topicTitleText, Title $pageTitle ) {
global $wgThanksLogging;
$uniqueId = "flow-{$postId->getAlphadecimal()}";
// Do one last check to make sure we haven't sent Thanks before
if ( $this->haveAlreadyThanked( $user, $uniqueId ) ) {
// Pretend the thanks were sent
$this->markResultSuccess( $recipient->getName() );
return;
}
// Create the notification via Echo extension
EchoEvent::create( array(
@ -134,14 +140,11 @@ class ApiFlowThank extends ApiThank {
'agent' => $user,
) );
// Mark the thank in session to prevent duplicates (Bug 46690).
// And mark the thank in session for a cheaper check to prevent duplicates (Bug 46690).
$user->getRequest()->setSessionData( "flow-thanked-{$postId->getAlphadecimal()}", true );
// Set success message.
$this->markResultSuccess( $recipient->getName() );
// Log it if we're supposed to log it.
if ( $wgThanksLogging ) {
$this->logThanks( $user, $recipient );
}
$this->logThanks( $user, $recipient, $uniqueId );
}
/**

View file

@ -73,9 +73,15 @@ class ApiRevThank extends ApiThank {
}
private function sendThanks( User $user, Revision $revision, User $recipient, $source ) {
global $wgThanksLogging;
$title = $this->getTitleFromRevision( $revision );
$uniqueId = "rev-{$revision->getId()}";
// Do one last check to make sure we haven't sent Thanks before
if ( $this->haveAlreadyThanked( $user, $uniqueId ) ) {
// Pretend the thanks were sent
$this->markResultSuccess( $recipient->getName() );
return;
}
$title = $this->getTitleFromRevision( $revision );
// Create the notification via Echo extension
EchoEvent::create( array(
'type' => 'edit-thank',
@ -88,14 +94,11 @@ class ApiRevThank extends ApiThank {
'agent' => $user,
) );
// Mark the thank in session to prevent duplicates (Bug 46690)
// And mark the thank in session for a cheaper check to prevent duplicates (Bug 46690).
$user->getRequest()->setSessionData( "thanks-thanked-{$revision->getId()}", true );
// Set success message
$this->markResultSuccess( $recipient->getName() );
// Log it if we're supposed to log it
if ( $wgThanksLogging ) {
$this->logThanks( $user, $recipient );
}
$this->logThanks( $user, $recipient, $uniqueId );
}
/**

View file

@ -39,9 +39,43 @@ abstract class ApiThank extends ApiBase {
) );
}
protected function logThanks( User $user, User $recipient ) {
/**
* This checks the log_search data
*
* @param User $thanker
* @param string $uniqueId
* @return bool Whether thanks has already been sent
*/
protected function haveAlreadyThanked( User $thanker, $uniqueId ) {
$dbw = wfGetDB( DB_MASTER );
return (bool)$dbw->selectRow(
array( 'log_search', 'logging' ),
array( 'ls_value' ),
array(
'log_user' => $thanker->getId(),
'ls_field' => 'thankid',
'ls_value' => $uniqueId,
),
__METHOD__,
array(),
array( 'logging' => array( 'INNER JOIN', 'ls_log_id=log_id' ) )
);
}
/**
* @param User $user
* @param User $recipient
* @param string $uniqueId A unique Id to identify the event being thanked for, to use
* when checking for duplicate thanks
*/
protected function logThanks( User $user, User $recipient, $uniqueId ) {
global $wgThanksLogging;
if ( !$wgThanksLogging ) {
return;
}
$logEntry = new ManualLogEntry( 'thanks', 'thank' );
$logEntry->setPerformer( $user );
$logEntry->setRelations( array( 'thankid' => $uniqueId ) );
$target = $recipient->getUserPage();
$logEntry->setTarget( $target );
$logId = $logEntry->insert();