Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 55
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
SignificantEditCreationHandler
0.00% covered (danger)
0.00%
0 / 55
0.00% covered (danger)
0.00%
0 / 2
56
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 onRevisionFromEditComplete
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2
3declare( strict_types=1 );
4
5namespace ContentTranslation\HookHandler;
6
7use ContentTranslation\Entity\RecentSignificantEdit;
8use ContentTranslation\Service\EditedSectionFinder;
9use ContentTranslation\Service\WikidataIdFetcher;
10use ContentTranslation\SiteMapper;
11use ContentTranslation\Store\RecentSignificantEditStore;
12use DeferredUpdates;
13use MediaWiki\Page\Hook\RevisionFromEditCompleteHook;
14use MediaWiki\Revision\RevisionRecord;
15use MediaWiki\Revision\RevisionStore;
16use MediaWiki\User\UserIdentity;
17use WikiPage;
18
19class SignificantEditCreationHandler implements RevisionFromEditCompleteHook {
20
21    /** @var RevisionStore */
22    private $revisionStore;
23
24    /** @var RecentSignificantEditStore */
25    private $significantEditStore;
26
27    /** @var EditedSectionFinder */
28    private $editedSectionFinder;
29
30    /** @var WikidataIdFetcher */
31    private $wikidataIdFetcher;
32
33    public function __construct(
34        RevisionStore $revisionStore,
35        RecentSignificantEditStore $significantEditStore,
36        EditedSectionFinder $editedSectionFinder,
37        WikidataIdFetcher $wikidataIdFetcher
38    ) {
39        $this->revisionStore = $revisionStore;
40        $this->significantEditStore = $significantEditStore;
41        $this->editedSectionFinder = $editedSectionFinder;
42        $this->wikidataIdFetcher = $wikidataIdFetcher;
43    }
44
45    /**
46     * This hook is registered for the "RevisionFromEditComplete" event.
47     * It adds a new row to the "cx_significant_edits" table, if the
48     * current revision fulfils some requirements.
49     *
50     * These requirements are:
51     * 1. This revision should be a significant contribution (size > 500 bytes)
52     * 2. This revision should affect at least one non-lead section
53     *
54     * @param WikiPage $wikiPage WikiPage edited
55     * @param RevisionRecord $rev New revision
56     * @param int|bool $originalRevId
57     * @param UserIdentity $user
58     * @param string[] &$tags
59     */
60    public function onRevisionFromEditComplete( $wikiPage, $rev, $originalRevId, $user, &$tags ) {
61        $isSignificantEdit = $rev->getSize() > 500;
62        $significantEditStore = $this->significantEditStore;
63        // If edit is not of a significant size,
64        // or if current wiki family is not supported for this entrypoint
65        if ( !$isSignificantEdit || !$significantEditStore->isCurrentWikiFamilySupported() ) {
66            return;
67        }
68
69        $currentLanguage = SiteMapper::getCurrentLanguageCode();
70        $qid = $this->wikidataIdFetcher->getWikidataId( (string)$wikiPage->getTitle(), $currentLanguage );
71        if ( !$qid ) {
72            wfDebugLog( 'cx-entrypoints-recent-edit', 'qid not found' );
73            return;
74        }
75
76        // get integer from Q id ("Q123")
77        $wikidataId = (int)filter_var( $qid, FILTER_SANITIZE_NUMBER_INT );
78        $revisionStore = $this->revisionStore;
79        $editedSectionFinder = $this->editedSectionFinder;
80
81        DeferredUpdates::addCallableUpdate(
82            static function () use (
83                $rev,
84                $user,
85                $wikiPage,
86                $revisionStore,
87                $editedSectionFinder,
88                $significantEditStore,
89                $wikidataId
90            ) {
91                $previousRev = $revisionStore->getPreviousRevision( $rev );
92                // Find all titles of non-lead sections that were edited in this revision
93                $editedSections = $editedSectionFinder->findEditedSectionsBetweenRevisions( $rev, $previousRev );
94                wfDebugLog( 'cx-entrypoints-recent-edit', 'Edited sections: ' . implode( ", ", $editedSections ) );
95
96                // If no non-lead section was edited, return
97                if ( !$editedSections ) {
98                    return;
99                }
100
101                $language = SiteMapper::getCurrentLanguageCode();
102
103                $userEdit = $significantEditStore->findExistingEdit(
104                    $user->getId(),
105                    $wikidataId,
106                    $language
107                );
108
109                if ( $userEdit instanceof RecentSignificantEdit ) {
110                    wfDebugLog( 'cx-entrypoints-recent-edit', 'Recent edit already exists' );
111                    $userEdit->mergeSectionTitles( $editedSections );
112                    $significantEditStore->update( $userEdit );
113
114                    return;
115                }
116
117                $edit = new RecentSignificantEdit(
118                    null,
119                    $user->getId(),
120                    $wikidataId,
121                    $language,
122                    (string)$wikiPage->getTitle(),
123                    $editedSections,
124                    null
125                );
126
127                $significantEditStore->insert( $edit );
128                wfDebugLog( 'cx-entrypoints-recent-edit', 'Recent edit created' );
129            }
130        );
131    }
132}