Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
92.42% |
61 / 66 |
|
80.00% |
8 / 10 |
CRAP | |
0.00% |
0 / 1 |
MediaFileHandler | |
92.42% |
61 / 66 |
|
80.00% |
8 / 10 |
22.21 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getPage | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
getFile | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
run | |
78.95% |
15 / 19 |
|
0.00% |
0 / 1 |
5.23 | |||
getResponse | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
1 | |||
needsWriteAccess | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getParamSettings | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
getETag | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
getLastModified | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
hasRepresentation | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Rest\Handler; |
4 | |
5 | use File; |
6 | use MediaFileTrait; |
7 | use MediaWiki\Page\ExistingPageRecord; |
8 | use MediaWiki\Page\PageLookup; |
9 | use MediaWiki\Rest\LocalizedHttpException; |
10 | use MediaWiki\Rest\Response; |
11 | use MediaWiki\Rest\SimpleHandler; |
12 | use RepoGroup; |
13 | use Wikimedia\Message\MessageValue; |
14 | use Wikimedia\ParamValidator\ParamValidator; |
15 | |
16 | /** |
17 | * Handler class for media meta-data |
18 | */ |
19 | class MediaFileHandler extends SimpleHandler { |
20 | use MediaFileTrait; |
21 | |
22 | /** @var RepoGroup */ |
23 | private $repoGroup; |
24 | |
25 | /** @var PageLookup */ |
26 | private $pageLookup; |
27 | |
28 | /** |
29 | * @var ExistingPageRecord|false|null |
30 | */ |
31 | private $page = false; |
32 | |
33 | /** |
34 | * @var File|false|null |
35 | */ |
36 | private $file = false; |
37 | |
38 | /** |
39 | * @param RepoGroup $repoGroup |
40 | * @param PageLookup $pageLookup |
41 | */ |
42 | public function __construct( |
43 | RepoGroup $repoGroup, |
44 | PageLookup $pageLookup |
45 | ) { |
46 | $this->repoGroup = $repoGroup; |
47 | $this->pageLookup = $pageLookup; |
48 | } |
49 | |
50 | /** |
51 | * @return ExistingPageRecord|null |
52 | */ |
53 | private function getPage(): ?ExistingPageRecord { |
54 | if ( $this->page === false ) { |
55 | $this->page = $this->pageLookup->getExistingPageByText( |
56 | $this->getValidatedParams()['title'], NS_FILE |
57 | ); |
58 | } |
59 | return $this->page; |
60 | } |
61 | |
62 | /** |
63 | * @return File|null |
64 | */ |
65 | private function getFile(): ?File { |
66 | if ( $this->file === false ) { |
67 | $page = $this->getPage(); |
68 | $this->file = |
69 | // @phan-suppress-next-line PhanTypeMismatchArgumentNullable |
70 | $this->repoGroup->findFile( $page, [ 'private' => $this->getAuthority() ] ) ?: null; |
71 | } |
72 | return $this->file; |
73 | } |
74 | |
75 | /** |
76 | * @param string $title |
77 | * @return Response |
78 | * @throws LocalizedHttpException |
79 | */ |
80 | public function run( $title ) { |
81 | $page = $this->getPage(); |
82 | |
83 | if ( !$page ) { |
84 | throw new LocalizedHttpException( |
85 | MessageValue::new( 'rest-nonexistent-title' )->plaintextParams( $title ), |
86 | 404 |
87 | ); |
88 | } |
89 | |
90 | if ( !$this->getAuthority()->authorizeRead( 'read', $page ) ) { |
91 | throw new LocalizedHttpException( |
92 | MessageValue::new( 'rest-permission-denied-title' )->plaintextParams( $title ), |
93 | 403 |
94 | ); |
95 | } |
96 | |
97 | $fileObj = $this->getFile(); |
98 | if ( !$fileObj || !$fileObj->exists() ) { |
99 | throw new LocalizedHttpException( |
100 | MessageValue::new( 'rest-cannot-load-file' )->plaintextParams( $title ), |
101 | 404 |
102 | ); |
103 | } |
104 | |
105 | $response = $this->getResponse( $fileObj ); |
106 | return $this->getResponseFactory()->createJson( $response ); |
107 | } |
108 | |
109 | /** |
110 | * @param File $file the file to load media links for |
111 | * @return array response data |
112 | */ |
113 | private function getResponse( File $file ): array { |
114 | [ $maxWidth, $maxHeight ] = self::getImageLimitsFromOption( |
115 | $this->getAuthority()->getUser(), 'imagesize' |
116 | ); |
117 | [ $maxThumbWidth, $maxThumbHeight ] = self::getImageLimitsFromOption( |
118 | $this->getAuthority()->getUser(), 'thumbsize' |
119 | ); |
120 | $transforms = [ |
121 | 'preferred' => [ |
122 | 'maxWidth' => $maxWidth, |
123 | 'maxHeight' => $maxHeight |
124 | ], |
125 | 'thumbnail' => [ |
126 | 'maxWidth' => $maxThumbWidth, |
127 | 'maxHeight' => $maxThumbHeight |
128 | ] |
129 | ]; |
130 | |
131 | return $this->getFileInfo( $file, $this->getAuthority(), $transforms ); |
132 | } |
133 | |
134 | public function needsWriteAccess() { |
135 | return false; |
136 | } |
137 | |
138 | public function getParamSettings() { |
139 | return [ |
140 | 'title' => [ |
141 | self::PARAM_SOURCE => 'path', |
142 | ParamValidator::PARAM_TYPE => 'string', |
143 | ParamValidator::PARAM_REQUIRED => true, |
144 | ], |
145 | ]; |
146 | } |
147 | |
148 | /** |
149 | * @return string|null |
150 | * @throws LocalizedHttpException |
151 | */ |
152 | protected function getETag(): ?string { |
153 | $file = $this->getFile(); |
154 | if ( !$file || !$file->exists() ) { |
155 | return null; |
156 | } |
157 | |
158 | return '"' . $file->getSha1() . '"'; |
159 | } |
160 | |
161 | /** |
162 | * @return string|null |
163 | * @throws LocalizedHttpException |
164 | */ |
165 | protected function getLastModified(): ?string { |
166 | $file = $this->getFile(); |
167 | if ( !$file || !$file->exists() ) { |
168 | return null; |
169 | } |
170 | |
171 | return $file->getTimestamp(); |
172 | } |
173 | |
174 | /** |
175 | * @return bool |
176 | */ |
177 | protected function hasRepresentation() { |
178 | $file = $this->getFile(); |
179 | return $file && $file->exists(); |
180 | } |
181 | } |