Completed
Pull Request — master (#32155)
by Thomas
26:27 queued 08:44
created

HookManager::copyZsyncMetadata()   C

Complexity

Conditions 12
Paths 10

Size

Total Lines 37

Duplication

Lines 7
Ratio 18.92 %

Importance

Changes 0
Metric Value
cc 12
nc 10
nop 1
dl 7
loc 37
rs 6.9666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\IUserManager;
31
use OCP\Util;
32
use OC\Files\View;
33
34
class HookManager {
35
36
	/** @var IUserManager */
37
	private $userManager;
38
39
	/** @var SyncService */
40
	private $syncService;
41
42
	/** @var IUser[] */
43
	private $usersToDelete;
44
45
	/** @var CalDavBackend */
46
	private $calDav;
47
48
	/** @var CardDavBackend */
49
	private $cardDav;
50
51
	/** @var IL10N */
52
	private $l10n;
53
54
	/** @var array */
55
	private $calendarsToDelete;
56
57
	/** @var array */
58
	private $addressBooksToDelete;
59
60
	public function __construct(IUserManager $userManager,
61
								SyncService $syncService,
62
								CalDavBackend $calDav,
63
								CardDavBackend $cardDav,
64
								IL10N $l10n) {
65
		$this->userManager = $userManager;
66
		$this->syncService = $syncService;
67
		$this->calDav = $calDav;
68
		$this->cardDav = $cardDav;
69
		$this->l10n = $l10n;
70
	}
71
72
	public function setup() {
73
		Util::connectHook('OC_User',
74
			'post_createUser',
75
			$this,
76
			'postCreateUser');
77
		Util::connectHook('OC_User',
78
			'pre_deleteUser',
79
			$this,
80
			'preDeleteUser');
81
		Util::connectHook('OC_User',
82
			'post_deleteUser',
83
			$this,
84
			'postDeleteUser');
85
		Util::connectHook('OC_User',
86
			'changeUser',
87
			$this,
88
			'changeUser');
89
90
		Util::connectHook('OC_Filesystem',
91
			'post_copy',
92
			$this,
93
			'copyZsyncMetadata');
94
		Util::connectHook('OC_Filesystem',
95
			'write',
96
			$this,
97
			'deleteZsyncMetadata');
98
		Util::connectHook('OC_Filesystem',
99
			'delete',
100
			$this,
101
			'deleteZsyncMetadata');
102
		Util::connectHook('\OCP\Versions',
103
			'rollback',
104
			$this,
105
			'deleteZsyncMetadata');
106
	}
107
108
	public function postCreateUser($params) {
109
		$user = $this->userManager->get($params['uid']);
110
		$this->syncService->updateUser($user);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userManager->get($params['uid']) on line 109 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...
111
	}
112
113
	public function preDeleteUser($params) {
114
		$uid = $params['uid'];
115
		$this->usersToDelete[$uid] = $this->userManager->get($uid);
116
		$this->calendarsToDelete = $this->calDav->getUsersOwnCalendars('principals/users/' . $uid);
117
		$this->addressBooksToDelete = $this->cardDav->getUsersOwnAddressBooks('principals/users/' . $uid);
118
	}
119
120
	public function postDeleteUser($params) {
121
		$uid = $params['uid'];
122
		if (isset($this->usersToDelete[$uid])) {
123
			$this->syncService->deleteUser($this->usersToDelete[$uid]);
124
		}
125
126
		foreach ($this->calendarsToDelete as $calendar) {
127
			$this->calDav->deleteCalendar($calendar['id']);
128
		}
129
		$this->calDav->deleteAllSharesForUser('principals/users/' . $uid);
130
131
		foreach ($this->addressBooksToDelete as $addressBook) {
132
			$this->cardDav->deleteAddressBook($addressBook['id']);
133
		}
134
	}
135
136
	public function changeUser($params) {
137
		$user = $params['user'];
138
		$this->syncService->updateUser($user);
139
	}
140
141
	public function firstLogin(IUser $user = null) {
142
		if ($user !== null) {
143
			$principal = 'principals/users/' . $user->getUID();
144
			$calendars = $this->calDav->getCalendarsForUser($principal);
145
			if (empty($calendars) || (\count($calendars) === 1 && $calendars[0]['uri'] === BirthdayService::BIRTHDAY_CALENDAR_URI)) {
146
				try {
147
					$this->calDav->createCalendar($principal, 'personal', [
148
						'{DAV:}displayname' => $this->l10n->t('Personal'),
149
						'{http://apple.com/ns/ical/}calendar-color' => '#1d2d44']);
150
				} catch (\Exception $ex) {
151
					\OC::$server->getLogger()->logException($ex);
152
				}
153
			}
154
			$books = $this->cardDav->getAddressBooksForUser($principal);
155
			if (empty($books)) {
156
				try {
157
					$this->cardDav->createAddressBook($principal, 'contacts', [
158
						'{DAV:}displayname' => $this->l10n->t('Contacts')]);
159
				} catch (\Exception $ex) {
160
					\OC::$server->getLogger()->logException($ex);
161
				}
162
			}
163
		}
164
	}
165
166
	public function deleteZsyncMetadata($params) {
167 View Code Duplication
		if (\OC::$server->getUserSession() === null || \OC::$server->getUserSession()->getUser() === null) {
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...
168
			return;
169
		}
170
		$view = new View('/' . \OC::$server->getUserSession()->getUser()->getUID());
171
		$path = $params[\OC\Files\Filesystem::signal_param_path];
172
		$path = 'files/' . \ltrim($path, '/');
173
174
		/* if a file then just delete zsync metadata for file */
175
		if ($view->is_file($path)) {
176
			$info = $view->getFileInfo($path);
177
			if ($view->file_exists('files_zsync/'.$info->getId())) {
178
				$view->unlink('files_zsync/'.$info->getId());
179
			}
180
		} elseif ($view->is_dir($path)) {
181
			/* if a folder then iteratively delete all zsync metadata for all files in folder, including subdirs */
182
			$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...
183
			while (\count($array)) {
184
				$current = \array_pop($array);
185
				$handle = $view->opendir($current);
186
				while (($entry = \readdir($handle)) !== false) {
187
					if ($entry[0]!='.' and $view->is_dir($current.'/'.$entry)) {
188
						$array[] = $current.'/'.$entry;
189
					} elseif ($view->is_file($current.'/'.$entry)) {
190
						$info = $view->getFileInfo($current.'/'.$entry);
191
						if ($view->file_exists('files_zsync/'.$info->getId())) {
192
							$view->unlink('files_zsync/'.$info->getId());
193
						}
194
					}
195
				}
196
			}
197
		}
198
	}
199
200
	public function copyZsyncMetadata($params) {
201 View Code Duplication
		if (\OC::$server->getUserSession() === null || \OC::$server->getUserSession()->getUser() === null) {
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...
202
			return;
203
		}
204
		$view = new View('/' . \OC::$server->getUserSession()->getUser()->getUID());
205
		$from = $params[\OC\Files\Filesystem::signal_param_oldpath];
206
		$from = 'files/' . \ltrim($from, '/');
207
		$to = $params[\OC\Files\Filesystem::signal_param_newpath];
208
		$to = 'files/' . \ltrim($to, '/');
209
210
		/* if a file then just copy zsync metadata for file */
211
		if ($view->is_file($from)) {
212
			$info_from = $view->getFileInfo($from);
213
			$info_to = $view->getFileInfo($to);
214 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...
215
				$view->copy('files_zsync/'.$info_from->getId(), 'files_zsync/'.$info_to->getId());
216
			}
217
		} elseif ($view->is_dir($from)) {
218
			/* if a folder then iteratively copy all zsync metadata for all files in folder, including subdirs */
219
			$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...
220
			while (\count($array)) {
221
				list($from_current, $to_current) = \array_pop($array);
222
				$handle = $view->opendir($from_current);
223
				while (($entry = \readdir($handle)) !== false) {
224
					if ($entry[0]!='.' and $view->is_dir($from_current.'/'.$entry)) {
225
						$array[] = [$from_current.'/'.$entry, $to_current.'/'.$entry];
226
					} elseif ($view->is_file($from_current.'/'.$entry)) {
227
						$info_from = $view->getFileInfo($from_current.'/'.$entry);
228
						$info_to = $view->getFileInfo($to_current.'/'.$entry);
229 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...
230
							$view->copy('files_zsync/'.$info_from->getId(), 'files_zsync/'.$info_to->getId());
231
						}
232
					}
233
				}
234
			}
235
		}
236
	}
237
}
238