Passed
Push — master ( 0837cd...cb2cf5 )
by Pauli
02:00
created

Maintenance::removeAlbumsWithNoArtist()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 2
ccs 2
cts 2
cp 1
crap 1
rs 10
c 1
b 0
f 0
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 2014
12
 * @copyright Pauli Järvinen 2017 - 2020
13
 */
14
15
namespace OCA\Music\Db;
16
17
use OCP\IDBConnection;
0 ignored issues
show
Bug introduced by
The type OCP\IDBConnection 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
19
use \OCA\Music\AppFramework\Core\Logger;
20
21
class Maintenance {
22
23
	/** @var IDBConnection */
24
	private $db;
25
	/** @var Logger */
26
	private $logger;
27
28 1
	public function __construct(IDBConnection $db, Logger $logger) {
29 1
		$this->db = $db;
30 1
		$this->logger = $logger;
31 1
	}
32
33
	/**
34
	 * Remove cover_file_id from album if the corresponding file does not exist
35
	 */
36 1
	private function removeObsoleteCoverImagesFromTable($table) {
37 1
		return $this->db->executeUpdate(
38 1
			"UPDATE `*PREFIX*$table` SET `cover_file_id` = NULL
39
			WHERE `cover_file_id` IS NOT NULL AND `cover_file_id` IN (
40
				SELECT `cover_file_id` FROM (
41 1
					SELECT `cover_file_id` FROM `*PREFIX*$table`
42
					LEFT JOIN `*PREFIX*filecache`
43
						ON `cover_file_id`=`fileid`
44
					WHERE `fileid` IS NULL
45
				) mysqlhack
46
			)"
47
		);
48
	}
49
50
	/**
51
	 * Remove cover_file_id from album if the corresponding file does not exist
52
	 */
53 1
	private function removeObsoleteAlbumCoverImages() {
54 1
		return $this->removeObsoleteCoverImagesFromTable('music_albums');
55
	}
56
57
	/**
58
	 * Remove cover_file_id from artist if the corresponding file does not exist
59
	 */
60 1
	private function removeObsoleteArtistCoverImages() {
61 1
		return $this->removeObsoleteCoverImagesFromTable('music_artists');
62
	}
63
64
	/**
65
	 * Remove all such rows from $tgtTable which don't have corresponding rows in $refTable
66
	 * so that $tgtTableKey = $refTableKey.
67
	 * @param string $tgtTable
68
	 * @param string $refTable
69
	 * @param string $tgtTableKey
70
	 * @param string $refTableKey
71
	 * @return Number of removed rows
72
	 */
73 1
	private function removeUnreferencedDbRows($tgtTable, $refTable, $tgtTableKey, $refTableKey) {
74 1
		$tgtTable = '*PREFIX*' . $tgtTable;
75 1
		$refTable = '*PREFIX*' . $refTable;
76
77 1
		return $this->db->executeUpdate(
78 1
			"DELETE FROM `$tgtTable` WHERE `id` IN (
79
				SELECT `id` FROM (
80 1
					SELECT `$tgtTable`.`id`
81 1
					FROM `$tgtTable` LEFT JOIN `$refTable`
82 1
					ON `$tgtTable`.`$tgtTableKey` = `$refTable`.`$refTableKey`
83 1
					WHERE `$refTable`.`$refTableKey` IS NULL
84
				) mysqlhack
85
			)"
86
		);
87
	}
88
89
	/**
90
	 * Remvoe tracks which do not have corresponding file in the file system
91
	 * @return Number of removed tracks
92
	 */
93 1
	private function removeObsoleteTracks() {
94 1
		return $this->removeUnreferencedDbRows('music_tracks', 'filecache', 'file_id', 'fileid');
95
	}
96
97
	/**
98
	 * Remove tracks which belong to non-existing album
99
	 * @return Number of removed tracks
100
	 */
101 1
	private function removeTracksWithNoAlbum() {
102 1
		return $this->removeUnreferencedDbRows('music_tracks', 'music_albums', 'album_id', 'id');
103
	}
104
105
	/**
106
	 * Remove tracks which are performed by non-existing artist
107
	 * @return Number of removed tracks
108
	 */
109 1
	private function removeTracksWithNoArtist() {
110 1
		return $this->removeUnreferencedDbRows('music_tracks', 'music_artists', 'artist_id', 'id');
111
	}
