Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
37.50% covered (danger)
37.50%
3 / 8
CRAP
68.29% covered (warning)
68.29%
28 / 41
WikipediaAppCounter
0.00% covered (danger)
0.00%
0 / 1
37.50% covered (danger)
37.50%
3 / 8
37.43
68.29% covered (warning)
68.29%
28 / 41
 validateComment
n/a
0 / 0
1
n/a
0 / 0
 getLanguageFromComment
n/a
0 / 0
2
n/a
0 / 0
 onEditSuccess
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 onRevert
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 6
 conditionallyIncrementEditCount
0.00% covered (danger)
0.00%
0 / 1
4.07
83.33% covered (warning)
83.33%
10 / 12
 conditionallyIncrementRevertCount
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
7 / 7
 hasSuggestedEditsChangeTag
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getLanguageFromWikibaseComment
0.00% covered (danger)
0.00%
0 / 1
4.05
85.71% covered (warning)
85.71%
6 / 7
 isWikipediaAppRequest
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
4 / 4
 getMagicCommentPattern
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
<?php
/**
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * @file
 */
namespace MediaWiki\Extension\WikimediaEditorTasks;
use ChangeTags;
use MediaWiki\Revision\RevisionRecord;
use WebRequest;
abstract class WikipediaAppCounter extends Counter {
    /**
     * @param string $comment Revision comment to be validated for whether to include this revision in the count.
     * @return bool Whether this revision should be counted by this counter.
     */
    abstract protected function validateComment( string $comment ): bool;
    /**
     * @param string $comment Revision comment from which the language may be extracted.
     * @return string|null Language parsed from the given comment, or a constant overridden language.
     */
    abstract protected function getLanguageFromComment( string $comment ): ?string;
    /** @inheritDoc */
    public function onEditSuccess( int $centralId, WebRequest $request, RevisionRecord $revision ): void {
        $this->conditionallyIncrementEditCount( $centralId, $request, $revision );
    }
    /** @inheritDoc */
    public function onRevert( int $centralId, int $revisionId, RevisionRecord $revision ): void {
        if ( !$this->hasSuggestedEditsChangeTag( $revisionId ) ) {
            return;
        }
        if ( $this->isRevertCountingEnabled() ) {
            $this->conditionallyIncrementRevertCount( $centralId, $revision );
        } else {
            $this->reset( $centralId );
        }
    }
    /**
     * Increment the counter corresponding to the provided MW API action
     * @param int $centralId central ID of the editing user
     * @param WebRequest $request
     * @param RevisionRecord $revision revision representing the successful edit
     */
    protected function conditionallyIncrementEditCount( int $centralId, WebRequest $request,
        RevisionRecord $revision ): void {
        if ( !$this->isWikipediaAppRequest( $request ) ) {
            return;
        }
        $comment = $revision->getComment()->text;
        if ( !$this->validateComment( $comment ) ) {
            return;
        }
        $lang = $this->getLanguageFromComment( $comment );
        if ( !$lang ) {
            return;
        }
        $this->incrementEditCountForLang( $centralId, $lang );
        $this->updateEditStreak( $centralId );
        ChangeTags::addTags( 'apps-suggested-edits', null, $revision->getId() );
    }
    /**
     * Increment the revert counter
     * @param int $centralId central ID of the editing user
     * @param RevisionRecord $revision the RevisionRecord corresponding with $revisionId
     */
    protected function conditionallyIncrementRevertCount(
        int $centralId,
        RevisionRecord $revision
    ): void {
        $comment = $revision->getComment()->text;
        if ( !$this->validateComment( $comment ) ) {
            return;
        }
        $lang = $this->getLanguageFromComment( $comment );
        if ( $lang ) {
            $this->incrementRevertCountForLang( $centralId, $lang );
        }
    }
    /**
     * Return true if the suggested edits change tag is associated with the revision.
     * @param int $revisionId
     * @return bool
     */
    protected function hasSuggestedEditsChangeTag( int $revisionId ): bool {
        $tags = ChangeTags::getTags( wfGetDB( DB_REPLICA ), null, $revisionId );
        return in_array( 'apps-suggested-edits', $tags, true );
    }
    /**
     * Get the language code from the semi-structured Wikibase edit summary text.
     * Examples:
     *  \/* wbsetdescription-add:1|en *\/ 19th century French painter
     *  \/* wbsetlabel-add:1|en *\/ A chicken in the snow
     * See docs at mediawiki-extensions-Wikibase/docs/summaries.md.
     * TODO: Update to use structured comment data when that's implemented (T215422)
     * @param string $action
     * @param string $comment
     * @return string|null language code, if found
     */
    protected function getLanguageFromWikibaseComment( string $action, string $comment ): ?string {
        if ( !$comment ) {
            return null;
        }
        $matches = [];
        $result = preg_match( $this->getMagicCommentPattern( $action ), $comment, $matches );
        if ( $result ) {
            return $matches[1];
        }
        return null;
    }
    /**
     * @param WebRequest $request
     * @return bool
     */
    private function isWikipediaAppRequest( WebRequest $request ) {
        $ua = $request->getHeader( 'User-agent' );
        if ( $ua ) {
            return strpos( $ua, 'WikipediaApp/' ) === 0;
        }
        return false;
    }
    /**
     * @param string $action Wikibase action to which this pattern will apply.
     * @return string pattern matching Wikibase magic comments associated with this counter.
     */
    protected function getMagicCommentPattern( string $action ): string {
        return '/^\/\* ' . $action . '-[a-z]{3}:[0-9]\|([a-z-]+) /';
    }
}