Completed
Pull Request — master (#777)
by Pauli
16:48 queued 14:24
created

PlaylistApiController::parseFile()   A

Complexity

Conditions 2
Paths 4

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 12
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 15
ccs 0
cts 11
cp 0
crap 6
rs 9.8666
1
<?php
2
3
/**
4
 * ownCloud - Music app
5
 *
6
 * This file is licensed under the Affero General Public License version 3 or
7
 * later. See the COPYING file.
8
 *
9
 * @author Morris Jobke <[email protected]>
10
 * @author Pauli Järvinen <[email protected]>
11
 * @copyright Morris Jobke 2013, 2014
12
 * @copyright Pauli Järvinen 2017 - 2020
13
 */
14
15
namespace OCA\Music\Controller;
16
17
use \OCP\AppFramework\Controller;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Controller was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use \OCP\AppFramework\Http;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Http was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use \OCP\AppFramework\Http\JSONResponse;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Http\JSONResponse was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
21
use \OCP\Files\Folder;
0 ignored issues
show
Bug introduced by
The type OCP\Files\Folder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
use \OCP\IRequest;
0 ignored issues
show
Bug introduced by
The type OCP\IRequest was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use \OCP\IURLGenerator;
0 ignored issues
show
Bug introduced by
The type OCP\IURLGenerator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
25
use \OCA\Music\AppFramework\BusinessLayer\BusinessLayerException;
26
use \OCA\Music\AppFramework\Core\Logger;
27
use \OCA\Music\BusinessLayer\AlbumBusinessLayer;
28
use \OCA\Music\BusinessLayer\ArtistBusinessLayer;
29
use \OCA\Music\BusinessLayer\PlaylistBusinessLayer;
30
use \OCA\Music\BusinessLayer\TrackBusinessLayer;
31
use \OCA\Music\Db\Playlist;
32
use \OCA\Music\Http\ErrorResponse;
33
use \OCA\Music\Utility\APISerializer;
34
use \OCA\Music\Utility\PlaylistFileService;
35
36
class PlaylistApiController extends Controller {
37
	private $urlGenerator;
38
	private $playlistBusinessLayer;
39
	private $artistBusinessLayer;
40
	private $albumBusinessLayer;
41
	private $trackBusinessLayer;
42
	private $playlistFileService;
43
	private $userId;
44
	private $userFolder;
45
	private $l10n;
46
	private $logger;
47
48
	public function __construct($appname,
49
								IRequest $request,
50
								IURLGenerator $urlGenerator,
51
								PlaylistBusinessLayer $playlistBusinessLayer,
52
								ArtistBusinessLayer $artistBusinessLayer,
53
								AlbumBusinessLayer $albumBusinessLayer,
54
								TrackBusinessLayer $trackBusinessLayer,
55
								PlaylistFileService $playlistFileService,
56
								$userId,
57
								Folder $userFolder,
58
								$l10n,
59
								Logger $logger) {
60
		parent::__construct($appname, $request);
61
		$this->urlGenerator = $urlGenerator;
62
		$this->playlistBusinessLayer = $playlistBusinessLayer;
63
		$this->artistBusinessLayer = $artistBusinessLayer;
64
		$this->albumBusinessLayer = $albumBusinessLayer;
65
		$this->trackBusinessLayer = $trackBusinessLayer;
66
		$this->playlistFileService = $playlistFileService;
67
		$this->userId = $userId;
68
		$this->userFolder = $userFolder;
69
		$this->l10n = $l10n;
70
		$this->logger = $logger;
71
	}
72
73
	/**
74
	 * lists all playlists
75
	 *
76
	 * @NoAdminRequired
77
	 * @NoCSRFRequired
78
	 */
79
	public function getAll() {
80
		$playlists = $this->playlistBusinessLayer->findAll($this->userId);
81
		$serializer = new APISerializer();
82
83
		return $serializer->serialize($playlists);
84
	}
85
86
	/**
87
	 * creates a playlist
88
	 *
89
	 * @NoAdminRequired
90
	 * @NoCSRFRequired
91
	 */
92
	public function create($name, $trackIds) {
93
		$playlist = $this->playlistBusinessLayer->create($name, $this->userId);
94
95
		// add trackIds to the newly created playlist if provided
96
		if (!empty($trackIds)) {
97
			$playlist = $this->playlistBusinessLayer->addTracks(
98
					self::toIntArray($trackIds), $playlist->getId(), $this->userId);
99
		}
100
101
		return $playlist->toAPI();
102
	}
103
104
	/**
105
	 * deletes a playlist
106
	 * @param  int $id playlist ID
107
	 *
108
	 * @NoAdminRequired
109
	 * @NoCSRFRequired
110
	 */
111
	public function delete($id) {
112
		$this->playlistBusinessLayer->delete($id, $this->userId);
113
		return [];
114
	}
115
116
	/**
117
	 * lists a single playlist
118
	 * @param  int $id playlist ID
119
	 *
120
	 * @NoAdminRequired
121
	 * @NoCSRFRequired
122
	 */
123
	public function get($id, $fulltree) {
124
		try {
125
			$playlist = $this->playlistBusinessLayer->find($id, $this->userId);
126
127
			$fulltree = \filter_var($fulltree, FILTER_VALIDATE_BOOLEAN);
128
			if ($fulltree) {
129
				return $this->toFullTree($playlist);
130
			} else {
131
				return $playlist->toAPI();
132
			}
133
		} catch (BusinessLayerException $ex) {
134
			return new ErrorResponse(Http::STATUS_NOT_FOUND, $ex->getMessage());
135
		}
136
	}
137
138
	private function toFullTree($playlist) {
139
		$songs = [];
140
141
		// Get all track information for all the tracks of the playlist
142
		foreach ($playlist->getTrackIdsAsArray() as $trackId) {
143
			$song = $this->trackBusinessLayer->find($trackId, $this->userId);
144
			$song->setAlbum($this->albumBusinessLayer->find($song->getAlbumId(), $this->userId));
145
			$song->setArtist($this->artistBusinessLayer->find($song->getArtistId(), $this->userId));
146
			$songs[] = $song->toAPI($this->urlGenerator);
147
		}
148
149
		$result = $playlist->toAPI();
150
		unset($result['trackIds']);
151
		$result['tracks'] = $songs;
152
153
		return $result;
154
	}
155
156
	/**
157
	 * update a playlist
158
	 * @param int $id playlist ID
159
	 * @param string|null $name
160
	 * @param string|null $comment
161
	 *
162
	 * @NoAdminRequired
163
	 * @NoCSRFRequired
164
	 */
165
	public function update($id, $name, $comment) {
166
		$result = null;
167
		if ($name !== null) {
168
			$result = $this->modifyPlaylist('rename', [$name, $id, $this->userId]); 
169
		}
170
		if ($comment !== null) {
171
			$result = $this->modifyPlaylist('setComment', [$comment, $id, $this->userId]);
172
		}
173
		if ($result === null) {
174
			$result = new ErrorResponse(Http::STATUS_BAD_REQUEST, "at least one of the args ['name', 'comment'] must be given");
175
		}
176
		return $result;
177
	}
178
179
	/**
180
	 * add tracks to a playlist
181
	 * @param  int $id playlist ID
182
	 *
183
	 * @NoAdminRequired
184
	 * @NoCSRFRequired
185
	 */
186
	public function addTracks($id, $trackIds) {
187
		return $this->modifyPlaylist('addTracks', [self::toIntArray($trackIds), $id, $this->userId]);
188
	}
189
190
	/**
191
	 * removes tracks from a playlist
192
	 * @param  int $id playlist ID
193
	 *
194
	 * @NoAdminRequired
195
	 * @NoCSRFRequired
196
	 */
197
	public function removeTracks($id, $indices) {
198
		return $this->modifyPlaylist('removeTracks', [self::toIntArray($indices), $id, $this->userId]);
199
	}
200
201
	/**
202
	 * moves single track on playlist to a new position
203
	 * @param  int $id playlist ID
204
	 *
205
	 * @NoAdminRequired
206
	 * @NoCSRFRequired
207
	 */
208
	public function reorder($id, $fromIndex, $toIndex) {
209
		return $this->modifyPlaylist('moveTrack',
210
				[$fromIndex, $toIndex, $id, $this->userId]);
211
	}
212
213
	/**
214
	 * export the playlist to a file
215
	 * @param int $id playlist ID
216
	 * @param string $path parent folder path
217
	 * @param string $oncollision action to take on file name collision,
218
	 *								supported values:
219
	 *								- 'overwrite' The existing file will be overwritten
220
	 *								- 'keepboth' The new file is named with a suffix to make it unique
221
	 *								- 'abort' (default) The operation will fail
222
	 *
223
	 * @NoAdminRequired
224
	 * @NoCSRFRequired
225
	 */
226
	public function exportToFile($id, $path, $oncollision) {
227
		try {
228
			$exportedFilePath = $this->playlistFileService->exportToFile($id, $path, $oncollision);
229
			return new JSONResponse(['wrote_to_file' => $exportedFilePath]);
230
		}
231
		catch (BusinessLayerException $ex) {
232
			return new ErrorResponse(Http::STATUS_NOT_FOUND, 'playlist not found');
233
		}
234
		catch (\OCP\Files\NotFoundException $ex) {
0 ignored issues
show
Bug introduced by
The type OCP\Files\NotFoundException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
235
			return new ErrorResponse(Http::STATUS_NOT_FOUND, 'folder not found');
236
		}
237
		catch (\RuntimeException $ex) {
238
			return new ErrorResponse(Http::STATUS_CONFLICT, $ex->getMessage());
239
		}
240
		catch (\OCP\Files\NotPermittedException $ex) {
0 ignored issues
show
Bug introduced by
The type OCP\Files\NotPermittedException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
241
			return new ErrorResponse(Http::STATUS_FORBIDDEN, 'user is not allowed to write to the target file');
242
		}
243
	}
244
245
	/**
246
	 * import playlist contents from a file
247
	 * @param int $id playlist ID
248
	 * @param string $filePath path of the file to import
249
	 *
250
	 * @NoAdminRequired
251
	 * @NoCSRFRequired
252
	 */
253
	public function importFromFile($id, $filePath) {
254
		try {
255
			$result = $this->playlistFileService->importFromFile($id, $filePath);
256
			$result['playlist'] = $result['playlist']->toAPI();
257
			return $result;
258
		}
259
		catch (BusinessLayerException $ex) {
260
			return new ErrorResponse(Http::STATUS_NOT_FOUND, 'playlist not found');
261
		}
262
		catch (\OCP\Files\NotFoundException $ex) {
263
			return new ErrorResponse(Http::STATUS_NOT_FOUND, 'playlist file not found');
264
		}
265
	}
266
267
	/**
268
	 * read and parse a playlist file
269
	 * @param int $fileId ID of the file to parse
270
	 *
271
	 * @NoAdminRequired
272
	 * @NoCSRFRequired
273
	 */
274
	public function parseFile($fileId) {
275
		try {
276
			$result = $this->playlistFileService->parseFile($fileId);
277
			$result['files'] = \array_map(function($file) {
278
				return [
279
					'id' => $file->getId(),
280
					'name' => $file->getName(),
281
					'path' => $this->userFolder->getRelativePath($file->getParent()->getPath()),
282
					'mimetype' => $file->getMimeType()
283
				];
284
			}, $result['files']);
285
			return new JSONResponse($result);
286
		}
287
		catch (\OCP\Files\NotFoundException $ex) {
288
			return new ErrorResponse(Http::STATUS_NOT_FOUND, 'playlist file not found');
289
		}
290
	}
291
292
	/**
293
	 * Modify playlist by calling a supplied method from PlaylistBusinessLayer
294
	 * @param string $funcName  Name of a function to call from PlaylistBusinessLayer
295
	 * @param array $funcParams Parameters to pass to the function 'funcName'
296
	 * @return \OCP\AppFramework\Http\JSONResponse JSON representation of the modified playlist
297
	 */
298
	private function modifyPlaylist($funcName, $funcParams) {
299
		try {
300
			$playlist = \call_user_func_array([$this->playlistBusinessLayer, $funcName], $funcParams);
301
			return $playlist->toAPI();
302
		} catch (BusinessLayerException $ex) {
303
			return new ErrorResponse(Http::STATUS_NOT_FOUND, $ex->getMessage());
304
		}
305
	}
306
307
	/**
308
	 * Get integer array passed as parameter to the Playlist API
309
	 * @param string $listAsString Comma-separated integer values in string
310
	 * @return int[]
311
	 */
312
	private static function toIntArray($listAsString) {
313
		return \array_map('intval', \explode(',', $listAsString));
314
	}
315
}
316