Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
n/a
0 / 0
n/a
0 / 0
CRAP
n/a
0 / 0
PopulateImageTables
n/a
0 / 0
n/a
0 / 0
17
n/a
0 / 0
 __construct
n/a
0 / 0
n/a
0 / 0
1
 execute
n/a
0 / 0
n/a
0 / 0
13
 getImages
n/a
0 / 0
n/a
0 / 0
3
1<?php
2
3namespace MediaWiki\Extension\MediaModeration\Maintenance\Dev;
4
5use Error;
6use LocalFile;
7use MediaWiki\Maintenance\Maintenance;
8use MediaWiki\Title\Title;
9use MediaWiki\User\User;
10use UploadFromUrl;
11
12// This is a local development only script, no need to count it in code coverage metrics.
13// @codeCoverageIgnoreStart
14$IP = getenv( 'MW_INSTALL_PATH' );
15if ( $IP === false ) {
16    $IP = __DIR__ . '/../../..';
17}
18require_once "$IP/maintenance/Maintenance.php";
19
20/**
21 * Maintenance script for importing some real world images from Commons to a local wiki. A subset
22 * of the total will have new versions uploaded and another subset of the total will be deleted, so
23 * as to populate various tables that MediaModeration scans.
24 */
25class PopulateImageTables extends Maintenance {
26
27    public function __construct() {
28        parent::__construct();
29        $this->addDescription( 'Populate rows in image tables with fake data.
30        This cannot be easily undone. Do not run this script in production!' );
31        $this->addOption( 'count', 'How many rows to create' );
32    }
33
34    public function execute() {
35        if ( !$this->getConfig()->get( 'MediaModerationDeveloperMode' ) ||
36            !$this->getConfig()->get( 'AllowCopyUploads' ) ) {
37            $this->error( 'AllowCopyUploads and MediaModerationDeveloperMode must be set to true.' );
38            return;
39        }
40        if ( $this->getConfig()->get( 'MaxImageArea' ) ) {
41            $this->output( 'For this script, the recommended value for $wgMaxImageArea is `false`.' );
42        }
43        if ( $this->getConfig()->get( 'CheckFileExtensions' ) ) {
44            $this->output( 'For this script, the recommended value for $wgCheckFileExtensions is `false`.' );
45        }
46        $count = $this->getOption( 'count', 100 );
47        $user = User::newSystemUser( 'MediaModeration' );
48
49        // TODO: Allow for continuation if the user wants e.g. 1000 images imported.
50
51        $uploadedImages = [];
52        $fileRepo = $this->getServiceContainer()->getRepoGroup()->getLocalRepo();
53
54        foreach ( $this->getImages( $count ) as $image ) {
55            $this->output( "Importing image {$image['title']}\n" );
56            $maintenanceUpload = new UploadFromUrl();
57            if ( !isset( $image['pageimage'] ) ) {
58                // TODO This occurs often. Should find some way to require that the metadata is present.
59                $this->output( "... skipping, does not have image metadata\n" );
60                continue;
61            }
62            $maintenanceUpload->initialize( $image['pageimage'], $image['original']['source'] );
63            if ( !$maintenanceUpload->getTitle() ) {
64                $this->fatalError( 'illegal-filename' );
65            }
66            $maintenanceUpload->fetchFile();
67            try {
68                $uploadResult = $maintenanceUpload->performUpload(
69                    'MediaModeration PopulateImageTables.php',
70                    'MediaModeration',
71                    false,
72                    $user
73                );
74                if ( $uploadResult->isGood() ) {
75                    $uploadedImages[] = $fileRepo->newFile(
76                        Title::newFromText( $image['title'], NS_FILE )
77                    );
78                } else {
79                    $this->error( "... unable to perform upload.\n" );
80                }
81            } catch ( Error $error ) {
82                $this->error( "... unable to import\n" );
83            }
84        }
85        // Upload new versions of 20% of images.
86        $newImageVersions = array_intersect_key( $uploadedImages, array_rand( $uploadedImages, $count / 5 ) );
87        // Get new images to use
88        $newImages = $this->getImages( $count / 5 );
89        /**
90         * @var int $key
91         * @var LocalFile $newImageVersion
92         */
93        foreach ( $newImageVersions as $key => $newImageVersion ) {
94            // Upload new version of image.
95            $maintenanceUpload = new UploadFromUrl();
96            $titleText = $newImageVersion->getTitle()->getText();
97            $maintenanceUpload->initialize( $titleText, $newImages[$key]['original']['source'] );
98            if ( !$maintenanceUpload->getTitle() ) {
99                $this->fatalError( 'illegal-filename' );
100            }
101            $maintenanceUpload->fetchFile();
102            $this->output( "Uploading new version of $titleText\n" );
103            $maintenanceUpload->performUpload(
104                'MediaModeration PopulateImages.php update',
105                'MediaModeration',
106                false,
107                $user
108            );
109        }
110        $deleteImages = array_intersect_key( $uploadedImages, array_rand( $uploadedImages, $count / 5 ) );
111        /** @var LocalFile $image */
112        foreach ( $deleteImages as $image ) {
113            $this->output( 'Deleting ' . $image->getTitle()->getText() . PHP_EOL );
114            $image->deleteFile( 'MediaModeration testing', $user );
115        }
116    }
117
118    private function getImages( int $count ): array {
119        $url = wfAppendQuery( 'https://commons.wikimedia.org/w/api.php', [
120            'action' => 'query',
121            'prop' => 'pageimages',
122            'generator' => 'search',
123            'piprop' => 'thumbnail|name|original',
124            'format' => 'json',
125            // Exclude items with .pdf
126            // TODO there's probably a nicer way to get just the file types we want.
127            'gsrsearch' => '!".pdf"',
128            'gsrnamespace' => NS_FILE,
129            'gsrsort' => 'random',
130            'gsrlimit' => $count,
131            'formatversion' => 2
132        ] );
133        $request = $this->getServiceContainer()->getHttpRequestFactory()->create( $url, [], __METHOD__ );
134        $result = $request->execute();
135        if ( !$result->isOK() ) {
136            return [];
137        }
138        $data = json_decode( $request->getContent(), true );
139        if ( !isset( $data['query']['pages'] ) ) {
140            $this->error( 'Unable to get images' );
141            return [];
142        }
143        return $data['query']['pages'];
144    }
145}
146
147$maintClass = PopulateImageTables::class;
148require_once RUN_MAINTENANCE_IF_MAIN;
149// @codeCoverageIgnoreEnd