Completed
Pull Request — stable9 (#244)
by Joas
23:06 queued 11:08
created

ThemingController::updateLogo()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 37
Code Lines 24

Duplication

Lines 21
Ratio 56.76 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 24
c 1
b 0
f 0
nc 5
nop 0
dl 21
loc 37
rs 8.439
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016 Bjoern Schiessle <[email protected]>
4
 * @copyright Copyright (c) 2016 Lukas Reschke <[email protected]>
5
 *
6
 * @license GNU AGPL version 3 or any later version
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22
23
namespace OCA\Theming\Controller;
24
25
use OCA\Theming\Template;
26
use OCP\AppFramework\Controller;
27
use OCP\AppFramework\Http;
28
use OCP\AppFramework\Http\DataResponse;
29
use OCP\Files\IRootFolder;
30
use OCP\IConfig;
31
use OCP\IL10N;
32
use OCP\IRequest;
33
34
/**
35
 * Class ThemingController
36
 *
37
 * handle ajax requests to update the theme
38
 *
39
 * @package OCA\Theming\Controller
40
 */
41
class ThemingController extends Controller {
42
	/** @var Template */
43
	private $template;
44
	/** @var IL10N */
45
	private $l;
46
	/** @var IConfig */
47
	private $config;
48
	/** @var IRootFolder */
49
	private $rootFolder;
50
51
	/**
52
	 * ThemingController constructor.
53
	 *
54
	 * @param string $appName
55
	 * @param IRequest $request
56
	 * @param IConfig $config
57
	 * @param Template $template
58
	 * @param IL10N $l
59
	 * @param IRootFolder $rootFolder
60
	 */
61
	public function __construct(
62
		$appName,
63
		IRequest $request,
64
		IConfig $config,
65
		Template $template,
66
		IL10N $l,
67
		IRootFolder $rootFolder
68
	) {
69
		parent::__construct($appName, $request);
70
		
71
		$this->template = $template;
72
		$this->l = $l;
73
		$this->config = $config;
74
		$this->rootFolder = $rootFolder;
75
	}
76
77
	/**
78
	 * @param string $setting
79
	 * @param string $value
80
	 * @return DataResponse
81
	 * @internal param string $color
82
	 */
83 View Code Duplication
	public function updateStylesheet($setting, $value) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
84
		$this->template->set($setting, $value);
85
		return new DataResponse(
86
			[
87
				'data' =>
88
					[
89
						'message' => $this->l->t('Saved')
90
					],
91
				'status' => 'success'
92
			]
93
		);
94
	}
95
96
	/**
97
	 * Update the logos and background image
98
	 *
99
	 * @return DataResponse
100
	 */
101
	public function updateLogo() {
102
		$newLogo = $this->request->getUploadedFile('uploadlogo');
103
		$newBackgroundLogo = $this->request->getUploadedFile('upload-login-background');
104 View Code Duplication
		if (empty($newLogo) && empty($newBackgroundLogo)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
105
			return new DataResponse(
106
				[
107
					'data' => [
108
						'message' => $this->l->t('No file uploaded')
109
					]
110
				],
111
				Http::STATUS_UNPROCESSABLE_ENTITY);
112
		}
113
		$name = '';
114 View Code Duplication
		if(!empty($newLogo)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
115
			$target = $this->rootFolder->newFile('themedinstancelogo');
116
			stream_copy_to_stream(fopen($newLogo['tmp_name'], 'r'), $target->fopen('w'));
117
			$this->template->set('logoMime', $newLogo['type']);
118
			$name = $newLogo['name'];
119
		}
120 View Code Duplication
		if(!empty($newBackgroundLogo)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
121
			$target = $this->rootFolder->newFile('themedbackgroundlogo');
122
			stream_copy_to_stream(fopen($newBackgroundLogo['tmp_name'], 'r'), $target->fopen('w'));
123
			$this->template->set('backgroundMime', $newBackgroundLogo['type']);
124
			$name = $newBackgroundLogo['name'];
125
		}
126
127
		return new DataResponse(
128
			[
129
				'data' =>
130
					[
131
						'name' => $name,
132
						'message' => $this->l->t('Saved')
133
					],
134
				'status' => 'success'
135
			]
136
		);
137
	}
138
139
	/**
140
	 * Revert setting to default value
141
	 *
142
	 * @param string $setting setting which should be reverted
143
	 * @return DataResponse
144
	 */
145 View Code Duplication
	public function undo($setting) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
146
		$value = $this->template->undo($setting);
147
		return new DataResponse(
148
			[
149
				'data' =>
150
					[
151
						'value' => $value,
152
						'message' => $this->l->t('Saved')
153
					],
154
				'status' => 'success'
155
			]
156
		);
157
	}
