Passed
Pull Request — master (#162)
by MusikAnimal
05:44
created

Project::userOptInPage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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