Passed
Push — master ( ce9a66...c3a2b5 )
by Pauli
02:52
created

CoverApiController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 8
nc 1
nop 9
dl 0
loc 17
rs 10
c 1
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php declare(strict_types=1);
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 Pauli Järvinen <[email protected]>
10
 * @copyright Pauli Järvinen 2024
11
 */
12
13
namespace OCA\Music\Controller;
14
15
use OCP\AppFramework\Controller;
16
use OCP\AppFramework\Http;
17
use OCP\AppFramework\Http\RedirectResponse;
18
use OCP\AppFramework\Http\Response;
19
use OCP\Files\IRootFolder;
20
use OCP\IRequest;
21
use OCP\IURLGenerator;
22
23
use OCA\Music\AppFramework\BusinessLayer\BusinessLayerException;
24
use OCA\Music\AppFramework\Core\Logger;
25
use OCA\Music\BusinessLayer\AlbumBusinessLayer;
26
use OCA\Music\BusinessLayer\ArtistBusinessLayer;
27
use OCA\Music\Db\Album;
28
use OCA\Music\Db\Artist;
29
use OCA\Music\Http\ErrorResponse;
30
use OCA\Music\Http\FileResponse;
31
use OCA\Music\Utility\CoverHelper;
32
33
class CoverApiController extends Controller {
34
35
	private IURLGenerator $urlGenerator;
36
	private IRootFolder $rootFolder;
37
	private ArtistBusinessLayer $artistBusinessLayer;
38
	private AlbumBusinessLayer $albumBusinessLayer;
39
	private CoverHelper $coverHelper;
40
	private ?string $userId;
41
	private Logger $logger;
42
43
	public function __construct(string $appname,
44
								IRequest $request,
45
								IURLGenerator $urlGenerator,
46
								IRootFolder $rootFolder,
47
								ArtistBusinessLayer $artistBusinessLayer,
48
								AlbumBusinessLayer $albumBusinessLayer,
49
								CoverHelper $coverHelper,
50
								?string $userId, // null if this gets called after the user has logged out or on a public page
51
								Logger $logger) {
52
		parent::__construct($appname, $request);
53
		$this->urlGenerator = $urlGenerator;
54
		$this->rootFolder = $rootFolder;
55
		$this->artistBusinessLayer = $artistBusinessLayer;
56
		$this->albumBusinessLayer = $albumBusinessLayer;
57
		$this->coverHelper = $coverHelper;
58
		$this->userId = $userId;
59
		$this->logger = $logger;
60
	}
61
62
	/**
63
	 * @PublicPage
64
	 * @NoCSRFRequired
65
	 */
66
	public function albumCover(int $albumId, $originalSize, $coverToken) {
67
		try {
68
			$userId = $this->userId ?? $this->coverHelper->getUserForAccessToken($coverToken);
69
			$album = $this->albumBusinessLayer->find($albumId, $userId);
70
			return $this->cover($album, $userId, $originalSize);
71
		} catch (BusinessLayerException | \OutOfBoundsException $ex) {
72
			$this->logger->log("Failed to get the requested cover: $ex", 'debug');
73
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
74
		}
75
	}
76
77
	/**
78
	 * @PublicPage
79
	 * @NoCSRFRequired
80
	 */
81
	public function artistCover(int $artistId, $originalSize, $coverToken) {
82
		try {
83
			$userId = $this->userId ?? $this->coverHelper->getUserForAccessToken($coverToken);
84
			$artist = $this->artistBusinessLayer->find($artistId, $userId);
85
			return $this->cover($artist, $userId, $originalSize);
86
		} catch (BusinessLayerException | \OutOfBoundsException $ex) {
87
			$this->logger->log("Failed to get the requested cover: $ex", 'debug');
88
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
89
		}
90
	}
91
92
	/**
93
	 * @PublicPage
94
	 * @NoCSRFRequired
95
	 */
96
	public function cachedCover(string $hash, ?string $coverToken) {
97
		try {
98
			$userId = $this->userId ?? $this->coverHelper->getUserForAccessToken($coverToken);
99
			$coverData = $this->coverHelper->getCoverFromCache($hash, $userId);
100
			if ($coverData === null) {
101
				throw new \OutOfBoundsException("Cover with hash $hash not found");
102
			}
103
			$response =  new FileResponse($coverData);
104
			// instruct also the client-side to cache the result, this is safe
105
			// as the resource URI contains the image hash
106
			self::setClientCaching($response);
107
			return $response;
108
		} catch (\OutOfBoundsException $ex) {
109
			$this->logger->log("Failed to get the requested cover: $ex", 'debug');
110
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
111
		}
112
	}
113
114
	/**
115
	 * @param Artist|Album $entity
116
	 */
117
	private function cover($entity, string $userId, $originalSize) {
118
		$originalSize = \filter_var($originalSize, FILTER_VALIDATE_BOOLEAN);
119
		$userFolder = $this->rootFolder->getUserFolder($userId);
120
121
		if ($originalSize) {
122
			// cover requested in original size, without scaling or cropping
123
			$cover = $this->coverHelper->getCover($entity, $userId, $userFolder, CoverHelper::DO_NOT_CROP_OR_SCALE);
124
			if ($cover !== null) {
125
				return new FileResponse($cover);
126
			} else {
127
				return new ErrorResponse(Http::STATUS_NOT_FOUND);
128
			}
129
		} else {
130
			$coverAndHash = $this->coverHelper->getCoverAndHash($entity, $userId, $userFolder);
131
132
			if ($coverAndHash['hash'] !== null && $this->userId !== null) {
133
				// Cover is in cache. Return a redirection response so that the client
134
				// will fetch the content through a cacheable route.
135
				// The redirection is not used in case this is a call from the Firefox mediaSession API with not
136
				// logged in user.
137
				$link = $this->urlGenerator->linkToRoute('music.coverApi.cachedCover', ['hash' => $coverAndHash['hash']]);
138
				return new RedirectResponse($link);
139
			} elseif ($coverAndHash['data'] !== null) {
140
				return new FileResponse($coverAndHash['data']);
141
			} else {
142
				return new ErrorResponse(Http::STATUS_NOT_FOUND);
143
			}
144
		}
145
	}
146
147
	private static function setClientCaching(Response &$httpResponse, int $days=365) : void {
148
		$httpResponse->cacheFor($days * 24 * 60 * 60);
149
		$httpResponse->addHeader('Pragma', 'cache');
150
	}
151
}
152