158
159
	/**
160
	 * @PublicPage
161
	 * @NoCSRFRequired
162
	 *
163
	 * @return Http\StreamResponse
164
	 */
165 View Code Duplication
	public function getLogo() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
166
		$pathToLogo = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/') . '/themedinstancelogo';
167
		if(!file_exists($pathToLogo)) {
168
			return new DataResponse();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \OCP\AppFramework\Http\DataResponse(); (OCP\AppFramework\Http\DataResponse) is incompatible with the return type documented by OCA\Theming\Controller\ThemingController::getLogo of type OCP\AppFramework\Http\StreamResponse.

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...
169
		}
170
171
		\OC_Response::setExpiresHeader(gmdate('D, d M Y H:i:s', time() + (60*60*24*45)) . ' GMT');
172
		\OC_Response::enableCaching();
173
		$response = new Http\StreamResponse($pathToLogo);
174
		$response->cacheFor(3600);
175
		$response->addHeader('Content-Disposition', 'attachment');
176
		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'logoMime', ''));
177
		return $response;
178
	}
179
180
	/**
181
	 * @PublicPage
182
	 * @NoCSRFRequired
183
	 *
184
	 * @return Http\StreamResponse
185
	 */
186 View Code Duplication
	public function getLoginBackground() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
187
		$pathToLogo = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/') . '/themedbackgroundlogo';
188
		if(!file_exists($pathToLogo)) {
189
			return new DataResponse();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \OCP\AppFramework\Http\DataResponse(); (OCP\AppFramework\Http\DataResponse) is incompatible with the return type documented by OCA\Theming\Controller\T...ler::getLoginBackground of type OCP\AppFramework\Http\StreamResponse.

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...
190
		}
191
192
		\OC_Response::setExpiresHeader(gmdate('D, d M Y H:i:s', time() + (60*60*24*45)) . ' GMT');
193
		\OC_Response::enableCaching();
194
		$response = new Http\StreamResponse($pathToLogo);
195
		$response->cacheFor(3600);
196
		$response->addHeader('Content-Disposition', 'attachment');
197
		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'backgroundMime', ''));
198
		return $response;
199
	}
200
201
	/**
202
	 * @NoCSRFRequired
203
	 * @PublicPage
204
	 *
205
	 * @return Http\DataDownloadResponse
206
	 */
207
	public function getStylesheet() {
208
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
209
		$responseCss = '';
210
		$color = $this->config->getAppValue($this->appName, 'color');
211
		if($color !== '') {
212
			$responseCss .= sprintf(
213
				'#body-user #header,#body-settings #header,#body-public #header {background-color: %s}',
214
				$color
215
			);
216
		}
217
		$logo = $this->config->getAppValue($this->appName, 'logoMime');
218
		if($logo !== '') {
219
			$responseCss .= sprintf('#header .logo {
220
				background-image: url(\'./logo?v='.$cacheBusterValue.'\');
221
			}
222
			#header .logo-icon {
223
				background-image: url(\'./logo?v='.$cacheBusterValue.'\');
224
				background-size: 62px 34px;
225
			}'
226
			);
227
		}
228
		$backgroundLogo = $this->config->getAppValue($this->appName, 'backgroundMime');
229
		if($backgroundLogo !== '') {
230
			$responseCss .= '#body-login {
231
				background-image: url(\'./loginbackground?v='.$cacheBusterValue.'\');
232
			}';
233
		}
234
235
		\OC_Response::setExpiresHeader(gmdate('D, d M Y H:i:s', time() + (60*60*24*45)) . ' GMT');
236
		\OC_Response::enableCaching();
237
		$response = new Http\DataDownloadResponse($responseCss, 'style.css', 'text/css');
238
		$response->cacheFor(3600);
239
		return $response;
240
	}
241
}
242