Completed
Pull Request — master (#551)
by Maxence
02:15
created

RemoteService::update()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.7666
c 0
b 0
f 0
cc 4
nc 4
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
6
/**
7
 * Circles - Bring cloud-users closer together.
8
 *
9
 * This file is licensed under the Affero General Public License version 3 or
10
 * later. See the COPYING file.
11
 *
12
 * @author Maxence Lange <[email protected]>
13
 * @copyright 2021
14
 * @license GNU AGPL version 3 or any later version
15
 *
16
 * This program is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License as
18
 * published by the Free Software Foundation, either version 3 of the
19
 * License, or (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
 *
29
 */
30
31
namespace OCA\Circles\Service;
32
33
34
use daita\MySmallPhpTools\ActivityPub\Nextcloud\nc21\NC21Signature;
35
use daita\MySmallPhpTools\Exceptions\InvalidItemException;
36
use daita\MySmallPhpTools\Exceptions\RequestNetworkException;
37
use daita\MySmallPhpTools\Exceptions\SignatoryException;
38
use daita\MySmallPhpTools\Model\Request;
39
use OCA\Circles\Db\CircleRequest;
40
use OCA\Circles\Db\MemberRequest;
41
use OCA\Circles\Exceptions\CircleNotFoundException;
42
use OCA\Circles\Exceptions\InvalidIdException;
43
use OCA\Circles\Exceptions\OwnerNotFoundException;
44
use OCA\Circles\Exceptions\RemoteInstanceException;
45
use OCA\Circles\Exceptions\RemoteNotFoundException;
46
use OCA\Circles\Exceptions\RemoteResourceNotFoundException;
47
use OCA\Circles\Exceptions\UnknownRemoteException;
48
use OCA\Circles\Model\Circle;
49
use OCA\Circles\Model\Federated\RemoteInstance;
50
use OCA\Circles\Model\FederatedUser;
51
use OCA\Circles\Model\Member;
52
53
54
/**
55
 * Class RemoteService
56
 *
57
 * @package OCA\Circles\Service
58
 */
59
class RemoteService extends NC21Signature {
60
61
62
	/** @var CircleRequest */
63
	private $circleRequest;
64
65
	/** @var MemberRequest */
66
	private $memberRequest;
67
68
	/** @var RemoteStreamService */
69
	private $remoteStreamService;
70
71
72
	/**
73
	 * RemoteStreamService constructor.
74
	 *
75
	 * @param CircleRequest $circleRequest
76
	 * @param MemberRequest $memberRequest
77
	 * @param RemoteStreamService $remoteStreamService
78
	 */
79
	public function __construct(
80
		CircleRequest $circleRequest, MemberRequest $memberRequest, RemoteStreamService $remoteStreamService
81
	) {
82
		$this->setup('app', 'circles');
83
84
		$this->circleRequest = $circleRequest;
85
		$this->memberRequest = $memberRequest;
86
		$this->remoteStreamService = $remoteStreamService;
87
	}
88
89
90
	/**
91
	 * TODO: might move this out from this class
92
	 *
93
	 * @param string $instance
94
	 *
95
	 * @return Circle[]
96
	 */
97
	public function getCirclesFromInstance(string $instance): array {
0 ignored issues
show
Unused Code introduced by
The parameter $instance is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
98
//		$circles = $this->resultRequestRemoteInstance($instance, RemoteInstance::CIRCLES);
99
		return [];
100
//		return $this->convertArray($circles, Circle::class);
101
	}
102
103
104
	/**
105
	 * @param string $circleId
106
	 * @param string $instance
107
	 *
108
	 * @return Circle
109
	 * @throws RemoteNotFoundException
110
	 * @throws RemoteResourceNotFoundException
111
	 * @throws RequestNetworkException
112
	 * @throws SignatoryException
113
	 * @throws UnknownRemoteException
114
	 * @throws InvalidItemException
115
	 * @throws RemoteInstanceException
116
	 * @throws CircleNotFoundException
117
	 */
118
	public function getCircleFromInstance(string $circleId, string $instance): Circle {
119
		$result = $this->remoteStreamService->resultRequestRemoteInstance(
120
			$instance,
121
			RemoteInstance::CIRCLE,
122
			Request::TYPE_GET,
123
			null,
124
			['circleId' => $circleId]
125
		);
126
127
		if (empty($result)) {
128
			throw new CircleNotFoundException();
129
		}
130
131
		$circle = new Circle();
132
		$circle->import($result);
133
134
		return $circle;
135
	}
136
137
138
	/**
139
	 * @param Circle $circle
140
	 *
141
	 * @throws CircleNotFoundException
142
	 * @throws InvalidIdException
143
	 * @throws InvalidItemException
144
	 * @throws OwnerNotFoundException
145
	 * @throws RemoteNotFoundException
146
	 * @throws RemoteResourceNotFoundException
147
	 * @throws RequestNetworkException
148
	 * @throws SignatoryException
149
	 * @throws UnknownRemoteException
150
	 * @throws RemoteInstanceException
151
	 */
152
	public function syncCircle(Circle $circle): void {
153
//		if ($this->configService->isLocalInstance($circle->getInstance())) {
154
//			$this->syncLocalCircle($circle);
155
//		} else {
156
		$this->syncRemoteCircle($circle->getId(), $circle->getInstance());
157
//		}
158
	}
159
160
	/**
161
	 * @param Circle $circle
162
	 */
163
	private function syncLocalCircle(Circle $circle): void {
0 ignored issues
show
Unused Code introduced by
The parameter $circle is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
164
165
	}
166
167
168
	/**
169
	 * TODO: move to RemoteStreamService ?
170
	 *
171
	 * @param string $circleId
172
	 * @param string $instance
173
	 *
174
	 * @throws InvalidItemException
175
	 * @throws OwnerNotFoundException
176
	 * @throws RemoteNotFoundException
177
	 * @throws RemoteResourceNotFoundException
178
	 * @throws RequestNetworkException
179
	 * @throws SignatoryException
180
	 * @throws UnknownRemoteException
181
	 * @throws CircleNotFoundException
182
	 * @throws InvalidIdException
183
	 * @throws RemoteInstanceException
184
	 */
185
	public function syncRemoteCircle(string $circleId, string $instance): void {
186
		$loop = 0;
187
		$knownInstance = [];
188
		while (true) {
189
			$loop++;
190
			if ($loop > 10 || in_array($instance, $knownInstance)) {
191
				throw new CircleNotFoundException(
192
					'circle not found after browsing ' . implode(', ', $knownInstance)
193
				);
194
			}
195
			$knownInstance[] = $instance;
196
197
			$circle = $this->getCircleFromInstance($circleId, $instance);
198
			if ($circle->getInstance() === $instance) {
199
				break;
200
			}
201
202
			$instance = $circle->getInstance();
203
		}
204
205
		$this->circleRequest->update($circle);
0 ignored issues
show
Bug introduced by
The variable $circle does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
206
		$this->memberRequest->insertOrUpdate($circle->getOwner());
207
208
		$this->syncRemoteMembers($circle);
209
	}
210
211
212
	/**
213
	 * @param Circle $circle
214
	 *
215
	 * @throws OwnerNotFoundException
216
	 * @throws RemoteNotFoundException
217
	 * @throws RemoteResourceNotFoundException
218
	 * @throws RequestNetworkException
219
	 * @throws SignatoryException
220
	 * @throws UnknownRemoteException
221
	 * @throws RemoteInstanceException
222
	 */
223
	public function syncRemoteMembers(Circle $circle) {
224
		$members = $this->getMembersFromInstance($circle->getId(), $circle->getInstance());
0 ignored issues
show
Unused Code introduced by
$members is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
225
		// TODO: compare/update/insert members
226
	}
227
228
229
	/**
230
	 * @param string $circleId
231
	 * @param string $instance
232
	 *
233
	 * @return Member[]
234
	 * @throws RemoteNotFoundException
235
	 * @throws RemoteResourceNotFoundException
236
	 * @throws RequestNetworkException
237
	 * @throws SignatoryException
238
	 * @throws UnknownRemoteException
239
	 * @throws RemoteInstanceException
240
	 */
241
	private function getMembersFromInstance(string $circleId, string $instance): array {
242
		$result = $this->remoteStreamService->resultRequestRemoteInstance(
243
			$instance,
244
			RemoteInstance::MEMBERS,
245
			Request::TYPE_GET,
246
			null,
247
			['circleId' => $circleId]
248
		);
249
250
		$members = [];
251
		foreach ($result as $item) {
252
			try {
253
				$member = new Member();
254
				$member->import($item);
255
				$members[] = $member;
256
			} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
257
			}
258
		}
259
260
		return $members;
261
	}
262
263
264
	/**
265
	 * @param string $userId
266
	 * @param string $instance
267
	 * @param int $type
268
	 *
269
	 * @return FederatedUser
270
	 * @throws InvalidItemException
271
	 * @throws RemoteNotFoundException
272
	 * @throws RemoteResourceNotFoundException
273
	 * @throws RequestNetworkException
274
	 * @throws SignatoryException
275
	 * @throws UnknownRemoteException
276
	 * @throws RemoteInstanceException
277
	 */
278
	public function getFederatedUserFromInstance(
279
		string $userId, string $instance, int $type = Member::TYPE_USER
280
	): FederatedUser {
281
		$result = $this->remoteStreamService->resultRequestRemoteInstance(
282
			$instance,
283
			RemoteInstance::MEMBERS,
284
			Request::TYPE_GET,
285
			null,
286
			['type' => Member::$DEF_TYPE[$type], 'userId' => $userId]
287
		);
288
289
		$federatedUser = new FederatedUser();
290
		$federatedUser->import($result);
291
292
		if ($federatedUser->getInstance() !== $instance) {
293
			throw new InvalidItemException('incorrect instance');
294
		}
295
296
		return $federatedUser;
297
	}
298
299
}
300
301