112
113
	/**
114
	 * Remove albums which have no tracks
115
	 * @return Number of removed albums
116
	 */
117 1
	private function removeObsoleteAlbums() {
118 1
		return $this->removeUnreferencedDbRows('music_albums', 'music_tracks', 'id', 'album_id');
119
	}
120
121
	/**
122
	 * Remove albums which have a non-existing album artist
123
	 * @return Number of removed albums
124
	 */
125 1
	private function removeAlbumsWithNoArtist() {
126 1
		return $this->removeUnreferencedDbRows('music_albums', 'music_artists', 'album_artist_id', 'id');
127
	}
128
129
	/**
130
	 * Remove artists which have no albums and no tracks
131
	 * @return Number of removed artists
132
	 */
133 1
	private function removeObsoleteArtists() {
134 1
		return $this->db->executeUpdate(
135 1
			'DELETE FROM `*PREFIX*music_artists` WHERE `id` NOT IN (
136
				SELECT `album_artist_id` FROM `*PREFIX*music_albums`
137
				UNION
138
				SELECT `artist_id` FROM `*PREFIX*music_tracks`
139
			)'
140
		);
141
	}
142
143
	/**
144
	 * Remove bookmarks referring tracks which do not exist
145
	 * @return Number of removed bookmarks
146
	 */
147 1
	private function removeObsoleteBookmarks() {
148 1
		return $this->removeUnreferencedDbRows('music_bookmarks', 'music_tracks', 'track_id', 'id');
149
	}
150
151
	/**
152
	 * Removes orphaned data from the database
153
	 * @return array describing the number of removed entries per type
154
	 */
155 1
	public function cleanUp() {
156 1
		$removedCovers = $this->removeObsoleteAlbumCoverImages();
157 1
		$removedCovers += $this->removeObsoleteArtistCoverImages();
158
159 1
		$removedTracks = $this->removeObsoleteTracks();
160 1
		$removedAlbums = $this->removeObsoleteAlbums();
161 1
		$removedArtists = $this->removeObsoleteArtists();
162 1
		$removedBookmarks = $this->removeObsoleteBookmarks();
163
164 1
		$removedAlbums += $this->removeAlbumsWithNoArtist();
165 1
		$removedTracks += $this->removeTracksWithNoAlbum();
166 1
		$removedTracks += $this->removeTracksWithNoArtist();
167
168
		return [
169 1
			'covers' => $removedCovers,
170 1
			'artists' => $removedArtists,
171 1
			'albums' => $removedAlbums,
172 1
			'tracks' => $removedTracks,
173 1
			'bookmarks' => $removedBookmarks
174
		];
175
	}
176
177
	/**
178
	 * Wipe clean the music database of the given user, or all users
179
	 * @param string $userId
180
	 * @param boolean $allUsers
181
	 */
182
	public function resetDb($userId, $allUsers = false) {
183
		if ($userId && $allUsers) {
184
			throw new InvalidArgumentException('userId should be null if allUsers targeted');
0 ignored issues
show
Bug introduced by
The type OCA\Music\Db\InvalidArgumentException was not found. Did you mean InvalidArgumentException? If so, make sure to prefix the type with \.
Loading history...
185
		}
186
187
		$sqls = [
188
				'DELETE FROM `*PREFIX*music_tracks`',
189
				'DELETE FROM `*PREFIX*music_albums`',
190
				'DELETE FROM `*PREFIX*music_artists`',
191
				'DELETE FROM `*PREFIX*music_playlists`',
192
				'DELETE FROM `*PREFIX*music_genres`',
193
				'DELETE FROM `*PREFIX*music_bookmarks`',
194
				'DELETE FROM `*PREFIX*music_cache`'
195
		];
196
197
		foreach ($sqls as $sql) {
198
			$params = [];
199
			if (!$allUsers) {
200
				$sql .=  ' WHERE `user_id` = ?';
201
				$params[] = $userId;
202
			}
203
			$this->db->executeUpdate($sql, $params);
204
		}
205
206
		if ($allUsers) {
207
			$this->logger->log("Erased music databases of all users", 'info');
208
		} else {
209
			$this->logger->log("Erased music database of user $userId", 'info');
210
		}
211
	}
212
}
213