Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.77% covered (success)
90.77%
59 / 65
25.00% covered (danger)
25.00%
1 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
RecentChangesListener
90.77% covered (success)
90.77%
59 / 65
25.00% covered (danger)
25.00%
1 / 4
11.10
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 onAfterInsert
92.59% covered (success)
92.59%
50 / 54
0.00% covered (danger)
0.00%
0 / 1
6.01
 getRcTitle
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 isAllowed
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
1<?php
2
3namespace Flow\Data\Listener;
4
5use Closure;
6use Flow\Data\Utils\RecentChangeFactory;
7use Flow\FlowActions;
8use Flow\Formatter\IRCLineUrlFormatter;
9use Flow\Model\AbstractRevision;
10use Flow\Model\Workflow;
11use Flow\Repository\UserNameBatch;
12use MediaWiki\MediaWikiServices;
13use MediaWiki\Title\Title;
14use MediaWiki\WikiMap\WikiMap;
15use RecentChange;
16
17/**
18 * Inserts mw recentchange rows for flow AbstractRevision instances.
19 */
20class RecentChangesListener extends AbstractListener {
21
22    // Value used in rc_source field of recentchanges to identify flow specific changes
23    public const SRC_FLOW = "flow";
24
25    /**
26     * @var FlowActions
27     */
28    protected $actions;
29
30    /**
31     * @var UserNameBatch
32     */
33    protected $usernames;
34
35    /**
36     * @var RecentChangeFactory
37     */
38    protected $rcFactory;
39
40    /**
41     * @var IRCLineUrlFormatter
42     */
43    protected $ircFormatter;
44
45    /**
46     * @param FlowActions $actions
47     * @param UserNameBatch $usernames
48     * @param RecentChangeFactory $rcFactory
49     * @param IRCLineUrlFormatter $ircFormatter
50     */
51    public function __construct(
52        FlowActions $actions,
53        UserNameBatch $usernames,
54        RecentChangeFactory $rcFactory,
55        IRCLineUrlFormatter $ircFormatter
56    ) {
57        $this->actions = $actions;
58        $this->usernames = $usernames;
59        $this->rcFactory = $rcFactory;
60        $this->ircFormatter = $ircFormatter;
61    }
62
63    /**
64     * @param AbstractRevision $revision
65     * @param array $row Revision row
66     * @param array $metadata
67     */
68    public function onAfterInsert( $revision, array $row, array $metadata ) {
69        global $wgRCFeeds;
70
71        // No action on imported revisions
72        if ( isset( $metadata['imported'] ) && $metadata['imported'] ) {
73            return;
74        }
75
76        $action = $revision->getChangeType();
77        $revisionId = $revision->getRevisionId()->getAlphadecimal();
78        $timestamp = $revision->getRevisionId()->getTimestamp();
79        /** @var Workflow $workflow */
80        $workflow = $metadata['workflow'];
81        $user = $revision->getUser();
82
83        if ( !$this->isAllowed( $revision, $action ) ) {
84            return;
85        }
86
87        $title = $this->getRcTitle( $workflow, $revision->getChangeType() );
88        $autopatrolAllowed = MediaWikiServices::getInstance()->getPermissionManager()
89            ->userHasRight( $user, 'autopatrol' );
90        $attribs = [
91            'rc_namespace' => $title->getNamespace(),
92            'rc_title' => $title->getDBkey(),
93            'rc_user' => $row['rev_user_id'],
94            'rc_user_text' => $this->usernames->get( WikiMap::getCurrentWikiId(), $row['rev_user_id'], $row['rev_user_ip'] ),
95            'rc_type' => RC_FLOW,
96            'rc_source' => self::SRC_FLOW,
97            'rc_minor' => 0,
98            'rc_bot' => 0, // TODO: is revision by bot
99            'rc_new' => 0,
100            'rc_patrolled' => $autopatrolAllowed ? RecentChange::PRC_AUTOPATROLLED : RecentChange::PRC_UNPATROLLED,
101            'rc_old_len' => $revision->getPreviousContentLength(),
102            'rc_new_len' => $revision->getContentLength(),
103            'rc_this_oldid' => 0,
104            'rc_last_oldid' => 0,
105            'rc_logid' => 0,
106            'rc_log_type' => null,
107            'rc_params' => serialize( [
108                'flow-workflow-change' => [
109                    'action' => $action,
110                    'revision_type' => get_class( $revision ),
111                    'revision' => $revisionId,
112                    'workflow' => $workflow->getId()->getAlphadecimal(),
113                ],
114            ] ),
115            'rc_cur_id' => 0,
116            'rc_comment' => '',
117            'rc_comment_text' => '',
118            'rc_comment_data' => null,
119            'rc_timestamp' => $timestamp,
120            'rc_deleted' => 0,
121        ];
122
123        $rc = $this->rcFactory->newFromRow( (object)$attribs );
124        // Insert into db only, don't send to any RC feeds (yet)
125        $rc->save( RecentChange::SEND_NONE );
126        $feeds = $wgRCFeeds;
127        // Override the IRC formatter with our own formatter
128        foreach ( $feeds as $name => &$feed ) {
129            $feed['original_formatter'] = $feed['formatter'];
130            $feed['formatter'] = $this->ircFormatter;
131        }
132        // pre-load the irc formatter which will be triggered via hook
133        $this->ircFormatter->associate( $rc, [
134            'revision' => $revision
135        ] + $metadata );
136        // run the feeds/irc/etc external notifications
137        $rc->notifyRCFeeds( $feeds );
138    }
139
140    /**
141     * @param Workflow $workflow
142     * @param string $action
143     * @return Title
144     */
145    public function getRcTitle( Workflow $workflow, $action ) {
146        if ( $this->actions->getValue( $action, 'rc_title' ) === 'owner' ) {
147            return $workflow->getOwnerTitle();
148        } else {
149            return $workflow->getArticleTitle();
150        }
151    }
152
153    /**
154     * @param AbstractRevision $revision
155     * @param string $action
156     * @return bool
157     */
158    public function isAllowed( AbstractRevision $revision, $action ) {
159        $allowed = $this->actions->getValue( $action, 'rc_insert' );
160        if ( $allowed instanceof Closure ) {
161            $allowed = $allowed( $revision, $this );
162        }
163
164        return (bool)$allowed;
165    }
166}