Completed
Push — master ( ec6e3a...a32d5d )
by Thomas
10:38
created

HookManager   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 194
Duplicated Lines 2.06 %

Coupling/Cohesion

Components 1
Dependencies 12

Importance

Changes 0
Metric Value
dl 4
loc 194
rs 8.6
c 0
b 0
f 0
wmc 37
lcom 1
cbo 12

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
B setup() 0 35 1
A postCreateUser() 0 4 1
A preDeleteUser() 0 6 1
A postDeleteUser() 0 15 4
A changeUser() 0 4 1
C firstLogin() 0 24 8
D deleteZsyncMetadata() 0 28 10
D copyZsyncMetadata() 4 32 10

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * @author Thomas Citharel <[email protected]>
4
 * @author Thomas Müller <[email protected]>
5
 *
6
 * @copyright Copyright (c) 2018, ownCloud GmbH
7
 * @license AGPL-3.0
8
 *
9
 * This code is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License, version 3,
11
 * as published by the Free Software Foundation.
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, version 3,
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
20
 *
21
 */
22
namespace OCA\DAV;
23
24
use OCA\DAV\CalDAV\BirthdayService;
25
use OCA\DAV\CalDAV\CalDavBackend;
26
use OCA\DAV\CardDAV\CardDavBackend;
27
use OCA\DAV\CardDAV\SyncService;
28
use OCP\IL10N;
29
use OCP\IUser;
30
use OCP\User;
31
use OCP\IUserManager;
32
use OCP\Util;
33
use OC\Files\View;
34
35
class HookManager {
36
37
	/** @var IUserManager */
38
	private $userManager;
39
40
	/** @var SyncService */
41
	private $syncService;
42
43
	/** @var IUser[] */
44
	private $usersToDelete;
45
46
	/** @var CalDavBackend */
47
	private $calDav;
48
49
	/** @var CardDavBackend */
50
	private $cardDav;
51
52
	/** @var IL10N */
53
	private $l10n;
54
55
	/** @var array */
56
	private $calendarsToDelete;
57
58
	/** @var array */
59
	private $addressBooksToDelete;
60
61
	public function __construct(IUserManager $userManager,
62
								SyncService $syncService,
63
								CalDavBackend $calDav,
64
								CardDavBackend $cardDav,
65
								IL10N $l10n) {
66
		$this->userManager = $userManager;
67
		$this->syncService = $syncService;
68
		$this->calDav = $calDav;
69
		$this->cardDav = $cardDav;
70
		$this->l10n = $l10n;
71
	}
72
73
	public function setup() {
74
		Util::connectHook('OC_User',
75
			'post_createUser',
76
			$this,
77
			'postCreateUser');
78
		Util::connectHook('OC_User',
79
			'pre_deleteUser',
80
			$this,
81
			'preDeleteUser');
82
		Util::connectHook('OC_User',
83
			'post_deleteUser',
84
			$this,
85
			'postDeleteUser');
86
		Util::connectHook('OC_User',
87
			'changeUser',
88
			$this,
89
			'changeUser');
90
91
		Util::connectHook('OC_Filesystem',
92
			'post_copy',
93
			$this,
94
			'copyZsyncMetadata');
95
		Util::connectHook('OC_Filesystem',
96
			'write',
97
			$this,
98
			'deleteZsyncMetadata');
99
		Util::connectHook('OC_Filesystem',
100
			'delete',
101
			$this,
102
			'deleteZsyncMetadata');
103
		Util::connectHook('\OCP\Versions',
104
			'rollback',
105
			$this,
106
			'deleteZsyncMetadata');
107
	}
108
109
	public function postCreateUser($params) {
110
		$user = $this->userManager->get($params['uid']);
111
		$this->syncService->updateUser($user);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userManager->get($params['uid']) on line 110 can be null; however, OCA\DAV\CardDAV\SyncService::updateUser() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
112
	}
113
114
	public function preDeleteUser($params) {
115
		$uid = $params['uid'];
116
		$this->usersToDelete[$uid] = $this->userManager->get($uid);
117
		$this->calendarsToDelete = $this->calDav->getUsersOwnCalendars('principals/users/' . $uid);
118
		$this->addressBooksToDelete = $this->cardDav->getUsersOwnAddressBooks('principals/users/' . $uid);
119
	}
120
121
	public function postDeleteUser($params) {
122
		$uid = $params['uid'];
123
		if (isset($this->usersToDelete[$uid])){
124
			$this->syncService->deleteUser($this->usersToDelete[$uid]);
125
		}
126
127
		foreach ($this->calendarsToDelete as $calendar) {
128
			$this->calDav->deleteCalendar($calendar['id']);
129
		}
130
		$this->calDav->deleteAllSharesForUser('principals/users/' . $uid);
131
132
		foreach ($this->addressBooksToDelete as $addressBook) {
133
			$this->cardDav->deleteAddressBook($addressBook['id']);
134
		}
135
	}
136
137
	public function changeUser($params) {
138
		$user = $params['user'];
139
		$this->syncService->updateUser($user);
140
	}
141
142
	public function firstLogin(IUser $user = null) {
143
		if (!is_null($user)) {
144
			$principal = 'principals/users/' . $user->getUID();
145
			$calendars = $this->calDav->getCalendarsForUser($principal);
146
			if (empty($calendars) || (count($calendars) === 1 && $calendars[0]['uri'] === BirthdayService::BIRTHDAY_CALENDAR_URI)) {
147
				try {
148
					$this->calDav->createCalendar($principal, 'personal', [
149
						'{DAV:}displayname' => $this->l10n->t('Personal'),
150
						'{http://apple.com/ns/ical/}calendar-color' => '#1d2d44']);
151
				} catch (\Exception $ex) {
152
					\OC::$server->getLogger()->logException($ex);
153
				}
154
			}
155
			$books = $this->cardDav->getAddressBooksForUser($principal);
156
			if (empty($books)) {
157
				try {
158
					$this->cardDav->createAddressBook($principal, 'contacts', [
159
						'{DAV:}displayname' => $this->l10n->t('Contacts')]);
160
				} catch (\Exception $ex) {
161
					\OC::$server->getLogger()->logException($ex);
162
				}
163
			}
164
		}
165
	}
166
167
	public function deleteZsyncMetadata($params) {
168
		$view = new View('/'.User::getUser());
169
		$path = $params[\OC\Files\Filesystem::signal_param_path];
170
		$path = 'files/' . ltrim($path, '/');
171
172
		/* if a file then just delete zsync metadata for file */
173
		if ($view->is_file($path)) {
174
			$info = $view->getFileInfo($path);
175
			if ($view->file_exists('files_zsync/'.$info->getId()))
176
				$view->unlink('files_zsync/'.$info->getId());
177
		} else if ($view->is_dir($path)) {
178
		/* if a folder then iteratively delete all zsync metadata for all files in folder, including subdirs */
179
			$array[] = $path;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$array was never initialized. Although not strictly required by PHP, it is generally a good practice to add $array = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
180
			while (count($array)) {
181
				$current = array_pop($array);
182
				$handle = $view->opendir($current);
183
				while (($entry = readdir($handle)) !== false) {
184
					if($entry[0]!='.' and $view->is_dir($current.'/'.$entry)) {
185
						$array[] = $current.'/'.$entry;
186
					} else if ($view->is_file($current.'/'.$entry)) {
187
						$info = $view->getFileInfo($current.'/'.$entry);
188
						if ($view->file_exists('files_zsync/'.$info->getId()))
189
							$view->unlink('files_zsync/'.$info->getId());
190
					}
191
				}
192
			}
193
		}
194
	}
195
196
	public function copyZsyncMetadata($params) {
197
		$view = new View('/'.User::getUser());
198
		$from = $params[\OC\Files\Filesystem::signal_param_oldpath];
199
		$from = 'files/' . ltrim($from, '/');
200
		$to = $params[\OC\Files\Filesystem::signal_param_newpath];
201
		$to = 'files/' . ltrim($to, '/');
202
203
		/* if a file then just copy zsync metadata for file */
204
		if ($view->is_file($from)) {
205
			$info_from = $view->getFileInfo($from);
206
			$info_to = $view->getFileInfo($to);
207 View Code Duplication
			if ($view->file_exists('files_zsync/'.$info_from->getId()))
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...
208
				$view->copy('files_zsync/'.$info_from->getId(), 'files_zsync/'.$info_to->getId());
209
		} else if ($view->is_dir($from)) {
210
		/* if a folder then iteratively copy all zsync metadata for all files in folder, including subdirs */
211
			$array[] = [$from, $to];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$array was never initialized. Although not strictly required by PHP, it is generally a good practice to add $array = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
212
			while (count($array)) {
213
				list($from_current, $to_current) = array_pop($array);
214
				$handle = $view->opendir($from_current);
215
				while (($entry = readdir($handle)) !== false) {
216
					if($entry[0]!='.' and $view->is_dir($from_current.'/'.$entry)) {
217
						$array[] = [$from_current.'/'.$entry, $to_current.'/'.$entry];
218
					} else if ($view->is_file($from_current.'/'.$entry)) {
219
						$info_from = $view->getFileInfo($from_current.'/'.$entry);
220
						$info_to = $view->getFileInfo($to_current.'/'.$entry);
221 View Code Duplication
						if ($view->file_exists('files_zsync/'.$info_from->getId()))
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...
222
							$view->copy('files_zsync/'.$info_from->getId(), 'files_zsync/'.$info_to->getId());
223
					}
224
				}
225
			}
226
		}
227
	}
228
}
229