Passed
Push — master ( ff8e4b...88fd0b )
by MusikAnimal
05:59
created

Project::getAssessmentsConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file contains only the Project class.
4
 */
5
6
namespace Xtools;
7
8
use Mediawiki\Api\MediawikiApi;
9
10
/**
11
 * A Project is a single wiki that XTools is querying.
12
 */
13
class Project extends Model
14
{
15
16
    /** @var string The project name as supplied by the user. */
17
    protected $nameUnnormalized;
18
19
    /** @var string[] Basic metadata about the project */
20
    protected $metadata;
21
22
    /** @var string[] Project's 'dbName', 'url' and 'lang'. */
23
    protected $basicInfo;
24
25
    /**
26
     * Whether the user being queried for in this session
27
     *   has opted in to restricted statistics
28
     * @var bool
29
     */
30
    protected $userOptedIn;
31
32
    /**
33
     * Create a new Project.
34
     * @param string $nameOrUrl The project's database name or URL.
35
     */
36 114
    public function __construct($nameOrUrl)
37
    {
38 114
        $this->nameUnnormalized = $nameOrUrl;
39 114
    }
40
41
    /**
42
     * Unique identifier this Project, to be used in cache keys.
43
     * @see Repository::getCacheKey()
44
     * @return string
45
     */
46
    public function getCacheKey()
47
    {
48
        return $this->getDatabaseName();
49
    }
50
51
    /**
52
     * Get 'dbName', 'url' and 'lang' of the project, the relevant basic info
53
     *   we can get from the meta database. This is all you need to make
54
     *   database queries. More comprehensive metadata can be fetched with
55
     *   getMetadata() at the expense of an API call, which may be cached.
56
     * @return string[]
57
     */
58 53
    protected function getBasicInfo()
59
    {
60 53
        if (empty($this->basicInfo)) {
61 53
            $this->basicInfo = $this->getRepository()->getOne($this->nameUnnormalized);
62
        }
63 52
        return $this->basicInfo;
64
    }
65
66
    /**
67
     * Get full metadata about the project. See ProjectRepository::getMetadata
68
     *   for more information.
69
     * @return string[]
70
     */
71 19
    protected function getMetadata()
72
    {
73 19
        if (empty($this->metadata)) {
74 19
            $url = $this->getBasicInfo()['url'];
75 18
            $this->metadata = $this->getRepository()->getMetadata($url);
76
        }
77 18
        return $this->metadata;
78
    }
79
80
    /**
81
     * Does this project exist?
82
     * @return bool
83
     */
84 11
    public function exists()
85
    {
86 11
        return !empty($this->getDomain());
87
    }
88
89
    /**
90
     * The unique domain name of this project, without protocol or path components.
91
     * This should be used as the canonical project identifier.
92
     *
93
     * @return string
94
     */
95 31
    public function getDomain()
96
    {
97 31
        $url = isset($this->getBasicInfo()['url']) ? $this->getBasicInfo()['url'] : '';
98 31
        return parse_url($url, PHP_URL_HOST);
99
    }
100
101
    /**
102
     * The name of the database for this project.
103
     *
104
     * @return string
105
     */
106 13
    public function getDatabaseName()
107
    {
108 13
        return isset($this->getBasicInfo()['dbName']) ? $this->getBasicInfo()['dbName'] : '';
109
    }
110
111
    /**
112
     * The language for this project.
113
     *
114
     * @return string
115
     */
116 16
    public function getLang()
117
    {
118 16
        return isset($this->getBasicInfo()['lang']) ? $this->getBasicInfo()['lang'] : '';
119
    }
120
121
    /**
122
     * The project URL is the fully-qualified domain name, with protocol and trailing slash.
123
     *
124
     * @param bool $withTrailingSlash Whether to append a slash.
125
     * @return string
126
     */
127 16
    public function getUrl($withTrailingSlash = true)
128
    {
129 16
        return rtrim($this->getBasicInfo()['url'], '/') . ($withTrailingSlash ? '/' : '');
130
    }
131
132
    /**
133
     * Get a MediawikiApi object for this Project.
134
     *
135
     * @return MediawikiApi
136
     */
137
    public function getApi()
138
    {
139
        return $this->getRepository()->getMediawikiApi($this);
140
    }
141
142
    /**
143
     * The base URL path of this project (that page titles are appended to).
144
     * For some wikis the title (apparently) may not be at the end.
145
     * Replace $1 with the article name.
146
     *
147
     * @link https://www.mediawiki.org/wiki/Manual:$wgArticlePath
148
     *
149
     * @return string
150
     */
151 5
    public function getArticlePath()
152
    {
153 5
        $metadata = $this->getMetadata();
154 5
        return isset($metadata['general']['articlePath'])
155 5
            ? $metadata['general']['articlePath']
156 5
            : '/wiki/$1';
157
    }
158
159
    /**
160
     * The URL path of the directory that contains index.php, with no trailing slash.
161
     * Defaults to '/w' which is the same as the normal WMF set-up.
162
     *
163
     * @link https://www.mediawiki.org/wiki/Manual:$wgScriptPath
164
     *
165
     * @return string
166
     */
167 2
    public function getScriptPath()
168
    {
169 2
        $metadata = $this->getMetadata();
170 2
        return isset($metadata['general']['scriptPath'])
171 2
            ? $metadata['general']['scriptPath']
172 2
            : '/w';
173
    }
174
175
    /**
176
     * The URL path to index.php
177
     * Defaults to '/w/index.php' which is the same as the normal WMF set-up.
178
     *
179
     * @return string
180
     */
181 1
    public function getScript()
182
    {
183 1
        $metadata = $this->getMetadata();
184 1
        return isset($metadata['general']['script'])
185 1
            ? $metadata['general']['script']
186 1
            : $this->getScriptPath() . '/index.php';
187
    }
188
189
    /**
190
     * The full URL to api.php
191
     *
192
     * @return string
193
     */
194 8
    public function getApiUrl()
195
    {
196 8
        return rtrim($this->getUrl(), '/') . $this->getRepository()->getApiPath();
197
    }
198
199
    /**
200
     * Get this project's title, the human-language full title of the wiki (e.g. "English
201
     * Wikipedia" or
202
     */
203 1
    public function getTitle()
204
    {
205 1
        $metadata = $this->getMetadata();
206
        return $metadata['general']['wikiName'].' ('.$this->getDomain().')';
207
    }
208
209
    /**
210
     * Get an array of this project's namespaces and their IDs.
211
     *
212
     * @return string[] Keys are IDs, values are names.
213
     */
214 11
    public function getNamespaces()
215
    {
216 11
        $metadata = $this->getMetadata();
217 11
        return $metadata['namespaces'];
218
    }
219
220
    /**
221
     * Get the title of the Main Page.
222
     * @return string
223
     */
224 1
    public function getMainPage()
225
    {
226 1
        $metadata = $this->getMetadata();
227 1
        return isset($metadata['general']['mainpage'])
228 1
            ? $metadata['general']['mainpage']
229 1
            : '';
230
    }
231
232
    /**
233
     * Get a list of users who are in one of the given user groups.
234
     * @param string[] User groups to search for.
235
     * @return string[] User groups keyed by user name.
236
     */
237 1
    public function getUsersInGroups($groups)
238
    {
239 1
        $users = [];
240 1
        $usersAndGroups = $this->getRepository()->getUsersInGroups($this, $groups);
241 1
        foreach ($usersAndGroups as $userAndGroup) {
242 1
            $username = $userAndGroup['user_name'];
243 1
            if (isset($users[$username])) {
244 1
                array_push($users[$username], $userAndGroup['ug_group']);
245
            } else {
246 1
                $users[$username] = [$userAndGroup['ug_group']];
247
            }
248
        }
249 1
        return $users;
250
    }
251
252
    /**
253
     * Get the name of the page on this project that the user must create in order to opt in for
254
     * restricted statistics display.
255
     * @param User $user
256
     * @return string
257
     */
258 2
    public function userOptInPage(User $user)
259
    {
260 2
        $localPageName = 'User:' . $user->getUsername() . '/EditCounterOptIn.js';
261 2
        return $localPageName;
262
    }
263
264
    /**
265
     * Has a user opted in to having their restricted statistics displayed to anyone?
266
     * @param User $user
267
     * @return bool
268
     */
269 3
    public function userHasOptedIn(User $user)
270
    {
271
        // 1. First check to see if the whole project has opted in.
272 3
        if (!$this->userOptedIn) {
273 3
            $optedInProjects = $this->getRepository()->optedIn();
274 3
            $this->userOptedIn = in_array($this->getDatabaseName(), $optedInProjects);
275
        }
276 3
        if ($this->userOptedIn) {
277 1
            return true;
278
        }
279
280
        // 2. Then see if the currently-logged-in user is requesting their own statistics.
281 2
        if ($user->isCurrentlyLoggedIn()) {
282
            return true;
283
        }
284
285
        // 3. Then see if the user has opted in on this project.
286 2
        $userNsId = 2;
287
        // Remove namespace since we're querying the database and supplying a namespace ID.
288 2
        $optInPage = preg_replace('/^User:/', '', $this->userOptInPage($user));
289 2
        $localExists = $this->getRepository()->pageHasContent($this, $userNsId, $optInPage);
290 2
        if ($localExists) {
291
            return true;
292
        }
293
294
        // 4. Lastly, see if they've opted in globally on the default project or Meta.
295 2
        $globalPageName = $user->getUsername() . '/EditCounterGlobalOptIn.js';
296 2
        $globalProject = $this->getRepository()->getGlobalProject();
297 2
        if ($globalProject instanceof Project) {
298
            $globalExists = $globalProject->getRepository()
299
                ->pageHasContent($globalProject, $userNsId, $globalPageName);
300
            if ($globalExists) {
301
                return true;
302
            }
303
        }
304
305 2
        return false;
306
    }
307
308
    /**
309
     * Does this project support page assessments?
310
     * @return bool
311
     */
312 3
    public function hasPageAssessments()
313
    {
314 3
        return (bool) $this->getRepository()->getAssessmentsConfig($this->getDomain());
315
    }
316
317
    /**
318
     * Get all the page assessment metadata for the project.
319
     * @return array
320
     */
321 1
    public function getAssessmentsConfig()
322
    {
323 1
        return $this->getRepository()->getAssessmentsConfig($this->getDomain());
324
    }
325
326
    /**
327
     * Get the image URL of the badge for the given page assessment
328
     * @param string $class Valid classification for project, such as 'Start', 'GA', etc.
329
     * @param bool $filenameOnly Get only the filename, not the URL.
330
     * @return string URL to image
331
     */
332 3
    public function getAssessmentBadgeURL($class, $filenameOnly = false)
333
    {
334 3
        $config = $this->getRepository()->getAssessmentsConfig($this->getDomain());
335
336 3
        if (isset($config['class'][$class])) {
337 2
            $url = "https://upload.wikimedia.org/wikipedia/commons/" . $config['class'][$class]['badge'];
338 3
        } elseif (isset($config['class']['Unknown'])) {
339 2
            $url = "https://upload.wikimedia.org/wikipedia/commons/" . $config['class']['Unknown']['badge'];
340
        } else {
341 1
            $url = "";
342
        }
343
344 3
        if ($filenameOnly) {
345
            $parts = explode('/', $url);
346
            return end($parts);
347
        }
348
349 3
        return $url;
350
    }
351
352
    /**
353
     * Normalize and quote a table name for use in SQL.
354
     * @param string $tableName
355
     * @param string|null $tableExtension Optional table extension, which will only get used if we're on Labs.
356
     * @return string Fully-qualified and quoted table name.
357
     */
358 1
    public function getTableName($tableName, $tableExtension = null)
359
    {
360 1
        return $this->getRepository()->getTableName($this->getDatabaseName(), $tableName, $tableExtension);
361
    }
362
}
363