Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 41 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
LogStore | |
0.00% |
0 / 41 |
|
0.00% |
0 / 4 |
110 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
thank | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
12 | |||
haveThanked | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
2 | |||
getLogEntryFromId | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
30 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\Thanks\Storage; |
4 | |
5 | use DatabaseLogEntry; |
6 | use ExtensionRegistry; |
7 | use ManualLogEntry; |
8 | use MediaWiki\CheckUser\Hooks; |
9 | use MediaWiki\Config\ServiceOptions; |
10 | use MediaWiki\Extension\Thanks\Storage\Exceptions\InvalidLogType; |
11 | use MediaWiki\Extension\Thanks\Storage\Exceptions\LogDeleted; |
12 | use MediaWiki\User\ActorNormalization; |
13 | use MediaWiki\User\User; |
14 | use Wikimedia\Rdbms\IConnectionProvider; |
15 | |
16 | /** |
17 | * Manages the storage for Thank events. |
18 | * Thanks are stored as logs with relations between users. |
19 | * Each thank action should have an unique ID generated by callers. |
20 | */ |
21 | class LogStore { |
22 | |
23 | protected IConnectionProvider $conn; |
24 | protected ActorNormalization $actorNormalization; |
25 | public const CONSTRUCTOR_OPTIONS = [ 'ThanksLogging', 'ThanksAllowedLogTypes' ]; |
26 | protected ServiceOptions $serviceOptions; |
27 | |
28 | public function __construct( |
29 | IConnectionProvider $conn, |
30 | ActorNormalization $actorNormalization, |
31 | ServiceOptions $serviceOptions |
32 | ) { |
33 | $this->conn = $conn; |
34 | $this->actorNormalization = $actorNormalization; |
35 | $serviceOptions->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS ); |
36 | $this->serviceOptions = $serviceOptions; |
37 | } |
38 | |
39 | /** |
40 | * @param User $user The user performing the thanks (and the log entry). |
41 | * @param User $recipient The target of the thanks (and the log entry). |
42 | * @param string $uniqueId A unique Id to identify the event being thanked for, to use |
43 | * when checking for duplicate thanks |
44 | */ |
45 | public function thank( User $user, User $recipient, string $uniqueId ): void { |
46 | if ( !$this->serviceOptions->get( 'ThanksLogging' ) ) { |
47 | return; |
48 | } |
49 | $logEntry = new ManualLogEntry( 'thanks', 'thank' ); |
50 | $logEntry->setPerformer( $user ); |
51 | $logEntry->setRelations( [ 'thankid' => $uniqueId ] ); |
52 | $target = $recipient->getUserPage(); |
53 | $logEntry->setTarget( $target ); |
54 | $logId = $logEntry->insert(); |
55 | $logEntry->publish( $logId, 'udp' ); |
56 | |
57 | if ( ExtensionRegistry::getInstance()->isLoaded( 'CheckUser' ) ) { |
58 | $recentChange = $logEntry->getRecentChange(); |
59 | // TODO: This should be done in a separate hook handler |
60 | Hooks::updateCheckUserData( $recentChange ); |
61 | } |
62 | } |
63 | |
64 | /** |
65 | * This checks the log_search data. |
66 | * |
67 | * @param User $thanker The user sending the thanks. |
68 | * @param string $uniqueId The identifier for the thanks. |
69 | * @return bool Whether thanks has already been sent |
70 | */ |
71 | public function haveThanked( User $thanker, string $uniqueId ): bool { |
72 | // TODO: Figure out why it's not getting the data from a replica |
73 | $dbw = $this->conn->getPrimaryDatabase(); |
74 | $thankerActor = $this->actorNormalization->acquireActorId( $thanker, $dbw ); |
75 | return (bool)$dbw->newSelectQueryBuilder() |
76 | ->select( 'ls_value' ) |
77 | ->from( 'log_search' ) |
78 | ->join( 'logging', null, [ 'ls_log_id=log_id' ] ) |
79 | ->where( |
80 | [ |
81 | 'log_actor' => $thankerActor, |
82 | 'ls_field' => 'thankid', |
83 | 'ls_value' => $uniqueId, |
84 | ] |
85 | ) |
86 | ->caller( __METHOD__ ) |
87 | ->fetchRow(); |
88 | } |
89 | |
90 | /** |
91 | * @throws InvalidLogType |
92 | * @throws LogDeleted |
93 | */ |
94 | public function getLogEntryFromId( int $logId ): ?DatabaseLogEntry { |
95 | $logEntry = DatabaseLogEntry::newFromId( $logId, $this->conn->getPrimaryDatabase() ); |
96 | |
97 | if ( !$logEntry ) { |
98 | return null; |
99 | } |
100 | |
101 | // Make sure this log type is allowed. |
102 | $allowedLogTypes = $this->serviceOptions->get( 'ThanksAllowedLogTypes' ); |
103 | if ( !in_array( $logEntry->getType(), $allowedLogTypes ) |
104 | && !in_array( $logEntry->getType() . '/' . $logEntry->getSubtype(), $allowedLogTypes ) ) { |
105 | throw new InvalidLogType( $logEntry->getType() ); |
106 | } |
107 | |
108 | // Don't permit thanks if any part of the log entry is deleted. |
109 | if ( $logEntry->getDeleted() ) { |
110 | throw new LogDeleted(); |
111 | } |
112 | return $logEntry; |
113 | } |
114 | } |