Completed
Push — master ( f2b8d7...c7becd )
by Roeland
11:44 queued 10:17
created

TemplatesController::add()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 35
ccs 0
cts 27
cp 0
rs 8.7377
c 0
b 0
f 0
cc 6
nc 4
nop 0
crap 42
1
<?php
2
declare(strict_types=1);
3
/**
4
 * @copyright Copyright (c) 2018 John Molakvoæ <[email protected]>
5
 *
6
 * @author John Molakvoæ <[email protected]>
7
 *
8
 * @license GNU AGPL version 3 or any later version
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License as
12
 * published by the Free Software Foundation, either version 3 of the
13
 * License, or (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License
21
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 */
24
25
namespace OCA\Richdocuments\Controller;
26
27
use OCA\Richdocuments\TemplateManager;
28
use OCP\AppFramework\Controller;
29
use OCP\AppFramework\Http;
30
use OCP\AppFramework\Http\DataResponse;
31
use OCP\AppFramework\Http\FileDisplayResponse;
32
use OCP\AppFramework\Http\JSONResponse;
33
use OCP\AppFramework\Http\NotFoundResponse;
34
use OCP\Files\Node;
35
use OCP\Files\NotFoundException;
36
use OCP\Files\SimpleFS\ISimpleFile;
37
use OCP\IL10N;
38
use OCP\IPreview;
39
use OCP\IRequest;
40
use OC\Files\Filesystem;
41
42
class TemplatesController extends Controller {
43
	/** @var IL10N */
44
	private $l10n;
45
46
	/** @var TemplateManager */
47
	private $manager;
48
49
	/** @var IPreview */
50
	private $preview;
51
52
	/** @var int Max template size */
53
	private $maxSize = 20 * 1024 * 1024;
54
55
	/**
56
	 * Templates controller
57
	 *
58
	 * @param string $appName
59
	 * @param IRequest $request
60
	 * @param L10N $l10n
61
	 * @param TemplateManager $manager
62
	 * @param IPreview $preview
63
	 */
64
	public function __construct($appName,
65
								IRequest $request,
66
								IL10N $l10n,
67
								TemplateManager $manager,
68
								IPreview $preview) {
69
		parent::__construct($appName, $request);
70
71
		$this->appName = $appName;
72
		$this->request = $request;
73
		$this->l10n    = $l10n;
74
		$this->manager = $manager;
75
		$this->preview = $preview;
76
	}
77
78
	/**
79
	 * @NoAdminRequired
80
	 * @NoCSRFRequired
81
	 *
82
	 * Get preview for a specific template
83
	 *
84
	 * @param int $fileId The template id
85
	 * @param int $x
86
	 * @param int $y
87
	 * @param bool $a
88
	 * @param bool $forceIcon
89
	 * @param string $mode
90
	 * @return DataResponse
91
	 * @throws NotFoundResponse
92
	 */
93
	public function getPreview($fileId,
94
		$x = 150,
95
		$y = 150,
96
		$a = false,
97
		$forceIcon = true,
98
		$mode = 'fill') {
99
100
		if ($fileId === '' || $x === 0 || $y === 0) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $fileId (integer) and '' (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
101
			return new DataResponse([], Http::STATUS_BAD_REQUEST);
102
		}
103
104
		try {
105
			$template = $this->manager->get($fileId);
106
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
107
			return new DataResponse([], Http::STATUS_NOT_FOUND);
108
		}
109
110
		if ($template instanceof ISimpleFile) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\SimpleFS\ISimpleFile does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
111
			return new DataResponse([], Http::STATUS_NOT_FOUND);
112
		}
113
114
		return $this->fetchPreview($template, $x, $y, $a, $forceIcon, $mode);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->fetchPrevi...$a, $forceIcon, $mode); (OCP\AppFramework\Http\Response) is incompatible with the return type documented by OCA\Richdocuments\Contro...sController::getPreview of type OCP\AppFramework\Http\DataResponse.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
115
	}
116
117
	/**
118
	 * Add a global template
119
	 *
120
	 * @return JSONResponse
121
	 */
122
	public function add() {
123
		$files = $this->request->getUploadedFile('files');
124
125
		if (!is_null($files)) {
126
			if ($files['error'][0] === 0
127
				&& is_uploaded_file($files['tmp_name'][0])
128
				&& !Filesystem::isFileBlacklisted($files['tmp_name'][0])) {
129
130
				// TODO: ensure the size limit is decent for preview
131
				if ($files['size'][0] > $this->maxSize) {
132
					return new JSONResponse(
133
						['data' => ['message' => $this->l10n->t('File is too big')]],
134
						Http::STATUS_BAD_REQUEST
135
					);
136
				}
137
138
				$templateName = $files['name'][0];
139
				$templateFile = file_get_contents($files['tmp_name'][0]);
140
141
				unlink($files['tmp_name'][0]);
142
143
				$template = $this->manager->add($templateName, $templateFile);
144
145
				return new JSONResponse(
146
					['data' => $template],
147
					Http::STATUS_CREATED
148
				);
149
			}
150
		}
151
152
		return new JSONResponse(
153
			['data' => ['message' => $this->l10n->t('Invalid file provided')]],
154
			Http::STATUS_BAD_REQUEST
155
		);
156
	}
157
158
	/**
159
	 * Delete a global template
160
	 *
161
	 * @param int $fileId
162
	 * @return JSONResponse
163
	 */
164
	public function delete($fileId) {
165
		try {
166
			$this->manager->delete($fileId);
167
168
			return new JSONResponse(
169
				['data' => ['status' => 'success']],
170
				Http::STATUS_NO_CONTENT
171
			);
172
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
173
			return new JSONResponse(
174
				['data' => ['message' => $this->l10n->t('Template not found')]],
175
				Http::STATUS_NOT_FOUND
176
			);
177
		}
178
	}
179
180
	/**
181
	 * @param Node $node
182
	 * @param int $x
183
	 * @param int $y
184
	 * @param bool $a
185
	 * @param bool $forceIcon
186
	 * @param string $mode
187
	 * @return DataResponse|FileDisplayResponse
188
	 */
189
	private function fetchPreview(
190
		Node $node,
191
		$x,
192
		$y,
193
		$a = false,
194
		$forceIcon = true,
195
		string $mode): Http\Response {
196
197
		if (!($node instanceof Node) || (!$forceIcon && !$this->preview->isAvailable($node))) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\Node does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
198
			return new DataResponse([], Http::STATUS_NOT_FOUND);
199
		}
200
		if (!$node->isReadable()) {
201
			return new DataResponse([], Http::STATUS_FORBIDDEN);
202
		}
203
204
		try {
205
			$f        = $this->preview->getPreview($node, $x, $y, !$a, $mode);
206
			$response = new FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]);
207
			$response->cacheFor(3600 * 24);
208
209
			return $response;
210
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
211
			return new DataResponse([], Http::STATUS_NOT_FOUND);
212
		} catch (\InvalidArgumentException $e) {
213
			return new DataResponse([], Http::STATUS_BAD_REQUEST);
214
		}
215
	}
216
}
217