Passed
Push — master ( 320fcc...a4168d )
by Pauli
12:49
created

PlaylistImport::executeForUser()   A

Complexity

Conditions 6
Paths 7

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
c 1
b 0
f 0
dl 0
loc 18
rs 9.2222
cc 6
nc 7
nop 5
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 2021
11
 */
12
13
namespace OCA\Music\Command;
14
15
use OCA\Music\AppFramework\BusinessLayer\BusinessLayerException;
16
use OCA\Music\BusinessLayer\PlaylistBusinessLayer;
17
use OCA\Music\Db\Playlist;
18
use OCA\Music\Utility\PlaylistFileService;
19
20
use OCP\Files\Folder;
21
use OCP\Files\IRootFolder;
22
23
use Symfony\Component\Console\Input\InputInterface;
24
use Symfony\Component\Console\Input\InputOption;
25
use Symfony\Component\Console\Output\OutputInterface;
26
27
class PlaylistImport extends BaseCommand {
28
	/** @var IRootFolder */
29
	private $rootFolder;
30
	/** @var PlaylistBusinessLayer */
31
	private $businessLayer;
32
	/** @var PlaylistFileService */
33
	private $playlistFileService;
34
35
	public function __construct(
36
			\OCP\IUserManager $userManager,
37
			\OCP\IGroupManager $groupManager,
38
			IRootFolder $rootFolder,
39
			PlaylistBusinessLayer $playlistBusinessLayer,
40
			PlaylistFileService $playlistFileService) {
41
		$this->rootFolder = $rootFolder;
42
		$this->businessLayer = $playlistBusinessLayer;
43
		$this->playlistFileService = $playlistFileService;
44
		parent::__construct($userManager, $groupManager);
45
	}
46
47
	protected function doConfigure() : void {
48
		$this
49
			->setName('music:playlist-import')
50
			->setDescription('import user playlist(s) from file(s)')
51
			->addOption(
52
				'file',
53
				null,
54
				InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
55
				'path of the playlist file, relative to the user home folder'
56
			)
57
			->addOption(
58
				'overwrite',
59
				null,
60
				InputOption::VALUE_NONE,
61
				'overwrite the target playlist if it already exists'
62
			)
63
			->addOption(
64
				'append',
65
				null,
66
				InputOption::VALUE_NONE,
67
				'append imported tracks to an existing playlist if found'
68
			)
69
		;
70
	}
71
72
	protected function doExecute(InputInterface $input, OutputInterface $output, array $users) : void {
73
		$files = $input->getOption('file');
74
		$overwrite = (bool)$input->getOption('overwrite');
75
		$append = (bool)$input->getOption('append');
76
77
		if (empty($files)) {
78
			throw new \InvalidArgumentException('At least one <error>file</error> argument must be given');
79
		}
80
81
		if ($overwrite && $append) {
82
			throw new \InvalidArgumentException('The options <error>overwrite</error> and <error>append</error> are mutually exclusive');
83
		}
84
85
		if ($input->getOption('all')) {
86
			$this->userManager->callForAllUsers(function($user) use ($output, $files, $overwrite, $append) {
87
				$this->executeForUser($user->getUID(), $files, $overwrite, $append, $output);
88
			});
89
		} else {
90
			foreach ($users as $userId) {
91
				$this->executeForUser($userId, $files, $overwrite, $append, $output);
92
			}
93
		}
94
	}
95
96
	private function executeForUser(string $userId, array $files, bool $overwrite, bool $append, OutputInterface $output) : void {
97
		$output->writeln("Importing playlist(s) for <info>$userId</info>...");
98
99
		$userFolder = $this->rootFolder->getUserFolder($userId);
100
101
		foreach ($files as $filePath) {
102
			$name = \pathinfo($filePath, PATHINFO_FILENAME);
103
			$existingLists = $this->businessLayer->findAllByName($name, $userId);
0 ignored issues
show
Bug introduced by
It seems like $name can also be of type array; however, parameter $name of OCA\Music\BusinessLayer\...sLayer::findAllByName() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

103
			$existingLists = $this->businessLayer->findAllByName(/** @scrutinizer ignore-type */ $name, $userId);
Loading history...
104
			if (\count($existingLists) === 0) {
105
				$playlist = $this->businessLayer->create($name, $userId);
106
			} elseif (!$overwrite && !$append) {
107
				$output->writeln("  The playlist <error>$name</error> already exists, give argument <info>overwrite</info> or <info>append</info>");
108
			} else {
109
				$playlist = $existingLists[0];
110
			}
111
112
			if ($playlist !== null) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $playlist does not seem to be defined for all execution paths leading up to this point.
Loading history...
113
				$this->importPlaylist($filePath, $playlist, $userId, $userFolder, $overwrite, $output);
114
			}
115
		}
116
	}
117
118
	private function importPlaylist(string $filePath, Playlist $playlist, string $userId, Folder $userFolder, bool $overwrite, OutputInterface $output) : void {
119
		try {
120
			$id = $playlist->getId();
121
			$result = $this->playlistFileService->importFromFile($playlist->getId(), $userId, $userFolder, $filePath, $overwrite ? 'overwrite' : 'append');
122
			$output->writeln("  <info>{$result['imported_count']}</info> tracks were imported to playlist <info>$id</info> from <info>$filePath</info>");
123
		} catch (BusinessLayerException $ex) {
124
			$output->writeln("  User <info>$userId</info> has no playlist with id <error>$id</error>");
125
		} catch (\OCP\Files\NotFoundException $ex) {
126
			$output->writeln("  Invalid file path <error>$filePath</error>");
127
		} catch (\UnexpectedValueException $ex) {
128
			$output->writeln("  The file <error>$filePath</error> is not a supported playlist file");
129
		}
130
	}
131
}
132