Completed
Push — master ( fb0b56...db3e84 )
by Daniel
27:54
created
apps/dav/tests/unit/CalDAV/Schedule/IMipPluginTest.php 2 patches
Indentation   +972 added lines, -972 removed lines patch added patch discarded remove patch
@@ -34,1010 +34,1010 @@
 block discarded – undo
34 34
 use function array_merge;
35 35
 
36 36
 interface IMailServiceMock extends IMailService, IMailMessageSend {
37
-	// workaround for creating mock class with multiple interfaces
38
-	// TODO: remove after phpUnit 10 is supported.
37
+    // workaround for creating mock class with multiple interfaces
38
+    // TODO: remove after phpUnit 10 is supported.
39 39
 }
40 40
 
41 41
 class IMipPluginTest extends TestCase {
42
-	use EmailValidatorTrait;
42
+    use EmailValidatorTrait;
43 43
 
44
-	private IMessage&MockObject $mailMessage;
45
-	private IMailer&MockObject $mailer;
46
-	private IEMailTemplate&MockObject $emailTemplate;
47
-	private IAttachment&MockObject $emailAttachment;
48
-	private ITimeFactory&MockObject $timeFactory;
49
-	private IAppConfig&MockObject $config;
50
-	private IUserSession&MockObject $userSession;
51
-	private IUser&MockObject $user;
52
-	private IMipPlugin $plugin;
53
-	private IMipService&MockObject $service;
54
-	private Defaults&MockObject $defaults;
55
-	private LoggerInterface&MockObject $logger;
56
-	private EventComparisonService&MockObject $eventComparisonService;
57
-	private IMailManager&MockObject $mailManager;
58
-	private IMailServiceMock&MockObject $mailService;
59
-	private IMailMessageNew&MockObject $mailMessageNew;
44
+    private IMessage&MockObject $mailMessage;
45
+    private IMailer&MockObject $mailer;
46
+    private IEMailTemplate&MockObject $emailTemplate;
47
+    private IAttachment&MockObject $emailAttachment;
48
+    private ITimeFactory&MockObject $timeFactory;
49
+    private IAppConfig&MockObject $config;
50
+    private IUserSession&MockObject $userSession;
51
+    private IUser&MockObject $user;
52
+    private IMipPlugin $plugin;
53
+    private IMipService&MockObject $service;
54
+    private Defaults&MockObject $defaults;
55
+    private LoggerInterface&MockObject $logger;
56
+    private EventComparisonService&MockObject $eventComparisonService;
57
+    private IMailManager&MockObject $mailManager;
58
+    private IMailServiceMock&MockObject $mailService;
59
+    private IMailMessageNew&MockObject $mailMessageNew;
60 60
 
61
-	protected function setUp(): void {
62
-		$this->mailMessage = $this->createMock(IMessage::class);
63
-		$this->mailMessage->method('setFrom')->willReturn($this->mailMessage);
64
-		$this->mailMessage->method('setReplyTo')->willReturn($this->mailMessage);
65
-		$this->mailMessage->method('setTo')->willReturn($this->mailMessage);
61
+    protected function setUp(): void {
62
+        $this->mailMessage = $this->createMock(IMessage::class);
63
+        $this->mailMessage->method('setFrom')->willReturn($this->mailMessage);
64
+        $this->mailMessage->method('setReplyTo')->willReturn($this->mailMessage);
65
+        $this->mailMessage->method('setTo')->willReturn($this->mailMessage);
66 66
 
67
-		$this->mailer = $this->createMock(IMailer::class);
68
-		$this->mailer->method('createMessage')->willReturn($this->mailMessage);
67
+        $this->mailer = $this->createMock(IMailer::class);
68
+        $this->mailer->method('createMessage')->willReturn($this->mailMessage);
69 69
 
70
-		$this->emailTemplate = $this->createMock(IEMailTemplate::class);
71
-		$this->mailer->method('createEMailTemplate')->willReturn($this->emailTemplate);
70
+        $this->emailTemplate = $this->createMock(IEMailTemplate::class);
71
+        $this->mailer->method('createEMailTemplate')->willReturn($this->emailTemplate);
72 72
 
73
-		$this->emailAttachment = $this->createMock(IAttachment::class);
74
-		$this->mailer->method('createAttachment')->willReturn($this->emailAttachment);
73
+        $this->emailAttachment = $this->createMock(IAttachment::class);
74
+        $this->mailer->method('createAttachment')->willReturn($this->emailAttachment);
75 75
 
76
-		$this->logger = $this->createMock(LoggerInterface::class);
76
+        $this->logger = $this->createMock(LoggerInterface::class);
77 77
 
78
-		$this->timeFactory = $this->createMock(ITimeFactory::class);
79
-		$this->timeFactory->method('getTime')->willReturn(1496912528); // 2017-01-01
78
+        $this->timeFactory = $this->createMock(ITimeFactory::class);
79
+        $this->timeFactory->method('getTime')->willReturn(1496912528); // 2017-01-01
80 80
 
81
-		$this->config = $this->createMock(IAppConfig::class);
81
+        $this->config = $this->createMock(IAppConfig::class);
82 82
 
83
-		$this->user = $this->createMock(IUser::class);
83
+        $this->user = $this->createMock(IUser::class);
84 84
 
85
-		$this->userSession = $this->createMock(IUserSession::class);
86
-		$this->userSession->method('getUser')
87
-			->willReturn($this->user);
85
+        $this->userSession = $this->createMock(IUserSession::class);
86
+        $this->userSession->method('getUser')
87
+            ->willReturn($this->user);
88 88
 
89
-		$this->defaults = $this->createMock(Defaults::class);
90
-		$this->defaults->method('getName')
91
-			->willReturn('Instance Name 123');
89
+        $this->defaults = $this->createMock(Defaults::class);
90
+        $this->defaults->method('getName')
91
+            ->willReturn('Instance Name 123');
92 92
 
93
-		$this->service = $this->createMock(IMipService::class);
93
+        $this->service = $this->createMock(IMipService::class);
94 94
 
95
-		$this->eventComparisonService = $this->createMock(EventComparisonService::class);
95
+        $this->eventComparisonService = $this->createMock(EventComparisonService::class);
96 96
 
97
-		$this->mailManager = $this->createMock(IMailManager::class);
97
+        $this->mailManager = $this->createMock(IMailManager::class);
98 98
 
99
-		$this->mailService = $this->createMock(IMailServiceMock::class);
99
+        $this->mailService = $this->createMock(IMailServiceMock::class);
100 100
 
101
-		$this->mailMessageNew = $this->createMock(IMailMessageNew::class);
101
+        $this->mailMessageNew = $this->createMock(IMailMessageNew::class);
102 102
 
103
-		$this->plugin = new IMipPlugin(
104
-			$this->config,
105
-			$this->mailer,
106
-			$this->logger,
107
-			$this->timeFactory,
108
-			$this->defaults,
109
-			$this->userSession,
110
-			$this->service,
111
-			$this->eventComparisonService,
112
-			$this->mailManager,
113
-			$this->getEmailValidatorWithStrictEmailCheck(),
114
-		);
115
-	}
103
+        $this->plugin = new IMipPlugin(
104
+            $this->config,
105
+            $this->mailer,
106
+            $this->logger,
107
+            $this->timeFactory,
108
+            $this->defaults,
109
+            $this->userSession,
110
+            $this->service,
111
+            $this->eventComparisonService,
112
+            $this->mailManager,
113
+            $this->getEmailValidatorWithStrictEmailCheck(),
114
+        );
115
+    }
116 116
 
117
-	public function testDeliveryNoSignificantChange(): void {
118
-		$message = new Message();
119
-		$message->method = 'REQUEST';
120
-		$message->message = new VCalendar();
121
-		$message->message->add('VEVENT', array_merge([
122
-			'UID' => 'uid-1234',
123
-			'SEQUENCE' => 0,
124
-			'SUMMARY' => 'Fellowship meeting',
125
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
126
-		], []));
127
-		$message->message->VEVENT->add('ORGANIZER', 'mailto:[email protected]');
128
-		$message->message->VEVENT->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
129
-		$message->sender = 'mailto:[email protected]';
130
-		$message->senderName = 'Mr. Wizard';
131
-		$message->recipient = 'mailto:' . '[email protected]';
132
-		$message->significantChange = false;
133
-		$this->plugin->schedule($message);
134
-		$this->assertEquals('1.0', $message->getScheduleStatus());
135
-	}
117
+    public function testDeliveryNoSignificantChange(): void {
118
+        $message = new Message();
119
+        $message->method = 'REQUEST';
120
+        $message->message = new VCalendar();
121
+        $message->message->add('VEVENT', array_merge([
122
+            'UID' => 'uid-1234',
123
+            'SEQUENCE' => 0,
124
+            'SUMMARY' => 'Fellowship meeting',
125
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
126
+        ], []));
127
+        $message->message->VEVENT->add('ORGANIZER', 'mailto:[email protected]');
128
+        $message->message->VEVENT->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
129
+        $message->sender = 'mailto:[email protected]';
130
+        $message->senderName = 'Mr. Wizard';
131
+        $message->recipient = 'mailto:' . '[email protected]';
132
+        $message->significantChange = false;
133
+        $this->plugin->schedule($message);
134
+        $this->assertEquals('1.0', $message->getScheduleStatus());
135
+    }
136 136
 
137
-	public function testParsingSingle(): void {
138
-		$message = new Message();
139
-		$message->method = 'REQUEST';
140
-		$newVCalendar = new VCalendar();
141
-		$newVevent = new VEvent($newVCalendar, 'one', array_merge([
142
-			'UID' => 'uid-1234',
143
-			'SEQUENCE' => 1,
144
-			'SUMMARY' => 'Fellowship meeting without (!) Boromir',
145
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
146
-		], []));
147
-		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
148
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
149
-		$message->message = $newVCalendar;
150
-		$message->sender = 'mailto:[email protected]';
151
-		$message->senderName = 'Mr. Wizard';
152
-		$message->recipient = 'mailto:' . '[email protected]';
153
-		// save the old copy in the plugin
154
-		$oldVCalendar = new VCalendar();
155
-		$oldVEvent = new VEvent($oldVCalendar, 'one', [
156
-			'UID' => 'uid-1234',
157
-			'SEQUENCE' => 0,
158
-			'SUMMARY' => 'Fellowship meeting',
159
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
160
-		]);
161
-		$oldVEvent->add('ORGANIZER', 'mailto:[email protected]');
162
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
163
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
164
-		$oldVCalendar->add($oldVEvent);
165
-		$data = ['invitee_name' => 'Mr. Wizard',
166
-			'meeting_title' => 'Fellowship meeting without (!) Boromir',
167
-			'attendee_name' => '[email protected]'
168
-		];
169
-		$attendees = $newVevent->select('ATTENDEE');
170
-		$atnd = '';
171
-		foreach ($attendees as $attendee) {
172
-			if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
173
-				$atnd = $attendee;
174
-			}
175
-		}
176
-		$this->plugin->setVCalendar($oldVCalendar);
177
-		$this->service->expects(self::once())
178
-			->method('getLastOccurrence')
179
-			->willReturn(1496912700);
180
-		$this->eventComparisonService->expects(self::once())
181
-			->method('findModified')
182
-			->willReturn(['new' => [$newVevent], 'old' => [$oldVEvent]]);
183
-		$this->service->expects(self::once())
184
-			->method('getCurrentAttendee')
185
-			->with($message)
186
-			->willReturn($atnd);
187
-		$this->service->expects(self::once())
188
-			->method('isRoomOrResource')
189
-			->with($atnd)
190
-			->willReturn(false);
191
-		$this->service->expects(self::once())
192
-			->method('isCircle')
193
-			->with($atnd)
194
-			->willReturn(false);
195
-		$this->service->expects(self::once())
196
-			->method('buildBodyData')
197
-			->with($newVevent, $oldVEvent)
198
-			->willReturn($data);
199
-		$this->user->expects(self::any())
200
-			->method('getUID')
201
-			->willReturn('user1');
202
-		$this->user->expects(self::any())
203
-			->method('getDisplayName')
204
-			->willReturn('Mr. Wizard');
205
-		$this->userSession->expects(self::any())
206
-			->method('getUser')
207
-			->willReturn($this->user);
208
-		$this->service->expects(self::once())
209
-			->method('getFrom');
210
-		$this->service->expects(self::once())
211
-			->method('addSubjectAndHeading')
212
-			->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Fellowship meeting without (!) Boromir', true);
213
-		$this->service->expects(self::once())
214
-			->method('addBulletList')
215
-			->with($this->emailTemplate, $newVevent, $data);
216
-		$this->service->expects(self::once())
217
-			->method('getAttendeeRsvpOrReqForParticipant')
218
-			->willReturn(true);
219
-		$this->config->expects(self::once())
220
-			->method('getValueString')
221
-			->with('dav', 'invitation_link_recipients', 'yes')
222
-			->willReturn('yes');
223
-		$this->service->expects(self::once())
224
-			->method('createInvitationToken')
225
-			->with($message, $newVevent, 1496912700)
226
-			->willReturn('token');
227
-		$this->service->expects(self::once())
228
-			->method('addResponseButtons')
229
-			->with($this->emailTemplate, 'token');
230
-		$this->service->expects(self::once())
231
-			->method('addMoreOptionsButton')
232
-			->with($this->emailTemplate, 'token');
233
-		$this->mailer->expects(self::once())
234
-			->method('send')
235
-			->willReturn([]);
236
-		$this->plugin->schedule($message);
237
-		$this->assertEquals('1.1', $message->getScheduleStatus());
238
-	}
137
+    public function testParsingSingle(): void {
138
+        $message = new Message();
139
+        $message->method = 'REQUEST';
140
+        $newVCalendar = new VCalendar();
141
+        $newVevent = new VEvent($newVCalendar, 'one', array_merge([
142
+            'UID' => 'uid-1234',
143
+            'SEQUENCE' => 1,
144
+            'SUMMARY' => 'Fellowship meeting without (!) Boromir',
145
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
146
+        ], []));
147
+        $newVevent->add('ORGANIZER', 'mailto:[email protected]');
148
+        $newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
149
+        $message->message = $newVCalendar;
150
+        $message->sender = 'mailto:[email protected]';
151
+        $message->senderName = 'Mr. Wizard';
152
+        $message->recipient = 'mailto:' . '[email protected]';
153
+        // save the old copy in the plugin
154
+        $oldVCalendar = new VCalendar();
155
+        $oldVEvent = new VEvent($oldVCalendar, 'one', [
156
+            'UID' => 'uid-1234',
157
+            'SEQUENCE' => 0,
158
+            'SUMMARY' => 'Fellowship meeting',
159
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
160
+        ]);
161
+        $oldVEvent->add('ORGANIZER', 'mailto:[email protected]');
162
+        $oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
163
+        $oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
164
+        $oldVCalendar->add($oldVEvent);
165
+        $data = ['invitee_name' => 'Mr. Wizard',
166
+            'meeting_title' => 'Fellowship meeting without (!) Boromir',
167
+            'attendee_name' => '[email protected]'
168
+        ];
169
+        $attendees = $newVevent->select('ATTENDEE');
170
+        $atnd = '';
171
+        foreach ($attendees as $attendee) {
172
+            if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
173
+                $atnd = $attendee;
174
+            }
175
+        }
176
+        $this->plugin->setVCalendar($oldVCalendar);
177
+        $this->service->expects(self::once())
178
+            ->method('getLastOccurrence')
179
+            ->willReturn(1496912700);
180
+        $this->eventComparisonService->expects(self::once())
181
+            ->method('findModified')
182
+            ->willReturn(['new' => [$newVevent], 'old' => [$oldVEvent]]);
183
+        $this->service->expects(self::once())
184
+            ->method('getCurrentAttendee')
185
+            ->with($message)
186
+            ->willReturn($atnd);
187
+        $this->service->expects(self::once())
188
+            ->method('isRoomOrResource')
189
+            ->with($atnd)
190
+            ->willReturn(false);
191
+        $this->service->expects(self::once())
192
+            ->method('isCircle')
193
+            ->with($atnd)
194
+            ->willReturn(false);
195
+        $this->service->expects(self::once())
196
+            ->method('buildBodyData')
197
+            ->with($newVevent, $oldVEvent)
198
+            ->willReturn($data);
199
+        $this->user->expects(self::any())
200
+            ->method('getUID')
201
+            ->willReturn('user1');
202
+        $this->user->expects(self::any())
203
+            ->method('getDisplayName')
204
+            ->willReturn('Mr. Wizard');
205
+        $this->userSession->expects(self::any())
206
+            ->method('getUser')
207
+            ->willReturn($this->user);
208
+        $this->service->expects(self::once())
209
+            ->method('getFrom');
210
+        $this->service->expects(self::once())
211
+            ->method('addSubjectAndHeading')
212
+            ->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Fellowship meeting without (!) Boromir', true);
213
+        $this->service->expects(self::once())
214
+            ->method('addBulletList')
215
+            ->with($this->emailTemplate, $newVevent, $data);
216
+        $this->service->expects(self::once())
217
+            ->method('getAttendeeRsvpOrReqForParticipant')
218
+            ->willReturn(true);
219
+        $this->config->expects(self::once())
220
+            ->method('getValueString')
221
+            ->with('dav', 'invitation_link_recipients', 'yes')
222
+            ->willReturn('yes');
223
+        $this->service->expects(self::once())
224
+            ->method('createInvitationToken')
225
+            ->with($message, $newVevent, 1496912700)
226
+            ->willReturn('token');
227
+        $this->service->expects(self::once())
228
+            ->method('addResponseButtons')
229
+            ->with($this->emailTemplate, 'token');
230
+        $this->service->expects(self::once())
231
+            ->method('addMoreOptionsButton')
232
+            ->with($this->emailTemplate, 'token');
233
+        $this->mailer->expects(self::once())
234
+            ->method('send')
235
+            ->willReturn([]);
236
+        $this->plugin->schedule($message);
237
+        $this->assertEquals('1.1', $message->getScheduleStatus());
238
+    }
239 239
 
240
-	public function testAttendeeIsResource(): void {
241
-		$message = new Message();
242
-		$message->method = 'REQUEST';
243
-		$newVCalendar = new VCalendar();
244
-		$newVevent = new VEvent($newVCalendar, 'one', array_merge([
245
-			'UID' => 'uid-1234',
246
-			'SEQUENCE' => 1,
247
-			'SUMMARY' => 'Fellowship meeting without (!) Boromir',
248
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
249
-		], []));
250
-		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
251
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'The Shire', 'CUTYPE' => 'ROOM']);
252
-		$message->message = $newVCalendar;
253
-		$message->sender = 'mailto:[email protected]';
254
-		$message->senderName = 'Mr. Wizard';
255
-		$message->recipient = 'mailto:' . '[email protected]';
256
-		// save the old copy in the plugin
257
-		$oldVCalendar = new VCalendar();
258
-		$oldVEvent = new VEvent($oldVCalendar, 'one', [
259
-			'UID' => 'uid-1234',
260
-			'SEQUENCE' => 0,
261
-			'SUMMARY' => 'Fellowship meeting',
262
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
263
-		]);
264
-		$oldVEvent->add('ORGANIZER', 'mailto:[email protected]');
265
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'The Shire', 'CUTYPE' => 'ROOM']);
266
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
267
-		$oldVCalendar->add($oldVEvent);
268
-		$data = ['invitee_name' => 'Mr. Wizard',
269
-			'meeting_title' => 'Fellowship meeting without (!) Boromir',
270
-			'attendee_name' => '[email protected]'
271
-		];
272
-		$attendees = $newVevent->select('ATTENDEE');
273
-		$room = '';
274
-		foreach ($attendees as $attendee) {
275
-			if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
276
-				$room = $attendee;
277
-			}
278
-		}
279
-		$this->plugin->setVCalendar($oldVCalendar);
280
-		$this->service->expects(self::once())
281
-			->method('getLastOccurrence')
282
-			->willReturn(1496912700);
283
-		$this->eventComparisonService->expects(self::once())
284
-			->method('findModified')
285
-			->willReturn(['new' => [$newVevent], 'old' => [$oldVEvent]]);
286
-		$this->service->expects(self::once())
287
-			->method('getCurrentAttendee')
288
-			->with($message)
289
-			->willReturn($room);
290
-		$this->service->expects(self::once())
291
-			->method('isRoomOrResource')
292
-			->with($room)
293
-			->willReturn(true);
294
-		$this->service->expects(self::never())
295
-			->method('isCircle');
296
-		$this->service->expects(self::never())
297
-			->method('buildBodyData');
298
-		$this->user->expects(self::any())
299
-			->method('getUID')
300
-			->willReturn('user1');
301
-		$this->user->expects(self::any())
302
-			->method('getDisplayName')
303
-			->willReturn('Mr. Wizard');
304
-		$this->userSession->expects(self::any())
305
-			->method('getUser')
306
-			->willReturn($this->user);
307
-		$this->service->expects(self::never())
308
-			->method('getFrom');
309
-		$this->service->expects(self::never())
310
-			->method('addSubjectAndHeading');
311
-		$this->service->expects(self::never())
312
-			->method('addBulletList');
313
-		$this->service->expects(self::never())
314
-			->method('getAttendeeRsvpOrReqForParticipant');
315
-		$this->config->expects(self::never())
316
-			->method('getValueString');
317
-		$this->service->expects(self::never())
318
-			->method('createInvitationToken');
319
-		$this->service->expects(self::never())
320
-			->method('addResponseButtons');
321
-		$this->service->expects(self::never())
322
-			->method('addMoreOptionsButton');
323
-		$this->mailer->expects(self::never())
324
-			->method('send');
325
-		$this->plugin->schedule($message);
326
-		$this->assertEquals('1.0', $message->getScheduleStatus());
327
-	}
240
+    public function testAttendeeIsResource(): void {
241
+        $message = new Message();
242
+        $message->method = 'REQUEST';
243
+        $newVCalendar = new VCalendar();
244
+        $newVevent = new VEvent($newVCalendar, 'one', array_merge([
245
+            'UID' => 'uid-1234',
246
+            'SEQUENCE' => 1,
247
+            'SUMMARY' => 'Fellowship meeting without (!) Boromir',
248
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
249
+        ], []));
250
+        $newVevent->add('ORGANIZER', 'mailto:[email protected]');
251
+        $newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'The Shire', 'CUTYPE' => 'ROOM']);
252
+        $message->message = $newVCalendar;
253
+        $message->sender = 'mailto:[email protected]';
254
+        $message->senderName = 'Mr. Wizard';
255
+        $message->recipient = 'mailto:' . '[email protected]';
256
+        // save the old copy in the plugin
257
+        $oldVCalendar = new VCalendar();
258
+        $oldVEvent = new VEvent($oldVCalendar, 'one', [
259
+            'UID' => 'uid-1234',
260
+            'SEQUENCE' => 0,
261
+            'SUMMARY' => 'Fellowship meeting',
262
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
263
+        ]);
264
+        $oldVEvent->add('ORGANIZER', 'mailto:[email protected]');
265
+        $oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'The Shire', 'CUTYPE' => 'ROOM']);
266
+        $oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
267
+        $oldVCalendar->add($oldVEvent);
268
+        $data = ['invitee_name' => 'Mr. Wizard',
269
+            'meeting_title' => 'Fellowship meeting without (!) Boromir',
270
+            'attendee_name' => '[email protected]'
271
+        ];
272
+        $attendees = $newVevent->select('ATTENDEE');
273
+        $room = '';
274
+        foreach ($attendees as $attendee) {
275
+            if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
276
+                $room = $attendee;
277
+            }
278
+        }
279
+        $this->plugin->setVCalendar($oldVCalendar);
280
+        $this->service->expects(self::once())
281
+            ->method('getLastOccurrence')
282
+            ->willReturn(1496912700);
283
+        $this->eventComparisonService->expects(self::once())
284
+            ->method('findModified')
285
+            ->willReturn(['new' => [$newVevent], 'old' => [$oldVEvent]]);
286
+        $this->service->expects(self::once())
287
+            ->method('getCurrentAttendee')
288
+            ->with($message)
289
+            ->willReturn($room);
290
+        $this->service->expects(self::once())
291
+            ->method('isRoomOrResource')
292
+            ->with($room)
293
+            ->willReturn(true);
294
+        $this->service->expects(self::never())
295
+            ->method('isCircle');
296
+        $this->service->expects(self::never())
297
+            ->method('buildBodyData');
298
+        $this->user->expects(self::any())
299
+            ->method('getUID')
300
+            ->willReturn('user1');
301
+        $this->user->expects(self::any())
302
+            ->method('getDisplayName')
303
+            ->willReturn('Mr. Wizard');
304
+        $this->userSession->expects(self::any())
305
+            ->method('getUser')
306
+            ->willReturn($this->user);
307
+        $this->service->expects(self::never())
308
+            ->method('getFrom');
309
+        $this->service->expects(self::never())
310
+            ->method('addSubjectAndHeading');
311
+        $this->service->expects(self::never())
312
+            ->method('addBulletList');
313
+        $this->service->expects(self::never())
314
+            ->method('getAttendeeRsvpOrReqForParticipant');
315
+        $this->config->expects(self::never())
316
+            ->method('getValueString');
317
+        $this->service->expects(self::never())
318
+            ->method('createInvitationToken');
319
+        $this->service->expects(self::never())
320
+            ->method('addResponseButtons');
321
+        $this->service->expects(self::never())
322
+            ->method('addMoreOptionsButton');
323
+        $this->mailer->expects(self::never())
324
+            ->method('send');
325
+        $this->plugin->schedule($message);
326
+        $this->assertEquals('1.0', $message->getScheduleStatus());
327
+    }
328 328
 
329
-	public function testAttendeeIsCircle(): void {
330
-		$message = new Message();
331
-		$message->method = 'REQUEST';
332
-		$newVCalendar = new VCalendar();
333
-		$newVevent = new VEvent($newVCalendar, 'one', array_merge([
334
-			'UID' => 'uid-1234',
335
-			'SEQUENCE' => 1,
336
-			'SUMMARY' => 'Fellowship meeting without (!) Boromir',
337
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
338
-		], []));
339
-		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
340
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'The Fellowship', 'CUTYPE' => 'GROUP']);
341
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'MEMBER' => '[email protected]']);
342
-		$message->message = $newVCalendar;
343
-		$message->sender = 'mailto:[email protected]';
344
-		$message->senderName = 'Mr. Wizard';
345
-		$message->recipient = 'mailto:' . '[email protected]';
346
-		$attendees = $newVevent->select('ATTENDEE');
347
-		$circle = '';
348
-		foreach ($attendees as $attendee) {
349
-			if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
350
-				$circle = $attendee;
351
-			}
352
-		}
353
-		$this->assertNotEmpty($circle, 'Failed to find attendee belonging to the circle');
354
-		$this->service->expects(self::once())
355
-			->method('getLastOccurrence')
356
-			->willReturn(1496912700);
357
-		$this->eventComparisonService->expects(self::once())
358
-			->method('findModified')
359
-			->willReturn(['new' => [$newVevent], 'old' => null]);
360
-		$this->service->expects(self::once())
361
-			->method('getCurrentAttendee')
362
-			->with($message)
363
-			->willReturn($circle);
364
-		$this->service->expects(self::once())
365
-			->method('isRoomOrResource')
366
-			->with($circle)
367
-			->willReturn(false);
368
-		$this->service->expects(self::once())
369
-			->method('isCircle')
370
-			->with($circle)
371
-			->willReturn(true);
372
-		$this->service->expects(self::never())
373
-			->method('buildBodyData');
374
-		$this->user->expects(self::any())
375
-			->method('getUID')
376
-			->willReturn('user1');
377
-		$this->user->expects(self::any())
378
-			->method('getDisplayName')
379
-			->willReturn('Mr. Wizard');
380
-		$this->userSession->expects(self::any())
381
-			->method('getUser')
382
-			->willReturn($this->user);
383
-		$this->service->expects(self::never())
384
-			->method('getFrom');
385
-		$this->service->expects(self::never())
386
-			->method('addSubjectAndHeading');
387
-		$this->service->expects(self::never())
388
-			->method('addBulletList');
389
-		$this->service->expects(self::never())
390
-			->method('getAttendeeRsvpOrReqForParticipant');
391
-		$this->config->expects(self::never())
392
-			->method('getValueString');
393
-		$this->service->expects(self::never())
394
-			->method('createInvitationToken');
395
-		$this->service->expects(self::never())
396
-			->method('addResponseButtons');
397
-		$this->service->expects(self::never())
398
-			->method('addMoreOptionsButton');
399
-		$this->mailer->expects(self::never())
400
-			->method('send');
401
-		$this->plugin->schedule($message);
402
-		$this->assertEquals('1.0', $message->getScheduleStatus());
403
-	}
329
+    public function testAttendeeIsCircle(): void {
330
+        $message = new Message();
331
+        $message->method = 'REQUEST';
332
+        $newVCalendar = new VCalendar();
333
+        $newVevent = new VEvent($newVCalendar, 'one', array_merge([
334
+            'UID' => 'uid-1234',
335
+            'SEQUENCE' => 1,
336
+            'SUMMARY' => 'Fellowship meeting without (!) Boromir',
337
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
338
+        ], []));
339
+        $newVevent->add('ORGANIZER', 'mailto:[email protected]');
340
+        $newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'The Fellowship', 'CUTYPE' => 'GROUP']);
341
+        $newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'MEMBER' => '[email protected]']);
342
+        $message->message = $newVCalendar;
343
+        $message->sender = 'mailto:[email protected]';
344
+        $message->senderName = 'Mr. Wizard';
345
+        $message->recipient = 'mailto:' . '[email protected]';
346
+        $attendees = $newVevent->select('ATTENDEE');
347
+        $circle = '';
348
+        foreach ($attendees as $attendee) {
349
+            if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
350
+                $circle = $attendee;
351
+            }
352
+        }
353
+        $this->assertNotEmpty($circle, 'Failed to find attendee belonging to the circle');
354
+        $this->service->expects(self::once())
355
+            ->method('getLastOccurrence')
356
+            ->willReturn(1496912700);
357
+        $this->eventComparisonService->expects(self::once())
358
+            ->method('findModified')
359
+            ->willReturn(['new' => [$newVevent], 'old' => null]);
360
+        $this->service->expects(self::once())
361
+            ->method('getCurrentAttendee')
362
+            ->with($message)
363
+            ->willReturn($circle);
364
+        $this->service->expects(self::once())
365
+            ->method('isRoomOrResource')
366
+            ->with($circle)
367
+            ->willReturn(false);
368
+        $this->service->expects(self::once())
369
+            ->method('isCircle')
370
+            ->with($circle)
371
+            ->willReturn(true);
372
+        $this->service->expects(self::never())
373
+            ->method('buildBodyData');
374
+        $this->user->expects(self::any())
375
+            ->method('getUID')
376
+            ->willReturn('user1');
377
+        $this->user->expects(self::any())
378
+            ->method('getDisplayName')
379
+            ->willReturn('Mr. Wizard');
380
+        $this->userSession->expects(self::any())
381
+            ->method('getUser')
382
+            ->willReturn($this->user);
383
+        $this->service->expects(self::never())
384
+            ->method('getFrom');
385
+        $this->service->expects(self::never())
386
+            ->method('addSubjectAndHeading');
387
+        $this->service->expects(self::never())
388
+            ->method('addBulletList');
389
+        $this->service->expects(self::never())
390
+            ->method('getAttendeeRsvpOrReqForParticipant');
391
+        $this->config->expects(self::never())
392
+            ->method('getValueString');
393
+        $this->service->expects(self::never())
394
+            ->method('createInvitationToken');
395
+        $this->service->expects(self::never())
396
+            ->method('addResponseButtons');
397
+        $this->service->expects(self::never())
398
+            ->method('addMoreOptionsButton');
399
+        $this->mailer->expects(self::never())
400
+            ->method('send');
401
+        $this->plugin->schedule($message);
402
+        $this->assertEquals('1.0', $message->getScheduleStatus());
403
+    }
404 404
 
405
-	public function testParsingRecurrence(): void {
406
-		$message = new Message();
407
-		$message->method = 'REQUEST';
408
-		$newVCalendar = new VCalendar();
409
-		$newVevent = new VEvent($newVCalendar, 'one', [
410
-			'UID' => 'uid-1234',
411
-			'LAST-MODIFIED' => 123456,
412
-			'SEQUENCE' => 2,
413
-			'SUMMARY' => 'Fellowship meeting',
414
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00'),
415
-			'RRULE' => 'FREQ=DAILY;INTERVAL=1;UNTIL=20160201T000000Z'
416
-		]);
417
-		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
418
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
419
-		$newvEvent2 = new VEvent($newVCalendar, 'two', [
420
-			'UID' => 'uid-1234',
421
-			'SEQUENCE' => 1,
422
-			'SUMMARY' => 'Elevenses',
423
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00'),
424
-			'RECURRENCE-ID' => new \DateTime('2016-01-01 00:00:00')
425
-		]);
426
-		$newvEvent2->add('ORGANIZER', 'mailto:[email protected]');
427
-		$newvEvent2->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
428
-		$message->message = $newVCalendar;
429
-		$message->sender = 'mailto:[email protected]';
430
-		$message->recipient = 'mailto:' . '[email protected]';
431
-		// save the old copy in the plugin
432
-		$oldVCalendar = new VCalendar();
433
-		$oldVEvent = new VEvent($oldVCalendar, 'one', [
434
-			'UID' => 'uid-1234',
435
-			'LAST-MODIFIED' => 123456,
436
-			'SEQUENCE' => 2,
437
-			'SUMMARY' => 'Fellowship meeting',
438
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00'),
439
-			'RRULE' => 'FREQ=DAILY;INTERVAL=1;UNTIL=20160201T000000Z'
440
-		]);
441
-		$oldVEvent->add('ORGANIZER', 'mailto:[email protected]');
442
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
443
-		$data = ['invitee_name' => 'Mr. Wizard',
444
-			'meeting_title' => 'Elevenses',
445
-			'attendee_name' => '[email protected]'
446
-		];
447
-		$attendees = $newVevent->select('ATTENDEE');
448
-		$atnd = '';
449
-		foreach ($attendees as $attendee) {
450
-			if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
451
-				$atnd = $attendee;
452
-			}
453
-		}
454
-		$this->plugin->setVCalendar($oldVCalendar);
455
-		$this->service->expects(self::once())
456
-			->method('getLastOccurrence')
457
-			->willReturn(1496912700);
458
-		$this->eventComparisonService->expects(self::once())
459
-			->method('findModified')
460
-			->willReturn(['old' => [] ,'new' => [$newVevent]]);
461
-		$this->service->expects(self::once())
462
-			->method('getCurrentAttendee')
463
-			->with($message)
464
-			->willReturn($atnd);
465
-		$this->service->expects(self::once())
466
-			->method('isRoomOrResource')
467
-			->with($atnd)
468
-			->willReturn(false);
469
-		$this->service->expects(self::once())
470
-			->method('isCircle')
471
-			->with($atnd)
472
-			->willReturn(false);
473
-		$this->service->expects(self::once())
474
-			->method('buildBodyData')
475
-			->with($newVevent, null)
476
-			->willReturn($data);
477
-		$this->user->expects(self::any())
478
-			->method('getUID')
479
-			->willReturn('user1');
480
-		$this->user->expects(self::any())
481
-			->method('getDisplayName')
482
-			->willReturn('Mr. Wizard');
483
-		$this->userSession->expects(self::any())
484
-			->method('getUser')
485
-			->willReturn($this->user);
486
-		$this->service->expects(self::once())
487
-			->method('getFrom');
488
-		$this->service->expects(self::once())
489
-			->method('addSubjectAndHeading')
490
-			->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Elevenses', false);
491
-		$this->service->expects(self::once())
492
-			->method('addBulletList')
493
-			->with($this->emailTemplate, $newVevent, $data);
494
-		$this->service->expects(self::once())
495
-			->method('getAttendeeRsvpOrReqForParticipant')
496
-			->willReturn(true);
497
-		$this->config->expects(self::once())
498
-			->method('getValueString')
499
-			->with('dav', 'invitation_link_recipients', 'yes')
500
-			->willReturn('yes');
501
-		$this->service->expects(self::once())
502
-			->method('createInvitationToken')
503
-			->with($message, $newVevent, 1496912700)
504
-			->willReturn('token');
505
-		$this->service->expects(self::once())
506
-			->method('addResponseButtons')
507
-			->with($this->emailTemplate, 'token');
508
-		$this->service->expects(self::once())
509
-			->method('addMoreOptionsButton')
510
-			->with($this->emailTemplate, 'token');
511
-		$this->mailer->expects(self::once())
512
-			->method('send')
513
-			->willReturn([]);
514
-		$this->plugin->schedule($message);
515
-		$this->assertEquals('1.1', $message->getScheduleStatus());
516
-	}
405
+    public function testParsingRecurrence(): void {
406
+        $message = new Message();
407
+        $message->method = 'REQUEST';
408
+        $newVCalendar = new VCalendar();
409
+        $newVevent = new VEvent($newVCalendar, 'one', [
410
+            'UID' => 'uid-1234',
411
+            'LAST-MODIFIED' => 123456,
412
+            'SEQUENCE' => 2,
413
+            'SUMMARY' => 'Fellowship meeting',
414
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00'),
415
+            'RRULE' => 'FREQ=DAILY;INTERVAL=1;UNTIL=20160201T000000Z'
416
+        ]);
417
+        $newVevent->add('ORGANIZER', 'mailto:[email protected]');
418
+        $newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
419
+        $newvEvent2 = new VEvent($newVCalendar, 'two', [
420
+            'UID' => 'uid-1234',
421
+            'SEQUENCE' => 1,
422
+            'SUMMARY' => 'Elevenses',
423
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00'),
424
+            'RECURRENCE-ID' => new \DateTime('2016-01-01 00:00:00')
425
+        ]);
426
+        $newvEvent2->add('ORGANIZER', 'mailto:[email protected]');
427
+        $newvEvent2->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
428
+        $message->message = $newVCalendar;
429
+        $message->sender = 'mailto:[email protected]';
430
+        $message->recipient = 'mailto:' . '[email protected]';
431
+        // save the old copy in the plugin
432
+        $oldVCalendar = new VCalendar();
433
+        $oldVEvent = new VEvent($oldVCalendar, 'one', [
434
+            'UID' => 'uid-1234',
435
+            'LAST-MODIFIED' => 123456,
436
+            'SEQUENCE' => 2,
437
+            'SUMMARY' => 'Fellowship meeting',
438
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00'),
439
+            'RRULE' => 'FREQ=DAILY;INTERVAL=1;UNTIL=20160201T000000Z'
440
+        ]);
441
+        $oldVEvent->add('ORGANIZER', 'mailto:[email protected]');
442
+        $oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
443
+        $data = ['invitee_name' => 'Mr. Wizard',
444
+            'meeting_title' => 'Elevenses',
445
+            'attendee_name' => '[email protected]'
446
+        ];
447
+        $attendees = $newVevent->select('ATTENDEE');
448
+        $atnd = '';
449
+        foreach ($attendees as $attendee) {
450
+            if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
451
+                $atnd = $attendee;
452
+            }
453
+        }
454
+        $this->plugin->setVCalendar($oldVCalendar);
455
+        $this->service->expects(self::once())
456
+            ->method('getLastOccurrence')
457
+            ->willReturn(1496912700);
458
+        $this->eventComparisonService->expects(self::once())
459
+            ->method('findModified')
460
+            ->willReturn(['old' => [] ,'new' => [$newVevent]]);
461
+        $this->service->expects(self::once())
462
+            ->method('getCurrentAttendee')
463
+            ->with($message)
464
+            ->willReturn($atnd);
465
+        $this->service->expects(self::once())
466
+            ->method('isRoomOrResource')
467
+            ->with($atnd)
468
+            ->willReturn(false);
469
+        $this->service->expects(self::once())
470
+            ->method('isCircle')
471
+            ->with($atnd)
472
+            ->willReturn(false);
473
+        $this->service->expects(self::once())
474
+            ->method('buildBodyData')
475
+            ->with($newVevent, null)
476
+            ->willReturn($data);
477
+        $this->user->expects(self::any())
478
+            ->method('getUID')
479
+            ->willReturn('user1');
480
+        $this->user->expects(self::any())
481
+            ->method('getDisplayName')
482
+            ->willReturn('Mr. Wizard');
483
+        $this->userSession->expects(self::any())
484
+            ->method('getUser')
485
+            ->willReturn($this->user);
486
+        $this->service->expects(self::once())
487
+            ->method('getFrom');
488
+        $this->service->expects(self::once())
489
+            ->method('addSubjectAndHeading')
490
+            ->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Elevenses', false);
491
+        $this->service->expects(self::once())
492
+            ->method('addBulletList')
493
+            ->with($this->emailTemplate, $newVevent, $data);
494
+        $this->service->expects(self::once())
495
+            ->method('getAttendeeRsvpOrReqForParticipant')
496
+            ->willReturn(true);
497
+        $this->config->expects(self::once())
498
+            ->method('getValueString')
499
+            ->with('dav', 'invitation_link_recipients', 'yes')
500
+            ->willReturn('yes');
501
+        $this->service->expects(self::once())
502
+            ->method('createInvitationToken')
503
+            ->with($message, $newVevent, 1496912700)
504
+            ->willReturn('token');
505
+        $this->service->expects(self::once())
506
+            ->method('addResponseButtons')
507
+            ->with($this->emailTemplate, 'token');
508
+        $this->service->expects(self::once())
509
+            ->method('addMoreOptionsButton')
510
+            ->with($this->emailTemplate, 'token');
511
+        $this->mailer->expects(self::once())
512
+            ->method('send')
513
+            ->willReturn([]);
514
+        $this->plugin->schedule($message);
515
+        $this->assertEquals('1.1', $message->getScheduleStatus());
516
+    }
517 517
 
518
-	public function testEmailValidationFailed(): void {
519
-		$message = new Message();
520
-		$message->method = 'REQUEST';
521
-		$message->message = new VCalendar();
522
-		$message->message->add('VEVENT', array_merge([
523
-			'UID' => 'uid-1234',
524
-			'SEQUENCE' => 0,
525
-			'SUMMARY' => 'Fellowship meeting',
526
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
527
-		], []));
528
-		$message->message->VEVENT->add('ORGANIZER', 'mailto:[email protected]');
529
-		$message->message->VEVENT->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
530
-		$message->sender = 'mailto:[email protected]';
531
-		$message->senderName = 'Mr. Wizard';
532
-		$message->recipient = 'mailto:' . 'frodo@@hobb.it';
518
+    public function testEmailValidationFailed(): void {
519
+        $message = new Message();
520
+        $message->method = 'REQUEST';
521
+        $message->message = new VCalendar();
522
+        $message->message->add('VEVENT', array_merge([
523
+            'UID' => 'uid-1234',
524
+            'SEQUENCE' => 0,
525
+            'SUMMARY' => 'Fellowship meeting',
526
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
527
+        ], []));
528
+        $message->message->VEVENT->add('ORGANIZER', 'mailto:[email protected]');
529
+        $message->message->VEVENT->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
530
+        $message->sender = 'mailto:[email protected]';
531
+        $message->senderName = 'Mr. Wizard';
532
+        $message->recipient = 'mailto:' . 'frodo@@hobb.it';
533 533
 
534
-		$this->service->expects(self::once())
535
-			->method('getLastOccurrence')
536
-			->willReturn(1496912700);
534
+        $this->service->expects(self::once())
535
+            ->method('getLastOccurrence')
536
+            ->willReturn(1496912700);
537 537
 
538
-		$this->plugin->schedule($message);
539
-		$this->assertEquals('5.0', $message->getScheduleStatus());
540
-	}
538
+        $this->plugin->schedule($message);
539
+        $this->assertEquals('5.0', $message->getScheduleStatus());
540
+    }
541 541
 
542
-	public function testFailedDelivery(): void {
543
-		$message = new Message();
544
-		$message->method = 'REQUEST';
545
-		$newVcalendar = new VCalendar();
546
-		$newVevent = new VEvent($newVcalendar, 'one', array_merge([
547
-			'UID' => 'uid-1234',
548
-			'SEQUENCE' => 1,
549
-			'SUMMARY' => 'Fellowship meeting without (!) Boromir',
550
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
551
-		], []));
552
-		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
553
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
554
-		$message->message = $newVcalendar;
555
-		$message->sender = 'mailto:[email protected]';
556
-		$message->senderName = 'Mr. Wizard';
557
-		$message->recipient = 'mailto:' . '[email protected]';
558
-		// save the old copy in the plugin
559
-		$oldVcalendar = new VCalendar();
560
-		$oldVevent = new VEvent($oldVcalendar, 'one', [
561
-			'UID' => 'uid-1234',
562
-			'SEQUENCE' => 0,
563
-			'SUMMARY' => 'Fellowship meeting',
564
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
565
-		]);
566
-		$oldVevent->add('ORGANIZER', 'mailto:[email protected]');
567
-		$oldVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
568
-		$oldVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
569
-		$oldVcalendar->add($oldVevent);
570
-		$data = ['invitee_name' => 'Mr. Wizard',
571
-			'meeting_title' => 'Fellowship meeting without (!) Boromir',
572
-			'attendee_name' => '[email protected]'
573
-		];
574
-		$attendees = $newVevent->select('ATTENDEE');
575
-		$atnd = '';
576
-		foreach ($attendees as $attendee) {
577
-			if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
578
-				$atnd = $attendee;
579
-			}
580
-		}
581
-		$this->plugin->setVCalendar($oldVcalendar);
582
-		$this->service->expects(self::once())
583
-			->method('getLastOccurrence')
584
-			->willReturn(1496912700);
585
-		$this->eventComparisonService->expects(self::once())
586
-			->method('findModified')
587
-			->willReturn(['old' => [] ,'new' => [$newVevent]]);
588
-		$this->service->expects(self::once())
589
-			->method('getCurrentAttendee')
590
-			->with($message)
591
-			->willReturn($atnd);
592
-		$this->service->expects(self::once())
593
-			->method('isRoomOrResource')
594
-			->with($atnd)
595
-			->willReturn(false);
596
-		$this->service->expects(self::once())
597
-			->method('isCircle')
598
-			->with($atnd)
599
-			->willReturn(false);
600
-		$this->service->expects(self::once())
601
-			->method('buildBodyData')
602
-			->with($newVevent, null)
603
-			->willReturn($data);
604
-		$this->user->expects(self::any())
605
-			->method('getUID')
606
-			->willReturn('user1');
607
-		$this->user->expects(self::any())
608
-			->method('getDisplayName')
609
-			->willReturn('Mr. Wizard');
610
-		$this->userSession->expects(self::any())
611
-			->method('getUser')
612
-			->willReturn($this->user);
613
-		$this->service->expects(self::once())
614
-			->method('getFrom');
615
-		$this->service->expects(self::once())
616
-			->method('addSubjectAndHeading')
617
-			->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Fellowship meeting without (!) Boromir', false);
618
-		$this->service->expects(self::once())
619
-			->method('addBulletList')
620
-			->with($this->emailTemplate, $newVevent, $data);
621
-		$this->service->expects(self::once())
622
-			->method('getAttendeeRsvpOrReqForParticipant')
623
-			->willReturn(true);
624
-		$this->config->expects(self::once())
625
-			->method('getValueString')
626
-			->with('dav', 'invitation_link_recipients', 'yes')
627
-			->willReturn('yes');
628
-		$this->service->expects(self::once())
629
-			->method('createInvitationToken')
630
-			->with($message, $newVevent, 1496912700)
631
-			->willReturn('token');
632
-		$this->service->expects(self::once())
633
-			->method('addResponseButtons')
634
-			->with($this->emailTemplate, 'token');
635
-		$this->service->expects(self::once())
636
-			->method('addMoreOptionsButton')
637
-			->with($this->emailTemplate, 'token');
638
-		$this->mailer->expects(self::once())
639
-			->method('send')
640
-			->willReturn([]);
641
-		$this->mailer
642
-			->method('send')
643
-			->willThrowException(new \Exception());
644
-		$this->logger->expects(self::once())
645
-			->method('error');
646
-		$this->plugin->schedule($message);
647
-		$this->assertEquals('5.0', $message->getScheduleStatus());
648
-	}
542
+    public function testFailedDelivery(): void {
543
+        $message = new Message();
544
+        $message->method = 'REQUEST';
545
+        $newVcalendar = new VCalendar();
546
+        $newVevent = new VEvent($newVcalendar, 'one', array_merge([
547
+            'UID' => 'uid-1234',
548
+            'SEQUENCE' => 1,
549
+            'SUMMARY' => 'Fellowship meeting without (!) Boromir',
550
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
551
+        ], []));
552
+        $newVevent->add('ORGANIZER', 'mailto:[email protected]');
553
+        $newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
554
+        $message->message = $newVcalendar;
555
+        $message->sender = 'mailto:[email protected]';
556
+        $message->senderName = 'Mr. Wizard';
557
+        $message->recipient = 'mailto:' . '[email protected]';
558
+        // save the old copy in the plugin
559
+        $oldVcalendar = new VCalendar();
560
+        $oldVevent = new VEvent($oldVcalendar, 'one', [
561
+            'UID' => 'uid-1234',
562
+            'SEQUENCE' => 0,
563
+            'SUMMARY' => 'Fellowship meeting',
564
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
565
+        ]);
566
+        $oldVevent->add('ORGANIZER', 'mailto:[email protected]');
567
+        $oldVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
568
+        $oldVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
569
+        $oldVcalendar->add($oldVevent);
570
+        $data = ['invitee_name' => 'Mr. Wizard',
571
+            'meeting_title' => 'Fellowship meeting without (!) Boromir',
572
+            'attendee_name' => '[email protected]'
573
+        ];
574
+        $attendees = $newVevent->select('ATTENDEE');
575
+        $atnd = '';
576
+        foreach ($attendees as $attendee) {
577
+            if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
578
+                $atnd = $attendee;
579
+            }
580
+        }
581
+        $this->plugin->setVCalendar($oldVcalendar);
582
+        $this->service->expects(self::once())
583
+            ->method('getLastOccurrence')
584
+            ->willReturn(1496912700);
585
+        $this->eventComparisonService->expects(self::once())
586
+            ->method('findModified')
587
+            ->willReturn(['old' => [] ,'new' => [$newVevent]]);
588
+        $this->service->expects(self::once())
589
+            ->method('getCurrentAttendee')
590
+            ->with($message)
591
+            ->willReturn($atnd);
592
+        $this->service->expects(self::once())
593
+            ->method('isRoomOrResource')
594
+            ->with($atnd)
595
+            ->willReturn(false);
596
+        $this->service->expects(self::once())
597
+            ->method('isCircle')
598
+            ->with($atnd)
599
+            ->willReturn(false);
600
+        $this->service->expects(self::once())
601
+            ->method('buildBodyData')
602
+            ->with($newVevent, null)
603
+            ->willReturn($data);
604
+        $this->user->expects(self::any())
605
+            ->method('getUID')
606
+            ->willReturn('user1');
607
+        $this->user->expects(self::any())
608
+            ->method('getDisplayName')
609
+            ->willReturn('Mr. Wizard');
610
+        $this->userSession->expects(self::any())
611
+            ->method('getUser')
612
+            ->willReturn($this->user);
613
+        $this->service->expects(self::once())
614
+            ->method('getFrom');
615
+        $this->service->expects(self::once())
616
+            ->method('addSubjectAndHeading')
617
+            ->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Fellowship meeting without (!) Boromir', false);
618
+        $this->service->expects(self::once())
619
+            ->method('addBulletList')
620
+            ->with($this->emailTemplate, $newVevent, $data);
621
+        $this->service->expects(self::once())
622
+            ->method('getAttendeeRsvpOrReqForParticipant')
623
+            ->willReturn(true);
624
+        $this->config->expects(self::once())
625
+            ->method('getValueString')
626
+            ->with('dav', 'invitation_link_recipients', 'yes')
627
+            ->willReturn('yes');
628
+        $this->service->expects(self::once())
629
+            ->method('createInvitationToken')
630
+            ->with($message, $newVevent, 1496912700)
631
+            ->willReturn('token');
632
+        $this->service->expects(self::once())
633
+            ->method('addResponseButtons')
634
+            ->with($this->emailTemplate, 'token');
635
+        $this->service->expects(self::once())
636
+            ->method('addMoreOptionsButton')
637
+            ->with($this->emailTemplate, 'token');
638
+        $this->mailer->expects(self::once())
639
+            ->method('send')
640
+            ->willReturn([]);
641
+        $this->mailer
642
+            ->method('send')
643
+            ->willThrowException(new \Exception());
644
+        $this->logger->expects(self::once())
645
+            ->method('error');
646
+        $this->plugin->schedule($message);
647
+        $this->assertEquals('5.0', $message->getScheduleStatus());
648
+    }
649 649
 
650
-	public function testMailProviderSend(): void {
651
-		// construct iTip message with event and attendees
652
-		$message = new Message();
653
-		$message->method = 'REQUEST';
654
-		$calendar = new VCalendar();
655
-		$event = new VEvent($calendar, 'one', array_merge([
656
-			'UID' => 'uid-1234',
657
-			'SEQUENCE' => 1,
658
-			'SUMMARY' => 'Fellowship meeting without (!) Boromir',
659
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
660
-		], []));
661
-		$event->add('ORGANIZER', 'mailto:[email protected]');
662
-		$event->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
663
-		$message->message = $calendar;
664
-		$message->sender = 'mailto:[email protected]';
665
-		$message->senderName = 'Mr. Wizard';
666
-		$message->recipient = 'mailto:' . '[email protected]';
667
-		// construct
668
-		foreach ($event->select('ATTENDEE') as $entry) {
669
-			if (strcasecmp($entry->getValue(), $message->recipient) === 0) {
670
-				$attendee = $entry;
671
-			}
672
-		}
673
-		// construct body data return
674
-		$data = ['invitee_name' => 'Mr. Wizard',
675
-			'meeting_title' => 'Fellowship meeting without (!) Boromir',
676
-			'attendee_name' => '[email protected]'
677
-		];
678
-		// construct system config mock returns
679
-		$this->config->expects(self::once())
680
-			->method('getValueString')
681
-			->with('dav', 'invitation_link_recipients', 'yes')
682
-			->willReturn('yes');
683
-		// construct user mock returns
684
-		$this->user->expects(self::any())
685
-			->method('getUID')
686
-			->willReturn('user1');
687
-		$this->user->expects(self::any())
688
-			->method('getDisplayName')
689
-			->willReturn('Mr. Wizard');
690
-		// construct user session mock returns
691
-		$this->userSession->expects(self::any())
692
-			->method('getUser')
693
-			->willReturn($this->user);
694
-		// construct service mock returns
695
-		$this->service->expects(self::once())
696
-			->method('getLastOccurrence')
697
-			->willReturn(1496912700);
698
-		$this->service->expects(self::once())
699
-			->method('getCurrentAttendee')
700
-			->with($message)
701
-			->willReturn($attendee);
702
-		$this->service->expects(self::once())
703
-			->method('isRoomOrResource')
704
-			->with($attendee)
705
-			->willReturn(false);
706
-		$this->service->expects(self::once())
707
-			->method('isCircle')
708
-			->with($attendee)
709
-			->willReturn(false);
710
-		$this->service->expects(self::once())
711
-			->method('buildBodyData')
712
-			->with($event, null)
713
-			->willReturn($data);
714
-		$this->service->expects(self::once())
715
-			->method('getFrom');
716
-		$this->service->expects(self::once())
717
-			->method('addSubjectAndHeading')
718
-			->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Fellowship meeting without (!) Boromir', false);
719
-		$this->service->expects(self::once())
720
-			->method('addBulletList')
721
-			->with($this->emailTemplate, $event, $data);
722
-		$this->service->expects(self::once())
723
-			->method('getAttendeeRsvpOrReqForParticipant')
724
-			->willReturn(true);
725
-		$this->service->expects(self::once())
726
-			->method('createInvitationToken')
727
-			->with($message, $event, 1496912700)
728
-			->willReturn('token');
729
-		$this->service->expects(self::once())
730
-			->method('addResponseButtons')
731
-			->with($this->emailTemplate, 'token');
732
-		$this->service->expects(self::once())
733
-			->method('addMoreOptionsButton')
734
-			->with($this->emailTemplate, 'token');
735
-		$this->eventComparisonService->expects(self::once())
736
-			->method('findModified')
737
-			->willReturn(['old' => [] ,'new' => [$event]]);
738
-		// construct mail provider mock returns
739
-		$this->mailService
740
-			->method('initiateMessage')
741
-			->willReturn($this->mailMessageNew);
742
-		$this->mailService
743
-			->method('sendMessage')
744
-			->with($this->mailMessageNew);
745
-		$this->mailManager
746
-			->method('findServiceByAddress')
747
-			->with('user1', '[email protected]')
748
-			->willReturn($this->mailService);
650
+    public function testMailProviderSend(): void {
651
+        // construct iTip message with event and attendees
652
+        $message = new Message();
653
+        $message->method = 'REQUEST';
654
+        $calendar = new VCalendar();
655
+        $event = new VEvent($calendar, 'one', array_merge([
656
+            'UID' => 'uid-1234',
657
+            'SEQUENCE' => 1,
658
+            'SUMMARY' => 'Fellowship meeting without (!) Boromir',
659
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
660
+        ], []));
661
+        $event->add('ORGANIZER', 'mailto:[email protected]');
662
+        $event->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
663
+        $message->message = $calendar;
664
+        $message->sender = 'mailto:[email protected]';
665
+        $message->senderName = 'Mr. Wizard';
666
+        $message->recipient = 'mailto:' . '[email protected]';
667
+        // construct
668
+        foreach ($event->select('ATTENDEE') as $entry) {
669
+            if (strcasecmp($entry->getValue(), $message->recipient) === 0) {
670
+                $attendee = $entry;
671
+            }
672
+        }
673
+        // construct body data return
674
+        $data = ['invitee_name' => 'Mr. Wizard',
675
+            'meeting_title' => 'Fellowship meeting without (!) Boromir',
676
+            'attendee_name' => '[email protected]'
677
+        ];
678
+        // construct system config mock returns
679
+        $this->config->expects(self::once())
680
+            ->method('getValueString')
681
+            ->with('dav', 'invitation_link_recipients', 'yes')
682
+            ->willReturn('yes');
683
+        // construct user mock returns
684
+        $this->user->expects(self::any())
685
+            ->method('getUID')
686
+            ->willReturn('user1');
687
+        $this->user->expects(self::any())
688
+            ->method('getDisplayName')
689
+            ->willReturn('Mr. Wizard');
690
+        // construct user session mock returns
691
+        $this->userSession->expects(self::any())
692
+            ->method('getUser')
693
+            ->willReturn($this->user);
694
+        // construct service mock returns
695
+        $this->service->expects(self::once())
696
+            ->method('getLastOccurrence')
697
+            ->willReturn(1496912700);
698
+        $this->service->expects(self::once())
699
+            ->method('getCurrentAttendee')
700
+            ->with($message)
701
+            ->willReturn($attendee);
702
+        $this->service->expects(self::once())
703
+            ->method('isRoomOrResource')
704
+            ->with($attendee)
705
+            ->willReturn(false);
706
+        $this->service->expects(self::once())
707
+            ->method('isCircle')
708
+            ->with($attendee)
709
+            ->willReturn(false);
710
+        $this->service->expects(self::once())
711
+            ->method('buildBodyData')
712
+            ->with($event, null)
713
+            ->willReturn($data);
714
+        $this->service->expects(self::once())
715
+            ->method('getFrom');
716
+        $this->service->expects(self::once())
717
+            ->method('addSubjectAndHeading')
718
+            ->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Fellowship meeting without (!) Boromir', false);
719
+        $this->service->expects(self::once())
720
+            ->method('addBulletList')
721
+            ->with($this->emailTemplate, $event, $data);
722
+        $this->service->expects(self::once())
723
+            ->method('getAttendeeRsvpOrReqForParticipant')
724
+            ->willReturn(true);
725
+        $this->service->expects(self::once())
726
+            ->method('createInvitationToken')
727
+            ->with($message, $event, 1496912700)
728
+            ->willReturn('token');
729
+        $this->service->expects(self::once())
730
+            ->method('addResponseButtons')
731
+            ->with($this->emailTemplate, 'token');
732
+        $this->service->expects(self::once())
733
+            ->method('addMoreOptionsButton')
734
+            ->with($this->emailTemplate, 'token');
735
+        $this->eventComparisonService->expects(self::once())
736
+            ->method('findModified')
737
+            ->willReturn(['old' => [] ,'new' => [$event]]);
738
+        // construct mail provider mock returns
739
+        $this->mailService
740
+            ->method('initiateMessage')
741
+            ->willReturn($this->mailMessageNew);
742
+        $this->mailService
743
+            ->method('sendMessage')
744
+            ->with($this->mailMessageNew);
745
+        $this->mailManager
746
+            ->method('findServiceByAddress')
747
+            ->with('user1', '[email protected]')
748
+            ->willReturn($this->mailService);
749 749
 
750
-		$this->plugin->schedule($message);
751
-		$this->assertEquals('1.1', $message->getScheduleStatus());
752
-	}
750
+        $this->plugin->schedule($message);
751
+        $this->assertEquals('1.1', $message->getScheduleStatus());
752
+    }
753 753
 
754
-	public function testMailProviderDisabled(): void {
755
-		$message = new Message();
756
-		$message->method = 'REQUEST';
757
-		$newVCalendar = new VCalendar();
758
-		$newVevent = new VEvent($newVCalendar, 'one', array_merge([
759
-			'UID' => 'uid-1234',
760
-			'SEQUENCE' => 1,
761
-			'SUMMARY' => 'Fellowship meeting without (!) Boromir',
762
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
763
-		], []));
764
-		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
765
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
766
-		$message->message = $newVCalendar;
767
-		$message->sender = 'mailto:[email protected]';
768
-		$message->senderName = 'Mr. Wizard';
769
-		$message->recipient = 'mailto:' . '[email protected]';
770
-		// save the old copy in the plugin
771
-		$oldVCalendar = new VCalendar();
772
-		$oldVEvent = new VEvent($oldVCalendar, 'one', [
773
-			'UID' => 'uid-1234',
774
-			'SEQUENCE' => 0,
775
-			'SUMMARY' => 'Fellowship meeting',
776
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
777
-		]);
778
-		$oldVEvent->add('ORGANIZER', 'mailto:[email protected]');
779
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
780
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
781
-		$oldVCalendar->add($oldVEvent);
782
-		$data = ['invitee_name' => 'Mr. Wizard',
783
-			'meeting_title' => 'Fellowship meeting without (!) Boromir',
784
-			'attendee_name' => '[email protected]'
785
-		];
786
-		$attendees = $newVevent->select('ATTENDEE');
787
-		$atnd = '';
788
-		foreach ($attendees as $attendee) {
789
-			if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
790
-				$atnd = $attendee;
791
-			}
792
-		}
793
-		$this->plugin->setVCalendar($oldVCalendar);
794
-		$this->service->expects(self::once())
795
-			->method('getLastOccurrence')
796
-			->willReturn(1496912700);
797
-		$this->eventComparisonService->expects(self::once())
798
-			->method('findModified')
799
-			->willReturn(['new' => [$newVevent], 'old' => [$oldVEvent]]);
800
-		$this->service->expects(self::once())
801
-			->method('getCurrentAttendee')
802
-			->with($message)
803
-			->willReturn($atnd);
804
-		$this->service->expects(self::once())
805
-			->method('isRoomOrResource')
806
-			->with($atnd)
807
-			->willReturn(false);
808
-		$this->service->expects(self::once())
809
-			->method('isCircle')
810
-			->with($atnd)
811
-			->willReturn(false);
812
-		$this->service->expects(self::once())
813
-			->method('buildBodyData')
814
-			->with($newVevent, $oldVEvent)
815
-			->willReturn($data);
816
-		$this->user->expects(self::any())
817
-			->method('getUID')
818
-			->willReturn('user1');
819
-		$this->user->expects(self::any())
820
-			->method('getDisplayName')
821
-			->willReturn('Mr. Wizard');
822
-		$this->userSession->expects(self::any())
823
-			->method('getUser')
824
-			->willReturn($this->user);
825
-		$this->service->expects(self::once())
826
-			->method('getFrom');
827
-		$this->service->expects(self::once())
828
-			->method('addSubjectAndHeading')
829
-			->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Fellowship meeting without (!) Boromir', true);
830
-		$this->service->expects(self::once())
831
-			->method('addBulletList')
832
-			->with($this->emailTemplate, $newVevent, $data);
833
-		$this->service->expects(self::once())
834
-			->method('getAttendeeRsvpOrReqForParticipant')
835
-			->willReturn(true);
836
-		$this->config->expects(self::once())
837
-			->method('getValueString')
838
-			->with('dav', 'invitation_link_recipients', 'yes')
839
-			->willReturn('yes');
840
-		$this->config->expects(self::once())
841
-			->method('getValueBool')
842
-			->with('core', 'mail_providers_enabled', true)
843
-			->willReturn(false);
844
-		$this->service->expects(self::once())
845
-			->method('createInvitationToken')
846
-			->with($message, $newVevent, 1496912700)
847
-			->willReturn('token');
848
-		$this->service->expects(self::once())
849
-			->method('addResponseButtons')
850
-			->with($this->emailTemplate, 'token');
851
-		$this->service->expects(self::once())
852
-			->method('addMoreOptionsButton')
853
-			->with($this->emailTemplate, 'token');
854
-		$this->mailer->expects(self::once())
855
-			->method('send')
856
-			->willReturn([]);
857
-		$this->plugin->schedule($message);
858
-		$this->assertEquals('1.1', $message->getScheduleStatus());
859
-	}
754
+    public function testMailProviderDisabled(): void {
755
+        $message = new Message();
756
+        $message->method = 'REQUEST';
757
+        $newVCalendar = new VCalendar();
758
+        $newVevent = new VEvent($newVCalendar, 'one', array_merge([
759
+            'UID' => 'uid-1234',
760
+            'SEQUENCE' => 1,
761
+            'SUMMARY' => 'Fellowship meeting without (!) Boromir',
762
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
763
+        ], []));
764
+        $newVevent->add('ORGANIZER', 'mailto:[email protected]');
765
+        $newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
766
+        $message->message = $newVCalendar;
767
+        $message->sender = 'mailto:[email protected]';
768
+        $message->senderName = 'Mr. Wizard';
769
+        $message->recipient = 'mailto:' . '[email protected]';
770
+        // save the old copy in the plugin
771
+        $oldVCalendar = new VCalendar();
772
+        $oldVEvent = new VEvent($oldVCalendar, 'one', [
773
+            'UID' => 'uid-1234',
774
+            'SEQUENCE' => 0,
775
+            'SUMMARY' => 'Fellowship meeting',
776
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
777
+        ]);
778
+        $oldVEvent->add('ORGANIZER', 'mailto:[email protected]');
779
+        $oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
780
+        $oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
781
+        $oldVCalendar->add($oldVEvent);
782
+        $data = ['invitee_name' => 'Mr. Wizard',
783
+            'meeting_title' => 'Fellowship meeting without (!) Boromir',
784
+            'attendee_name' => '[email protected]'
785
+        ];
786
+        $attendees = $newVevent->select('ATTENDEE');
787
+        $atnd = '';
788
+        foreach ($attendees as $attendee) {
789
+            if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
790
+                $atnd = $attendee;
791
+            }
792
+        }
793
+        $this->plugin->setVCalendar($oldVCalendar);
794
+        $this->service->expects(self::once())
795
+            ->method('getLastOccurrence')
796
+            ->willReturn(1496912700);
797
+        $this->eventComparisonService->expects(self::once())
798
+            ->method('findModified')
799
+            ->willReturn(['new' => [$newVevent], 'old' => [$oldVEvent]]);
800
+        $this->service->expects(self::once())
801
+            ->method('getCurrentAttendee')
802
+            ->with($message)
803
+            ->willReturn($atnd);
804
+        $this->service->expects(self::once())
805
+            ->method('isRoomOrResource')
806
+            ->with($atnd)
807
+            ->willReturn(false);
808
+        $this->service->expects(self::once())
809
+            ->method('isCircle')
810
+            ->with($atnd)
811
+            ->willReturn(false);
812
+        $this->service->expects(self::once())
813
+            ->method('buildBodyData')
814
+            ->with($newVevent, $oldVEvent)
815
+            ->willReturn($data);
816
+        $this->user->expects(self::any())
817
+            ->method('getUID')
818
+            ->willReturn('user1');
819
+        $this->user->expects(self::any())
820
+            ->method('getDisplayName')
821
+            ->willReturn('Mr. Wizard');
822
+        $this->userSession->expects(self::any())
823
+            ->method('getUser')
824
+            ->willReturn($this->user);
825
+        $this->service->expects(self::once())
826
+            ->method('getFrom');
827
+        $this->service->expects(self::once())
828
+            ->method('addSubjectAndHeading')
829
+            ->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Fellowship meeting without (!) Boromir', true);
830
+        $this->service->expects(self::once())
831
+            ->method('addBulletList')
832
+            ->with($this->emailTemplate, $newVevent, $data);
833
+        $this->service->expects(self::once())
834
+            ->method('getAttendeeRsvpOrReqForParticipant')
835
+            ->willReturn(true);
836
+        $this->config->expects(self::once())
837
+            ->method('getValueString')
838
+            ->with('dav', 'invitation_link_recipients', 'yes')
839
+            ->willReturn('yes');
840
+        $this->config->expects(self::once())
841
+            ->method('getValueBool')
842
+            ->with('core', 'mail_providers_enabled', true)
843
+            ->willReturn(false);
844
+        $this->service->expects(self::once())
845
+            ->method('createInvitationToken')
846
+            ->with($message, $newVevent, 1496912700)
847
+            ->willReturn('token');
848
+        $this->service->expects(self::once())
849
+            ->method('addResponseButtons')
850
+            ->with($this->emailTemplate, 'token');
851
+        $this->service->expects(self::once())
852
+            ->method('addMoreOptionsButton')
853
+            ->with($this->emailTemplate, 'token');
854
+        $this->mailer->expects(self::once())
855
+            ->method('send')
856
+            ->willReturn([]);
857
+        $this->plugin->schedule($message);
858
+        $this->assertEquals('1.1', $message->getScheduleStatus());
859
+    }
860 860
 
861
-	public function testNoOldEvent(): void {
862
-		$message = new Message();
863
-		$message->method = 'REQUEST';
864
-		$newVCalendar = new VCalendar();
865
-		$newVevent = new VEvent($newVCalendar, 'VEVENT', array_merge([
866
-			'UID' => 'uid-1234',
867
-			'SEQUENCE' => 1,
868
-			'SUMMARY' => 'Fellowship meeting',
869
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
870
-		], []));
871
-		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
872
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
873
-		$message->message = $newVCalendar;
874
-		$message->sender = 'mailto:[email protected]';
875
-		$message->senderName = 'Mr. Wizard';
876
-		$message->recipient = 'mailto:' . '[email protected]';
877
-		$data = ['invitee_name' => 'Mr. Wizard',
878
-			'meeting_title' => 'Fellowship meeting',
879
-			'attendee_name' => '[email protected]'
880
-		];
881
-		$attendees = $newVevent->select('ATTENDEE');
882
-		$atnd = '';
883
-		foreach ($attendees as $attendee) {
884
-			if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
885
-				$atnd = $attendee;
886
-			}
887
-		}
888
-		$this->service->expects(self::once())
889
-			->method('getLastOccurrence')
890
-			->willReturn(1496912700);
891
-		$this->eventComparisonService->expects(self::once())
892
-			->method('findModified')
893
-			->with($newVCalendar, null)
894
-			->willReturn(['old' => [] ,'new' => [$newVevent]]);
895
-		$this->service->expects(self::once())
896
-			->method('getCurrentAttendee')
897
-			->with($message)
898
-			->willReturn($atnd);
899
-		$this->service->expects(self::once())
900
-			->method('isRoomOrResource')
901
-			->with($atnd)
902
-			->willReturn(false);
903
-		$this->service->expects(self::once())
904
-			->method('isCircle')
905
-			->with($atnd)
906
-			->willReturn(false);
907
-		$this->service->expects(self::once())
908
-			->method('buildBodyData')
909
-			->with($newVevent, null)
910
-			->willReturn($data);
911
-		$this->user->expects(self::any())
912
-			->method('getUID')
913
-			->willReturn('user1');
914
-		$this->user->expects(self::any())
915
-			->method('getDisplayName')
916
-			->willReturn('Mr. Wizard');
917
-		$this->userSession->expects(self::any())
918
-			->method('getUser')
919
-			->willReturn($this->user);
920
-		$this->service->expects(self::once())
921
-			->method('getFrom');
922
-		$this->service->expects(self::once())
923
-			->method('addSubjectAndHeading')
924
-			->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Fellowship meeting', false);
925
-		$this->service->expects(self::once())
926
-			->method('addBulletList')
927
-			->with($this->emailTemplate, $newVevent, $data);
928
-		$this->service->expects(self::once())
929
-			->method('getAttendeeRsvpOrReqForParticipant')
930
-			->willReturn(true);
931
-		$this->config->expects(self::once())
932
-			->method('getValueString')
933
-			->with('dav', 'invitation_link_recipients', 'yes')
934
-			->willReturn('yes');
935
-		$this->service->expects(self::once())
936
-			->method('createInvitationToken')
937
-			->with($message, $newVevent, 1496912700)
938
-			->willReturn('token');
939
-		$this->service->expects(self::once())
940
-			->method('addResponseButtons')
941
-			->with($this->emailTemplate, 'token');
942
-		$this->service->expects(self::once())
943
-			->method('addMoreOptionsButton')
944
-			->with($this->emailTemplate, 'token');
945
-		$this->mailer->expects(self::once())
946
-			->method('send')
947
-			->willReturn([]);
948
-		$this->mailer
949
-			->method('send')
950
-			->willReturn([]);
951
-		$this->plugin->schedule($message);
952
-		$this->assertEquals('1.1', $message->getScheduleStatus());
953
-	}
861
+    public function testNoOldEvent(): void {
862
+        $message = new Message();
863
+        $message->method = 'REQUEST';
864
+        $newVCalendar = new VCalendar();
865
+        $newVevent = new VEvent($newVCalendar, 'VEVENT', array_merge([
866
+            'UID' => 'uid-1234',
867
+            'SEQUENCE' => 1,
868
+            'SUMMARY' => 'Fellowship meeting',
869
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
870
+        ], []));
871
+        $newVevent->add('ORGANIZER', 'mailto:[email protected]');
872
+        $newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
873
+        $message->message = $newVCalendar;
874
+        $message->sender = 'mailto:[email protected]';
875
+        $message->senderName = 'Mr. Wizard';
876
+        $message->recipient = 'mailto:' . '[email protected]';
877
+        $data = ['invitee_name' => 'Mr. Wizard',
878
+            'meeting_title' => 'Fellowship meeting',
879
+            'attendee_name' => '[email protected]'
880
+        ];
881
+        $attendees = $newVevent->select('ATTENDEE');
882
+        $atnd = '';
883
+        foreach ($attendees as $attendee) {
884
+            if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
885
+                $atnd = $attendee;
886
+            }
887
+        }
888
+        $this->service->expects(self::once())
889
+            ->method('getLastOccurrence')
890
+            ->willReturn(1496912700);
891
+        $this->eventComparisonService->expects(self::once())
892
+            ->method('findModified')
893
+            ->with($newVCalendar, null)
894
+            ->willReturn(['old' => [] ,'new' => [$newVevent]]);
895
+        $this->service->expects(self::once())
896
+            ->method('getCurrentAttendee')
897
+            ->with($message)
898
+            ->willReturn($atnd);
899
+        $this->service->expects(self::once())
900
+            ->method('isRoomOrResource')
901
+            ->with($atnd)
902
+            ->willReturn(false);
903
+        $this->service->expects(self::once())
904
+            ->method('isCircle')
905
+            ->with($atnd)
906
+            ->willReturn(false);
907
+        $this->service->expects(self::once())
908
+            ->method('buildBodyData')
909
+            ->with($newVevent, null)
910
+            ->willReturn($data);
911
+        $this->user->expects(self::any())
912
+            ->method('getUID')
913
+            ->willReturn('user1');
914
+        $this->user->expects(self::any())
915
+            ->method('getDisplayName')
916
+            ->willReturn('Mr. Wizard');
917
+        $this->userSession->expects(self::any())
918
+            ->method('getUser')
919
+            ->willReturn($this->user);
920
+        $this->service->expects(self::once())
921
+            ->method('getFrom');
922
+        $this->service->expects(self::once())
923
+            ->method('addSubjectAndHeading')
924
+            ->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Fellowship meeting', false);
925
+        $this->service->expects(self::once())
926
+            ->method('addBulletList')
927
+            ->with($this->emailTemplate, $newVevent, $data);
928
+        $this->service->expects(self::once())
929
+            ->method('getAttendeeRsvpOrReqForParticipant')
930
+            ->willReturn(true);
931
+        $this->config->expects(self::once())
932
+            ->method('getValueString')
933
+            ->with('dav', 'invitation_link_recipients', 'yes')
934
+            ->willReturn('yes');
935
+        $this->service->expects(self::once())
936
+            ->method('createInvitationToken')
937
+            ->with($message, $newVevent, 1496912700)
938
+            ->willReturn('token');
939
+        $this->service->expects(self::once())
940
+            ->method('addResponseButtons')
941
+            ->with($this->emailTemplate, 'token');
942
+        $this->service->expects(self::once())
943
+            ->method('addMoreOptionsButton')
944
+            ->with($this->emailTemplate, 'token');
945
+        $this->mailer->expects(self::once())
946
+            ->method('send')
947
+            ->willReturn([]);
948
+        $this->mailer
949
+            ->method('send')
950
+            ->willReturn([]);
951
+        $this->plugin->schedule($message);
952
+        $this->assertEquals('1.1', $message->getScheduleStatus());
953
+    }
954 954
 
955
-	public function testNoButtons(): void {
956
-		$message = new Message();
957
-		$message->method = 'REQUEST';
958
-		$newVCalendar = new VCalendar();
959
-		$newVevent = new VEvent($newVCalendar, 'VEVENT', array_merge([
960
-			'UID' => 'uid-1234',
961
-			'SEQUENCE' => 1,
962
-			'SUMMARY' => 'Fellowship meeting',
963
-			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
964
-		], []));
965
-		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
966
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
967
-		$message->message = $newVCalendar;
968
-		$message->sender = 'mailto:[email protected]';
969
-		$message->recipient = 'mailto:' . '[email protected]';
970
-		$data = ['invitee_name' => 'Mr. Wizard',
971
-			'meeting_title' => 'Fellowship meeting',
972
-			'attendee_name' => '[email protected]'
973
-		];
974
-		$attendees = $newVevent->select('ATTENDEE');
975
-		$atnd = '';
976
-		foreach ($attendees as $attendee) {
977
-			if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
978
-				$atnd = $attendee;
979
-			}
980
-		}
981
-		$this->service->expects(self::once())
982
-			->method('getLastOccurrence')
983
-			->willReturn(1496912700);
984
-		$this->eventComparisonService->expects(self::once())
985
-			->method('findModified')
986
-			->with($newVCalendar, null)
987
-			->willReturn(['old' => [] ,'new' => [$newVevent]]);
988
-		$this->service->expects(self::once())
989
-			->method('getCurrentAttendee')
990
-			->with($message)
991
-			->willReturn($atnd);
992
-		$this->service->expects(self::once())
993
-			->method('isRoomOrResource')
994
-			->with($atnd)
995
-			->willReturn(false);
996
-		$this->service->expects(self::once())
997
-			->method('isCircle')
998
-			->with($atnd)
999
-			->willReturn(false);
1000
-		$this->service->expects(self::once())
1001
-			->method('buildBodyData')
1002
-			->with($newVevent, null)
1003
-			->willReturn($data);
1004
-		$this->user->expects(self::any())
1005
-			->method('getUID')
1006
-			->willReturn('user1');
1007
-		$this->user->expects(self::any())
1008
-			->method('getDisplayName')
1009
-			->willReturn('Mr. Wizard');
1010
-		$this->userSession->expects(self::any())
1011
-			->method('getUser')
1012
-			->willReturn($this->user);
1013
-		$this->service->expects(self::once())
1014
-			->method('getFrom');
1015
-		$this->service->expects(self::once())
1016
-			->method('addSubjectAndHeading')
1017
-			->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Fellowship meeting', false);
1018
-		$this->service->expects(self::once())
1019
-			->method('addBulletList')
1020
-			->with($this->emailTemplate, $newVevent, $data);
1021
-		$this->service->expects(self::once())
1022
-			->method('getAttendeeRsvpOrReqForParticipant')
1023
-			->willReturn(true);
1024
-		$this->config->expects(self::once())
1025
-			->method('getValueString')
1026
-			->with('dav', 'invitation_link_recipients', 'yes')
1027
-			->willReturn('no');
1028
-		$this->service->expects(self::never())
1029
-			->method('createInvitationToken');
1030
-		$this->service->expects(self::never())
1031
-			->method('addResponseButtons');
1032
-		$this->service->expects(self::never())
1033
-			->method('addMoreOptionsButton');
1034
-		$this->mailer->expects(self::once())
1035
-			->method('send')
1036
-			->willReturn([]);
1037
-		$this->mailer
1038
-			->method('send')
1039
-			->willReturn([]);
1040
-		$this->plugin->schedule($message);
1041
-		$this->assertEquals('1.1', $message->getScheduleStatus());
1042
-	}
955
+    public function testNoButtons(): void {
956
+        $message = new Message();
957
+        $message->method = 'REQUEST';
958
+        $newVCalendar = new VCalendar();
959
+        $newVevent = new VEvent($newVCalendar, 'VEVENT', array_merge([
960
+            'UID' => 'uid-1234',
961
+            'SEQUENCE' => 1,
962
+            'SUMMARY' => 'Fellowship meeting',
963
+            'DTSTART' => new \DateTime('2016-01-01 00:00:00')
964
+        ], []));
965
+        $newVevent->add('ORGANIZER', 'mailto:[email protected]');
966
+        $newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
967
+        $message->message = $newVCalendar;
968
+        $message->sender = 'mailto:[email protected]';
969
+        $message->recipient = 'mailto:' . '[email protected]';
970
+        $data = ['invitee_name' => 'Mr. Wizard',
971
+            'meeting_title' => 'Fellowship meeting',
972
+            'attendee_name' => '[email protected]'
973
+        ];
974
+        $attendees = $newVevent->select('ATTENDEE');
975
+        $atnd = '';
976
+        foreach ($attendees as $attendee) {
977
+            if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
978
+                $atnd = $attendee;
979
+            }
980
+        }
981
+        $this->service->expects(self::once())
982
+            ->method('getLastOccurrence')
983
+            ->willReturn(1496912700);
984
+        $this->eventComparisonService->expects(self::once())
985
+            ->method('findModified')
986
+            ->with($newVCalendar, null)
987
+            ->willReturn(['old' => [] ,'new' => [$newVevent]]);
988
+        $this->service->expects(self::once())
989
+            ->method('getCurrentAttendee')
990
+            ->with($message)
991
+            ->willReturn($atnd);
992
+        $this->service->expects(self::once())
993
+            ->method('isRoomOrResource')
994
+            ->with($atnd)
995
+            ->willReturn(false);
996
+        $this->service->expects(self::once())
997
+            ->method('isCircle')
998
+            ->with($atnd)
999
+            ->willReturn(false);
1000
+        $this->service->expects(self::once())
1001
+            ->method('buildBodyData')
1002
+            ->with($newVevent, null)
1003
+            ->willReturn($data);
1004
+        $this->user->expects(self::any())
1005
+            ->method('getUID')
1006
+            ->willReturn('user1');
1007
+        $this->user->expects(self::any())
1008
+            ->method('getDisplayName')
1009
+            ->willReturn('Mr. Wizard');
1010
+        $this->userSession->expects(self::any())
1011
+            ->method('getUser')
1012
+            ->willReturn($this->user);
1013
+        $this->service->expects(self::once())
1014
+            ->method('getFrom');
1015
+        $this->service->expects(self::once())
1016
+            ->method('addSubjectAndHeading')
1017
+            ->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Fellowship meeting', false);
1018
+        $this->service->expects(self::once())
1019
+            ->method('addBulletList')
1020
+            ->with($this->emailTemplate, $newVevent, $data);
1021
+        $this->service->expects(self::once())
1022
+            ->method('getAttendeeRsvpOrReqForParticipant')
1023
+            ->willReturn(true);
1024
+        $this->config->expects(self::once())
1025
+            ->method('getValueString')
1026
+            ->with('dav', 'invitation_link_recipients', 'yes')
1027
+            ->willReturn('no');
1028
+        $this->service->expects(self::never())
1029
+            ->method('createInvitationToken');
1030
+        $this->service->expects(self::never())
1031
+            ->method('addResponseButtons');
1032
+        $this->service->expects(self::never())
1033
+            ->method('addMoreOptionsButton');
1034
+        $this->mailer->expects(self::once())
1035
+            ->method('send')
1036
+            ->willReturn([]);
1037
+        $this->mailer
1038
+            ->method('send')
1039
+            ->willReturn([]);
1040
+        $this->plugin->schedule($message);
1041
+        $this->assertEquals('1.1', $message->getScheduleStatus());
1042
+    }
1043 1043
 }
Please login to merge, or discard this patch.
Spacing   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -125,10 +125,10 @@  discard block
 block discarded – undo
125 125
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
126 126
 		], []));
127 127
 		$message->message->VEVENT->add('ORGANIZER', 'mailto:[email protected]');
128
-		$message->message->VEVENT->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
128
+		$message->message->VEVENT->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE']);
129 129
 		$message->sender = 'mailto:[email protected]';
130 130
 		$message->senderName = 'Mr. Wizard';
131
-		$message->recipient = 'mailto:' . '[email protected]';
131
+		$message->recipient = 'mailto:'.'[email protected]';
132 132
 		$message->significantChange = false;
133 133
 		$this->plugin->schedule($message);
134 134
 		$this->assertEquals('1.0', $message->getScheduleStatus());
@@ -145,11 +145,11 @@  discard block
 block discarded – undo
145 145
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
146 146
 		], []));
147 147
 		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
148
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
148
+		$newVevent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
149 149
 		$message->message = $newVCalendar;
150 150
 		$message->sender = 'mailto:[email protected]';
151 151
 		$message->senderName = 'Mr. Wizard';
152
-		$message->recipient = 'mailto:' . '[email protected]';
152
+		$message->recipient = 'mailto:'.'[email protected]';
153 153
 		// save the old copy in the plugin
154 154
 		$oldVCalendar = new VCalendar();
155 155
 		$oldVEvent = new VEvent($oldVCalendar, 'one', [
@@ -159,8 +159,8 @@  discard block
 block discarded – undo
159 159
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
160 160
 		]);
161 161
 		$oldVEvent->add('ORGANIZER', 'mailto:[email protected]');
162
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
163
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
162
+		$oldVEvent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
163
+		$oldVEvent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE']);
164 164
 		$oldVCalendar->add($oldVEvent);
165 165
 		$data = ['invitee_name' => 'Mr. Wizard',
166 166
 			'meeting_title' => 'Fellowship meeting without (!) Boromir',
@@ -248,11 +248,11 @@  discard block
 block discarded – undo
248 248
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
249 249
 		], []));
250 250
 		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
251
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'The Shire', 'CUTYPE' => 'ROOM']);
251
+		$newVevent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'The Shire', 'CUTYPE' => 'ROOM']);
252 252
 		$message->message = $newVCalendar;
253 253
 		$message->sender = 'mailto:[email protected]';
254 254
 		$message->senderName = 'Mr. Wizard';
255
-		$message->recipient = 'mailto:' . '[email protected]';
255
+		$message->recipient = 'mailto:'.'[email protected]';
256 256
 		// save the old copy in the plugin
257 257
 		$oldVCalendar = new VCalendar();
258 258
 		$oldVEvent = new VEvent($oldVCalendar, 'one', [
@@ -262,8 +262,8 @@  discard block
 block discarded – undo
262 262
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
263 263
 		]);
264 264
 		$oldVEvent->add('ORGANIZER', 'mailto:[email protected]');
265
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'The Shire', 'CUTYPE' => 'ROOM']);
266
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
265
+		$oldVEvent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'The Shire', 'CUTYPE' => 'ROOM']);
266
+		$oldVEvent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE']);
267 267
 		$oldVCalendar->add($oldVEvent);
268 268
 		$data = ['invitee_name' => 'Mr. Wizard',
269 269
 			'meeting_title' => 'Fellowship meeting without (!) Boromir',
@@ -337,12 +337,12 @@  discard block
 block discarded – undo
337 337
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
338 338
 		], []));
339 339
 		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
340
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'The Fellowship', 'CUTYPE' => 'GROUP']);
341
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'MEMBER' => '[email protected]']);
340
+		$newVevent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'The Fellowship', 'CUTYPE' => 'GROUP']);
341
+		$newVevent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'MEMBER' => '[email protected]']);
342 342
 		$message->message = $newVCalendar;
343 343
 		$message->sender = 'mailto:[email protected]';
344 344
 		$message->senderName = 'Mr. Wizard';
345
-		$message->recipient = 'mailto:' . '[email protected]';
345
+		$message->recipient = 'mailto:'.'[email protected]';
346 346
 		$attendees = $newVevent->select('ATTENDEE');
347 347
 		$circle = '';
348 348
 		foreach ($attendees as $attendee) {
@@ -415,7 +415,7 @@  discard block
 block discarded – undo
415 415
 			'RRULE' => 'FREQ=DAILY;INTERVAL=1;UNTIL=20160201T000000Z'
416 416
 		]);
417 417
 		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
418
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
418
+		$newVevent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
419 419
 		$newvEvent2 = new VEvent($newVCalendar, 'two', [
420 420
 			'UID' => 'uid-1234',
421 421
 			'SEQUENCE' => 1,
@@ -424,10 +424,10 @@  discard block
 block discarded – undo
424 424
 			'RECURRENCE-ID' => new \DateTime('2016-01-01 00:00:00')
425 425
 		]);
426 426
 		$newvEvent2->add('ORGANIZER', 'mailto:[email protected]');
427
-		$newvEvent2->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
427
+		$newvEvent2->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
428 428
 		$message->message = $newVCalendar;
429 429
 		$message->sender = 'mailto:[email protected]';
430
-		$message->recipient = 'mailto:' . '[email protected]';
430
+		$message->recipient = 'mailto:'.'[email protected]';
431 431
 		// save the old copy in the plugin
432 432
 		$oldVCalendar = new VCalendar();
433 433
 		$oldVEvent = new VEvent($oldVCalendar, 'one', [
@@ -439,7 +439,7 @@  discard block
 block discarded – undo
439 439
 			'RRULE' => 'FREQ=DAILY;INTERVAL=1;UNTIL=20160201T000000Z'
440 440
 		]);
441 441
 		$oldVEvent->add('ORGANIZER', 'mailto:[email protected]');
442
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
442
+		$oldVEvent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
443 443
 		$data = ['invitee_name' => 'Mr. Wizard',
444 444
 			'meeting_title' => 'Elevenses',
445 445
 			'attendee_name' => '[email protected]'
@@ -457,7 +457,7 @@  discard block
 block discarded – undo
457 457
 			->willReturn(1496912700);
458 458
 		$this->eventComparisonService->expects(self::once())
459 459
 			->method('findModified')
460
-			->willReturn(['old' => [] ,'new' => [$newVevent]]);
460
+			->willReturn(['old' => [], 'new' => [$newVevent]]);
461 461
 		$this->service->expects(self::once())
462 462
 			->method('getCurrentAttendee')
463 463
 			->with($message)
@@ -526,10 +526,10 @@  discard block
 block discarded – undo
526 526
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
527 527
 		], []));
528 528
 		$message->message->VEVENT->add('ORGANIZER', 'mailto:[email protected]');
529
-		$message->message->VEVENT->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
529
+		$message->message->VEVENT->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE']);
530 530
 		$message->sender = 'mailto:[email protected]';
531 531
 		$message->senderName = 'Mr. Wizard';
532
-		$message->recipient = 'mailto:' . 'frodo@@hobb.it';
532
+		$message->recipient = 'mailto:'.'frodo@@hobb.it';
533 533
 
534 534
 		$this->service->expects(self::once())
535 535
 			->method('getLastOccurrence')
@@ -550,11 +550,11 @@  discard block
 block discarded – undo
550 550
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
551 551
 		], []));
552 552
 		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
553
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
553
+		$newVevent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
554 554
 		$message->message = $newVcalendar;
555 555
 		$message->sender = 'mailto:[email protected]';
556 556
 		$message->senderName = 'Mr. Wizard';
557
-		$message->recipient = 'mailto:' . '[email protected]';
557
+		$message->recipient = 'mailto:'.'[email protected]';
558 558
 		// save the old copy in the plugin
559 559
 		$oldVcalendar = new VCalendar();
560 560
 		$oldVevent = new VEvent($oldVcalendar, 'one', [
@@ -564,8 +564,8 @@  discard block
 block discarded – undo
564 564
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
565 565
 		]);
566 566
 		$oldVevent->add('ORGANIZER', 'mailto:[email protected]');
567
-		$oldVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
568
-		$oldVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
567
+		$oldVevent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
568
+		$oldVevent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE']);
569 569
 		$oldVcalendar->add($oldVevent);
570 570
 		$data = ['invitee_name' => 'Mr. Wizard',
571 571
 			'meeting_title' => 'Fellowship meeting without (!) Boromir',
@@ -584,7 +584,7 @@  discard block
 block discarded – undo
584 584
 			->willReturn(1496912700);
585 585
 		$this->eventComparisonService->expects(self::once())
586 586
 			->method('findModified')
587
-			->willReturn(['old' => [] ,'new' => [$newVevent]]);
587
+			->willReturn(['old' => [], 'new' => [$newVevent]]);
588 588
 		$this->service->expects(self::once())
589 589
 			->method('getCurrentAttendee')
590 590
 			->with($message)
@@ -659,11 +659,11 @@  discard block
 block discarded – undo
659 659
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
660 660
 		], []));
661 661
 		$event->add('ORGANIZER', 'mailto:[email protected]');
662
-		$event->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
662
+		$event->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
663 663
 		$message->message = $calendar;
664 664
 		$message->sender = 'mailto:[email protected]';
665 665
 		$message->senderName = 'Mr. Wizard';
666
-		$message->recipient = 'mailto:' . '[email protected]';
666
+		$message->recipient = 'mailto:'.'[email protected]';
667 667
 		// construct
668 668
 		foreach ($event->select('ATTENDEE') as $entry) {
669 669
 			if (strcasecmp($entry->getValue(), $message->recipient) === 0) {
@@ -734,7 +734,7 @@  discard block
 block discarded – undo
734 734
 			->with($this->emailTemplate, 'token');
735 735
 		$this->eventComparisonService->expects(self::once())
736 736
 			->method('findModified')
737
-			->willReturn(['old' => [] ,'new' => [$event]]);
737
+			->willReturn(['old' => [], 'new' => [$event]]);
738 738
 		// construct mail provider mock returns
739 739
 		$this->mailService
740 740
 			->method('initiateMessage')
@@ -762,11 +762,11 @@  discard block
 block discarded – undo
762 762
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
763 763
 		], []));
764 764
 		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
765
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE',  'CN' => 'Frodo']);
765
+		$newVevent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
766 766
 		$message->message = $newVCalendar;
767 767
 		$message->sender = 'mailto:[email protected]';
768 768
 		$message->senderName = 'Mr. Wizard';
769
-		$message->recipient = 'mailto:' . '[email protected]';
769
+		$message->recipient = 'mailto:'.'[email protected]';
770 770
 		// save the old copy in the plugin
771 771
 		$oldVCalendar = new VCalendar();
772 772
 		$oldVEvent = new VEvent($oldVCalendar, 'one', [
@@ -776,8 +776,8 @@  discard block
 block discarded – undo
776 776
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
777 777
 		]);
778 778
 		$oldVEvent->add('ORGANIZER', 'mailto:[email protected]');
779
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
780
-		$oldVEvent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE']);
779
+		$oldVEvent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
780
+		$oldVEvent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE']);
781 781
 		$oldVCalendar->add($oldVEvent);
782 782
 		$data = ['invitee_name' => 'Mr. Wizard',
783 783
 			'meeting_title' => 'Fellowship meeting without (!) Boromir',
@@ -869,11 +869,11 @@  discard block
 block discarded – undo
869 869
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
870 870
 		], []));
871 871
 		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
872
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
872
+		$newVevent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
873 873
 		$message->message = $newVCalendar;
874 874
 		$message->sender = 'mailto:[email protected]';
875 875
 		$message->senderName = 'Mr. Wizard';
876
-		$message->recipient = 'mailto:' . '[email protected]';
876
+		$message->recipient = 'mailto:'.'[email protected]';
877 877
 		$data = ['invitee_name' => 'Mr. Wizard',
878 878
 			'meeting_title' => 'Fellowship meeting',
879 879
 			'attendee_name' => '[email protected]'
@@ -891,7 +891,7 @@  discard block
 block discarded – undo
891 891
 		$this->eventComparisonService->expects(self::once())
892 892
 			->method('findModified')
893 893
 			->with($newVCalendar, null)
894
-			->willReturn(['old' => [] ,'new' => [$newVevent]]);
894
+			->willReturn(['old' => [], 'new' => [$newVevent]]);
895 895
 		$this->service->expects(self::once())
896 896
 			->method('getCurrentAttendee')
897 897
 			->with($message)
@@ -963,10 +963,10 @@  discard block
 block discarded – undo
963 963
 			'DTSTART' => new \DateTime('2016-01-01 00:00:00')
964 964
 		], []));
965 965
 		$newVevent->add('ORGANIZER', 'mailto:[email protected]');
966
-		$newVevent->add('ATTENDEE', 'mailto:' . '[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
966
+		$newVevent->add('ATTENDEE', 'mailto:'.'[email protected]', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
967 967
 		$message->message = $newVCalendar;
968 968
 		$message->sender = 'mailto:[email protected]';
969
-		$message->recipient = 'mailto:' . '[email protected]';
969
+		$message->recipient = 'mailto:'.'[email protected]';
970 970
 		$data = ['invitee_name' => 'Mr. Wizard',
971 971
 			'meeting_title' => 'Fellowship meeting',
972 972
 			'attendee_name' => '[email protected]'
@@ -984,7 +984,7 @@  discard block
 block discarded – undo
984 984
 		$this->eventComparisonService->expects(self::once())
985 985
 			->method('findModified')
986 986
 			->with($newVCalendar, null)
987
-			->willReturn(['old' => [] ,'new' => [$newVevent]]);
987
+			->willReturn(['old' => [], 'new' => [$newVevent]]);
988 988
 		$this->service->expects(self::once())
989 989
 			->method('getCurrentAttendee')
990 990
 			->with($message)
Please login to merge, or discard this patch.
apps/dav/tests/unit/CalDAV/Schedule/IMipPluginCharsetTest.php 1 patch
Indentation   +150 added lines, -150 removed lines patch added patch discarded remove patch
@@ -41,154 +41,154 @@
 block discarded – undo
41 41
 use Test\Traits\EmailValidatorTrait;
42 42
 
43 43
 class IMipPluginCharsetTest extends TestCase {
44
-	use EmailValidatorTrait;
45
-	// Dependencies
46
-	private Defaults&MockObject $defaults;
47
-	private IAppConfig&MockObject $appConfig;
48
-	private IConfig&MockObject $config;
49
-	private IDBConnection&MockObject $db;
50
-	private IFactory $l10nFactory;
51
-	private IManager&MockObject $mailManager;
52
-	private IMailer&MockObject $mailer;
53
-	private ISecureRandom&MockObject $random;
54
-	private ITimeFactory&MockObject $timeFactory;
55
-	private IUrlGenerator&MockObject $urlGenerator;
56
-	private IUserSession&MockObject $userSession;
57
-	private LoggerInterface $logger;
58
-
59
-	// Services
60
-	private EventComparisonService $eventComparisonService;
61
-	private IMipPlugin $imipPlugin;
62
-	private IMipService $imipService;
63
-
64
-	// ITip Message
65
-	private Message $itipMessage;
66
-
67
-	protected function setUp(): void {
68
-		// Used by IMipService and IMipPlugin
69
-		$today = new \DateTime('2025-06-15 14:30');
70
-		$this->timeFactory = $this->createMock(ITimeFactory::class);
71
-		$this->timeFactory->method('getTime')
72
-			->willReturn($today->getTimestamp());
73
-		$this->timeFactory->method('getDateTime')
74
-			->willReturn($today);
75
-
76
-		// IMipService
77
-		$this->urlGenerator = $this->createMock(URLGenerator::class);
78
-		$this->config = $this->createMock(IConfig::class);
79
-		$this->db = $this->createMock(IDBConnection::class);
80
-		$this->random = $this->createMock(ISecureRandom::class);
81
-		$l10n = $this->createMock(L10N::class);
82
-		$this->l10nFactory = $this->createMock(IFactory::class);
83
-		$this->l10nFactory->method('findGenericLanguage')
84
-			->willReturn('en');
85
-		$this->l10nFactory->method('findLocale')
86
-			->willReturn('en_US');
87
-		$this->l10nFactory->method('get')
88
-			->willReturn($l10n);
89
-		$this->imipService = new IMipService(
90
-			$this->urlGenerator,
91
-			$this->config,
92
-			$this->db,
93
-			$this->random,
94
-			$this->l10nFactory,
95
-			$this->timeFactory,
96
-		);
97
-
98
-		// EventComparisonService
99
-		$this->eventComparisonService = new EventComparisonService();
100
-
101
-		// IMipPlugin
102
-		$this->appConfig = $this->createMock(IAppConfig::class);
103
-		$message = new \OC\Mail\Message(new Email(), false);
104
-		$this->mailer = $this->createMock(IMailer::class);
105
-		$this->mailer->method('createMessage')
106
-			->willReturn($message);
107
-		$this->logger = new NullLogger();
108
-		$this->defaults = $this->createMock(Defaults::class);
109
-		$this->defaults->method('getName')
110
-			->willReturn('Instance Name 123');
111
-		$user = $this->createMock(IUser::class);
112
-		$user->method('getUID')
113
-			->willReturn('luigi');
114
-		$this->userSession = $this->createMock(IUserSession::class);
115
-		$this->userSession->method('getUser')
116
-			->willReturn($user);
117
-		$this->mailManager = $this->createMock(IManager::class);
118
-		$this->imipPlugin = new IMipPlugin(
119
-			$this->appConfig,
120
-			$this->mailer,
121
-			$this->logger,
122
-			$this->timeFactory,
123
-			$this->defaults,
124
-			$this->userSession,
125
-			$this->imipService,
126
-			$this->eventComparisonService,
127
-			$this->mailManager,
128
-			$this->getEmailValidatorWithStrictEmailCheck(),
129
-		);
130
-
131
-		// ITipMessage
132
-		$calendar = new VCalendar();
133
-		$event = new VEvent($calendar, 'VEVENT');
134
-		$event->UID = 'uid-1234';
135
-		$event->SEQUENCE = 1;
136
-		$event->SUMMARY = 'Lunch';
137
-		$event->DTSTART = new \DateTime('2025-06-20 12:30:00');
138
-		$organizer = new CalAddress($calendar, 'ORGANIZER', 'mailto:[email protected]');
139
-		$event->add($organizer);
140
-		$attendee = new CalAddress($calendar, 'ATTENDEE', 'mailto:[email protected]', ['RSVP' => 'TRUE', 'CN' => 'José']);
141
-		$event->add($attendee);
142
-		$calendar->add($event);
143
-		$this->itipMessage = new Message();
144
-		$this->itipMessage->method = 'REQUEST';
145
-		$this->itipMessage->message = $calendar;
146
-		$this->itipMessage->sender = 'mailto:[email protected]';
147
-		$this->itipMessage->senderName = 'Luigi';
148
-		$this->itipMessage->recipient = 'mailto:' . '[email protected]';
149
-	}
150
-
151
-	public function testCharsetMailer(): void {
152
-		// Arrange
153
-		$symfonyEmail = null;
154
-		$this->mailer->expects(self::once())
155
-			->method('send')
156
-			->willReturnCallback(function (IMessage $message) use (&$symfonyEmail): array {
157
-				if ($message instanceof \OC\Mail\Message) {
158
-					$symfonyEmail = $message->getSymfonyEmail();
159
-				}
160
-				return [];
161
-			});
162
-
163
-		// Act
164
-		$this->imipPlugin->schedule($this->itipMessage);
165
-
166
-		// Assert
167
-		$this->assertNotNull($symfonyEmail);
168
-		$body = $symfonyEmail->getBody()->toString();
169
-		$this->assertStringContainsString('Content-Type: text/calendar; method=REQUEST; charset="utf-8"; name=event.ics', $body);
170
-	}
171
-
172
-	public function testCharsetMailProvider(): void {
173
-		// Arrange
174
-		$this->appConfig->method('getValueBool')
175
-			->with('core', 'mail_providers_enabled', true)
176
-			->willReturn(true);
177
-		$mailMessage = new MailProviderMessage();
178
-		$mailService = $this->createStubForIntersectionOfInterfaces([IService::class, IMessageSend::class]);
179
-		$mailService->method('initiateMessage')
180
-			->willReturn($mailMessage);
181
-		$mailService->expects(self::once())
182
-			->method('sendMessage');
183
-		$this->mailManager->method('findServiceByAddress')
184
-			->willReturn($mailService);
185
-
186
-		// Act
187
-		$this->imipPlugin->schedule($this->itipMessage);
188
-
189
-		// Assert
190
-		$attachments = $mailMessage->getAttachments();
191
-		$this->assertCount(1, $attachments);
192
-		$this->assertStringContainsString('text/calendar; method=REQUEST; charset="utf-8"; name=event.ics', $attachments[0]->getType());
193
-	}
44
+    use EmailValidatorTrait;
45
+    // Dependencies
46
+    private Defaults&MockObject $defaults;
47
+    private IAppConfig&MockObject $appConfig;
48
+    private IConfig&MockObject $config;
49
+    private IDBConnection&MockObject $db;
50
+    private IFactory $l10nFactory;
51
+    private IManager&MockObject $mailManager;
52
+    private IMailer&MockObject $mailer;
53
+    private ISecureRandom&MockObject $random;
54
+    private ITimeFactory&MockObject $timeFactory;
55
+    private IUrlGenerator&MockObject $urlGenerator;
56
+    private IUserSession&MockObject $userSession;
57
+    private LoggerInterface $logger;
58
+
59
+    // Services
60
+    private EventComparisonService $eventComparisonService;
61
+    private IMipPlugin $imipPlugin;
62
+    private IMipService $imipService;
63
+
64
+    // ITip Message
65
+    private Message $itipMessage;
66
+
67
+    protected function setUp(): void {
68
+        // Used by IMipService and IMipPlugin
69
+        $today = new \DateTime('2025-06-15 14:30');
70
+        $this->timeFactory = $this->createMock(ITimeFactory::class);
71
+        $this->timeFactory->method('getTime')
72
+            ->willReturn($today->getTimestamp());
73
+        $this->timeFactory->method('getDateTime')
74
+            ->willReturn($today);
75
+
76
+        // IMipService
77
+        $this->urlGenerator = $this->createMock(URLGenerator::class);
78
+        $this->config = $this->createMock(IConfig::class);
79
+        $this->db = $this->createMock(IDBConnection::class);
80
+        $this->random = $this->createMock(ISecureRandom::class);
81
+        $l10n = $this->createMock(L10N::class);
82
+        $this->l10nFactory = $this->createMock(IFactory::class);
83
+        $this->l10nFactory->method('findGenericLanguage')
84
+            ->willReturn('en');
85
+        $this->l10nFactory->method('findLocale')
86
+            ->willReturn('en_US');
87
+        $this->l10nFactory->method('get')
88
+            ->willReturn($l10n);
89
+        $this->imipService = new IMipService(
90
+            $this->urlGenerator,
91
+            $this->config,
92
+            $this->db,
93
+            $this->random,
94
+            $this->l10nFactory,
95
+            $this->timeFactory,
96
+        );
97
+
98
+        // EventComparisonService
99
+        $this->eventComparisonService = new EventComparisonService();
100
+
101
+        // IMipPlugin
102
+        $this->appConfig = $this->createMock(IAppConfig::class);
103
+        $message = new \OC\Mail\Message(new Email(), false);
104
+        $this->mailer = $this->createMock(IMailer::class);
105
+        $this->mailer->method('createMessage')
106
+            ->willReturn($message);
107
+        $this->logger = new NullLogger();
108
+        $this->defaults = $this->createMock(Defaults::class);
109
+        $this->defaults->method('getName')
110
+            ->willReturn('Instance Name 123');
111
+        $user = $this->createMock(IUser::class);
112
+        $user->method('getUID')
113
+            ->willReturn('luigi');
114
+        $this->userSession = $this->createMock(IUserSession::class);
115
+        $this->userSession->method('getUser')
116
+            ->willReturn($user);
117
+        $this->mailManager = $this->createMock(IManager::class);
118
+        $this->imipPlugin = new IMipPlugin(
119
+            $this->appConfig,
120
+            $this->mailer,
121
+            $this->logger,
122
+            $this->timeFactory,
123
+            $this->defaults,
124
+            $this->userSession,
125
+            $this->imipService,
126
+            $this->eventComparisonService,
127
+            $this->mailManager,
128
+            $this->getEmailValidatorWithStrictEmailCheck(),
129
+        );
130
+
131
+        // ITipMessage
132
+        $calendar = new VCalendar();
133
+        $event = new VEvent($calendar, 'VEVENT');
134
+        $event->UID = 'uid-1234';
135
+        $event->SEQUENCE = 1;
136
+        $event->SUMMARY = 'Lunch';
137
+        $event->DTSTART = new \DateTime('2025-06-20 12:30:00');
138
+        $organizer = new CalAddress($calendar, 'ORGANIZER', 'mailto:[email protected]');
139
+        $event->add($organizer);
140
+        $attendee = new CalAddress($calendar, 'ATTENDEE', 'mailto:[email protected]', ['RSVP' => 'TRUE', 'CN' => 'José']);
141
+        $event->add($attendee);
142
+        $calendar->add($event);
143
+        $this->itipMessage = new Message();
144
+        $this->itipMessage->method = 'REQUEST';
145
+        $this->itipMessage->message = $calendar;
146
+        $this->itipMessage->sender = 'mailto:[email protected]';
147
+        $this->itipMessage->senderName = 'Luigi';
148
+        $this->itipMessage->recipient = 'mailto:' . '[email protected]';
149
+    }
150
+
151
+    public function testCharsetMailer(): void {
152
+        // Arrange
153
+        $symfonyEmail = null;
154
+        $this->mailer->expects(self::once())
155
+            ->method('send')
156
+            ->willReturnCallback(function (IMessage $message) use (&$symfonyEmail): array {
157
+                if ($message instanceof \OC\Mail\Message) {
158
+                    $symfonyEmail = $message->getSymfonyEmail();
159
+                }
160
+                return [];
161
+            });
162
+
163
+        // Act
164
+        $this->imipPlugin->schedule($this->itipMessage);
165
+
166
+        // Assert
167
+        $this->assertNotNull($symfonyEmail);
168
+        $body = $symfonyEmail->getBody()->toString();
169
+        $this->assertStringContainsString('Content-Type: text/calendar; method=REQUEST; charset="utf-8"; name=event.ics', $body);
170
+    }
171
+
172
+    public function testCharsetMailProvider(): void {
173
+        // Arrange
174
+        $this->appConfig->method('getValueBool')
175
+            ->with('core', 'mail_providers_enabled', true)
176
+            ->willReturn(true);
177
+        $mailMessage = new MailProviderMessage();
178
+        $mailService = $this->createStubForIntersectionOfInterfaces([IService::class, IMessageSend::class]);
179
+        $mailService->method('initiateMessage')
180
+            ->willReturn($mailMessage);
181
+        $mailService->expects(self::once())
182
+            ->method('sendMessage');
183
+        $this->mailManager->method('findServiceByAddress')
184
+            ->willReturn($mailService);
185
+
186
+        // Act
187
+        $this->imipPlugin->schedule($this->itipMessage);
188
+
189
+        // Assert
190
+        $attachments = $mailMessage->getAttachments();
191
+        $this->assertCount(1, $attachments);
192
+        $this->assertStringContainsString('text/calendar; method=REQUEST; charset="utf-8"; name=event.ics', $attachments[0]->getType());
193
+    }
194 194
 }
Please login to merge, or discard this patch.
dav/tests/unit/CalDAV/Reminder/NotificationProvider/EmailProviderTest.php 1 patch
Indentation   +458 added lines, -458 removed lines patch added patch discarded remove patch
@@ -20,462 +20,462 @@
 block discarded – undo
20 20
 use Test\Traits\EmailValidatorTrait;
21 21
 
22 22
 class EmailProviderTest extends AbstractNotificationProviderTestCase {
23
-	use EmailValidatorTrait;
24
-	public const USER_EMAIL = '[email protected]';
25
-	private IMailer&MockObject $mailer;
26
-
27
-	protected function setUp(): void {
28
-		parent::setUp();
29
-
30
-		$this->mailer = $this->createMock(IMailer::class);
31
-
32
-		$this->provider = new EmailProvider(
33
-			$this->config,
34
-			$this->mailer,
35
-			$this->logger,
36
-			$this->l10nFactory,
37
-			$this->urlGenerator,
38
-			$this->getEmailValidatorWithStrictEmailCheck(),
39
-		);
40
-	}
41
-
42
-	public function testSendWithoutAttendees():void {
43
-		[$user1, $user2, $user3, , $user5] = $users = $this->getUsers();
44
-		$principalEmailAddresses = [$user1->getEmailAddress()];
45
-
46
-		$enL10N = $this->createMock(IL10N::class);
47
-		$enL10N->method('t')
48
-			->willReturnArgument(0);
49
-		$enL10N->method('l')
50
-			->willReturnArgument(0);
51
-
52
-		$deL10N = $this->createMock(IL10N::class);
53
-		$deL10N->method('t')
54
-			->willReturnArgument(0);
55
-		$deL10N->method('l')
56
-			->willReturnArgument(0);
57
-
58
-		$this->l10nFactory
59
-			->method('getUserLanguage')
60
-			->willReturnMap([
61
-				[$user1, 'en'],
62
-				[$user2, 'de'],
63
-				[$user3, 'de'],
64
-				[$user5, 'de'],
65
-			]);
66
-
67
-		$this->l10nFactory
68
-			->method('findGenericLanguage')
69
-			->willReturn('en');
70
-
71
-		$this->l10nFactory
72
-			->method('languageExists')
73
-			->willReturnMap([
74
-				['dav', 'en', true],
75
-				['dav', 'de', true],
76
-			]);
77
-
78
-		$this->l10nFactory
79
-			->method('get')
80
-			->willReturnMap([
81
-				['dav', 'en', null, $enL10N],
82
-				['dav', 'de', null, $deL10N],
83
-			]);
84
-
85
-		$template1 = $this->getTemplateMock();
86
-		$message11 = $this->getMessageMock('[email protected]', $template1);
87
-		$template2 = $this->getTemplateMock();
88
-		$message21 = $this->getMessageMock('[email protected]', $template2);
89
-		$message22 = $this->getMessageMock('[email protected]', $template2);
90
-
91
-		$this->mailer->expects($this->exactly(2))
92
-			->method('createEMailTemplate')
93
-			->with('dav.calendarReminder')
94
-			->willReturnOnConsecutiveCalls(
95
-				$template1,
96
-				$template2
97
-			);
98
-
99
-		$this->mailer->expects($this->exactly(3))
100
-			->method('createMessage')
101
-			->with()
102
-			->willReturnOnConsecutiveCalls(
103
-				$message11,
104
-				$message21,
105
-				$message22
106
-			);
107
-
108
-		$calls = [
109
-			[$message11],
110
-			[$message21],
111
-			[$message22],
112
-		];
113
-		$this->mailer->expects($this->exactly(count($calls)))
114
-			->method('send')
115
-			->willReturnCallback(function () use (&$calls) {
116
-				$expected = array_shift($calls);
117
-				$this->assertEquals($expected, func_get_args());
118
-				return [];
119
-			});
120
-
121
-		$this->setupURLGeneratorMock(2);
122
-
123
-		$vcalendar = $this->getNoAttendeeVCalendar();
124
-		$this->provider->send($vcalendar->VEVENT, $this->calendarDisplayName, $principalEmailAddresses, $users);
125
-	}
126
-
127
-	public function testSendWithAttendeesWhenOwnerIsOrganizer(): void {
128
-		[$user1, $user2, $user3, , $user5] = $users = $this->getUsers();
129
-		$principalEmailAddresses = [$user1->getEmailAddress()];
130
-
131
-		$enL10N = $this->createMock(IL10N::class);
132
-		$enL10N->method('t')
133
-			->willReturnArgument(0);
134
-		$enL10N->method('l')
135
-			->willReturnArgument(0);
136
-
137
-		$deL10N = $this->createMock(IL10N::class);
138
-		$deL10N->method('t')
139
-			->willReturnArgument(0);
140
-		$deL10N->method('l')
141
-			->willReturnArgument(0);
142
-
143
-		$this->l10nFactory
144
-			->method('getUserLanguage')
145
-			->willReturnMap([
146
-				[$user1, 'en'],
147
-				[$user2, 'de'],
148
-				[$user3, 'de'],
149
-				[$user5, 'de'],
150
-			]);
151
-
152
-		$this->l10nFactory
153
-			->method('findGenericLanguage')
154
-			->willReturn('en');
155
-
156
-		$this->l10nFactory
157
-			->method('languageExists')
158
-			->willReturnMap([
159
-				['dav', 'en', true],
160
-				['dav', 'de', true],
161
-			]);
162
-
163
-		$this->l10nFactory
164
-			->method('get')
165
-			->willReturnMap([
166
-				['dav', 'en', null, $enL10N],
167
-				['dav', 'de', null, $deL10N],
168
-			]);
169
-
170
-		$template1 = $this->getTemplateMock();
171
-		$message11 = $this->getMessageMock('[email protected]', $template1);
172
-		$message12 = $this->getMessageMock('[email protected]', $template1);
173
-		$message13 = $this->getMessageMock('[email protected]', $template1);
174
-		$template2 = $this->getTemplateMock();
175
-		$message21 = $this->getMessageMock('[email protected]', $template2);
176
-		$message22 = $this->getMessageMock('[email protected]', $template2);
177
-		$message23 = $this->getMessageMock('[email protected]', $template2);
178
-
179
-		$this->mailer->expects(self::exactly(2))
180
-			->method('createEMailTemplate')
181
-			->with('dav.calendarReminder')
182
-			->willReturnOnConsecutiveCalls(
183
-				$template1,
184
-				$template2,
185
-			);
186
-		$this->mailer->expects($this->exactly(6))
187
-			->method('createMessage')
188
-			->with()
189
-			->willReturnOnConsecutiveCalls(
190
-				$message11,
191
-				$message12,
192
-				$message13,
193
-				$message21,
194
-				$message22,
195
-				$message23,
196
-			);
197
-
198
-		$calls = [
199
-			[$message11],
200
-			[$message12],
201
-			[$message13],
202
-			[$message21],
203
-			[$message22],
204
-			[$message23],
205
-		];
206
-		$this->mailer->expects($this->exactly(count($calls)))
207
-			->method('send')
208
-			->willReturnCallback(function () use (&$calls) {
209
-				$expected = array_shift($calls);
210
-				$this->assertEquals($expected, func_get_args());
211
-				return [];
212
-			});
213
-		$this->setupURLGeneratorMock(2);
214
-
215
-		$vcalendar = $this->getAttendeeVCalendar();
216
-		$this->provider->send($vcalendar->VEVENT, $this->calendarDisplayName, $principalEmailAddresses, $users);
217
-	}
218
-
219
-	public function testSendWithAttendeesWhenOwnerIsAttendee(): void {
220
-		[$user1, $user2, $user3] = $this->getUsers();
221
-		$users = [$user2, $user3];
222
-		$principalEmailAddresses = [$user2->getEmailAddress()];
223
-
224
-		$deL10N = $this->createMock(IL10N::class);
225
-		$deL10N->method('t')
226
-			->willReturnArgument(0);
227
-		$deL10N->method('l')
228
-			->willReturnArgument(0);
229
-
230
-		$this->l10nFactory
231
-			->method('getUserLanguage')
232
-			->willReturnMap([
233
-				[$user2, 'de'],
234
-				[$user3, 'de'],
235
-			]);
236
-
237
-		$this->l10nFactory
238
-			->method('findGenericLanguage')
239
-			->willReturn('en');
240
-
241
-		$this->l10nFactory
242
-			->method('languageExists')
243
-			->willReturnMap([
244
-				['dav', 'de', true],
245
-			]);
246
-
247
-		$this->l10nFactory
248
-			->method('get')
249
-			->willReturnMap([
250
-				['dav', 'de', null, $deL10N],
251
-			]);
252
-
253
-		$template1 = $this->getTemplateMock();
254
-		$message12 = $this->getMessageMock('[email protected]', $template1);
255
-		$message13 = $this->getMessageMock('[email protected]', $template1);
256
-
257
-		$this->mailer->expects(self::once())
258
-			->method('createEMailTemplate')
259
-			->with('dav.calendarReminder')
260
-			->willReturnOnConsecutiveCalls(
261
-				$template1,
262
-			);
263
-		$this->mailer->expects($this->exactly(2))
264
-			->method('createMessage')
265
-			->with()
266
-			->willReturnOnConsecutiveCalls(
267
-				$message12,
268
-				$message13,
269
-			);
270
-
271
-		$calls = [
272
-			[$message12],
273
-			[$message13],
274
-		];
275
-		$this->mailer->expects($this->exactly(count($calls)))
276
-			->method('send')
277
-			->willReturnCallback(function () use (&$calls) {
278
-				$expected = array_shift($calls);
279
-				$this->assertEquals($expected, func_get_args());
280
-				return [];
281
-			});
282
-		$this->setupURLGeneratorMock(1);
283
-
284
-		$vcalendar = $this->getAttendeeVCalendar();
285
-		$this->provider->send($vcalendar->VEVENT, $this->calendarDisplayName, $principalEmailAddresses, $users);
286
-	}
287
-
288
-	/**
289
-	 * @return IEMailTemplate
290
-	 */
291
-	private function getTemplateMock():IEMailTemplate {
292
-		$template = $this->createMock(IEMailTemplate::class);
293
-
294
-		$template->expects($this->once())
295
-			->method('addHeader')
296
-			->with()
297
-			->willReturn($template);
298
-
299
-		$template->expects($this->once())
300
-			->method('setSubject')
301
-			->with()
302
-			->willReturn($template);
303
-
304
-		$template->expects($this->once())
305
-			->method('addHeading')
306
-			->with()
307
-			->willReturn($template);
308
-
309
-		$template->expects($this->exactly(4))
310
-			->method('addBodyListItem')
311
-			->with()
312
-			->willReturn($template);
313
-
314
-		$template->expects($this->once())
315
-			->method('addFooter')
316
-			->with()
317
-			->willReturn($template);
318
-
319
-		return $template;
320
-	}
321
-
322
-	/**
323
-	 * @param string $toMail
324
-	 * @param IEMailTemplate $templateMock
325
-	 * @param array|null $replyTo
326
-	 * @return IMessage
327
-	 */
328
-	private function getMessageMock(string $toMail, IEMailTemplate $templateMock, ?array $replyTo = null):IMessage {
329
-		$message = $this->createMock(IMessage::class);
330
-		$i = 0;
331
-
332
-		$message->expects($this->once())
333
-			->method('setFrom')
334
-			->with([Util::getDefaultEmailAddress('reminders-noreply')])
335
-			->willReturn($message);
336
-
337
-		if ($replyTo) {
338
-			$message->expects($this->once())
339
-				->method('setReplyTo')
340
-				->with($replyTo)
341
-				->willReturn($message);
342
-		} else {
343
-			$message->expects($this->never())
344
-				->method('setReplyTo');
345
-		}
346
-
347
-		$message->expects($this->once())
348
-			->method('setTo')
349
-			->with([$toMail])
350
-			->willReturn($message);
351
-
352
-		$message->expects($this->once())
353
-			->method('useTemplate')
354
-			->with($templateMock)
355
-			->willReturn($message);
356
-
357
-		return $message;
358
-	}
359
-
360
-	private function getNoAttendeeVCalendar():VCalendar {
361
-		$vcalendar = new VCalendar();
362
-		$vcalendar->add('VEVENT', [
363
-			'SUMMARY' => 'Fellowship meeting',
364
-			'DTSTART' => new \DateTime('2017-01-01 00:00:00+00:00'), // 1483228800,
365
-			'UID' => 'uid1234',
366
-			'LOCATION' => 'Location 123',
367
-			'DESCRIPTION' => 'DESCRIPTION 456',
368
-		]);
369
-
370
-		return $vcalendar;
371
-	}
372
-
373
-	private function getAttendeeVCalendar():VCalendar {
374
-		$vcalendar = new VCalendar();
375
-		$vcalendar->add('VEVENT', [
376
-			'SUMMARY' => 'Fellowship meeting',
377
-			'DTSTART' => new \DateTime('2017-01-01 00:00:00+00:00'), // 1483228800,
378
-			'UID' => 'uid1234',
379
-			'LOCATION' => 'Location 123',
380
-			'DESCRIPTION' => 'DESCRIPTION 456',
381
-		]);
382
-
383
-		$vcalendar->VEVENT->add(
384
-			'ORGANIZER',
385
-			'mailto:[email protected]',
386
-			[
387
-				'LANG' => 'en'
388
-			]
389
-		);
390
-
391
-		$vcalendar->VEVENT->add(
392
-			'ATTENDEE',
393
-			'mailto:[email protected]',
394
-			[
395
-				'LANG' => 'de',
396
-				'PARTSTAT' => 'NEEDS-ACTION',
397
-			]
398
-		);
399
-
400
-		$vcalendar->VEVENT->add(
401
-			'ATTENDEE',
402
-			'mailto:[email protected]',
403
-			[
404
-				'LANG' => 'de',
405
-				'PARTSTAT' => 'DECLINED',
406
-			]
407
-		);
408
-
409
-		$vcalendar->VEVENT->add(
410
-			'ATTENDEE',
411
-			'mailto:[email protected]',
412
-			[
413
-				'LANG' => 'en',
414
-				'PARTSTAT' => 'CONFIRMED',
415
-			]
416
-		);
417
-
418
-		$vcalendar->VEVENT->add(
419
-			'ATTENDEE',
420
-			'mailto:[email protected]'
421
-		);
422
-
423
-		$vcalendar->VEVENT->add(
424
-			'ATTENDEE',
425
-			'tomail:[email protected]'
426
-		);
427
-
428
-		return $vcalendar;
429
-	}
430
-
431
-	private function setupURLGeneratorMock(int $times = 1): void {
432
-		$this->urlGenerator
433
-			->expects($this->exactly($times * 4))
434
-			->method('imagePath')
435
-			->willReturnMap([
436
-				['core', 'actions/info.png', 'imagePath1'],
437
-				['core', 'places/calendar.png', 'imagePath2'],
438
-				['core', 'actions/address.png', 'imagePath3'],
439
-				['core', 'actions/more.png', 'imagePath4'],
440
-			]);
441
-		$this->urlGenerator
442
-			->expects($this->exactly($times * 4))
443
-			->method('getAbsoluteURL')
444
-			->willReturnMap([
445
-				['imagePath1', 'AbsURL1'],
446
-				['imagePath2', 'AbsURL2'],
447
-				['imagePath3', 'AbsURL3'],
448
-				['imagePath4', 'AbsURL4'],
449
-			]);
450
-	}
451
-
452
-	private function getUsers(): array {
453
-		$user1 = $this->createMock(IUser::class);
454
-		$user1->method('getUID')
455
-			->willReturn('uid1');
456
-		$user1->method('getEMailAddress')
457
-			->willReturn('[email protected]');
458
-		$user2 = $this->createMock(IUser::class);
459
-		$user2->method('getUID')
460
-			->willReturn('uid2');
461
-		$user2->method('getEMailAddress')
462
-			->willReturn('[email protected]');
463
-		$user3 = $this->createMock(IUser::class);
464
-		$user3->method('getUID')
465
-			->willReturn('uid3');
466
-		$user3->method('getEMailAddress')
467
-			->willReturn('[email protected]');
468
-		$user4 = $this->createMock(IUser::class);
469
-		$user4->method('getUID')
470
-			->willReturn('uid4');
471
-		$user4->method('getEMailAddress')
472
-			->willReturn(null);
473
-		$user5 = $this->createMock(IUser::class);
474
-		$user5->method('getUID')
475
-			->willReturn('uid5');
476
-		$user5->method('getEMailAddress')
477
-			->willReturn('invalid');
478
-
479
-		return [$user1, $user2, $user3, $user4, $user5];
480
-	}
23
+    use EmailValidatorTrait;
24
+    public const USER_EMAIL = '[email protected]';
25
+    private IMailer&MockObject $mailer;
26
+
27
+    protected function setUp(): void {
28
+        parent::setUp();
29
+
30
+        $this->mailer = $this->createMock(IMailer::class);
31
+
32
+        $this->provider = new EmailProvider(
33
+            $this->config,
34
+            $this->mailer,
35
+            $this->logger,
36
+            $this->l10nFactory,
37
+            $this->urlGenerator,
38
+            $this->getEmailValidatorWithStrictEmailCheck(),
39
+        );
40
+    }
41
+
42
+    public function testSendWithoutAttendees():void {
43
+        [$user1, $user2, $user3, , $user5] = $users = $this->getUsers();
44
+        $principalEmailAddresses = [$user1->getEmailAddress()];
45
+
46
+        $enL10N = $this->createMock(IL10N::class);
47
+        $enL10N->method('t')
48
+            ->willReturnArgument(0);
49
+        $enL10N->method('l')
50
+            ->willReturnArgument(0);
51
+
52
+        $deL10N = $this->createMock(IL10N::class);
53
+        $deL10N->method('t')
54
+            ->willReturnArgument(0);
55
+        $deL10N->method('l')
56
+            ->willReturnArgument(0);
57
+
58
+        $this->l10nFactory
59
+            ->method('getUserLanguage')
60
+            ->willReturnMap([
61
+                [$user1, 'en'],
62
+                [$user2, 'de'],
63
+                [$user3, 'de'],
64
+                [$user5, 'de'],
65
+            ]);
66
+
67
+        $this->l10nFactory
68
+            ->method('findGenericLanguage')
69
+            ->willReturn('en');
70
+
71
+        $this->l10nFactory
72
+            ->method('languageExists')
73
+            ->willReturnMap([
74
+                ['dav', 'en', true],
75
+                ['dav', 'de', true],
76
+            ]);
77
+
78
+        $this->l10nFactory
79
+            ->method('get')
80
+            ->willReturnMap([
81
+                ['dav', 'en', null, $enL10N],
82
+                ['dav', 'de', null, $deL10N],
83
+            ]);
84
+
85
+        $template1 = $this->getTemplateMock();
86
+        $message11 = $this->getMessageMock('[email protected]', $template1);
87
+        $template2 = $this->getTemplateMock();
88
+        $message21 = $this->getMessageMock('[email protected]', $template2);
89
+        $message22 = $this->getMessageMock('[email protected]', $template2);
90
+
91
+        $this->mailer->expects($this->exactly(2))
92
+            ->method('createEMailTemplate')
93
+            ->with('dav.calendarReminder')
94
+            ->willReturnOnConsecutiveCalls(
95
+                $template1,
96
+                $template2
97
+            );
98
+
99
+        $this->mailer->expects($this->exactly(3))
100
+            ->method('createMessage')
101
+            ->with()
102
+            ->willReturnOnConsecutiveCalls(
103
+                $message11,
104
+                $message21,
105
+                $message22
106
+            );
107
+
108
+        $calls = [
109
+            [$message11],
110
+            [$message21],
111
+            [$message22],
112
+        ];
113
+        $this->mailer->expects($this->exactly(count($calls)))
114
+            ->method('send')
115
+            ->willReturnCallback(function () use (&$calls) {
116
+                $expected = array_shift($calls);
117
+                $this->assertEquals($expected, func_get_args());
118
+                return [];
119
+            });
120
+
121
+        $this->setupURLGeneratorMock(2);
122
+
123
+        $vcalendar = $this->getNoAttendeeVCalendar();
124
+        $this->provider->send($vcalendar->VEVENT, $this->calendarDisplayName, $principalEmailAddresses, $users);
125
+    }
126
+
127
+    public function testSendWithAttendeesWhenOwnerIsOrganizer(): void {
128
+        [$user1, $user2, $user3, , $user5] = $users = $this->getUsers();
129
+        $principalEmailAddresses = [$user1->getEmailAddress()];
130
+
131
+        $enL10N = $this->createMock(IL10N::class);
132
+        $enL10N->method('t')
133
+            ->willReturnArgument(0);
134
+        $enL10N->method('l')
135
+            ->willReturnArgument(0);
136
+
137
+        $deL10N = $this->createMock(IL10N::class);
138
+        $deL10N->method('t')
139
+            ->willReturnArgument(0);
140
+        $deL10N->method('l')
141
+            ->willReturnArgument(0);
142
+
143
+        $this->l10nFactory
144
+            ->method('getUserLanguage')
145
+            ->willReturnMap([
146
+                [$user1, 'en'],
147
+                [$user2, 'de'],
148
+                [$user3, 'de'],
149
+                [$user5, 'de'],
150
+            ]);
151
+
152
+        $this->l10nFactory
153
+            ->method('findGenericLanguage')
154
+            ->willReturn('en');
155
+
156
+        $this->l10nFactory
157
+            ->method('languageExists')
158
+            ->willReturnMap([
159
+                ['dav', 'en', true],
160
+                ['dav', 'de', true],
161
+            ]);
162
+
163
+        $this->l10nFactory
164
+            ->method('get')
165
+            ->willReturnMap([
166
+                ['dav', 'en', null, $enL10N],
167
+                ['dav', 'de', null, $deL10N],
168
+            ]);
169
+
170
+        $template1 = $this->getTemplateMock();
171
+        $message11 = $this->getMessageMock('[email protected]', $template1);
172
+        $message12 = $this->getMessageMock('[email protected]', $template1);
173
+        $message13 = $this->getMessageMock('[email protected]', $template1);
174
+        $template2 = $this->getTemplateMock();
175
+        $message21 = $this->getMessageMock('[email protected]', $template2);
176
+        $message22 = $this->getMessageMock('[email protected]', $template2);
177
+        $message23 = $this->getMessageMock('[email protected]', $template2);
178
+
179
+        $this->mailer->expects(self::exactly(2))
180
+            ->method('createEMailTemplate')
181
+            ->with('dav.calendarReminder')
182
+            ->willReturnOnConsecutiveCalls(
183
+                $template1,
184
+                $template2,
185
+            );
186
+        $this->mailer->expects($this->exactly(6))
187
+            ->method('createMessage')
188
+            ->with()
189
+            ->willReturnOnConsecutiveCalls(
190
+                $message11,
191
+                $message12,
192
+                $message13,
193
+                $message21,
194
+                $message22,
195
+                $message23,
196
+            );
197
+
198
+        $calls = [
199
+            [$message11],
200
+            [$message12],
201
+            [$message13],
202
+            [$message21],
203
+            [$message22],
204
+            [$message23],
205
+        ];
206
+        $this->mailer->expects($this->exactly(count($calls)))
207
+            ->method('send')
208
+            ->willReturnCallback(function () use (&$calls) {
209
+                $expected = array_shift($calls);
210
+                $this->assertEquals($expected, func_get_args());
211
+                return [];
212
+            });
213
+        $this->setupURLGeneratorMock(2);
214
+
215
+        $vcalendar = $this->getAttendeeVCalendar();
216
+        $this->provider->send($vcalendar->VEVENT, $this->calendarDisplayName, $principalEmailAddresses, $users);
217
+    }
218
+
219
+    public function testSendWithAttendeesWhenOwnerIsAttendee(): void {
220
+        [$user1, $user2, $user3] = $this->getUsers();
221
+        $users = [$user2, $user3];
222
+        $principalEmailAddresses = [$user2->getEmailAddress()];
223
+
224
+        $deL10N = $this->createMock(IL10N::class);
225
+        $deL10N->method('t')
226
+            ->willReturnArgument(0);
227
+        $deL10N->method('l')
228
+            ->willReturnArgument(0);
229
+
230
+        $this->l10nFactory
231
+            ->method('getUserLanguage')
232
+            ->willReturnMap([
233
+                [$user2, 'de'],
234
+                [$user3, 'de'],
235
+            ]);
236
+
237
+        $this->l10nFactory
238
+            ->method('findGenericLanguage')
239
+            ->willReturn('en');
240
+
241
+        $this->l10nFactory
242
+            ->method('languageExists')
243
+            ->willReturnMap([
244
+                ['dav', 'de', true],
245
+            ]);
246
+
247
+        $this->l10nFactory
248
+            ->method('get')
249
+            ->willReturnMap([
250
+                ['dav', 'de', null, $deL10N],
251
+            ]);
252
+
253
+        $template1 = $this->getTemplateMock();
254
+        $message12 = $this->getMessageMock('[email protected]', $template1);
255
+        $message13 = $this->getMessageMock('[email protected]', $template1);
256
+
257
+        $this->mailer->expects(self::once())
258
+            ->method('createEMailTemplate')
259
+            ->with('dav.calendarReminder')
260
+            ->willReturnOnConsecutiveCalls(
261
+                $template1,
262
+            );
263
+        $this->mailer->expects($this->exactly(2))
264
+            ->method('createMessage')
265
+            ->with()
266
+            ->willReturnOnConsecutiveCalls(
267
+                $message12,
268
+                $message13,
269
+            );
270
+
271
+        $calls = [
272
+            [$message12],
273
+            [$message13],
274
+        ];
275
+        $this->mailer->expects($this->exactly(count($calls)))
276
+            ->method('send')
277
+            ->willReturnCallback(function () use (&$calls) {
278
+                $expected = array_shift($calls);
279
+                $this->assertEquals($expected, func_get_args());
280
+                return [];
281
+            });
282
+        $this->setupURLGeneratorMock(1);
283
+
284
+        $vcalendar = $this->getAttendeeVCalendar();
285
+        $this->provider->send($vcalendar->VEVENT, $this->calendarDisplayName, $principalEmailAddresses, $users);
286
+    }
287
+
288
+    /**
289
+     * @return IEMailTemplate
290
+     */
291
+    private function getTemplateMock():IEMailTemplate {
292
+        $template = $this->createMock(IEMailTemplate::class);
293
+
294
+        $template->expects($this->once())
295
+            ->method('addHeader')
296
+            ->with()
297
+            ->willReturn($template);
298
+
299
+        $template->expects($this->once())
300
+            ->method('setSubject')
301
+            ->with()
302
+            ->willReturn($template);
303
+
304
+        $template->expects($this->once())
305
+            ->method('addHeading')
306
+            ->with()
307
+            ->willReturn($template);
308
+
309
+        $template->expects($this->exactly(4))
310
+            ->method('addBodyListItem')
311
+            ->with()
312
+            ->willReturn($template);
313
+
314
+        $template->expects($this->once())
315
+            ->method('addFooter')
316
+            ->with()
317
+            ->willReturn($template);
318
+
319
+        return $template;
320
+    }
321
+
322
+    /**
323
+     * @param string $toMail
324
+     * @param IEMailTemplate $templateMock
325
+     * @param array|null $replyTo
326
+     * @return IMessage
327
+     */
328
+    private function getMessageMock(string $toMail, IEMailTemplate $templateMock, ?array $replyTo = null):IMessage {
329
+        $message = $this->createMock(IMessage::class);
330
+        $i = 0;
331
+
332
+        $message->expects($this->once())
333
+            ->method('setFrom')
334
+            ->with([Util::getDefaultEmailAddress('reminders-noreply')])
335
+            ->willReturn($message);
336
+
337
+        if ($replyTo) {
338
+            $message->expects($this->once())
339
+                ->method('setReplyTo')
340
+                ->with($replyTo)
341
+                ->willReturn($message);
342
+        } else {
343
+            $message->expects($this->never())
344
+                ->method('setReplyTo');
345
+        }
346
+
347
+        $message->expects($this->once())
348
+            ->method('setTo')
349
+            ->with([$toMail])
350
+            ->willReturn($message);
351
+
352
+        $message->expects($this->once())
353
+            ->method('useTemplate')
354
+            ->with($templateMock)
355
+            ->willReturn($message);
356
+
357
+        return $message;
358
+    }
359
+
360
+    private function getNoAttendeeVCalendar():VCalendar {
361
+        $vcalendar = new VCalendar();
362
+        $vcalendar->add('VEVENT', [
363
+            'SUMMARY' => 'Fellowship meeting',
364
+            'DTSTART' => new \DateTime('2017-01-01 00:00:00+00:00'), // 1483228800,
365
+            'UID' => 'uid1234',
366
+            'LOCATION' => 'Location 123',
367
+            'DESCRIPTION' => 'DESCRIPTION 456',
368
+        ]);
369
+
370
+        return $vcalendar;
371
+    }
372
+
373
+    private function getAttendeeVCalendar():VCalendar {
374
+        $vcalendar = new VCalendar();
375
+        $vcalendar->add('VEVENT', [
376
+            'SUMMARY' => 'Fellowship meeting',
377
+            'DTSTART' => new \DateTime('2017-01-01 00:00:00+00:00'), // 1483228800,
378
+            'UID' => 'uid1234',
379
+            'LOCATION' => 'Location 123',
380
+            'DESCRIPTION' => 'DESCRIPTION 456',
381
+        ]);
382
+
383
+        $vcalendar->VEVENT->add(
384
+            'ORGANIZER',
385
+            'mailto:[email protected]',
386
+            [
387
+                'LANG' => 'en'
388
+            ]
389
+        );
390
+
391
+        $vcalendar->VEVENT->add(
392
+            'ATTENDEE',
393
+            'mailto:[email protected]',
394
+            [
395
+                'LANG' => 'de',
396
+                'PARTSTAT' => 'NEEDS-ACTION',
397
+            ]
398
+        );
399
+
400
+        $vcalendar->VEVENT->add(
401
+            'ATTENDEE',
402
+            'mailto:[email protected]',
403
+            [
404
+                'LANG' => 'de',
405
+                'PARTSTAT' => 'DECLINED',
406
+            ]
407
+        );
408
+
409
+        $vcalendar->VEVENT->add(
410
+            'ATTENDEE',
411
+            'mailto:[email protected]',
412
+            [
413
+                'LANG' => 'en',
414
+                'PARTSTAT' => 'CONFIRMED',
415
+            ]
416
+        );
417
+
418
+        $vcalendar->VEVENT->add(
419
+            'ATTENDEE',
420
+            'mailto:[email protected]'
421
+        );
422
+
423
+        $vcalendar->VEVENT->add(
424
+            'ATTENDEE',
425
+            'tomail:[email protected]'
426
+        );
427
+
428
+        return $vcalendar;
429
+    }
430
+
431
+    private function setupURLGeneratorMock(int $times = 1): void {
432
+        $this->urlGenerator
433
+            ->expects($this->exactly($times * 4))
434
+            ->method('imagePath')
435
+            ->willReturnMap([
436
+                ['core', 'actions/info.png', 'imagePath1'],
437
+                ['core', 'places/calendar.png', 'imagePath2'],
438
+                ['core', 'actions/address.png', 'imagePath3'],
439
+                ['core', 'actions/more.png', 'imagePath4'],
440
+            ]);
441
+        $this->urlGenerator
442
+            ->expects($this->exactly($times * 4))
443
+            ->method('getAbsoluteURL')
444
+            ->willReturnMap([
445
+                ['imagePath1', 'AbsURL1'],
446
+                ['imagePath2', 'AbsURL2'],
447
+                ['imagePath3', 'AbsURL3'],
448
+                ['imagePath4', 'AbsURL4'],
449
+            ]);
450
+    }
451
+
452
+    private function getUsers(): array {
453
+        $user1 = $this->createMock(IUser::class);
454
+        $user1->method('getUID')
455
+            ->willReturn('uid1');
456
+        $user1->method('getEMailAddress')
457
+            ->willReturn('[email protected]');
458
+        $user2 = $this->createMock(IUser::class);
459
+        $user2->method('getUID')
460
+            ->willReturn('uid2');
461
+        $user2->method('getEMailAddress')
462
+            ->willReturn('[email protected]');
463
+        $user3 = $this->createMock(IUser::class);
464
+        $user3->method('getUID')
465
+            ->willReturn('uid3');
466
+        $user3->method('getEMailAddress')
467
+            ->willReturn('[email protected]');
468
+        $user4 = $this->createMock(IUser::class);
469
+        $user4->method('getUID')
470
+            ->willReturn('uid4');
471
+        $user4->method('getEMailAddress')
472
+            ->willReturn(null);
473
+        $user5 = $this->createMock(IUser::class);
474
+        $user5->method('getUID')
475
+            ->willReturn('uid5');
476
+        $user5->method('getEMailAddress')
477
+            ->willReturn('invalid');
478
+
479
+        return [$user1, $user2, $user3, $user4, $user5];
480
+    }
481 481
 }
Please login to merge, or discard this patch.
apps/files_sharing/lib/Controller/ShareAPIController.php 1 patch
Indentation   +2184 added lines, -2184 removed lines patch added patch discarded remove patch
@@ -77,2191 +77,2191 @@
 block discarded – undo
77 77
  */
78 78
 class ShareAPIController extends OCSController {
79 79
 
80
-	private ?Node $lockedNode = null;
81
-	private array $trustedServerCache = [];
82
-
83
-	/**
84
-	 * Share20OCS constructor.
85
-	 */
86
-	public function __construct(
87
-		string $appName,
88
-		IRequest $request,
89
-		private IManager $shareManager,
90
-		private IGroupManager $groupManager,
91
-		private IUserManager $userManager,
92
-		private IRootFolder $rootFolder,
93
-		private IURLGenerator $urlGenerator,
94
-		private IL10N $l,
95
-		private IConfig $config,
96
-		private IAppConfig $appConfig,
97
-		private IAppManager $appManager,
98
-		private ContainerInterface $serverContainer,
99
-		private IUserStatusManager $userStatusManager,
100
-		private IPreview $previewManager,
101
-		private IDateTimeZone $dateTimeZone,
102
-		private LoggerInterface $logger,
103
-		private IProviderFactory $factory,
104
-		private IMailer $mailer,
105
-		private ITagManager $tagManager,
106
-		private IEmailValidator $emailValidator,
107
-		private ?TrustedServers $trustedServers,
108
-		private ?string $userId = null,
109
-	) {
110
-		parent::__construct($appName, $request);
111
-	}
112
-
113
-	/**
114
-	 * Convert an IShare to an array for OCS output
115
-	 *
116
-	 * @param IShare $share
117
-	 * @param Node|null $recipientNode
118
-	 * @return Files_SharingShare
119
-	 * @throws NotFoundException In case the node can't be resolved.
120
-	 *
121
-	 * @suppress PhanUndeclaredClassMethod
122
-	 */
123
-	protected function formatShare(IShare $share, ?Node $recipientNode = null): array {
124
-		$sharedBy = $this->userManager->get($share->getSharedBy());
125
-		$shareOwner = $this->userManager->get($share->getShareOwner());
126
-
127
-		$isOwnShare = false;
128
-		if ($shareOwner !== null) {
129
-			$isOwnShare = $shareOwner->getUID() === $this->userId;
130
-		}
131
-
132
-		$result = [
133
-			'id' => $share->getId(),
134
-			'share_type' => $share->getShareType(),
135
-			'uid_owner' => $share->getSharedBy(),
136
-			'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
137
-			// recipient permissions
138
-			'permissions' => $share->getPermissions(),
139
-			// current user permissions on this share
140
-			'can_edit' => $this->canEditShare($share),
141
-			'can_delete' => $this->canDeleteShare($share),
142
-			'stime' => $share->getShareTime()->getTimestamp(),
143
-			'parent' => null,
144
-			'expiration' => null,
145
-			'token' => null,
146
-			'uid_file_owner' => $share->getShareOwner(),
147
-			'note' => $share->getNote(),
148
-			'label' => $share->getLabel(),
149
-			'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
150
-		];
151
-
152
-		$userFolder = $this->rootFolder->getUserFolder($this->userId);
153
-		if ($recipientNode) {
154
-			$node = $recipientNode;
155
-		} else {
156
-			$node = $userFolder->getFirstNodeById($share->getNodeId());
157
-			if (!$node) {
158
-				// fallback to guessing the path
159
-				$node = $userFolder->get($share->getTarget());
160
-				if ($node === null || $share->getTarget() === '') {
161
-					throw new NotFoundException();
162
-				}
163
-			}
164
-		}
165
-
166
-		$result['path'] = $userFolder->getRelativePath($node->getPath());
167
-		if ($node instanceof Folder) {
168
-			$result['item_type'] = 'folder';
169
-		} else {
170
-			$result['item_type'] = 'file';
171
-		}
172
-
173
-		// Get the original node permission if the share owner is the current user
174
-		if ($isOwnShare) {
175
-			$result['item_permissions'] = $node->getPermissions();
176
-		}
177
-
178
-		// If we're on the recipient side, the node permissions
179
-		// are bound to the share permissions. So we need to
180
-		// adjust the permissions to the share permissions if necessary.
181
-		if (!$isOwnShare) {
182
-			$result['item_permissions'] = $share->getPermissions();
183
-
184
-			// For some reason, single files share are forbidden to have the delete permission
185
-			// since we have custom methods to check those, let's adjust straight away.
186
-			// DAV permissions does not have that issue though.
187
-			if ($this->canDeleteShare($share) || $this->canDeleteShareFromSelf($share)) {
188
-				$result['item_permissions'] |= Constants::PERMISSION_DELETE;
189
-			}
190
-			if ($this->canEditShare($share)) {
191
-				$result['item_permissions'] |= Constants::PERMISSION_UPDATE;
192
-			}
193
-		}
194
-
195
-		// See MOUNT_ROOT_PROPERTYNAME dav property
196
-		$result['is-mount-root'] = $node->getInternalPath() === '';
197
-		$result['mount-type'] = $node->getMountPoint()->getMountType();
198
-
199
-		$result['mimetype'] = $node->getMimetype();
200
-		$result['has_preview'] = $this->previewManager->isAvailable($node);
201
-		$result['storage_id'] = $node->getStorage()->getId();
202
-		$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
203
-		$result['item_source'] = $node->getId();
204
-		$result['file_source'] = $node->getId();
205
-		$result['file_parent'] = $node->getParent()->getId();
206
-		$result['file_target'] = $share->getTarget();
207
-		$result['item_size'] = $node->getSize();
208
-		$result['item_mtime'] = $node->getMTime();
209
-
210
-		if ($this->trustedServers !== null && in_array($share->getShareType(), [IShare::TYPE_REMOTE, IShare::TYPE_REMOTE_GROUP], true)) {
211
-			$result['is_trusted_server'] = false;
212
-			$sharedWith = $share->getSharedWith();
213
-			$remoteIdentifier = is_string($sharedWith) ? strrchr($sharedWith, '@') : false;
214
-			if ($remoteIdentifier !== false) {
215
-				$remote = substr($remoteIdentifier, 1);
216
-
217
-				if (isset($this->trustedServerCache[$remote])) {
218
-					$result['is_trusted_server'] = $this->trustedServerCache[$remote];
219
-				} else {
220
-					try {
221
-						$isTrusted = $this->trustedServers->isTrustedServer($remote);
222
-						$this->trustedServerCache[$remote] = $isTrusted;
223
-						$result['is_trusted_server'] = $isTrusted;
224
-					} catch (\Exception $e) {
225
-						// Server not found or other issue, we consider it not trusted
226
-						$this->trustedServerCache[$remote] = false;
227
-						$this->logger->error(
228
-							'Error checking if remote server is trusted (treating as untrusted): ' . $e->getMessage(),
229
-							['exception' => $e]
230
-						);
231
-					}
232
-				}
233
-			}
234
-		}
235
-
236
-		$expiration = $share->getExpirationDate();
237
-		if ($expiration !== null) {
238
-			$expiration->setTimezone($this->dateTimeZone->getTimeZone());
239
-			$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
240
-		}
241
-
242
-		if ($share->getShareType() === IShare::TYPE_USER) {
243
-			$sharedWith = $this->userManager->get($share->getSharedWith());
244
-			$result['share_with'] = $share->getSharedWith();
245
-			$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
246
-			$result['share_with_displayname_unique'] = $sharedWith !== null ? (
247
-				!empty($sharedWith->getSystemEMailAddress()) ? $sharedWith->getSystemEMailAddress() : $sharedWith->getUID()
248
-			) : $share->getSharedWith();
249
-
250
-			$userStatuses = $this->userStatusManager->getUserStatuses([$share->getSharedWith()]);
251
-			$userStatus = array_shift($userStatuses);
252
-			if ($userStatus) {
253
-				$result['status'] = [
254
-					'status' => $userStatus->getStatus(),
255
-					'message' => $userStatus->getMessage(),
256
-					'icon' => $userStatus->getIcon(),
257
-					'clearAt' => $userStatus->getClearAt()
258
-						? (int)$userStatus->getClearAt()->format('U')
259
-						: null,
260
-				];
261
-			}
262
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
263
-			$group = $this->groupManager->get($share->getSharedWith());
264
-			$result['share_with'] = $share->getSharedWith();
265
-			$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
266
-		} elseif ($share->getShareType() === IShare::TYPE_LINK) {
267
-
268
-			// "share_with" and "share_with_displayname" for passwords of link
269
-			// shares was deprecated in Nextcloud 15, use "password" instead.
270
-			$result['share_with'] = $share->getPassword();
271
-			$result['share_with_displayname'] = '(' . $this->l->t('Shared link') . ')';
272
-
273
-			$result['password'] = $share->getPassword();
274
-
275
-			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
276
-
277
-			$result['token'] = $share->getToken();
278
-			$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
279
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE) {
280
-			$result['share_with'] = $share->getSharedWith();
281
-			$result['share_with_displayname'] = $this->getCachedFederatedDisplayName($share->getSharedWith());
282
-			$result['token'] = $share->getToken();
283
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
284
-			$result['share_with'] = $share->getSharedWith();
285
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
286
-			$result['token'] = $share->getToken();
287
-		} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
288
-			$result['share_with'] = $share->getSharedWith();
289
-			$result['password'] = $share->getPassword();
290
-			$result['password_expiration_time'] = $share->getPasswordExpirationTime() !== null ? $share->getPasswordExpirationTime()->format(\DateTime::ATOM) : null;
291
-			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
292
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
293
-			$result['token'] = $share->getToken();
294
-		} elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
295
-			// getSharedWith() returns either "name (type, owner)" or
296
-			// "name (type, owner) [id]", depending on the Teams app version.
297
-			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
298
-
299
-			$result['share_with_displayname'] = $share->getSharedWithDisplayName();
300
-			if (empty($result['share_with_displayname'])) {
301
-				$displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith()));
302
-				$result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
303
-			}
304
-
305
-			$result['share_with_avatar'] = $share->getSharedWithAvatar();
306
-
307
-			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
308
-			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
309
-			if ($shareWithLength === false) {
310
-				$result['share_with'] = substr($share->getSharedWith(), $shareWithStart);
311
-			} else {
312
-				$result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
313
-			}
314
-		} elseif ($share->getShareType() === IShare::TYPE_ROOM) {
315
-			$result['share_with'] = $share->getSharedWith();
316
-			$result['share_with_displayname'] = '';
317
-
318
-			try {
319
-				/** @var array{share_with_displayname: string, share_with_link: string, share_with?: string, token?: string} $roomShare */
320
-				$roomShare = $this->getRoomShareHelper()->formatShare($share);
321
-				$result = array_merge($result, $roomShare);
322
-			} catch (ContainerExceptionInterface $e) {
323
-			}
324
-		} elseif ($share->getShareType() === IShare::TYPE_DECK) {
325
-			$result['share_with'] = $share->getSharedWith();
326
-			$result['share_with_displayname'] = '';
327
-
328
-			try {
329
-				/** @var array{share_with: string, share_with_displayname: string, share_with_link: string} $deckShare */
330
-				$deckShare = $this->getDeckShareHelper()->formatShare($share);
331
-				$result = array_merge($result, $deckShare);
332
-			} catch (ContainerExceptionInterface $e) {
333
-			}
334
-		} elseif ($share->getShareType() === IShare::TYPE_SCIENCEMESH) {
335
-			$result['share_with'] = $share->getSharedWith();
336
-			$result['share_with_displayname'] = '';
337
-
338
-			try {
339
-				/** @var array{share_with: string, share_with_displayname: string, token: string} $scienceMeshShare */
340
-				$scienceMeshShare = $this->getSciencemeshShareHelper()->formatShare($share);
341
-				$result = array_merge($result, $scienceMeshShare);
342
-			} catch (ContainerExceptionInterface $e) {
343
-			}
344
-		}
345
-
346
-
347
-		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
348
-		$result['hide_download'] = $share->getHideDownload() ? 1 : 0;
349
-
350
-		$result['attributes'] = null;
351
-		if ($attributes = $share->getAttributes()) {
352
-			$result['attributes'] = (string)\json_encode($attributes->toArray());
353
-		}
354
-
355
-		return $result;
356
-	}
357
-
358
-	/**
359
-	 * Check if one of the users address books knows the exact property, if
360
-	 * not we return the full name.
361
-	 *
362
-	 * @param string $query
363
-	 * @param string $property
364
-	 * @return string
365
-	 */
366
-	private function getDisplayNameFromAddressBook(string $query, string $property): string {
367
-		// FIXME: If we inject the contacts manager it gets initialized before any address books are registered
368
-		try {
369
-			$result = Server::get(\OCP\Contacts\IManager::class)->search($query, [$property], [
370
-				'limit' => 1,
371
-				'enumeration' => false,
372
-				'strict_search' => true,
373
-			]);
374
-		} catch (Exception $e) {
375
-			$this->logger->error(
376
-				$e->getMessage(),
377
-				['exception' => $e]
378
-			);
379
-			return $query;
380
-		}
381
-
382
-		foreach ($result as $r) {
383
-			foreach ($r[$property] as $value) {
384
-				if ($value === $query && $r['FN']) {
385
-					return $r['FN'];
386
-				}
387
-			}
388
-		}
389
-
390
-		return $query;
391
-	}
392
-
393
-
394
-	/**
395
-	 * @param list<Files_SharingShare> $shares
396
-	 * @param array<string, string>|null $updatedDisplayName
397
-	 *
398
-	 * @return list<Files_SharingShare>
399
-	 */
400
-	private function fixMissingDisplayName(array $shares, ?array $updatedDisplayName = null): array {
401
-		$userIds = $updated = [];
402
-		foreach ($shares as $share) {
403
-			// share is federated and share have no display name yet
404
-			if ($share['share_type'] === IShare::TYPE_REMOTE
405
-				&& ($share['share_with'] ?? '') !== ''
406
-				&& ($share['share_with_displayname'] ?? '') === '') {
407
-				$userIds[] = $userId = $share['share_with'];
408
-
409
-				if ($updatedDisplayName !== null && array_key_exists($userId, $updatedDisplayName)) {
410
-					$share['share_with_displayname'] = $updatedDisplayName[$userId];
411
-				}
412
-			}
413
-
414
-			// prepping userIds with displayName to be updated
415
-			$updated[] = $share;
416
-		}
417
-
418
-		// if $updatedDisplayName is not null, it means we should have already fixed displayNames of the shares
419
-		if ($updatedDisplayName !== null) {
420
-			return $updated;
421
-		}
422
-
423
-		// get displayName for the generated list of userId with no displayName
424
-		$displayNames = $this->retrieveFederatedDisplayName($userIds);
425
-
426
-		// if no displayName are updated, we exit
427
-		if (empty($displayNames)) {
428
-			return $updated;
429
-		}
430
-
431
-		// let's fix missing display name and returns all shares
432
-		return $this->fixMissingDisplayName($shares, $displayNames);
433
-	}
434
-
435
-
436
-	/**
437
-	 * get displayName of a list of userIds from the lookup-server; through the globalsiteselector app.
438
-	 * returns an array with userIds as keys and displayName as values.
439
-	 *
440
-	 * @param array $userIds
441
-	 * @param bool $cacheOnly - do not reach LUS, get data from cache.
442
-	 *
443
-	 * @return array
444
-	 * @throws ContainerExceptionInterface
445
-	 */
446
-	private function retrieveFederatedDisplayName(array $userIds, bool $cacheOnly = false): array {
447
-		// check if gss is enabled and available
448
-		if (count($userIds) === 0
449
-			|| !$this->appManager->isEnabledForAnyone('globalsiteselector')
450
-			|| !class_exists('\OCA\GlobalSiteSelector\Service\SlaveService')) {
451
-			return [];
452
-		}
453
-
454
-		try {
455
-			$slaveService = Server::get(SlaveService::class);
456
-		} catch (\Throwable $e) {
457
-			$this->logger->error(
458
-				$e->getMessage(),
459
-				['exception' => $e]
460
-			);
461
-			return [];
462
-		}
463
-
464
-		return $slaveService->getUsersDisplayName($userIds, $cacheOnly);
465
-	}
466
-
467
-
468
-	/**
469
-	 * retrieve displayName from cache if available (should be used on federated shares)
470
-	 * if not available in cache/lus, try for get from address-book, else returns empty string.
471
-	 *
472
-	 * @param string $userId
473
-	 * @param bool $cacheOnly if true will not reach the lus but will only get data from cache
474
-	 *
475
-	 * @return string
476
-	 */
477
-	private function getCachedFederatedDisplayName(string $userId, bool $cacheOnly = true): string {
478
-		$details = $this->retrieveFederatedDisplayName([$userId], $cacheOnly);
479
-		if (array_key_exists($userId, $details)) {
480
-			return $details[$userId];
481
-		}
482
-
483
-		$displayName = $this->getDisplayNameFromAddressBook($userId, 'CLOUD');
484
-		return ($displayName === $userId) ? '' : $displayName;
485
-	}
486
-
487
-
488
-
489
-	/**
490
-	 * Get a specific share by id
491
-	 *
492
-	 * @param string $id ID of the share
493
-	 * @param bool $include_tags Include tags in the share
494
-	 * @return DataResponse<Http::STATUS_OK, list<Files_SharingShare>, array{}>
495
-	 * @throws OCSNotFoundException Share not found
496
-	 *
497
-	 * 200: Share returned
498
-	 */
499
-	#[NoAdminRequired]
500
-	public function getShare(string $id, bool $include_tags = false): DataResponse {
501
-		try {
502
-			$share = $this->getShareById($id);
503
-		} catch (ShareNotFound $e) {
504
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
505
-		}
506
-
507
-		try {
508
-			if ($this->canAccessShare($share)) {
509
-				$share = $this->formatShare($share);
510
-
511
-				if ($include_tags) {
512
-					$share = $this->populateTags([$share]);
513
-				} else {
514
-					$share = [$share];
515
-				}
516
-
517
-				return new DataResponse($share);
518
-			}
519
-		} catch (NotFoundException $e) {
520
-			// Fall through
521
-		}
522
-
523
-		throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
524
-	}
525
-
526
-	/**
527
-	 * Delete a share
528
-	 *
529
-	 * @param string $id ID of the share
530
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
531
-	 * @throws OCSNotFoundException Share not found
532
-	 * @throws OCSForbiddenException Missing permissions to delete the share
533
-	 *
534
-	 * 200: Share deleted successfully
535
-	 */
536
-	#[NoAdminRequired]
537
-	public function deleteShare(string $id): DataResponse {
538
-		try {
539
-			$share = $this->getShareById($id);
540
-		} catch (ShareNotFound $e) {
541
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
542
-		}
543
-
544
-		try {
545
-			$this->lock($share->getNode());
546
-		} catch (LockedException $e) {
547
-			throw new OCSNotFoundException($this->l->t('Could not delete share'));
548
-		}
549
-
550
-		if (!$this->canAccessShare($share)) {
551
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
552
-		}
553
-
554
-		// if it's a group share or a room share
555
-		// we don't delete the share, but only the
556
-		// mount point. Allowing it to be restored
557
-		// from the deleted shares
558
-		if ($this->canDeleteShareFromSelf($share)) {
559
-			$this->shareManager->deleteFromSelf($share, $this->userId);
560
-		} else {
561
-			if (!$this->canDeleteShare($share)) {
562
-				throw new OCSForbiddenException($this->l->t('Could not delete share'));
563
-			}
564
-
565
-			$this->shareManager->deleteShare($share);
566
-		}
567
-
568
-		return new DataResponse();
569
-	}
570
-
571
-	/**
572
-	 * Create a share
573
-	 *
574
-	 * @param string|null $path Path of the share
575
-	 * @param int|null $permissions Permissions for the share
576
-	 * @param int $shareType Type of the share
577
-	 * @param ?string $shareWith The entity this should be shared with
578
-	 * @param 'true'|'false'|null $publicUpload If public uploading is allowed (deprecated)
579
-	 * @param string $password Password for the share
580
-	 * @param string|null $sendPasswordByTalk Send the password for the share over Talk
581
-	 * @param ?string $expireDate The expiry date of the share in the user's timezone at 00:00.
582
-	 *                            If $expireDate is not supplied or set to `null`, the system default will be used.
583
-	 * @param string $note Note for the share
584
-	 * @param string $label Label for the share (only used in link and email)
585
-	 * @param string|null $attributes Additional attributes for the share
586
-	 * @param 'false'|'true'|null $sendMail Send a mail to the recipient
587
-	 *
588
-	 * @return DataResponse<Http::STATUS_OK, Files_SharingShare, array{}>
589
-	 * @throws OCSBadRequestException Unknown share type
590
-	 * @throws OCSException
591
-	 * @throws OCSForbiddenException Creating the share is not allowed
592
-	 * @throws OCSNotFoundException Creating the share failed
593
-	 * @suppress PhanUndeclaredClassMethod
594
-	 *
595
-	 * 200: Share created
596
-	 */
597
-	#[NoAdminRequired]
598
-	#[UserRateLimit(limit: 20, period: 600)]
599
-	public function createShare(
600
-		?string $path = null,
601
-		?int $permissions = null,
602
-		int $shareType = -1,
603
-		?string $shareWith = null,
604
-		?string $publicUpload = null,
605
-		string $password = '',
606
-		?string $sendPasswordByTalk = null,
607
-		?string $expireDate = null,
608
-		string $note = '',
609
-		string $label = '',
610
-		?string $attributes = null,
611
-		?string $sendMail = null,
612
-	): DataResponse {
613
-		assert($this->userId !== null);
614
-
615
-		$share = $this->shareManager->newShare();
616
-		$hasPublicUpload = $this->getLegacyPublicUpload($publicUpload);
617
-
618
-		// Verify path
619
-		if ($path === null) {
620
-			throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
621
-		}
622
-
623
-		$userFolder = $this->rootFolder->getUserFolder($this->userId);
624
-		try {
625
-			/** @var \OC\Files\Node\Node $node */
626
-			$node = $userFolder->get($path);
627
-		} catch (NotFoundException $e) {
628
-			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder does not exist'));
629
-		}
630
-
631
-		// a user can have access to a file through different paths, with differing permissions
632
-		// combine all permissions to determine if the user can share this file
633
-		$nodes = $userFolder->getById($node->getId());
634
-		foreach ($nodes as $nodeById) {
635
-			/** @var FileInfo $fileInfo */
636
-			$fileInfo = $node->getFileInfo();
637
-			$fileInfo['permissions'] |= $nodeById->getPermissions();
638
-		}
639
-
640
-		$share->setNode($node);
641
-
642
-		try {
643
-			$this->lock($share->getNode());
644
-		} catch (LockedException $e) {
645
-			throw new OCSNotFoundException($this->l->t('Could not create share'));
646
-		}
647
-
648
-		// Set permissions
649
-		if ($shareType === IShare::TYPE_LINK || $shareType === IShare::TYPE_EMAIL) {
650
-			$permissions = $this->getLinkSharePermissions($permissions, $hasPublicUpload);
651
-			$this->validateLinkSharePermissions($node, $permissions, $hasPublicUpload);
652
-		} else {
653
-			// Use default permissions only for non-link shares to keep legacy behavior
654
-			if ($permissions === null) {
655
-				$permissions = (int)$this->config->getAppValue('core', 'shareapi_default_permissions', (string)Constants::PERMISSION_ALL);
656
-			}
657
-			// Non-link shares always require read permissions (link shares could be file drop)
658
-			$permissions |= Constants::PERMISSION_READ;
659
-		}
660
-
661
-		// For legacy reasons the API allows to pass PERMISSIONS_ALL even for single file shares (I look at you Talk)
662
-		if ($node instanceof File) {
663
-			// if this is a single file share we remove the DELETE and CREATE permissions
664
-			$permissions = $permissions & ~(Constants::PERMISSION_DELETE | Constants::PERMISSION_CREATE);
665
-		}
666
-
667
-		/**
668
-		 * Hack for https://github.com/owncloud/core/issues/22587
669
-		 * We check the permissions via webdav. But the permissions of the mount point
670
-		 * do not equal the share permissions. Here we fix that for federated mounts.
671
-		 */
672
-		if ($node->getStorage()->instanceOfStorage(Storage::class)) {
673
-			$permissions &= ~($permissions & ~$node->getPermissions());
674
-		}
675
-
676
-		if ($attributes !== null) {
677
-			$share = $this->setShareAttributes($share, $attributes);
678
-		}
679
-
680
-		// Expire date checks
681
-		// Normally, null means no expiration date but we still set the default for backwards compatibility
682
-		// If the client sends an empty string, we set noExpirationDate to true
683
-		if ($expireDate !== null) {
684
-			if ($expireDate !== '') {
685
-				try {
686
-					$expireDateTime = $this->parseDate($expireDate);
687
-					$share->setExpirationDate($expireDateTime);
688
-				} catch (\Exception $e) {
689
-					throw new OCSNotFoundException($e->getMessage(), $e);
690
-				}
691
-			} else {
692
-				// Client sent empty string for expire date.
693
-				// Set noExpirationDate to true so overwrite is prevented.
694
-				$share->setNoExpirationDate(true);
695
-			}
696
-		}
697
-
698
-		$share->setSharedBy($this->userId);
699
-
700
-		// Handle mail send
701
-		if (is_null($sendMail)) {
702
-			$allowSendMail = $this->config->getSystemValueBool('sharing.enable_share_mail', true);
703
-			if ($allowSendMail !== true || $shareType === IShare::TYPE_EMAIL) {
704
-				// Define a default behavior when sendMail is not provided
705
-				// For email shares with a valid recipient, the default is to send the mail
706
-				// For all other share types, the default is to not send the mail
707
-				$allowSendMail = ($shareType === IShare::TYPE_EMAIL && $shareWith !== null && $shareWith !== '');
708
-			}
709
-			$share->setMailSend($allowSendMail);
710
-		} else {
711
-			$share->setMailSend($sendMail === 'true');
712
-		}
713
-
714
-		if ($shareType === IShare::TYPE_USER) {
715
-			// Valid user is required to share
716
-			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
717
-				throw new OCSNotFoundException($this->l->t('Please specify a valid account to share with'));
718
-			}
719
-			$share->setSharedWith($shareWith);
720
-			$share->setPermissions($permissions);
721
-		} elseif ($shareType === IShare::TYPE_GROUP) {
722
-			if (!$this->shareManager->allowGroupSharing()) {
723
-				throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
724
-			}
725
-
726
-			// Valid group is required to share
727
-			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
728
-				throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
729
-			}
730
-			$share->setSharedWith($shareWith);
731
-			$share->setPermissions($permissions);
732
-		} elseif ($shareType === IShare::TYPE_LINK
733
-			|| $shareType === IShare::TYPE_EMAIL) {
734
-
735
-			// Can we even share links?
736
-			if (!$this->shareManager->shareApiAllowLinks()) {
737
-				throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
738
-			}
739
-
740
-			$this->validateLinkSharePermissions($node, $permissions, $hasPublicUpload);
741
-			$share->setPermissions($permissions);
742
-
743
-			// Set password
744
-			if ($password !== '') {
745
-				$share->setPassword($password);
746
-			}
747
-
748
-			// Only share by mail have a recipient
749
-			if (is_string($shareWith) && $shareType === IShare::TYPE_EMAIL) {
750
-				// If sending a mail have been requested, validate the mail address
751
-				if ($share->getMailSend() && !$this->emailValidator->isValid($shareWith)) {
752
-					throw new OCSNotFoundException($this->l->t('Please specify a valid email address'));
753
-				}
754
-				$share->setSharedWith($shareWith);
755
-			}
756
-
757
-			// If we have a label, use it
758
-			if ($label !== '') {
759
-				if (strlen($label) > 255) {
760
-					throw new OCSBadRequestException('Maximum label length is 255');
761
-				}
762
-				$share->setLabel($label);
763
-			}
764
-
765
-			if ($sendPasswordByTalk === 'true') {
766
-				if (!$this->appManager->isEnabledForUser('spreed')) {
767
-					throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$node->getPath()]));
768
-				}
769
-
770
-				$share->setSendPasswordByTalk(true);
771
-			}
772
-		} elseif ($shareType === IShare::TYPE_REMOTE) {
773
-			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
774
-				throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$node->getPath(), $shareType]));
775
-			}
776
-
777
-			if ($shareWith === null) {
778
-				throw new OCSNotFoundException($this->l->t('Please specify a valid federated account ID'));
779
-			}
780
-
781
-			$share->setSharedWith($shareWith);
782
-			$share->setPermissions($permissions);
783
-			$share->setSharedWithDisplayName($this->getCachedFederatedDisplayName($shareWith, false));
784
-		} elseif ($shareType === IShare::TYPE_REMOTE_GROUP) {
785
-			if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
786
-				throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$node->getPath(), $shareType]));
787
-			}
788
-
789
-			if ($shareWith === null) {
790
-				throw new OCSNotFoundException($this->l->t('Please specify a valid federated group ID'));
791
-			}
792
-
793
-			$share->setSharedWith($shareWith);
794
-			$share->setPermissions($permissions);
795
-		} elseif ($shareType === IShare::TYPE_CIRCLE) {
796
-			if (!Server::get(IAppManager::class)->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
797
-				throw new OCSNotFoundException($this->l->t('You cannot share to a Team if the app is not enabled'));
798
-			}
799
-
800
-			$circle = Circles::detailsCircle($shareWith);
801
-
802
-			// Valid team is required to share
803
-			if ($circle === null) {
804
-				throw new OCSNotFoundException($this->l->t('Please specify a valid team'));
805
-			}
806
-			$share->setSharedWith($shareWith);
807
-			$share->setPermissions($permissions);
808
-		} elseif ($shareType === IShare::TYPE_ROOM) {
809
-			try {
810
-				$this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate ?? '');
811
-			} catch (ContainerExceptionInterface $e) {
812
-				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$node->getPath()]));
813
-			}
814
-		} elseif ($shareType === IShare::TYPE_DECK) {
815
-			try {
816
-				$this->getDeckShareHelper()->createShare($share, $shareWith, $permissions, $expireDate ?? '');
817
-			} catch (ContainerExceptionInterface $e) {
818
-				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$node->getPath()]));
819
-			}
820
-		} elseif ($shareType === IShare::TYPE_SCIENCEMESH) {
821
-			try {
822
-				$this->getSciencemeshShareHelper()->createShare($share, $shareWith, $permissions, $expireDate ?? '');
823
-			} catch (ContainerExceptionInterface $e) {
824
-				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support ScienceMesh shares', [$node->getPath()]));
825
-			}
826
-		} else {
827
-			throw new OCSBadRequestException($this->l->t('Unknown share type'));
828
-		}
829
-
830
-		$share->setShareType($shareType);
831
-		$this->checkInheritedAttributes($share);
832
-
833
-		if ($note !== '') {
834
-			$share->setNote($note);
835
-		}
836
-
837
-		try {
838
-			$share = $this->shareManager->createShare($share);
839
-		} catch (HintException $e) {
840
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
841
-			throw new OCSException($e->getHint(), $code);
842
-		} catch (GenericShareException|\InvalidArgumentException $e) {
843
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
844
-			throw new OCSForbiddenException($e->getMessage(), $e);
845
-		} catch (\Exception $e) {
846
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
847
-			throw new OCSForbiddenException('Failed to create share.', $e);
848
-		}
849
-
850
-		$output = $this->formatShare($share);
851
-
852
-		return new DataResponse($output);
853
-	}
854
-
855
-	/**
856
-	 * @param null|Node $node
857
-	 * @param boolean $includeTags
858
-	 *
859
-	 * @return list<Files_SharingShare>
860
-	 */
861
-	private function getSharedWithMe($node, bool $includeTags): array {
862
-		$userShares = $this->shareManager->getSharedWith($this->userId, IShare::TYPE_USER, $node, -1, 0);
863
-		$groupShares = $this->shareManager->getSharedWith($this->userId, IShare::TYPE_GROUP, $node, -1, 0);
864
-		$circleShares = $this->shareManager->getSharedWith($this->userId, IShare::TYPE_CIRCLE, $node, -1, 0);
865
-		$roomShares = $this->shareManager->getSharedWith($this->userId, IShare::TYPE_ROOM, $node, -1, 0);
866
-		$deckShares = $this->shareManager->getSharedWith($this->userId, IShare::TYPE_DECK, $node, -1, 0);
867
-		$sciencemeshShares = $this->shareManager->getSharedWith($this->userId, IShare::TYPE_SCIENCEMESH, $node, -1, 0);
868
-
869
-		$shares = array_merge($userShares, $groupShares, $circleShares, $roomShares, $deckShares, $sciencemeshShares);
870
-
871
-		$filteredShares = array_filter($shares, function (IShare $share) {
872
-			return $share->getShareOwner() !== $this->userId && $share->getSharedBy() !== $this->userId;
873
-		});
874
-
875
-		$formatted = [];
876
-		foreach ($filteredShares as $share) {
877
-			if ($this->canAccessShare($share)) {
878
-				try {
879
-					$formatted[] = $this->formatShare($share);
880
-				} catch (NotFoundException $e) {
881
-					// Ignore this share
882
-				}
883
-			}
884
-		}
885
-
886
-		if ($includeTags) {
887
-			$formatted = $this->populateTags($formatted);
888
-		}
889
-
890
-		return $formatted;
891
-	}
892
-
893
-	/**
894
-	 * @param Node $folder
895
-	 *
896
-	 * @return list<Files_SharingShare>
897
-	 * @throws OCSBadRequestException
898
-	 * @throws NotFoundException
899
-	 */
900
-	private function getSharesInDir(Node $folder): array {
901
-		if (!($folder instanceof Folder)) {
902
-			throw new OCSBadRequestException($this->l->t('Not a directory'));
903
-		}
904
-
905
-		$nodes = $folder->getDirectoryListing();
906
-
907
-		/** @var IShare[] $shares */
908
-		$shares = array_reduce($nodes, function ($carry, $node) {
909
-			$carry = array_merge($carry, $this->getAllShares($node, true));
910
-			return $carry;
911
-		}, []);
912
-
913
-		// filter out duplicate shares
914
-		$known = [];
915
-
916
-		$formatted = $miniFormatted = [];
917
-		$resharingRight = false;
918
-		$known = [];
919
-		foreach ($shares as $share) {
920
-			if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->userId) {
921
-				continue;
922
-			}
923
-
924
-			try {
925
-				$format = $this->formatShare($share);
926
-
927
-				$known[] = $share->getId();
928
-				$formatted[] = $format;
929
-				if ($share->getSharedBy() === $this->userId) {
930
-					$miniFormatted[] = $format;
931
-				}
932
-				if (!$resharingRight && $this->shareProviderResharingRights($this->userId, $share, $folder)) {
933
-					$resharingRight = true;
934
-				}
935
-			} catch (\Exception $e) {
936
-				//Ignore this share
937
-			}
938
-		}
939
-
940
-		if (!$resharingRight) {
941
-			$formatted = $miniFormatted;
942
-		}
943
-
944
-		return $formatted;
945
-	}
946
-
947
-	/**
948
-	 * Get shares of the current user
949
-	 *
950
-	 * @param string $shared_with_me Only get shares with the current user
951
-	 * @param string $reshares Only get shares by the current user and reshares
952
-	 * @param string $subfiles Only get all shares in a folder
953
-	 * @param string $path Get shares for a specific path
954
-	 * @param string $include_tags Include tags in the share
955
-	 *
956
-	 * @return DataResponse<Http::STATUS_OK, list<Files_SharingShare>, array{}>
957
-	 * @throws OCSNotFoundException The folder was not found or is inaccessible
958
-	 *
959
-	 * 200: Shares returned
960
-	 */
961
-	#[NoAdminRequired]
962
-	public function getShares(
963
-		string $shared_with_me = 'false',
964
-		string $reshares = 'false',
965
-		string $subfiles = 'false',
966
-		string $path = '',
967
-		string $include_tags = 'false',
968
-	): DataResponse {
969
-		$node = null;
970
-		if ($path !== '') {
971
-			$userFolder = $this->rootFolder->getUserFolder($this->userId);
972
-			try {
973
-				$node = $userFolder->get($path);
974
-				$this->lock($node);
975
-			} catch (NotFoundException $e) {
976
-				throw new OCSNotFoundException(
977
-					$this->l->t('Wrong path, file/folder does not exist')
978
-				);
979
-			} catch (LockedException $e) {
980
-				throw new OCSNotFoundException($this->l->t('Could not lock node'));
981
-			}
982
-		}
983
-
984
-		$shares = $this->getFormattedShares(
985
-			$this->userId,
986
-			$node,
987
-			($shared_with_me === 'true'),
988
-			($reshares === 'true'),
989
-			($subfiles === 'true'),
990
-			($include_tags === 'true')
991
-		);
992
-
993
-		return new DataResponse($shares);
994
-	}
995
-
996
-	private function getLinkSharePermissions(?int $permissions, ?bool $legacyPublicUpload): int {
997
-		$permissions = $permissions ?? Constants::PERMISSION_READ;
998
-
999
-		// Legacy option handling
1000
-		if ($legacyPublicUpload !== null) {
1001
-			$permissions = $legacyPublicUpload
1002
-				? (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
1003
-				: Constants::PERMISSION_READ;
1004
-		}
1005
-
1006
-		if ($this->hasPermission($permissions, Constants::PERMISSION_READ)
1007
-			&& $this->shareManager->outgoingServer2ServerSharesAllowed()
1008
-			&& $this->appConfig->getValueBool('core', ConfigLexicon::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES)) {
1009
-			$permissions |= Constants::PERMISSION_SHARE;
1010
-		}
1011
-
1012
-		return $permissions;
1013
-	}
1014
-
1015
-	/**
1016
-	 * Helper to check for legacy "publicUpload" handling.
1017
-	 * If the value is set to `true` or `false` then true or false are returned.
1018
-	 * Otherwise null is returned to indicate that the option was not (or wrong) set.
1019
-	 *
1020
-	 * @param null|string $legacyPublicUpload The value of `publicUpload`
1021
-	 */
1022
-	private function getLegacyPublicUpload(?string $legacyPublicUpload): ?bool {
1023
-		if ($legacyPublicUpload === 'true') {
1024
-			return true;
1025
-		} elseif ($legacyPublicUpload === 'false') {
1026
-			return false;
1027
-		}
1028
-		// Not set at all
1029
-		return null;
1030
-	}
1031
-
1032
-	/**
1033
-	 * For link and email shares validate that only allowed combinations are set.
1034
-	 *
1035
-	 * @throw OCSBadRequestException If permission combination is invalid.
1036
-	 * @throw OCSForbiddenException If public upload was forbidden by the administrator.
1037
-	 */
1038
-	private function validateLinkSharePermissions(Node $node, int $permissions, ?bool $legacyPublicUpload): void {
1039
-		if ($legacyPublicUpload && ($node instanceof File)) {
1040
-			throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
1041
-		}
1042
-
1043
-		// We need at least READ or CREATE (file drop)
1044
-		if (!$this->hasPermission($permissions, Constants::PERMISSION_READ)
1045
-			&& !$this->hasPermission($permissions, Constants::PERMISSION_CREATE)) {
1046
-			throw new OCSBadRequestException($this->l->t('Share must at least have READ or CREATE permissions'));
1047
-		}
1048
-
1049
-		// UPDATE and DELETE require a READ permission
1050
-		if (!$this->hasPermission($permissions, Constants::PERMISSION_READ)
1051
-			&& ($this->hasPermission($permissions, Constants::PERMISSION_UPDATE) || $this->hasPermission($permissions, Constants::PERMISSION_DELETE))) {
1052
-			throw new OCSBadRequestException($this->l->t('Share must have READ permission if UPDATE or DELETE permission is set'));
1053
-		}
1054
-
1055
-		// Check if public uploading was disabled
1056
-		if ($this->hasPermission($permissions, Constants::PERMISSION_CREATE)
1057
-			&& !$this->shareManager->shareApiLinkAllowPublicUpload()) {
1058
-			throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
1059
-		}
1060
-	}
1061
-
1062
-	/**
1063
-	 * @param string $viewer
1064
-	 * @param Node $node
1065
-	 * @param bool $sharedWithMe
1066
-	 * @param bool $reShares
1067
-	 * @param bool $subFiles
1068
-	 * @param bool $includeTags
1069
-	 *
1070
-	 * @return list<Files_SharingShare>
1071
-	 * @throws NotFoundException
1072
-	 * @throws OCSBadRequestException
1073
-	 */
1074
-	private function getFormattedShares(
1075
-		string $viewer,
1076
-		$node = null,
1077
-		bool $sharedWithMe = false,
1078
-		bool $reShares = false,
1079
-		bool $subFiles = false,
1080
-		bool $includeTags = false,
1081
-	): array {
1082
-		if ($sharedWithMe) {
1083
-			return $this->getSharedWithMe($node, $includeTags);
1084
-		}
1085
-
1086
-		if ($subFiles) {
1087
-			return $this->getSharesInDir($node);
1088
-		}
1089
-
1090
-		$shares = $this->getSharesFromNode($viewer, $node, $reShares);
1091
-
1092
-		$known = $formatted = $miniFormatted = [];
1093
-		$resharingRight = false;
1094
-		foreach ($shares as $share) {
1095
-			try {
1096
-				$share->getNode();
1097
-			} catch (NotFoundException $e) {
1098
-				/*
80
+    private ?Node $lockedNode = null;
81
+    private array $trustedServerCache = [];
82
+
83
+    /**
84
+     * Share20OCS constructor.
85
+     */
86
+    public function __construct(
87
+        string $appName,
88
+        IRequest $request,
89
+        private IManager $shareManager,
90
+        private IGroupManager $groupManager,
91
+        private IUserManager $userManager,
92
+        private IRootFolder $rootFolder,
93
+        private IURLGenerator $urlGenerator,
94
+        private IL10N $l,
95
+        private IConfig $config,
96
+        private IAppConfig $appConfig,
97
+        private IAppManager $appManager,
98
+        private ContainerInterface $serverContainer,
99
+        private IUserStatusManager $userStatusManager,
100
+        private IPreview $previewManager,
101
+        private IDateTimeZone $dateTimeZone,
102
+        private LoggerInterface $logger,
103
+        private IProviderFactory $factory,
104
+        private IMailer $mailer,
105
+        private ITagManager $tagManager,
106
+        private IEmailValidator $emailValidator,
107
+        private ?TrustedServers $trustedServers,
108
+        private ?string $userId = null,
109
+    ) {
110
+        parent::__construct($appName, $request);
111
+    }
112
+
113
+    /**
114
+     * Convert an IShare to an array for OCS output
115
+     *
116
+     * @param IShare $share
117
+     * @param Node|null $recipientNode
118
+     * @return Files_SharingShare
119
+     * @throws NotFoundException In case the node can't be resolved.
120
+     *
121
+     * @suppress PhanUndeclaredClassMethod
122
+     */
123
+    protected function formatShare(IShare $share, ?Node $recipientNode = null): array {
124
+        $sharedBy = $this->userManager->get($share->getSharedBy());
125
+        $shareOwner = $this->userManager->get($share->getShareOwner());
126
+
127
+        $isOwnShare = false;
128
+        if ($shareOwner !== null) {
129
+            $isOwnShare = $shareOwner->getUID() === $this->userId;
130
+        }
131
+
132
+        $result = [
133
+            'id' => $share->getId(),
134
+            'share_type' => $share->getShareType(),
135
+            'uid_owner' => $share->getSharedBy(),
136
+            'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
137
+            // recipient permissions
138
+            'permissions' => $share->getPermissions(),
139
+            // current user permissions on this share
140
+            'can_edit' => $this->canEditShare($share),
141
+            'can_delete' => $this->canDeleteShare($share),
142
+            'stime' => $share->getShareTime()->getTimestamp(),
143
+            'parent' => null,
144
+            'expiration' => null,
145
+            'token' => null,
146
+            'uid_file_owner' => $share->getShareOwner(),
147
+            'note' => $share->getNote(),
148
+            'label' => $share->getLabel(),
149
+            'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
150
+        ];
151
+
152
+        $userFolder = $this->rootFolder->getUserFolder($this->userId);
153
+        if ($recipientNode) {
154
+            $node = $recipientNode;
155
+        } else {
156
+            $node = $userFolder->getFirstNodeById($share->getNodeId());
157
+            if (!$node) {
158
+                // fallback to guessing the path
159
+                $node = $userFolder->get($share->getTarget());
160
+                if ($node === null || $share->getTarget() === '') {
161
+                    throw new NotFoundException();
162
+                }
163
+            }
164
+        }
165
+
166
+        $result['path'] = $userFolder->getRelativePath($node->getPath());
167
+        if ($node instanceof Folder) {
168
+            $result['item_type'] = 'folder';
169
+        } else {
170
+            $result['item_type'] = 'file';
171
+        }
172
+
173
+        // Get the original node permission if the share owner is the current user
174
+        if ($isOwnShare) {
175
+            $result['item_permissions'] = $node->getPermissions();
176
+        }
177
+
178
+        // If we're on the recipient side, the node permissions
179
+        // are bound to the share permissions. So we need to
180
+        // adjust the permissions to the share permissions if necessary.
181
+        if (!$isOwnShare) {
182
+            $result['item_permissions'] = $share->getPermissions();
183
+
184
+            // For some reason, single files share are forbidden to have the delete permission
185
+            // since we have custom methods to check those, let's adjust straight away.
186
+            // DAV permissions does not have that issue though.
187
+            if ($this->canDeleteShare($share) || $this->canDeleteShareFromSelf($share)) {
188
+                $result['item_permissions'] |= Constants::PERMISSION_DELETE;
189
+            }
190
+            if ($this->canEditShare($share)) {
191
+                $result['item_permissions'] |= Constants::PERMISSION_UPDATE;
192
+            }
193
+        }
194
+
195
+        // See MOUNT_ROOT_PROPERTYNAME dav property
196
+        $result['is-mount-root'] = $node->getInternalPath() === '';
197
+        $result['mount-type'] = $node->getMountPoint()->getMountType();
198
+
199
+        $result['mimetype'] = $node->getMimetype();
200
+        $result['has_preview'] = $this->previewManager->isAvailable($node);
201
+        $result['storage_id'] = $node->getStorage()->getId();
202
+        $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
203
+        $result['item_source'] = $node->getId();
204
+        $result['file_source'] = $node->getId();
205
+        $result['file_parent'] = $node->getParent()->getId();
206
+        $result['file_target'] = $share->getTarget();
207
+        $result['item_size'] = $node->getSize();
208
+        $result['item_mtime'] = $node->getMTime();
209
+
210
+        if ($this->trustedServers !== null && in_array($share->getShareType(), [IShare::TYPE_REMOTE, IShare::TYPE_REMOTE_GROUP], true)) {
211
+            $result['is_trusted_server'] = false;
212
+            $sharedWith = $share->getSharedWith();
213
+            $remoteIdentifier = is_string($sharedWith) ? strrchr($sharedWith, '@') : false;
214
+            if ($remoteIdentifier !== false) {
215
+                $remote = substr($remoteIdentifier, 1);
216
+
217
+                if (isset($this->trustedServerCache[$remote])) {
218
+                    $result['is_trusted_server'] = $this->trustedServerCache[$remote];
219
+                } else {
220
+                    try {
221
+                        $isTrusted = $this->trustedServers->isTrustedServer($remote);
222
+                        $this->trustedServerCache[$remote] = $isTrusted;
223
+                        $result['is_trusted_server'] = $isTrusted;
224
+                    } catch (\Exception $e) {
225
+                        // Server not found or other issue, we consider it not trusted
226
+                        $this->trustedServerCache[$remote] = false;
227
+                        $this->logger->error(
228
+                            'Error checking if remote server is trusted (treating as untrusted): ' . $e->getMessage(),
229
+                            ['exception' => $e]
230
+                        );
231
+                    }
232
+                }
233
+            }
234
+        }
235
+
236
+        $expiration = $share->getExpirationDate();
237
+        if ($expiration !== null) {
238
+            $expiration->setTimezone($this->dateTimeZone->getTimeZone());
239
+            $result['expiration'] = $expiration->format('Y-m-d 00:00:00');
240
+        }
241
+
242
+        if ($share->getShareType() === IShare::TYPE_USER) {
243
+            $sharedWith = $this->userManager->get($share->getSharedWith());
244
+            $result['share_with'] = $share->getSharedWith();
245
+            $result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
246
+            $result['share_with_displayname_unique'] = $sharedWith !== null ? (
247
+                !empty($sharedWith->getSystemEMailAddress()) ? $sharedWith->getSystemEMailAddress() : $sharedWith->getUID()
248
+            ) : $share->getSharedWith();
249
+
250
+            $userStatuses = $this->userStatusManager->getUserStatuses([$share->getSharedWith()]);
251
+            $userStatus = array_shift($userStatuses);
252
+            if ($userStatus) {
253
+                $result['status'] = [
254
+                    'status' => $userStatus->getStatus(),
255
+                    'message' => $userStatus->getMessage(),
256
+                    'icon' => $userStatus->getIcon(),
257
+                    'clearAt' => $userStatus->getClearAt()
258
+                        ? (int)$userStatus->getClearAt()->format('U')
259
+                        : null,
260
+                ];
261
+            }
262
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
263
+            $group = $this->groupManager->get($share->getSharedWith());
264
+            $result['share_with'] = $share->getSharedWith();
265
+            $result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
266
+        } elseif ($share->getShareType() === IShare::TYPE_LINK) {
267
+
268
+            // "share_with" and "share_with_displayname" for passwords of link
269
+            // shares was deprecated in Nextcloud 15, use "password" instead.
270
+            $result['share_with'] = $share->getPassword();
271
+            $result['share_with_displayname'] = '(' . $this->l->t('Shared link') . ')';
272
+
273
+            $result['password'] = $share->getPassword();
274
+
275
+            $result['send_password_by_talk'] = $share->getSendPasswordByTalk();
276
+
277
+            $result['token'] = $share->getToken();
278
+            $result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
279
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE) {
280
+            $result['share_with'] = $share->getSharedWith();
281
+            $result['share_with_displayname'] = $this->getCachedFederatedDisplayName($share->getSharedWith());
282
+            $result['token'] = $share->getToken();
283
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
284
+            $result['share_with'] = $share->getSharedWith();
285
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
286
+            $result['token'] = $share->getToken();
287
+        } elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
288
+            $result['share_with'] = $share->getSharedWith();
289
+            $result['password'] = $share->getPassword();
290
+            $result['password_expiration_time'] = $share->getPasswordExpirationTime() !== null ? $share->getPasswordExpirationTime()->format(\DateTime::ATOM) : null;
291
+            $result['send_password_by_talk'] = $share->getSendPasswordByTalk();
292
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
293
+            $result['token'] = $share->getToken();
294
+        } elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
295
+            // getSharedWith() returns either "name (type, owner)" or
296
+            // "name (type, owner) [id]", depending on the Teams app version.
297
+            $hasCircleId = (substr($share->getSharedWith(), -1) === ']');
298
+
299
+            $result['share_with_displayname'] = $share->getSharedWithDisplayName();
300
+            if (empty($result['share_with_displayname'])) {
301
+                $displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith()));
302
+                $result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
303
+            }
304
+
305
+            $result['share_with_avatar'] = $share->getSharedWithAvatar();
306
+
307
+            $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
308
+            $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
309
+            if ($shareWithLength === false) {
310
+                $result['share_with'] = substr($share->getSharedWith(), $shareWithStart);
311
+            } else {
312
+                $result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
313
+            }
314
+        } elseif ($share->getShareType() === IShare::TYPE_ROOM) {
315
+            $result['share_with'] = $share->getSharedWith();
316
+            $result['share_with_displayname'] = '';
317
+
318
+            try {
319
+                /** @var array{share_with_displayname: string, share_with_link: string, share_with?: string, token?: string} $roomShare */
320
+                $roomShare = $this->getRoomShareHelper()->formatShare($share);
321
+                $result = array_merge($result, $roomShare);
322
+            } catch (ContainerExceptionInterface $e) {
323
+            }
324
+        } elseif ($share->getShareType() === IShare::TYPE_DECK) {
325
+            $result['share_with'] = $share->getSharedWith();
326
+            $result['share_with_displayname'] = '';
327
+
328
+            try {
329
+                /** @var array{share_with: string, share_with_displayname: string, share_with_link: string} $deckShare */
330
+                $deckShare = $this->getDeckShareHelper()->formatShare($share);
331
+                $result = array_merge($result, $deckShare);
332
+            } catch (ContainerExceptionInterface $e) {
333
+            }
334
+        } elseif ($share->getShareType() === IShare::TYPE_SCIENCEMESH) {
335
+            $result['share_with'] = $share->getSharedWith();
336
+            $result['share_with_displayname'] = '';
337
+
338
+            try {
339
+                /** @var array{share_with: string, share_with_displayname: string, token: string} $scienceMeshShare */
340
+                $scienceMeshShare = $this->getSciencemeshShareHelper()->formatShare($share);
341
+                $result = array_merge($result, $scienceMeshShare);
342
+            } catch (ContainerExceptionInterface $e) {
343
+            }
344
+        }
345
+
346
+
347
+        $result['mail_send'] = $share->getMailSend() ? 1 : 0;
348
+        $result['hide_download'] = $share->getHideDownload() ? 1 : 0;
349
+
350
+        $result['attributes'] = null;
351
+        if ($attributes = $share->getAttributes()) {
352
+            $result['attributes'] = (string)\json_encode($attributes->toArray());
353
+        }
354
+
355
+        return $result;
356
+    }
357
+
358
+    /**
359
+     * Check if one of the users address books knows the exact property, if
360
+     * not we return the full name.
361
+     *
362
+     * @param string $query
363
+     * @param string $property
364
+     * @return string
365
+     */
366
+    private function getDisplayNameFromAddressBook(string $query, string $property): string {
367
+        // FIXME: If we inject the contacts manager it gets initialized before any address books are registered
368
+        try {
369
+            $result = Server::get(\OCP\Contacts\IManager::class)->search($query, [$property], [
370
+                'limit' => 1,
371
+                'enumeration' => false,
372
+                'strict_search' => true,
373
+            ]);
374
+        } catch (Exception $e) {
375
+            $this->logger->error(
376
+                $e->getMessage(),
377
+                ['exception' => $e]
378
+            );
379
+            return $query;
380
+        }
381
+
382
+        foreach ($result as $r) {
383
+            foreach ($r[$property] as $value) {
384
+                if ($value === $query && $r['FN']) {
385
+                    return $r['FN'];
386
+                }
387
+            }
388
+        }
389
+
390
+        return $query;
391
+    }
392
+
393
+
394
+    /**
395
+     * @param list<Files_SharingShare> $shares
396
+     * @param array<string, string>|null $updatedDisplayName
397
+     *
398
+     * @return list<Files_SharingShare>
399
+     */
400
+    private function fixMissingDisplayName(array $shares, ?array $updatedDisplayName = null): array {
401
+        $userIds = $updated = [];
402
+        foreach ($shares as $share) {
403
+            // share is federated and share have no display name yet
404
+            if ($share['share_type'] === IShare::TYPE_REMOTE
405
+                && ($share['share_with'] ?? '') !== ''
406
+                && ($share['share_with_displayname'] ?? '') === '') {
407
+                $userIds[] = $userId = $share['share_with'];
408
+
409
+                if ($updatedDisplayName !== null && array_key_exists($userId, $updatedDisplayName)) {
410
+                    $share['share_with_displayname'] = $updatedDisplayName[$userId];
411
+                }
412
+            }
413
+
414
+            // prepping userIds with displayName to be updated
415
+            $updated[] = $share;
416
+        }
417
+
418
+        // if $updatedDisplayName is not null, it means we should have already fixed displayNames of the shares
419
+        if ($updatedDisplayName !== null) {
420
+            return $updated;
421
+        }
422
+
423
+        // get displayName for the generated list of userId with no displayName
424
+        $displayNames = $this->retrieveFederatedDisplayName($userIds);
425
+
426
+        // if no displayName are updated, we exit
427
+        if (empty($displayNames)) {
428
+            return $updated;
429
+        }
430
+
431
+        // let's fix missing display name and returns all shares
432
+        return $this->fixMissingDisplayName($shares, $displayNames);
433
+    }
434
+
435
+
436
+    /**
437
+     * get displayName of a list of userIds from the lookup-server; through the globalsiteselector app.
438
+     * returns an array with userIds as keys and displayName as values.
439
+     *
440
+     * @param array $userIds
441
+     * @param bool $cacheOnly - do not reach LUS, get data from cache.
442
+     *
443
+     * @return array
444
+     * @throws ContainerExceptionInterface
445
+     */
446
+    private function retrieveFederatedDisplayName(array $userIds, bool $cacheOnly = false): array {
447
+        // check if gss is enabled and available
448
+        if (count($userIds) === 0
449
+            || !$this->appManager->isEnabledForAnyone('globalsiteselector')
450
+            || !class_exists('\OCA\GlobalSiteSelector\Service\SlaveService')) {
451
+            return [];
452
+        }
453
+
454
+        try {
455
+            $slaveService = Server::get(SlaveService::class);
456
+        } catch (\Throwable $e) {
457
+            $this->logger->error(
458
+                $e->getMessage(),
459
+                ['exception' => $e]
460
+            );
461
+            return [];
462
+        }
463
+
464
+        return $slaveService->getUsersDisplayName($userIds, $cacheOnly);
465
+    }
466
+
467
+
468
+    /**
469
+     * retrieve displayName from cache if available (should be used on federated shares)
470
+     * if not available in cache/lus, try for get from address-book, else returns empty string.
471
+     *
472
+     * @param string $userId
473
+     * @param bool $cacheOnly if true will not reach the lus but will only get data from cache
474
+     *
475
+     * @return string
476
+     */
477
+    private function getCachedFederatedDisplayName(string $userId, bool $cacheOnly = true): string {
478
+        $details = $this->retrieveFederatedDisplayName([$userId], $cacheOnly);
479
+        if (array_key_exists($userId, $details)) {
480
+            return $details[$userId];
481
+        }
482
+
483
+        $displayName = $this->getDisplayNameFromAddressBook($userId, 'CLOUD');
484
+        return ($displayName === $userId) ? '' : $displayName;
485
+    }
486
+
487
+
488
+
489
+    /**
490
+     * Get a specific share by id
491
+     *
492
+     * @param string $id ID of the share
493
+     * @param bool $include_tags Include tags in the share
494
+     * @return DataResponse<Http::STATUS_OK, list<Files_SharingShare>, array{}>
495
+     * @throws OCSNotFoundException Share not found
496
+     *
497
+     * 200: Share returned
498
+     */
499
+    #[NoAdminRequired]
500
+    public function getShare(string $id, bool $include_tags = false): DataResponse {
501
+        try {
502
+            $share = $this->getShareById($id);
503
+        } catch (ShareNotFound $e) {
504
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
505
+        }
506
+
507
+        try {
508
+            if ($this->canAccessShare($share)) {
509
+                $share = $this->formatShare($share);
510
+
511
+                if ($include_tags) {
512
+                    $share = $this->populateTags([$share]);
513
+                } else {
514
+                    $share = [$share];
515
+                }
516
+
517
+                return new DataResponse($share);
518
+            }
519
+        } catch (NotFoundException $e) {
520
+            // Fall through
521
+        }
522
+
523
+        throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
524
+    }
525
+
526
+    /**
527
+     * Delete a share
528
+     *
529
+     * @param string $id ID of the share
530
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
531
+     * @throws OCSNotFoundException Share not found
532
+     * @throws OCSForbiddenException Missing permissions to delete the share
533
+     *
534
+     * 200: Share deleted successfully
535
+     */
536
+    #[NoAdminRequired]
537
+    public function deleteShare(string $id): DataResponse {
538
+        try {
539
+            $share = $this->getShareById($id);
540
+        } catch (ShareNotFound $e) {
541
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
542
+        }
543
+
544
+        try {
545
+            $this->lock($share->getNode());
546
+        } catch (LockedException $e) {
547
+            throw new OCSNotFoundException($this->l->t('Could not delete share'));
548
+        }
549
+
550
+        if (!$this->canAccessShare($share)) {
551
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
552
+        }
553
+
554
+        // if it's a group share or a room share
555
+        // we don't delete the share, but only the
556
+        // mount point. Allowing it to be restored
557
+        // from the deleted shares
558
+        if ($this->canDeleteShareFromSelf($share)) {
559
+            $this->shareManager->deleteFromSelf($share, $this->userId);
560
+        } else {
561
+            if (!$this->canDeleteShare($share)) {
562
+                throw new OCSForbiddenException($this->l->t('Could not delete share'));
563
+            }
564
+
565
+            $this->shareManager->deleteShare($share);
566
+        }
567
+
568
+        return new DataResponse();
569
+    }
570
+
571
+    /**
572
+     * Create a share
573
+     *
574
+     * @param string|null $path Path of the share
575
+     * @param int|null $permissions Permissions for the share
576
+     * @param int $shareType Type of the share
577
+     * @param ?string $shareWith The entity this should be shared with
578
+     * @param 'true'|'false'|null $publicUpload If public uploading is allowed (deprecated)
579
+     * @param string $password Password for the share
580
+     * @param string|null $sendPasswordByTalk Send the password for the share over Talk
581
+     * @param ?string $expireDate The expiry date of the share in the user's timezone at 00:00.
582
+     *                            If $expireDate is not supplied or set to `null`, the system default will be used.
583
+     * @param string $note Note for the share
584
+     * @param string $label Label for the share (only used in link and email)
585
+     * @param string|null $attributes Additional attributes for the share
586
+     * @param 'false'|'true'|null $sendMail Send a mail to the recipient
587
+     *
588
+     * @return DataResponse<Http::STATUS_OK, Files_SharingShare, array{}>
589
+     * @throws OCSBadRequestException Unknown share type
590
+     * @throws OCSException
591
+     * @throws OCSForbiddenException Creating the share is not allowed
592
+     * @throws OCSNotFoundException Creating the share failed
593
+     * @suppress PhanUndeclaredClassMethod
594
+     *
595
+     * 200: Share created
596
+     */
597
+    #[NoAdminRequired]
598
+    #[UserRateLimit(limit: 20, period: 600)]
599
+    public function createShare(
600
+        ?string $path = null,
601
+        ?int $permissions = null,
602
+        int $shareType = -1,
603
+        ?string $shareWith = null,
604
+        ?string $publicUpload = null,
605
+        string $password = '',
606
+        ?string $sendPasswordByTalk = null,
607
+        ?string $expireDate = null,
608
+        string $note = '',
609
+        string $label = '',
610
+        ?string $attributes = null,
611
+        ?string $sendMail = null,
612
+    ): DataResponse {
613
+        assert($this->userId !== null);
614
+
615
+        $share = $this->shareManager->newShare();
616
+        $hasPublicUpload = $this->getLegacyPublicUpload($publicUpload);
617
+
618
+        // Verify path
619
+        if ($path === null) {
620
+            throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
621
+        }
622
+
623
+        $userFolder = $this->rootFolder->getUserFolder($this->userId);
624
+        try {
625
+            /** @var \OC\Files\Node\Node $node */
626
+            $node = $userFolder->get($path);
627
+        } catch (NotFoundException $e) {
628
+            throw new OCSNotFoundException($this->l->t('Wrong path, file/folder does not exist'));
629
+        }
630
+
631
+        // a user can have access to a file through different paths, with differing permissions
632
+        // combine all permissions to determine if the user can share this file
633
+        $nodes = $userFolder->getById($node->getId());
634
+        foreach ($nodes as $nodeById) {
635
+            /** @var FileInfo $fileInfo */
636
+            $fileInfo = $node->getFileInfo();
637
+            $fileInfo['permissions'] |= $nodeById->getPermissions();
638
+        }
639
+
640
+        $share->setNode($node);
641
+
642
+        try {
643
+            $this->lock($share->getNode());
644
+        } catch (LockedException $e) {
645
+            throw new OCSNotFoundException($this->l->t('Could not create share'));
646
+        }
647
+
648
+        // Set permissions
649
+        if ($shareType === IShare::TYPE_LINK || $shareType === IShare::TYPE_EMAIL) {
650
+            $permissions = $this->getLinkSharePermissions($permissions, $hasPublicUpload);
651
+            $this->validateLinkSharePermissions($node, $permissions, $hasPublicUpload);
652
+        } else {
653
+            // Use default permissions only for non-link shares to keep legacy behavior
654
+            if ($permissions === null) {
655
+                $permissions = (int)$this->config->getAppValue('core', 'shareapi_default_permissions', (string)Constants::PERMISSION_ALL);
656
+            }
657
+            // Non-link shares always require read permissions (link shares could be file drop)
658
+            $permissions |= Constants::PERMISSION_READ;
659
+        }
660
+
661
+        // For legacy reasons the API allows to pass PERMISSIONS_ALL even for single file shares (I look at you Talk)
662
+        if ($node instanceof File) {
663
+            // if this is a single file share we remove the DELETE and CREATE permissions
664
+            $permissions = $permissions & ~(Constants::PERMISSION_DELETE | Constants::PERMISSION_CREATE);
665
+        }
666
+
667
+        /**
668
+         * Hack for https://github.com/owncloud/core/issues/22587
669
+         * We check the permissions via webdav. But the permissions of the mount point
670
+         * do not equal the share permissions. Here we fix that for federated mounts.
671
+         */
672
+        if ($node->getStorage()->instanceOfStorage(Storage::class)) {
673
+            $permissions &= ~($permissions & ~$node->getPermissions());
674
+        }
675
+
676
+        if ($attributes !== null) {
677
+            $share = $this->setShareAttributes($share, $attributes);
678
+        }
679
+
680
+        // Expire date checks
681
+        // Normally, null means no expiration date but we still set the default for backwards compatibility
682
+        // If the client sends an empty string, we set noExpirationDate to true
683
+        if ($expireDate !== null) {
684
+            if ($expireDate !== '') {
685
+                try {
686
+                    $expireDateTime = $this->parseDate($expireDate);
687
+                    $share->setExpirationDate($expireDateTime);
688
+                } catch (\Exception $e) {
689
+                    throw new OCSNotFoundException($e->getMessage(), $e);
690
+                }
691
+            } else {
692
+                // Client sent empty string for expire date.
693
+                // Set noExpirationDate to true so overwrite is prevented.
694
+                $share->setNoExpirationDate(true);
695
+            }
696
+        }
697
+
698
+        $share->setSharedBy($this->userId);
699
+
700
+        // Handle mail send
701
+        if (is_null($sendMail)) {
702
+            $allowSendMail = $this->config->getSystemValueBool('sharing.enable_share_mail', true);
703
+            if ($allowSendMail !== true || $shareType === IShare::TYPE_EMAIL) {
704
+                // Define a default behavior when sendMail is not provided
705
+                // For email shares with a valid recipient, the default is to send the mail
706
+                // For all other share types, the default is to not send the mail
707
+                $allowSendMail = ($shareType === IShare::TYPE_EMAIL && $shareWith !== null && $shareWith !== '');
708
+            }
709
+            $share->setMailSend($allowSendMail);
710
+        } else {
711
+            $share->setMailSend($sendMail === 'true');
712
+        }
713
+
714
+        if ($shareType === IShare::TYPE_USER) {
715
+            // Valid user is required to share
716
+            if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
717
+                throw new OCSNotFoundException($this->l->t('Please specify a valid account to share with'));
718
+            }
719
+            $share->setSharedWith($shareWith);
720
+            $share->setPermissions($permissions);
721
+        } elseif ($shareType === IShare::TYPE_GROUP) {
722
+            if (!$this->shareManager->allowGroupSharing()) {
723
+                throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
724
+            }
725
+
726
+            // Valid group is required to share
727
+            if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
728
+                throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
729
+            }
730
+            $share->setSharedWith($shareWith);
731
+            $share->setPermissions($permissions);
732
+        } elseif ($shareType === IShare::TYPE_LINK
733
+            || $shareType === IShare::TYPE_EMAIL) {
734
+
735
+            // Can we even share links?
736
+            if (!$this->shareManager->shareApiAllowLinks()) {
737
+                throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
738
+            }
739
+
740
+            $this->validateLinkSharePermissions($node, $permissions, $hasPublicUpload);
741
+            $share->setPermissions($permissions);
742
+
743
+            // Set password
744
+            if ($password !== '') {
745
+                $share->setPassword($password);
746
+            }
747
+
748
+            // Only share by mail have a recipient
749
+            if (is_string($shareWith) && $shareType === IShare::TYPE_EMAIL) {
750
+                // If sending a mail have been requested, validate the mail address
751
+                if ($share->getMailSend() && !$this->emailValidator->isValid($shareWith)) {
752
+                    throw new OCSNotFoundException($this->l->t('Please specify a valid email address'));
753
+                }
754
+                $share->setSharedWith($shareWith);
755
+            }
756
+
757
+            // If we have a label, use it
758
+            if ($label !== '') {
759
+                if (strlen($label) > 255) {
760
+                    throw new OCSBadRequestException('Maximum label length is 255');
761
+                }
762
+                $share->setLabel($label);
763
+            }
764
+
765
+            if ($sendPasswordByTalk === 'true') {
766
+                if (!$this->appManager->isEnabledForUser('spreed')) {
767
+                    throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$node->getPath()]));
768
+                }
769
+
770
+                $share->setSendPasswordByTalk(true);
771
+            }
772
+        } elseif ($shareType === IShare::TYPE_REMOTE) {
773
+            if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
774
+                throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$node->getPath(), $shareType]));
775
+            }
776
+
777
+            if ($shareWith === null) {
778
+                throw new OCSNotFoundException($this->l->t('Please specify a valid federated account ID'));
779
+            }
780
+
781
+            $share->setSharedWith($shareWith);
782
+            $share->setPermissions($permissions);
783
+            $share->setSharedWithDisplayName($this->getCachedFederatedDisplayName($shareWith, false));
784
+        } elseif ($shareType === IShare::TYPE_REMOTE_GROUP) {
785
+            if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
786
+                throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$node->getPath(), $shareType]));
787
+            }
788
+
789
+            if ($shareWith === null) {
790
+                throw new OCSNotFoundException($this->l->t('Please specify a valid federated group ID'));
791
+            }
792
+
793
+            $share->setSharedWith($shareWith);
794
+            $share->setPermissions($permissions);
795
+        } elseif ($shareType === IShare::TYPE_CIRCLE) {
796
+            if (!Server::get(IAppManager::class)->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
797
+                throw new OCSNotFoundException($this->l->t('You cannot share to a Team if the app is not enabled'));
798
+            }
799
+
800
+            $circle = Circles::detailsCircle($shareWith);
801
+
802
+            // Valid team is required to share
803
+            if ($circle === null) {
804
+                throw new OCSNotFoundException($this->l->t('Please specify a valid team'));
805
+            }
806
+            $share->setSharedWith($shareWith);
807
+            $share->setPermissions($permissions);
808
+        } elseif ($shareType === IShare::TYPE_ROOM) {
809
+            try {
810
+                $this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate ?? '');
811
+            } catch (ContainerExceptionInterface $e) {
812
+                throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$node->getPath()]));
813
+            }
814
+        } elseif ($shareType === IShare::TYPE_DECK) {
815
+            try {
816
+                $this->getDeckShareHelper()->createShare($share, $shareWith, $permissions, $expireDate ?? '');
817
+            } catch (ContainerExceptionInterface $e) {
818
+                throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$node->getPath()]));
819
+            }
820
+        } elseif ($shareType === IShare::TYPE_SCIENCEMESH) {
821
+            try {
822
+                $this->getSciencemeshShareHelper()->createShare($share, $shareWith, $permissions, $expireDate ?? '');
823
+            } catch (ContainerExceptionInterface $e) {
824
+                throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support ScienceMesh shares', [$node->getPath()]));
825
+            }
826
+        } else {
827
+            throw new OCSBadRequestException($this->l->t('Unknown share type'));
828
+        }
829
+
830
+        $share->setShareType($shareType);
831
+        $this->checkInheritedAttributes($share);
832
+
833
+        if ($note !== '') {
834
+            $share->setNote($note);
835
+        }
836
+
837
+        try {
838
+            $share = $this->shareManager->createShare($share);
839
+        } catch (HintException $e) {
840
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
841
+            throw new OCSException($e->getHint(), $code);
842
+        } catch (GenericShareException|\InvalidArgumentException $e) {
843
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
844
+            throw new OCSForbiddenException($e->getMessage(), $e);
845
+        } catch (\Exception $e) {
846
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
847
+            throw new OCSForbiddenException('Failed to create share.', $e);
848
+        }
849
+
850
+        $output = $this->formatShare($share);
851
+
852
+        return new DataResponse($output);
853
+    }
854
+
855
+    /**
856
+     * @param null|Node $node
857
+     * @param boolean $includeTags
858
+     *
859
+     * @return list<Files_SharingShare>
860
+     */
861
+    private function getSharedWithMe($node, bool $includeTags): array {
862
+        $userShares = $this->shareManager->getSharedWith($this->userId, IShare::TYPE_USER, $node, -1, 0);
863
+        $groupShares = $this->shareManager->getSharedWith($this->userId, IShare::TYPE_GROUP, $node, -1, 0);
864
+        $circleShares = $this->shareManager->getSharedWith($this->userId, IShare::TYPE_CIRCLE, $node, -1, 0);
865
+        $roomShares = $this->shareManager->getSharedWith($this->userId, IShare::TYPE_ROOM, $node, -1, 0);
866
+        $deckShares = $this->shareManager->getSharedWith($this->userId, IShare::TYPE_DECK, $node, -1, 0);
867
+        $sciencemeshShares = $this->shareManager->getSharedWith($this->userId, IShare::TYPE_SCIENCEMESH, $node, -1, 0);
868
+
869
+        $shares = array_merge($userShares, $groupShares, $circleShares, $roomShares, $deckShares, $sciencemeshShares);
870
+
871
+        $filteredShares = array_filter($shares, function (IShare $share) {
872
+            return $share->getShareOwner() !== $this->userId && $share->getSharedBy() !== $this->userId;
873
+        });
874
+
875
+        $formatted = [];
876
+        foreach ($filteredShares as $share) {
877
+            if ($this->canAccessShare($share)) {
878
+                try {
879
+                    $formatted[] = $this->formatShare($share);
880
+                } catch (NotFoundException $e) {
881
+                    // Ignore this share
882
+                }
883
+            }
884
+        }
885
+
886
+        if ($includeTags) {
887
+            $formatted = $this->populateTags($formatted);
888
+        }
889
+
890
+        return $formatted;
891
+    }
892
+
893
+    /**
894
+     * @param Node $folder
895
+     *
896
+     * @return list<Files_SharingShare>
897
+     * @throws OCSBadRequestException
898
+     * @throws NotFoundException
899
+     */
900
+    private function getSharesInDir(Node $folder): array {
901
+        if (!($folder instanceof Folder)) {
902
+            throw new OCSBadRequestException($this->l->t('Not a directory'));
903
+        }
904
+
905
+        $nodes = $folder->getDirectoryListing();
906
+
907
+        /** @var IShare[] $shares */
908
+        $shares = array_reduce($nodes, function ($carry, $node) {
909
+            $carry = array_merge($carry, $this->getAllShares($node, true));
910
+            return $carry;
911
+        }, []);
912
+
913
+        // filter out duplicate shares
914
+        $known = [];
915
+
916
+        $formatted = $miniFormatted = [];
917
+        $resharingRight = false;
918
+        $known = [];
919
+        foreach ($shares as $share) {
920
+            if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->userId) {
921
+                continue;
922
+            }
923
+
924
+            try {
925
+                $format = $this->formatShare($share);
926
+
927
+                $known[] = $share->getId();
928
+                $formatted[] = $format;
929
+                if ($share->getSharedBy() === $this->userId) {
930
+                    $miniFormatted[] = $format;
931
+                }
932
+                if (!$resharingRight && $this->shareProviderResharingRights($this->userId, $share, $folder)) {
933
+                    $resharingRight = true;
934
+                }
935
+            } catch (\Exception $e) {
936
+                //Ignore this share
937
+            }
938
+        }
939
+
940
+        if (!$resharingRight) {
941
+            $formatted = $miniFormatted;
942
+        }
943
+
944
+        return $formatted;
945
+    }
946
+
947
+    /**
948
+     * Get shares of the current user
949
+     *
950
+     * @param string $shared_with_me Only get shares with the current user
951
+     * @param string $reshares Only get shares by the current user and reshares
952
+     * @param string $subfiles Only get all shares in a folder
953
+     * @param string $path Get shares for a specific path
954
+     * @param string $include_tags Include tags in the share
955
+     *
956
+     * @return DataResponse<Http::STATUS_OK, list<Files_SharingShare>, array{}>
957
+     * @throws OCSNotFoundException The folder was not found or is inaccessible
958
+     *
959
+     * 200: Shares returned
960
+     */
961
+    #[NoAdminRequired]
962
+    public function getShares(
963
+        string $shared_with_me = 'false',
964
+        string $reshares = 'false',
965
+        string $subfiles = 'false',
966
+        string $path = '',
967
+        string $include_tags = 'false',
968
+    ): DataResponse {
969
+        $node = null;
970
+        if ($path !== '') {
971
+            $userFolder = $this->rootFolder->getUserFolder($this->userId);
972
+            try {
973
+                $node = $userFolder->get($path);
974
+                $this->lock($node);
975
+            } catch (NotFoundException $e) {
976
+                throw new OCSNotFoundException(
977
+                    $this->l->t('Wrong path, file/folder does not exist')
978
+                );
979
+            } catch (LockedException $e) {
980
+                throw new OCSNotFoundException($this->l->t('Could not lock node'));
981
+            }
982
+        }
983
+
984
+        $shares = $this->getFormattedShares(
985
+            $this->userId,
986
+            $node,
987
+            ($shared_with_me === 'true'),
988
+            ($reshares === 'true'),
989
+            ($subfiles === 'true'),
990
+            ($include_tags === 'true')
991
+        );
992
+
993
+        return new DataResponse($shares);
994
+    }
995
+
996
+    private function getLinkSharePermissions(?int $permissions, ?bool $legacyPublicUpload): int {
997
+        $permissions = $permissions ?? Constants::PERMISSION_READ;
998
+
999
+        // Legacy option handling
1000
+        if ($legacyPublicUpload !== null) {
1001
+            $permissions = $legacyPublicUpload
1002
+                ? (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
1003
+                : Constants::PERMISSION_READ;
1004
+        }
1005
+
1006
+        if ($this->hasPermission($permissions, Constants::PERMISSION_READ)
1007
+            && $this->shareManager->outgoingServer2ServerSharesAllowed()
1008
+            && $this->appConfig->getValueBool('core', ConfigLexicon::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES)) {
1009
+            $permissions |= Constants::PERMISSION_SHARE;
1010
+        }
1011
+
1012
+        return $permissions;
1013
+    }
1014
+
1015
+    /**
1016
+     * Helper to check for legacy "publicUpload" handling.
1017
+     * If the value is set to `true` or `false` then true or false are returned.
1018
+     * Otherwise null is returned to indicate that the option was not (or wrong) set.
1019
+     *
1020
+     * @param null|string $legacyPublicUpload The value of `publicUpload`
1021
+     */
1022
+    private function getLegacyPublicUpload(?string $legacyPublicUpload): ?bool {
1023
+        if ($legacyPublicUpload === 'true') {
1024
+            return true;
1025
+        } elseif ($legacyPublicUpload === 'false') {
1026
+            return false;
1027
+        }
1028
+        // Not set at all
1029
+        return null;
1030
+    }
1031
+
1032
+    /**
1033
+     * For link and email shares validate that only allowed combinations are set.
1034
+     *
1035
+     * @throw OCSBadRequestException If permission combination is invalid.
1036
+     * @throw OCSForbiddenException If public upload was forbidden by the administrator.
1037
+     */
1038
+    private function validateLinkSharePermissions(Node $node, int $permissions, ?bool $legacyPublicUpload): void {
1039
+        if ($legacyPublicUpload && ($node instanceof File)) {
1040
+            throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
1041
+        }
1042
+
1043
+        // We need at least READ or CREATE (file drop)
1044
+        if (!$this->hasPermission($permissions, Constants::PERMISSION_READ)
1045
+            && !$this->hasPermission($permissions, Constants::PERMISSION_CREATE)) {
1046
+            throw new OCSBadRequestException($this->l->t('Share must at least have READ or CREATE permissions'));
1047
+        }
1048
+
1049
+        // UPDATE and DELETE require a READ permission
1050
+        if (!$this->hasPermission($permissions, Constants::PERMISSION_READ)
1051
+            && ($this->hasPermission($permissions, Constants::PERMISSION_UPDATE) || $this->hasPermission($permissions, Constants::PERMISSION_DELETE))) {
1052
+            throw new OCSBadRequestException($this->l->t('Share must have READ permission if UPDATE or DELETE permission is set'));
1053
+        }
1054
+
1055
+        // Check if public uploading was disabled
1056
+        if ($this->hasPermission($permissions, Constants::PERMISSION_CREATE)
1057
+            && !$this->shareManager->shareApiLinkAllowPublicUpload()) {
1058
+            throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
1059
+        }
1060
+    }
1061
+
1062
+    /**
1063
+     * @param string $viewer
1064
+     * @param Node $node
1065
+     * @param bool $sharedWithMe
1066
+     * @param bool $reShares
1067
+     * @param bool $subFiles
1068
+     * @param bool $includeTags
1069
+     *
1070
+     * @return list<Files_SharingShare>
1071
+     * @throws NotFoundException
1072
+     * @throws OCSBadRequestException
1073
+     */
1074
+    private function getFormattedShares(
1075
+        string $viewer,
1076
+        $node = null,
1077
+        bool $sharedWithMe = false,
1078
+        bool $reShares = false,
1079
+        bool $subFiles = false,
1080
+        bool $includeTags = false,
1081
+    ): array {
1082
+        if ($sharedWithMe) {
1083
+            return $this->getSharedWithMe($node, $includeTags);
1084
+        }
1085
+
1086
+        if ($subFiles) {
1087
+            return $this->getSharesInDir($node);
1088
+        }
1089
+
1090
+        $shares = $this->getSharesFromNode($viewer, $node, $reShares);
1091
+
1092
+        $known = $formatted = $miniFormatted = [];
1093
+        $resharingRight = false;
1094
+        foreach ($shares as $share) {
1095
+            try {
1096
+                $share->getNode();
1097
+            } catch (NotFoundException $e) {
1098
+                /*
1099 1099
 				 * Ignore shares where we can't get the node
1100 1100
 				 * For example deleted shares
1101 1101
 				 */
1102
-				continue;
1103
-			}
1104
-
1105
-			if (in_array($share->getId(), $known)
1106
-				|| ($share->getSharedWith() === $this->userId && $share->getShareType() === IShare::TYPE_USER)) {
1107
-				continue;
1108
-			}
1109
-
1110
-			$known[] = $share->getId();
1111
-			try {
1112
-				/** @var IShare $share */
1113
-				$format = $this->formatShare($share, $node);
1114
-				$formatted[] = $format;
1115
-
1116
-				// let's also build a list of shares created
1117
-				// by the current user only, in case
1118
-				// there is no resharing rights
1119
-				if ($share->getSharedBy() === $this->userId) {
1120
-					$miniFormatted[] = $format;
1121
-				}
1122
-
1123
-				// check if one of those share is shared with me
1124
-				// and if I have resharing rights on it
1125
-				if (!$resharingRight && $this->shareProviderResharingRights($this->userId, $share, $node)) {
1126
-					$resharingRight = true;
1127
-				}
1128
-			} catch (InvalidPathException|NotFoundException $e) {
1129
-			}
1130
-		}
1131
-
1132
-		if (!$resharingRight) {
1133
-			$formatted = $miniFormatted;
1134
-		}
1135
-
1136
-		// fix eventual missing display name from federated shares
1137
-		$formatted = $this->fixMissingDisplayName($formatted);
1138
-
1139
-		if ($includeTags) {
1140
-			$formatted = $this->populateTags($formatted);
1141
-		}
1142
-
1143
-		return $formatted;
1144
-	}
1145
-
1146
-
1147
-	/**
1148
-	 * Get all shares relative to a file, including parent folders shares rights
1149
-	 *
1150
-	 * @param string $path Path all shares will be relative to
1151
-	 *
1152
-	 * @return DataResponse<Http::STATUS_OK, list<Files_SharingShare>, array{}>
1153
-	 * @throws InvalidPathException
1154
-	 * @throws NotFoundException
1155
-	 * @throws OCSNotFoundException The given path is invalid
1156
-	 * @throws SharingRightsException
1157
-	 *
1158
-	 * 200: Shares returned
1159
-	 */
1160
-	#[NoAdminRequired]
1161
-	public function getInheritedShares(string $path): DataResponse {
1162
-		// get Node from (string) path.
1163
-		$userFolder = $this->rootFolder->getUserFolder($this->userId);
1164
-		try {
1165
-			$node = $userFolder->get($path);
1166
-			$this->lock($node);
1167
-		} catch (NotFoundException $e) {
1168
-			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder does not exist'));
1169
-		} catch (LockedException $e) {
1170
-			throw new OCSNotFoundException($this->l->t('Could not lock path'));
1171
-		}
1172
-
1173
-		if (!($node->getPermissions() & Constants::PERMISSION_SHARE)) {
1174
-			throw new SharingRightsException($this->l->t('no sharing rights on this item'));
1175
-		}
1176
-
1177
-		// The current top parent we have access to
1178
-		$parent = $node;
1179
-
1180
-		// initiate real owner.
1181
-		$owner = $node->getOwner()
1182
-			->getUID();
1183
-		if (!$this->userManager->userExists($owner)) {
1184
-			return new DataResponse([]);
1185
-		}
1186
-
1187
-		// get node based on the owner, fix owner in case of external storage
1188
-		$userFolder = $this->rootFolder->getUserFolder($owner);
1189
-		if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
1190
-			$owner = $node->getOwner()
1191
-				->getUID();
1192
-			$userFolder = $this->rootFolder->getUserFolder($owner);
1193
-			$node = $userFolder->getFirstNodeById($node->getId());
1194
-		}
1195
-		$basePath = $userFolder->getPath();
1196
-
1197
-		// generate node list for each parent folders
1198
-		/** @var Node[] $nodes */
1199
-		$nodes = [];
1200
-		while (true) {
1201
-			$node = $node->getParent();
1202
-			if ($node->getPath() === $basePath) {
1203
-				break;
1204
-			}
1205
-			$nodes[] = $node;
1206
-		}
1207
-
1208
-		// The user that is requesting this list
1209
-		$currentUserFolder = $this->rootFolder->getUserFolder($this->userId);
1210
-
1211
-		// for each nodes, retrieve shares.
1212
-		$shares = [];
1213
-
1214
-		foreach ($nodes as $node) {
1215
-			$getShares = $this->getFormattedShares($owner, $node, false, true);
1216
-
1217
-			$currentUserNode = $currentUserFolder->getFirstNodeById($node->getId());
1218
-			if ($currentUserNode) {
1219
-				$parent = $currentUserNode;
1220
-			}
1221
-
1222
-			$subPath = $currentUserFolder->getRelativePath($parent->getPath());
1223
-			foreach ($getShares as &$share) {
1224
-				$share['via_fileid'] = $parent->getId();
1225
-				$share['via_path'] = $subPath;
1226
-			}
1227
-			$this->mergeFormattedShares($shares, $getShares);
1228
-		}
1229
-
1230
-		return new DataResponse(array_values($shares));
1231
-	}
1232
-
1233
-	/**
1234
-	 * Check whether a set of permissions contains the permissions to check.
1235
-	 */
1236
-	private function hasPermission(int $permissionsSet, int $permissionsToCheck): bool {
1237
-		return ($permissionsSet & $permissionsToCheck) === $permissionsToCheck;
1238
-	}
1239
-
1240
-	/**
1241
-	 * Update a share
1242
-	 *
1243
-	 * @param string $id ID of the share
1244
-	 * @param int|null $permissions New permissions
1245
-	 * @param string|null $password New password
1246
-	 * @param string|null $sendPasswordByTalk New condition if the password should be send over Talk
1247
-	 * @param string|null $publicUpload New condition if public uploading is allowed
1248
-	 * @param string|null $expireDate New expiry date
1249
-	 * @param string|null $note New note
1250
-	 * @param string|null $label New label
1251
-	 * @param string|null $hideDownload New condition if the download should be hidden
1252
-	 * @param string|null $attributes New additional attributes
1253
-	 * @param string|null $sendMail if the share should be send by mail.
1254
-	 *                              Considering the share already exists, no mail will be send after the share is updated.
1255
-	 *                              You will have to use the sendMail action to send the mail.
1256
-	 * @param string|null $shareWith New recipient for email shares
1257
-	 * @param string|null $token New token
1258
-	 * @return DataResponse<Http::STATUS_OK, Files_SharingShare, array{}>
1259
-	 * @throws OCSBadRequestException Share could not be updated because the requested changes are invalid
1260
-	 * @throws OCSForbiddenException Missing permissions to update the share
1261
-	 * @throws OCSNotFoundException Share not found
1262
-	 *
1263
-	 * 200: Share updated successfully
1264
-	 */
1265
-	#[NoAdminRequired]
1266
-	public function updateShare(
1267
-		string $id,
1268
-		?int $permissions = null,
1269
-		?string $password = null,
1270
-		?string $sendPasswordByTalk = null,
1271
-		?string $publicUpload = null,
1272
-		?string $expireDate = null,
1273
-		?string $note = null,
1274
-		?string $label = null,
1275
-		?string $hideDownload = null,
1276
-		?string $attributes = null,
1277
-		?string $sendMail = null,
1278
-		?string $token = null,
1279
-	): DataResponse {
1280
-		try {
1281
-			$share = $this->getShareById($id);
1282
-		} catch (ShareNotFound $e) {
1283
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
1284
-		}
1285
-
1286
-		$this->lock($share->getNode());
1287
-
1288
-		if (!$this->canAccessShare($share, false)) {
1289
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
1290
-		}
1291
-
1292
-		if (!$this->canEditShare($share)) {
1293
-			throw new OCSForbiddenException($this->l->t('You are not allowed to edit incoming shares'));
1294
-		}
1295
-
1296
-		if (
1297
-			$permissions === null
1298
-			&& $password === null
1299
-			&& $sendPasswordByTalk === null
1300
-			&& $publicUpload === null
1301
-			&& $expireDate === null
1302
-			&& $note === null
1303
-			&& $label === null
1304
-			&& $hideDownload === null
1305
-			&& $attributes === null
1306
-			&& $sendMail === null
1307
-			&& $token === null
1308
-		) {
1309
-			throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
1310
-		}
1311
-
1312
-		if ($note !== null) {
1313
-			$share->setNote($note);
1314
-		}
1315
-
1316
-		if ($attributes !== null) {
1317
-			$share = $this->setShareAttributes($share, $attributes);
1318
-		}
1319
-
1320
-		// Handle mail send
1321
-		if ($sendMail === 'true' || $sendMail === 'false') {
1322
-			$share->setMailSend($sendMail === 'true');
1323
-		}
1324
-
1325
-		/**
1326
-		 * expiration date, password and publicUpload only make sense for link shares
1327
-		 */
1328
-		if ($share->getShareType() === IShare::TYPE_LINK
1329
-			|| $share->getShareType() === IShare::TYPE_EMAIL) {
1330
-
1331
-			// Update hide download state
1332
-			if ($hideDownload === 'true') {
1333
-				$share->setHideDownload(true);
1334
-			} elseif ($hideDownload === 'false') {
1335
-				$share->setHideDownload(false);
1336
-			}
1337
-
1338
-			// If either manual permissions are specified or publicUpload
1339
-			// then we need to also update the permissions of the share
1340
-			if ($permissions !== null || $publicUpload !== null) {
1341
-				$hasPublicUpload = $this->getLegacyPublicUpload($publicUpload);
1342
-				$permissions = $this->getLinkSharePermissions($permissions ?? Constants::PERMISSION_READ, $hasPublicUpload);
1343
-				$this->validateLinkSharePermissions($share->getNode(), $permissions, $hasPublicUpload);
1344
-				$share->setPermissions($permissions);
1345
-			}
1346
-
1347
-			if ($password === '') {
1348
-				$share->setPassword(null);
1349
-			} elseif ($password !== null) {
1350
-				$share->setPassword($password);
1351
-			}
1352
-
1353
-			if ($label !== null) {
1354
-				if (strlen($label) > 255) {
1355
-					throw new OCSBadRequestException('Maximum label length is 255');
1356
-				}
1357
-				$share->setLabel($label);
1358
-			}
1359
-
1360
-			if ($sendPasswordByTalk === 'true') {
1361
-				if (!$this->appManager->isEnabledForUser('spreed')) {
1362
-					throw new OCSForbiddenException($this->l->t('"Sending the password by Nextcloud Talk" for sharing a file or folder failed because Nextcloud Talk is not enabled.'));
1363
-				}
1364
-
1365
-				$share->setSendPasswordByTalk(true);
1366
-			} elseif ($sendPasswordByTalk !== null) {
1367
-				$share->setSendPasswordByTalk(false);
1368
-			}
1369
-
1370
-			if ($token !== null) {
1371
-				if (!$this->shareManager->allowCustomTokens()) {
1372
-					throw new OCSForbiddenException($this->l->t('Custom share link tokens have been disabled by the administrator'));
1373
-				}
1374
-				if (!$this->validateToken($token)) {
1375
-					throw new OCSBadRequestException($this->l->t('Tokens must contain at least 1 character and may only contain letters, numbers, or a hyphen'));
1376
-				}
1377
-				$share->setToken($token);
1378
-			}
1379
-		}
1380
-
1381
-		// NOT A LINK SHARE
1382
-		else {
1383
-			if ($permissions !== null) {
1384
-				$share->setPermissions($permissions);
1385
-			}
1386
-		}
1387
-
1388
-		if ($expireDate === '') {
1389
-			$share->setExpirationDate(null);
1390
-		} elseif ($expireDate !== null) {
1391
-			try {
1392
-				$expireDateTime = $this->parseDate($expireDate);
1393
-				$share->setExpirationDate($expireDateTime);
1394
-			} catch (\Exception $e) {
1395
-				throw new OCSBadRequestException($e->getMessage(), $e);
1396
-			}
1397
-		}
1398
-
1399
-		try {
1400
-			$this->checkInheritedAttributes($share);
1401
-			$share = $this->shareManager->updateShare($share);
1402
-		} catch (HintException $e) {
1403
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1404
-			throw new OCSException($e->getHint(), (int)$code);
1405
-		} catch (\Exception $e) {
1406
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
1407
-			throw new OCSBadRequestException('Failed to update share.', $e);
1408
-		}
1409
-
1410
-		return new DataResponse($this->formatShare($share));
1411
-	}
1412
-
1413
-	private function validateToken(string $token): bool {
1414
-		if (mb_strlen($token) === 0) {
1415
-			return false;
1416
-		}
1417
-		if (!preg_match('/^[a-z0-9-]+$/i', $token)) {
1418
-			return false;
1419
-		}
1420
-		return true;
1421
-	}
1422
-
1423
-	/**
1424
-	 * Get all shares that are still pending
1425
-	 *
1426
-	 * @return DataResponse<Http::STATUS_OK, list<Files_SharingShare>, array{}>
1427
-	 *
1428
-	 * 200: Pending shares returned
1429
-	 */
1430
-	#[NoAdminRequired]
1431
-	public function pendingShares(): DataResponse {
1432
-		$pendingShares = [];
1433
-
1434
-		$shareTypes = [
1435
-			IShare::TYPE_USER,
1436
-			IShare::TYPE_GROUP
1437
-		];
1438
-
1439
-		foreach ($shareTypes as $shareType) {
1440
-			$shares = $this->shareManager->getSharedWith($this->userId, $shareType, null, -1, 0);
1441
-
1442
-			foreach ($shares as $share) {
1443
-				if ($share->getStatus() === IShare::STATUS_PENDING || $share->getStatus() === IShare::STATUS_REJECTED) {
1444
-					$pendingShares[] = $share;
1445
-				}
1446
-			}
1447
-		}
1448
-
1449
-		$result = array_values(array_filter(array_map(function (IShare $share) {
1450
-			$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1451
-			$node = $userFolder->getFirstNodeById($share->getNodeId());
1452
-			if (!$node) {
1453
-				// fallback to guessing the path
1454
-				$node = $userFolder->get($share->getTarget());
1455
-				if ($node === null || $share->getTarget() === '') {
1456
-					return null;
1457
-				}
1458
-			}
1459
-
1460
-			try {
1461
-				$formattedShare = $this->formatShare($share, $node);
1462
-				$formattedShare['path'] = '/' . $share->getNode()->getName();
1463
-				$formattedShare['permissions'] = 0;
1464
-				return $formattedShare;
1465
-			} catch (NotFoundException $e) {
1466
-				return null;
1467
-			}
1468
-		}, $pendingShares), function ($entry) {
1469
-			return $entry !== null;
1470
-		}));
1471
-
1472
-		return new DataResponse($result);
1473
-	}
1474
-
1475
-	/**
1476
-	 * Accept a share
1477
-	 *
1478
-	 * @param string $id ID of the share
1479
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1480
-	 * @throws OCSNotFoundException Share not found
1481
-	 * @throws OCSException
1482
-	 * @throws OCSBadRequestException Share could not be accepted
1483
-	 *
1484
-	 * 200: Share accepted successfully
1485
-	 */
1486
-	#[NoAdminRequired]
1487
-	public function acceptShare(string $id): DataResponse {
1488
-		try {
1489
-			$share = $this->getShareById($id);
1490
-		} catch (ShareNotFound $e) {
1491
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
1492
-		}
1493
-
1494
-		if (!$this->canAccessShare($share)) {
1495
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
1496
-		}
1497
-
1498
-		try {
1499
-			$this->shareManager->acceptShare($share, $this->userId);
1500
-		} catch (HintException $e) {
1501
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1502
-			throw new OCSException($e->getHint(), (int)$code);
1503
-		} catch (\Exception $e) {
1504
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
1505
-			throw new OCSBadRequestException('Failed to accept share.', $e);
1506
-		}
1507
-
1508
-		return new DataResponse();
1509
-	}
1510
-
1511
-	/**
1512
-	 * Does the user have read permission on the share
1513
-	 *
1514
-	 * @param IShare $share the share to check
1515
-	 * @param boolean $checkGroups check groups as well?
1516
-	 * @return boolean
1517
-	 * @throws NotFoundException
1518
-	 *
1519
-	 * @suppress PhanUndeclaredClassMethod
1520
-	 */
1521
-	protected function canAccessShare(IShare $share, bool $checkGroups = true): bool {
1522
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1523
-		if ($share->getPermissions() === 0) {
1524
-			return false;
1525
-		}
1526
-
1527
-		// Owner of the file and the sharer of the file can always get share
1528
-		if ($share->getShareOwner() === $this->userId
1529
-			|| $share->getSharedBy() === $this->userId) {
1530
-			return true;
1531
-		}
1532
-
1533
-		// If the share is shared with you, you can access it!
1534
-		if ($share->getShareType() === IShare::TYPE_USER
1535
-			&& $share->getSharedWith() === $this->userId) {
1536
-			return true;
1537
-		}
1538
-
1539
-		// Have reshare rights on the shared file/folder ?
1540
-		// Does the currentUser have access to the shared file?
1541
-		$userFolder = $this->rootFolder->getUserFolder($this->userId);
1542
-		$file = $userFolder->getFirstNodeById($share->getNodeId());
1543
-		if ($file && $this->shareProviderResharingRights($this->userId, $share, $file)) {
1544
-			return true;
1545
-		}
1546
-
1547
-		// If in the recipient group, you can see the share
1548
-		if ($checkGroups && $share->getShareType() === IShare::TYPE_GROUP) {
1549
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1550
-			$user = $this->userManager->get($this->userId);
1551
-			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1552
-				return true;
1553
-			}
1554
-		}
1555
-
1556
-		if ($share->getShareType() === IShare::TYPE_CIRCLE) {
1557
-			// TODO: have a sanity check like above?
1558
-			return true;
1559
-		}
1560
-
1561
-		if ($share->getShareType() === IShare::TYPE_ROOM) {
1562
-			try {
1563
-				return $this->getRoomShareHelper()->canAccessShare($share, $this->userId);
1564
-			} catch (ContainerExceptionInterface $e) {
1565
-				return false;
1566
-			}
1567
-		}
1568
-
1569
-		if ($share->getShareType() === IShare::TYPE_DECK) {
1570
-			try {
1571
-				return $this->getDeckShareHelper()->canAccessShare($share, $this->userId);
1572
-			} catch (ContainerExceptionInterface $e) {
1573
-				return false;
1574
-			}
1575
-		}
1576
-
1577
-		if ($share->getShareType() === IShare::TYPE_SCIENCEMESH) {
1578
-			try {
1579
-				return $this->getSciencemeshShareHelper()->canAccessShare($share, $this->userId);
1580
-			} catch (ContainerExceptionInterface $e) {
1581
-				return false;
1582
-			}
1583
-		}
1584
-
1585
-		return false;
1586
-	}
1587
-
1588
-	/**
1589
-	 * Does the user have edit permission on the share
1590
-	 *
1591
-	 * @param IShare $share the share to check
1592
-	 * @return boolean
1593
-	 */
1594
-	protected function canEditShare(IShare $share): bool {
1595
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1596
-		if ($share->getPermissions() === 0) {
1597
-			return false;
1598
-		}
1599
-
1600
-		// The owner of the file and the creator of the share
1601
-		// can always edit the share
1602
-		if ($share->getShareOwner() === $this->userId
1603
-			|| $share->getSharedBy() === $this->userId
1604
-		) {
1605
-			return true;
1606
-		}
1607
-
1608
-		$userFolder = $this->rootFolder->getUserFolder($this->userId);
1609
-		$file = $userFolder->getFirstNodeById($share->getNodeId());
1610
-		if ($file?->getMountPoint() instanceof IShareOwnerlessMount && $this->shareProviderResharingRights($this->userId, $share, $file)) {
1611
-			return true;
1612
-		}
1613
-
1614
-		//! we do NOT support some kind of `admin` in groups.
1615
-		//! You cannot edit shares shared to a group you're
1616
-		//! a member of if you're not the share owner or the file owner!
1617
-
1618
-		return false;
1619
-	}
1620
-
1621
-	/**
1622
-	 * Does the user have delete permission on the share
1623
-	 *
1624
-	 * @param IShare $share the share to check
1625
-	 * @return boolean
1626
-	 */
1627
-	protected function canDeleteShare(IShare $share): bool {
1628
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1629
-		if ($share->getPermissions() === 0) {
1630
-			return false;
1631
-		}
1632
-
1633
-		// if the user is the recipient, i can unshare
1634
-		// the share with self
1635
-		if ($share->getShareType() === IShare::TYPE_USER
1636
-			&& $share->getSharedWith() === $this->userId
1637
-		) {
1638
-			return true;
1639
-		}
1640
-
1641
-		// The owner of the file and the creator of the share
1642
-		// can always delete the share
1643
-		if ($share->getShareOwner() === $this->userId
1644
-			|| $share->getSharedBy() === $this->userId
1645
-		) {
1646
-			return true;
1647
-		}
1648
-
1649
-		$userFolder = $this->rootFolder->getUserFolder($this->userId);
1650
-		$file = $userFolder->getFirstNodeById($share->getNodeId());
1651
-		if ($file?->getMountPoint() instanceof IShareOwnerlessMount && $this->shareProviderResharingRights($this->userId, $share, $file)) {
1652
-			return true;
1653
-		}
1654
-
1655
-		return false;
1656
-	}
1657
-
1658
-	/**
1659
-	 * Does the user have delete permission on the share
1660
-	 * This differs from the canDeleteShare function as it only
1661
-	 * remove the share for the current user. It does NOT
1662
-	 * completely delete the share but only the mount point.
1663
-	 * It can then be restored from the deleted shares section.
1664
-	 *
1665
-	 * @param IShare $share the share to check
1666
-	 * @return boolean
1667
-	 *
1668
-	 * @suppress PhanUndeclaredClassMethod
1669
-	 */
1670
-	protected function canDeleteShareFromSelf(IShare $share): bool {
1671
-		if ($share->getShareType() !== IShare::TYPE_GROUP
1672
-			&& $share->getShareType() !== IShare::TYPE_ROOM
1673
-			&& $share->getShareType() !== IShare::TYPE_DECK
1674
-			&& $share->getShareType() !== IShare::TYPE_SCIENCEMESH
1675
-		) {
1676
-			return false;
1677
-		}
1678
-
1679
-		if ($share->getShareOwner() === $this->userId
1680
-			|| $share->getSharedBy() === $this->userId
1681
-		) {
1682
-			// Delete the whole share, not just for self
1683
-			return false;
1684
-		}
1685
-
1686
-		// If in the recipient group, you can delete the share from self
1687
-		if ($share->getShareType() === IShare::TYPE_GROUP) {
1688
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1689
-			$user = $this->userManager->get($this->userId);
1690
-			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1691
-				return true;
1692
-			}
1693
-		}
1694
-
1695
-		if ($share->getShareType() === IShare::TYPE_ROOM) {
1696
-			try {
1697
-				return $this->getRoomShareHelper()->canAccessShare($share, $this->userId);
1698
-			} catch (ContainerExceptionInterface $e) {
1699
-				return false;
1700
-			}
1701
-		}
1702
-
1703
-		if ($share->getShareType() === IShare::TYPE_DECK) {
1704
-			try {
1705
-				return $this->getDeckShareHelper()->canAccessShare($share, $this->userId);
1706
-			} catch (ContainerExceptionInterface $e) {
1707
-				return false;
1708
-			}
1709
-		}
1710
-
1711
-		if ($share->getShareType() === IShare::TYPE_SCIENCEMESH) {
1712
-			try {
1713
-				return $this->getSciencemeshShareHelper()->canAccessShare($share, $this->userId);
1714
-			} catch (ContainerExceptionInterface $e) {
1715
-				return false;
1716
-			}
1717
-		}
1718
-
1719
-		return false;
1720
-	}
1721
-
1722
-	/**
1723
-	 * Make sure that the passed date is valid ISO 8601
1724
-	 * So YYYY-MM-DD
1725
-	 * If not throw an exception
1726
-	 *
1727
-	 * @param string $expireDate
1728
-	 *
1729
-	 * @throws \Exception
1730
-	 * @return \DateTime
1731
-	 */
1732
-	private function parseDate(string $expireDate): \DateTime {
1733
-		try {
1734
-			$date = new \DateTime(trim($expireDate, '"'), $this->dateTimeZone->getTimeZone());
1735
-			// Make sure it expires at midnight in owner timezone
1736
-			$date->setTime(0, 0, 0);
1737
-		} catch (\Exception $e) {
1738
-			throw new \Exception($this->l->t('Invalid date. Format must be YYYY-MM-DD'));
1739
-		}
1740
-
1741
-		return $date;
1742
-	}
1743
-
1744
-	/**
1745
-	 * Since we have multiple providers but the OCS Share API v1 does
1746
-	 * not support this we need to check all backends.
1747
-	 *
1748
-	 * @param string $id
1749
-	 * @return IShare
1750
-	 * @throws ShareNotFound
1751
-	 */
1752
-	private function getShareById(string $id): IShare {
1753
-		$providers = [
1754
-			'ocinternal' => null, // No type check needed
1755
-			'ocCircleShare' => IShare::TYPE_CIRCLE,
1756
-			'ocMailShare' => IShare::TYPE_EMAIL,
1757
-			'ocRoomShare' => null,
1758
-			'deck' => IShare::TYPE_DECK,
1759
-			'sciencemesh' => IShare::TYPE_SCIENCEMESH,
1760
-		];
1761
-
1762
-		// Add federated sharing as a provider only if it's allowed
1763
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1764
-			$providers['ocFederatedSharing'] = null; // No type check needed
1765
-		}
1766
-
1767
-		foreach ($providers as $prefix => $type) {
1768
-			try {
1769
-				if ($type === null || $this->shareManager->shareProviderExists($type)) {
1770
-					return $this->shareManager->getShareById($prefix . ':' . $id, $this->userId);
1771
-				}
1772
-			} catch (ShareNotFound $e) {
1773
-				// Do nothing, continue to next provider
1774
-			} catch (\Exception $e) {
1775
-				$this->logger->warning('Unexpected error in share provider', [
1776
-					'shareId' => $id,
1777
-					'provider' => $prefix,
1778
-					'exception' => $e,
1779
-				]);
1780
-			}
1781
-		}
1782
-		throw new ShareNotFound();
1783
-	}
1784
-
1785
-	/**
1786
-	 * Lock a Node
1787
-	 *
1788
-	 * @param Node $node
1789
-	 * @throws LockedException
1790
-	 */
1791
-	private function lock(Node $node) {
1792
-		$node->lock(ILockingProvider::LOCK_SHARED);
1793
-		$this->lockedNode = $node;
1794
-	}
1795
-
1796
-	/**
1797
-	 * Cleanup the remaining locks
1798
-	 * @throws LockedException
1799
-	 */
1800
-	public function cleanup() {
1801
-		if ($this->lockedNode !== null) {
1802
-			$this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1803
-		}
1804
-	}
1805
-
1806
-	/**
1807
-	 * Returns the helper of ShareAPIController for room shares.
1808
-	 *
1809
-	 * If the Talk application is not enabled or the helper is not available
1810
-	 * a ContainerExceptionInterface is thrown instead.
1811
-	 *
1812
-	 * @return \OCA\Talk\Share\Helper\ShareAPIController
1813
-	 * @throws ContainerExceptionInterface
1814
-	 */
1815
-	private function getRoomShareHelper() {
1816
-		if (!$this->appManager->isEnabledForUser('spreed')) {
1817
-			throw new QueryException();
1818
-		}
1819
-
1820
-		return $this->serverContainer->get('\OCA\Talk\Share\Helper\ShareAPIController');
1821
-	}
1822
-
1823
-	/**
1824
-	 * Returns the helper of ShareAPIHelper for deck shares.
1825
-	 *
1826
-	 * If the Deck application is not enabled or the helper is not available
1827
-	 * a ContainerExceptionInterface is thrown instead.
1828
-	 *
1829
-	 * @return ShareAPIHelper
1830
-	 * @throws ContainerExceptionInterface
1831
-	 */
1832
-	private function getDeckShareHelper() {
1833
-		if (!$this->appManager->isEnabledForUser('deck')) {
1834
-			throw new QueryException();
1835
-		}
1836
-
1837
-		return $this->serverContainer->get('\OCA\Deck\Sharing\ShareAPIHelper');
1838
-	}
1839
-
1840
-	/**
1841
-	 * Returns the helper of ShareAPIHelper for sciencemesh shares.
1842
-	 *
1843
-	 * If the sciencemesh application is not enabled or the helper is not available
1844
-	 * a ContainerExceptionInterface is thrown instead.
1845
-	 *
1846
-	 * @return ShareAPIHelper
1847
-	 * @throws ContainerExceptionInterface
1848
-	 */
1849
-	private function getSciencemeshShareHelper() {
1850
-		if (!$this->appManager->isEnabledForUser('sciencemesh')) {
1851
-			throw new QueryException();
1852
-		}
1853
-
1854
-		return $this->serverContainer->get('\OCA\ScienceMesh\Sharing\ShareAPIHelper');
1855
-	}
1856
-
1857
-	/**
1858
-	 * @param string $viewer
1859
-	 * @param Node $node
1860
-	 * @param bool $reShares
1861
-	 *
1862
-	 * @return IShare[]
1863
-	 */
1864
-	private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1865
-		$providers = [
1866
-			IShare::TYPE_USER,
1867
-			IShare::TYPE_GROUP,
1868
-			IShare::TYPE_LINK,
1869
-			IShare::TYPE_EMAIL,
1870
-			IShare::TYPE_CIRCLE,
1871
-			IShare::TYPE_ROOM,
1872
-			IShare::TYPE_DECK,
1873
-			IShare::TYPE_SCIENCEMESH
1874
-		];
1875
-
1876
-		// Should we assume that the (currentUser) viewer is the owner of the node !?
1877
-		$shares = [];
1878
-		foreach ($providers as $provider) {
1879
-			if (!$this->shareManager->shareProviderExists($provider)) {
1880
-				continue;
1881
-			}
1882
-
1883
-			$providerShares
1884
-				= $this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
1885
-			$shares = array_merge($shares, $providerShares);
1886
-		}
1887
-
1888
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1889
-			$federatedShares = $this->shareManager->getSharesBy(
1890
-				$this->userId, IShare::TYPE_REMOTE, $node, $reShares, -1, 0
1891
-			);
1892
-			$shares = array_merge($shares, $federatedShares);
1893
-		}
1894
-
1895
-		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1896
-			$federatedShares = $this->shareManager->getSharesBy(
1897
-				$this->userId, IShare::TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
1898
-			);
1899
-			$shares = array_merge($shares, $federatedShares);
1900
-		}
1901
-
1902
-		return $shares;
1903
-	}
1904
-
1905
-
1906
-	/**
1907
-	 * @param Node $node
1908
-	 *
1909
-	 * @throws SharingRightsException
1910
-	 */
1911
-	private function confirmSharingRights(Node $node): void {
1912
-		if (!$this->hasResharingRights($this->userId, $node)) {
1913
-			throw new SharingRightsException($this->l->t('No sharing rights on this item'));
1914
-		}
1915
-	}
1916
-
1917
-
1918
-	/**
1919
-	 * @param string $viewer
1920
-	 * @param Node $node
1921
-	 *
1922
-	 * @return bool
1923
-	 */
1924
-	private function hasResharingRights($viewer, $node): bool {
1925
-		if ($viewer === $node->getOwner()->getUID()) {
1926
-			return true;
1927
-		}
1928
-
1929
-		foreach ([$node, $node->getParent()] as $node) {
1930
-			$shares = $this->getSharesFromNode($viewer, $node, true);
1931
-			foreach ($shares as $share) {
1932
-				try {
1933
-					if ($this->shareProviderResharingRights($viewer, $share, $node)) {
1934
-						return true;
1935
-					}
1936
-				} catch (InvalidPathException|NotFoundException $e) {
1937
-				}
1938
-			}
1939
-		}
1940
-
1941
-		return false;
1942
-	}
1943
-
1944
-
1945
-	/**
1946
-	 * Returns if we can find resharing rights in an IShare object for a specific user.
1947
-	 *
1948
-	 * @suppress PhanUndeclaredClassMethod
1949
-	 *
1950
-	 * @param string $userId
1951
-	 * @param IShare $share
1952
-	 * @param Node $node
1953
-	 *
1954
-	 * @return bool
1955
-	 * @throws NotFoundException
1956
-	 * @throws InvalidPathException
1957
-	 */
1958
-	private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1959
-		if ($share->getShareOwner() === $userId) {
1960
-			return true;
1961
-		}
1962
-
1963
-		// we check that current user have parent resharing rights on the current file
1964
-		if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
1965
-			return true;
1966
-		}
1967
-
1968
-		if ((Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1969
-			return false;
1970
-		}
1971
-
1972
-		if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() === $userId) {
1973
-			return true;
1974
-		}
1975
-
1976
-		if ($share->getShareType() === IShare::TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1977
-			return true;
1978
-		}
1979
-
1980
-		if ($share->getShareType() === IShare::TYPE_CIRCLE && Server::get(IAppManager::class)->isEnabledForUser('circles')
1981
-			&& class_exists('\OCA\Circles\Api\v1\Circles')) {
1982
-			$hasCircleId = (str_ends_with($share->getSharedWith(), ']'));
1983
-			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1984
-			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1985
-			if ($shareWithLength === false) {
1986
-				$sharedWith = substr($share->getSharedWith(), $shareWithStart);
1987
-			} else {
1988
-				$sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1989
-			}
1990
-			try {
1991
-				$member = Circles::getMember($sharedWith, $userId, 1);
1992
-				if ($member->getLevel() >= 4) {
1993
-					return true;
1994
-				}
1995
-				return false;
1996
-			} catch (ContainerExceptionInterface $e) {
1997
-				return false;
1998
-			}
1999
-		}
2000
-
2001
-		return false;
2002
-	}
2003
-
2004
-	/**
2005
-	 * Get all the shares for the current user
2006
-	 *
2007
-	 * @param Node|null $path
2008
-	 * @param boolean $reshares
2009
-	 * @return IShare[]
2010
-	 */
2011
-	private function getAllShares(?Node $path = null, bool $reshares = false) {
2012
-		// Get all shares
2013
-		$userShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_USER, $path, $reshares, -1, 0);
2014
-		$groupShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_GROUP, $path, $reshares, -1, 0);
2015
-		$linkShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_LINK, $path, $reshares, -1, 0);
2016
-
2017
-		// EMAIL SHARES
2018
-		$mailShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_EMAIL, $path, $reshares, -1, 0);
2019
-
2020
-		// TEAM SHARES
2021
-		$circleShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_CIRCLE, $path, $reshares, -1, 0);
2022
-
2023
-		// TALK SHARES
2024
-		$roomShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_ROOM, $path, $reshares, -1, 0);
2025
-
2026
-		// DECK SHARES
2027
-		$deckShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_DECK, $path, $reshares, -1, 0);
2028
-
2029
-		// SCIENCEMESH SHARES
2030
-		$sciencemeshShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_SCIENCEMESH, $path, $reshares, -1, 0);
2031
-
2032
-		// FEDERATION
2033
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
2034
-			$federatedShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_REMOTE, $path, $reshares, -1, 0);
2035
-		} else {
2036
-			$federatedShares = [];
2037
-		}
2038
-		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
2039
-			$federatedGroupShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
2040
-		} else {
2041
-			$federatedGroupShares = [];
2042
-		}
2043
-
2044
-		return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $deckShares, $sciencemeshShares, $federatedShares, $federatedGroupShares);
2045
-	}
2046
-
2047
-
2048
-	/**
2049
-	 * merging already formatted shares.
2050
-	 * We'll make an associative array to easily detect duplicate Ids.
2051
-	 * Keys _needs_ to be removed after all shares are retrieved and merged.
2052
-	 *
2053
-	 * @param array $shares
2054
-	 * @param array $newShares
2055
-	 */
2056
-	private function mergeFormattedShares(array &$shares, array $newShares) {
2057
-		foreach ($newShares as $newShare) {
2058
-			if (!array_key_exists($newShare['id'], $shares)) {
2059
-				$shares[$newShare['id']] = $newShare;
2060
-			}
2061
-		}
2062
-	}
2063
-
2064
-	/**
2065
-	 * @param IShare $share
2066
-	 * @param string|null $attributesString
2067
-	 * @return IShare modified share
2068
-	 */
2069
-	private function setShareAttributes(IShare $share, ?string $attributesString) {
2070
-		$newShareAttributes = null;
2071
-		if ($attributesString !== null) {
2072
-			$newShareAttributes = $this->shareManager->newShare()->newAttributes();
2073
-			$formattedShareAttributes = \json_decode($attributesString, true);
2074
-			if (is_array($formattedShareAttributes)) {
2075
-				foreach ($formattedShareAttributes as $formattedAttr) {
2076
-					$newShareAttributes->setAttribute(
2077
-						$formattedAttr['scope'],
2078
-						$formattedAttr['key'],
2079
-						$formattedAttr['value'],
2080
-					);
2081
-				}
2082
-			} else {
2083
-				throw new OCSBadRequestException($this->l->t('Invalid share attributes provided: "%s"', [$attributesString]));
2084
-			}
2085
-		}
2086
-		$share->setAttributes($newShareAttributes);
2087
-
2088
-		return $share;
2089
-	}
2090
-
2091
-	private function checkInheritedAttributes(IShare $share): void {
2092
-		if (!$share->getSharedBy()) {
2093
-			return; // Probably in a test
2094
-		}
2095
-
2096
-		$canDownload = false;
2097
-		$hideDownload = true;
2098
-
2099
-		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
2100
-		$nodes = $userFolder->getById($share->getNodeId());
2101
-		foreach ($nodes as $node) {
2102
-			// Owner always can download it - so allow it and break
2103
-			if ($node->getOwner()?->getUID() === $share->getSharedBy()) {
2104
-				$canDownload = true;
2105
-				$hideDownload = false;
2106
-				break;
2107
-			}
2108
-
2109
-			if ($node->getStorage()->instanceOfStorage(SharedStorage::class)) {
2110
-				$storage = $node->getStorage();
2111
-				if ($storage instanceof Wrapper) {
2112
-					$storage = $storage->getInstanceOfStorage(SharedStorage::class);
2113
-					if ($storage === null) {
2114
-						throw new \RuntimeException('Should not happen, instanceOfStorage but getInstanceOfStorage return null');
2115
-					}
2116
-				} else {
2117
-					throw new \RuntimeException('Should not happen, instanceOfStorage but not a wrapper');
2118
-				}
2119
-
2120
-				/** @var SharedStorage $storage */
2121
-				$originalShare = $storage->getShare();
2122
-				$inheritedAttributes = $originalShare->getAttributes();
2123
-				// hide if hidden and also the current share enforces hide (can only be false if one share is false or user is owner)
2124
-				$hideDownload = $hideDownload && $originalShare->getHideDownload();
2125
-				// allow download if already allowed by previous share or when the current share allows downloading
2126
-				$canDownload = $canDownload || $inheritedAttributes === null || $inheritedAttributes->getAttribute('permissions', 'download') !== false;
2127
-			} elseif ($node->getStorage()->instanceOfStorage(Storage::class)) {
2128
-				$canDownload = true; // in case of federation storage, we can expect the download to be activated by default
2129
-			}
2130
-		}
2131
-
2132
-		if ($hideDownload || !$canDownload) {
2133
-			$share->setHideDownload(true);
2134
-
2135
-			if (!$canDownload) {
2136
-				$attributes = $share->getAttributes() ?? $share->newAttributes();
2137
-				$attributes->setAttribute('permissions', 'download', false);
2138
-				$share->setAttributes($attributes);
2139
-			}
2140
-		}
2141
-	}
2142
-
2143
-	/**
2144
-	 * Send a mail notification again for a share.
2145
-	 * The mail_send option must be enabled for the given share.
2146
-	 * @param string $id the share ID
2147
-	 * @param string $password the password to check against. Necessary for password protected shares.
2148
-	 * @throws OCSNotFoundException Share not found
2149
-	 * @throws OCSForbiddenException You are not allowed to send mail notifications
2150
-	 * @throws OCSBadRequestException Invalid request or wrong password
2151
-	 * @throws OCSException Error while sending mail notification
2152
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
2153
-	 *
2154
-	 * 200: The email notification was sent successfully
2155
-	 */
2156
-	#[NoAdminRequired]
2157
-	#[UserRateLimit(limit: 10, period: 600)]
2158
-	public function sendShareEmail(string $id, $password = ''): DataResponse {
2159
-		try {
2160
-			$share = $this->getShareById($id);
2161
-
2162
-			if (!$this->canAccessShare($share, false)) {
2163
-				throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
2164
-			}
2165
-
2166
-			if (!$this->canEditShare($share)) {
2167
-				throw new OCSForbiddenException($this->l->t('You are not allowed to send mail notifications'));
2168
-			}
2169
-
2170
-			// For mail and link shares, the user must be
2171
-			// the owner of the share, not only the file owner.
2172
-			if ($share->getShareType() === IShare::TYPE_EMAIL
2173
-				|| $share->getShareType() === IShare::TYPE_LINK) {
2174
-				if ($share->getSharedBy() !== $this->userId) {
2175
-					throw new OCSForbiddenException($this->l->t('You are not allowed to send mail notifications'));
2176
-				}
2177
-			}
2178
-
2179
-			try {
2180
-				$provider = $this->factory->getProviderForType($share->getShareType());
2181
-				if (!($provider instanceof IShareProviderWithNotification)) {
2182
-					throw new OCSBadRequestException($this->l->t('No mail notification configured for this share type'));
2183
-				}
2184
-
2185
-				// Circumvent the password encrypted data by
2186
-				// setting the password clear. We're not storing
2187
-				// the password clear, it is just a temporary
2188
-				// object manipulation. The password will stay
2189
-				// encrypted in the database.
2190
-				if ($share->getPassword() !== null && $share->getPassword() !== $password) {
2191
-					if (!$this->shareManager->checkPassword($share, $password)) {
2192
-						throw new OCSBadRequestException($this->l->t('Wrong password'));
2193
-					}
2194
-					$share = $share->setPassword($password);
2195
-				}
2196
-
2197
-				$provider->sendMailNotification($share);
2198
-				return new DataResponse();
2199
-			} catch (Exception $e) {
2200
-				$this->logger->error($e->getMessage(), ['exception' => $e]);
2201
-				throw new OCSException($this->l->t('Error while sending mail notification'));
2202
-			}
2203
-
2204
-		} catch (ShareNotFound $e) {
2205
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
2206
-		}
2207
-	}
2208
-
2209
-	/**
2210
-	 * Get a unique share token
2211
-	 *
2212
-	 * @throws OCSException Failed to generate a unique token
2213
-	 *
2214
-	 * @return DataResponse<Http::STATUS_OK, array{token: string}, array{}>
2215
-	 *
2216
-	 * 200: Token generated successfully
2217
-	 */
2218
-	#[ApiRoute(verb: 'GET', url: '/api/v1/token')]
2219
-	#[NoAdminRequired]
2220
-	public function generateToken(): DataResponse {
2221
-		try {
2222
-			$token = $this->shareManager->generateToken();
2223
-			return new DataResponse([
2224
-				'token' => $token,
2225
-			]);
2226
-		} catch (ShareTokenException $e) {
2227
-			throw new OCSException($this->l->t('Failed to generate a unique token'));
2228
-		}
2229
-	}
2230
-
2231
-	/**
2232
-	 * Populate the result set with file tags
2233
-	 *
2234
-	 * @psalm-template T of array{tags?: list<string>, file_source: int, ...array<string, mixed>}
2235
-	 * @param list<T> $fileList
2236
-	 * @return list<T> file list populated with tags
2237
-	 */
2238
-	private function populateTags(array $fileList): array {
2239
-		$tagger = $this->tagManager->load('files');
2240
-		$tags = $tagger->getTagsForObjects(array_map(static fn (array $fileData) => $fileData['file_source'], $fileList));
2241
-
2242
-		if (!is_array($tags)) {
2243
-			throw new \UnexpectedValueException('$tags must be an array');
2244
-		}
2245
-
2246
-		// Set empty tag array
2247
-		foreach ($fileList as &$fileData) {
2248
-			$fileData['tags'] = [];
2249
-		}
2250
-		unset($fileData);
2251
-
2252
-		if (!empty($tags)) {
2253
-			foreach ($tags as $fileId => $fileTags) {
2254
-				foreach ($fileList as &$fileData) {
2255
-					if ($fileId !== $fileData['file_source']) {
2256
-						continue;
2257
-					}
2258
-
2259
-					$fileData['tags'] = $fileTags;
2260
-				}
2261
-				unset($fileData);
2262
-			}
2263
-		}
2264
-
2265
-		return $fileList;
2266
-	}
1102
+                continue;
1103
+            }
1104
+
1105
+            if (in_array($share->getId(), $known)
1106
+                || ($share->getSharedWith() === $this->userId && $share->getShareType() === IShare::TYPE_USER)) {
1107
+                continue;
1108
+            }
1109
+
1110
+            $known[] = $share->getId();
1111
+            try {
1112
+                /** @var IShare $share */
1113
+                $format = $this->formatShare($share, $node);
1114
+                $formatted[] = $format;
1115
+
1116
+                // let's also build a list of shares created
1117
+                // by the current user only, in case
1118
+                // there is no resharing rights
1119
+                if ($share->getSharedBy() === $this->userId) {
1120
+                    $miniFormatted[] = $format;
1121
+                }
1122
+
1123
+                // check if one of those share is shared with me
1124
+                // and if I have resharing rights on it
1125
+                if (!$resharingRight && $this->shareProviderResharingRights($this->userId, $share, $node)) {
1126
+                    $resharingRight = true;
1127
+                }
1128
+            } catch (InvalidPathException|NotFoundException $e) {
1129
+            }
1130
+        }
1131
+
1132
+        if (!$resharingRight) {
1133
+            $formatted = $miniFormatted;
1134
+        }
1135
+
1136
+        // fix eventual missing display name from federated shares
1137
+        $formatted = $this->fixMissingDisplayName($formatted);
1138
+
1139
+        if ($includeTags) {
1140
+            $formatted = $this->populateTags($formatted);
1141
+        }
1142
+
1143
+        return $formatted;
1144
+    }
1145
+
1146
+
1147
+    /**
1148
+     * Get all shares relative to a file, including parent folders shares rights
1149
+     *
1150
+     * @param string $path Path all shares will be relative to
1151
+     *
1152
+     * @return DataResponse<Http::STATUS_OK, list<Files_SharingShare>, array{}>
1153
+     * @throws InvalidPathException
1154
+     * @throws NotFoundException
1155
+     * @throws OCSNotFoundException The given path is invalid
1156
+     * @throws SharingRightsException
1157
+     *
1158
+     * 200: Shares returned
1159
+     */
1160
+    #[NoAdminRequired]
1161
+    public function getInheritedShares(string $path): DataResponse {
1162
+        // get Node from (string) path.
1163
+        $userFolder = $this->rootFolder->getUserFolder($this->userId);
1164
+        try {
1165
+            $node = $userFolder->get($path);
1166
+            $this->lock($node);
1167
+        } catch (NotFoundException $e) {
1168
+            throw new OCSNotFoundException($this->l->t('Wrong path, file/folder does not exist'));
1169
+        } catch (LockedException $e) {
1170
+            throw new OCSNotFoundException($this->l->t('Could not lock path'));
1171
+        }
1172
+
1173
+        if (!($node->getPermissions() & Constants::PERMISSION_SHARE)) {
1174
+            throw new SharingRightsException($this->l->t('no sharing rights on this item'));
1175
+        }
1176
+
1177
+        // The current top parent we have access to
1178
+        $parent = $node;
1179
+
1180
+        // initiate real owner.
1181
+        $owner = $node->getOwner()
1182
+            ->getUID();
1183
+        if (!$this->userManager->userExists($owner)) {
1184
+            return new DataResponse([]);
1185
+        }
1186
+
1187
+        // get node based on the owner, fix owner in case of external storage
1188
+        $userFolder = $this->rootFolder->getUserFolder($owner);
1189
+        if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
1190
+            $owner = $node->getOwner()
1191
+                ->getUID();
1192
+            $userFolder = $this->rootFolder->getUserFolder($owner);
1193
+            $node = $userFolder->getFirstNodeById($node->getId());
1194
+        }
1195
+        $basePath = $userFolder->getPath();
1196
+
1197
+        // generate node list for each parent folders
1198
+        /** @var Node[] $nodes */
1199
+        $nodes = [];
1200
+        while (true) {
1201
+            $node = $node->getParent();
1202
+            if ($node->getPath() === $basePath) {
1203
+                break;
1204
+            }
1205
+            $nodes[] = $node;
1206
+        }
1207
+
1208
+        // The user that is requesting this list
1209
+        $currentUserFolder = $this->rootFolder->getUserFolder($this->userId);
1210
+
1211
+        // for each nodes, retrieve shares.
1212
+        $shares = [];
1213
+
1214
+        foreach ($nodes as $node) {
1215
+            $getShares = $this->getFormattedShares($owner, $node, false, true);
1216
+
1217
+            $currentUserNode = $currentUserFolder->getFirstNodeById($node->getId());
1218
+            if ($currentUserNode) {
1219
+                $parent = $currentUserNode;
1220
+            }
1221
+
1222
+            $subPath = $currentUserFolder->getRelativePath($parent->getPath());
1223
+            foreach ($getShares as &$share) {
1224
+                $share['via_fileid'] = $parent->getId();
1225
+                $share['via_path'] = $subPath;
1226
+            }
1227
+            $this->mergeFormattedShares($shares, $getShares);
1228
+        }
1229
+
1230
+        return new DataResponse(array_values($shares));
1231
+    }
1232
+
1233
+    /**
1234
+     * Check whether a set of permissions contains the permissions to check.
1235
+     */
1236
+    private function hasPermission(int $permissionsSet, int $permissionsToCheck): bool {
1237
+        return ($permissionsSet & $permissionsToCheck) === $permissionsToCheck;
1238
+    }
1239
+
1240
+    /**
1241
+     * Update a share
1242
+     *
1243
+     * @param string $id ID of the share
1244
+     * @param int|null $permissions New permissions
1245
+     * @param string|null $password New password
1246
+     * @param string|null $sendPasswordByTalk New condition if the password should be send over Talk
1247
+     * @param string|null $publicUpload New condition if public uploading is allowed
1248
+     * @param string|null $expireDate New expiry date
1249
+     * @param string|null $note New note
1250
+     * @param string|null $label New label
1251
+     * @param string|null $hideDownload New condition if the download should be hidden
1252
+     * @param string|null $attributes New additional attributes
1253
+     * @param string|null $sendMail if the share should be send by mail.
1254
+     *                              Considering the share already exists, no mail will be send after the share is updated.
1255
+     *                              You will have to use the sendMail action to send the mail.
1256
+     * @param string|null $shareWith New recipient for email shares
1257
+     * @param string|null $token New token
1258
+     * @return DataResponse<Http::STATUS_OK, Files_SharingShare, array{}>
1259
+     * @throws OCSBadRequestException Share could not be updated because the requested changes are invalid
1260
+     * @throws OCSForbiddenException Missing permissions to update the share
1261
+     * @throws OCSNotFoundException Share not found
1262
+     *
1263
+     * 200: Share updated successfully
1264
+     */
1265
+    #[NoAdminRequired]
1266
+    public function updateShare(
1267
+        string $id,
1268
+        ?int $permissions = null,
1269
+        ?string $password = null,
1270
+        ?string $sendPasswordByTalk = null,
1271
+        ?string $publicUpload = null,
1272
+        ?string $expireDate = null,
1273
+        ?string $note = null,
1274
+        ?string $label = null,
1275
+        ?string $hideDownload = null,
1276
+        ?string $attributes = null,
1277
+        ?string $sendMail = null,
1278
+        ?string $token = null,
1279
+    ): DataResponse {
1280
+        try {
1281
+            $share = $this->getShareById($id);
1282
+        } catch (ShareNotFound $e) {
1283
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
1284
+        }
1285
+
1286
+        $this->lock($share->getNode());
1287
+
1288
+        if (!$this->canAccessShare($share, false)) {
1289
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
1290
+        }
1291
+
1292
+        if (!$this->canEditShare($share)) {
1293
+            throw new OCSForbiddenException($this->l->t('You are not allowed to edit incoming shares'));
1294
+        }
1295
+
1296
+        if (
1297
+            $permissions === null
1298
+            && $password === null
1299
+            && $sendPasswordByTalk === null
1300
+            && $publicUpload === null
1301
+            && $expireDate === null
1302
+            && $note === null
1303
+            && $label === null
1304
+            && $hideDownload === null
1305
+            && $attributes === null
1306
+            && $sendMail === null
1307
+            && $token === null
1308
+        ) {
1309
+            throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
1310
+        }
1311
+
1312
+        if ($note !== null) {
1313
+            $share->setNote($note);
1314
+        }
1315
+
1316
+        if ($attributes !== null) {
1317
+            $share = $this->setShareAttributes($share, $attributes);
1318
+        }
1319
+
1320
+        // Handle mail send
1321
+        if ($sendMail === 'true' || $sendMail === 'false') {
1322
+            $share->setMailSend($sendMail === 'true');
1323
+        }
1324
+
1325
+        /**
1326
+         * expiration date, password and publicUpload only make sense for link shares
1327
+         */
1328
+        if ($share->getShareType() === IShare::TYPE_LINK
1329
+            || $share->getShareType() === IShare::TYPE_EMAIL) {
1330
+
1331
+            // Update hide download state
1332
+            if ($hideDownload === 'true') {
1333
+                $share->setHideDownload(true);
1334
+            } elseif ($hideDownload === 'false') {
1335
+                $share->setHideDownload(false);
1336
+            }
1337
+
1338
+            // If either manual permissions are specified or publicUpload
1339
+            // then we need to also update the permissions of the share
1340
+            if ($permissions !== null || $publicUpload !== null) {
1341
+                $hasPublicUpload = $this->getLegacyPublicUpload($publicUpload);
1342
+                $permissions = $this->getLinkSharePermissions($permissions ?? Constants::PERMISSION_READ, $hasPublicUpload);
1343
+                $this->validateLinkSharePermissions($share->getNode(), $permissions, $hasPublicUpload);
1344
+                $share->setPermissions($permissions);
1345
+            }
1346
+
1347
+            if ($password === '') {
1348
+                $share->setPassword(null);
1349
+            } elseif ($password !== null) {
1350
+                $share->setPassword($password);
1351
+            }
1352
+
1353
+            if ($label !== null) {
1354
+                if (strlen($label) > 255) {
1355
+                    throw new OCSBadRequestException('Maximum label length is 255');
1356
+                }
1357
+                $share->setLabel($label);
1358
+            }
1359
+
1360
+            if ($sendPasswordByTalk === 'true') {
1361
+                if (!$this->appManager->isEnabledForUser('spreed')) {
1362
+                    throw new OCSForbiddenException($this->l->t('"Sending the password by Nextcloud Talk" for sharing a file or folder failed because Nextcloud Talk is not enabled.'));
1363
+                }
1364
+
1365
+                $share->setSendPasswordByTalk(true);
1366
+            } elseif ($sendPasswordByTalk !== null) {
1367
+                $share->setSendPasswordByTalk(false);
1368
+            }
1369
+
1370
+            if ($token !== null) {
1371
+                if (!$this->shareManager->allowCustomTokens()) {
1372
+                    throw new OCSForbiddenException($this->l->t('Custom share link tokens have been disabled by the administrator'));
1373
+                }
1374
+                if (!$this->validateToken($token)) {
1375
+                    throw new OCSBadRequestException($this->l->t('Tokens must contain at least 1 character and may only contain letters, numbers, or a hyphen'));
1376
+                }
1377
+                $share->setToken($token);
1378
+            }
1379
+        }
1380
+
1381
+        // NOT A LINK SHARE
1382
+        else {
1383
+            if ($permissions !== null) {
1384
+                $share->setPermissions($permissions);
1385
+            }
1386
+        }
1387
+
1388
+        if ($expireDate === '') {
1389
+            $share->setExpirationDate(null);
1390
+        } elseif ($expireDate !== null) {
1391
+            try {
1392
+                $expireDateTime = $this->parseDate($expireDate);
1393
+                $share->setExpirationDate($expireDateTime);
1394
+            } catch (\Exception $e) {
1395
+                throw new OCSBadRequestException($e->getMessage(), $e);
1396
+            }
1397
+        }
1398
+
1399
+        try {
1400
+            $this->checkInheritedAttributes($share);
1401
+            $share = $this->shareManager->updateShare($share);
1402
+        } catch (HintException $e) {
1403
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
1404
+            throw new OCSException($e->getHint(), (int)$code);
1405
+        } catch (\Exception $e) {
1406
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
1407
+            throw new OCSBadRequestException('Failed to update share.', $e);
1408
+        }
1409
+
1410
+        return new DataResponse($this->formatShare($share));
1411
+    }
1412
+
1413
+    private function validateToken(string $token): bool {
1414
+        if (mb_strlen($token) === 0) {
1415
+            return false;
1416
+        }
1417
+        if (!preg_match('/^[a-z0-9-]+$/i', $token)) {
1418
+            return false;
1419
+        }
1420
+        return true;
1421
+    }
1422
+
1423
+    /**
1424
+     * Get all shares that are still pending
1425
+     *
1426
+     * @return DataResponse<Http::STATUS_OK, list<Files_SharingShare>, array{}>
1427
+     *
1428
+     * 200: Pending shares returned
1429
+     */
1430
+    #[NoAdminRequired]
1431
+    public function pendingShares(): DataResponse {
1432
+        $pendingShares = [];
1433
+
1434
+        $shareTypes = [
1435
+            IShare::TYPE_USER,
1436
+            IShare::TYPE_GROUP
1437
+        ];
1438
+
1439
+        foreach ($shareTypes as $shareType) {
1440
+            $shares = $this->shareManager->getSharedWith($this->userId, $shareType, null, -1, 0);
1441
+
1442
+            foreach ($shares as $share) {
1443
+                if ($share->getStatus() === IShare::STATUS_PENDING || $share->getStatus() === IShare::STATUS_REJECTED) {
1444
+                    $pendingShares[] = $share;
1445
+                }
1446
+            }
1447
+        }
1448
+
1449
+        $result = array_values(array_filter(array_map(function (IShare $share) {
1450
+            $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1451
+            $node = $userFolder->getFirstNodeById($share->getNodeId());
1452
+            if (!$node) {
1453
+                // fallback to guessing the path
1454
+                $node = $userFolder->get($share->getTarget());
1455
+                if ($node === null || $share->getTarget() === '') {
1456
+                    return null;
1457
+                }
1458
+            }
1459
+
1460
+            try {
1461
+                $formattedShare = $this->formatShare($share, $node);
1462
+                $formattedShare['path'] = '/' . $share->getNode()->getName();
1463
+                $formattedShare['permissions'] = 0;
1464
+                return $formattedShare;
1465
+            } catch (NotFoundException $e) {
1466
+                return null;
1467
+            }
1468
+        }, $pendingShares), function ($entry) {
1469
+            return $entry !== null;
1470
+        }));
1471
+
1472
+        return new DataResponse($result);
1473
+    }
1474
+
1475
+    /**
1476
+     * Accept a share
1477
+     *
1478
+     * @param string $id ID of the share
1479
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1480
+     * @throws OCSNotFoundException Share not found
1481
+     * @throws OCSException
1482
+     * @throws OCSBadRequestException Share could not be accepted
1483
+     *
1484
+     * 200: Share accepted successfully
1485
+     */
1486
+    #[NoAdminRequired]
1487
+    public function acceptShare(string $id): DataResponse {
1488
+        try {
1489
+            $share = $this->getShareById($id);
1490
+        } catch (ShareNotFound $e) {
1491
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
1492
+        }
1493
+
1494
+        if (!$this->canAccessShare($share)) {
1495
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
1496
+        }
1497
+
1498
+        try {
1499
+            $this->shareManager->acceptShare($share, $this->userId);
1500
+        } catch (HintException $e) {
1501
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
1502
+            throw new OCSException($e->getHint(), (int)$code);
1503
+        } catch (\Exception $e) {
1504
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
1505
+            throw new OCSBadRequestException('Failed to accept share.', $e);
1506
+        }
1507
+
1508
+        return new DataResponse();
1509
+    }
1510
+
1511
+    /**
1512
+     * Does the user have read permission on the share
1513
+     *
1514
+     * @param IShare $share the share to check
1515
+     * @param boolean $checkGroups check groups as well?
1516
+     * @return boolean
1517
+     * @throws NotFoundException
1518
+     *
1519
+     * @suppress PhanUndeclaredClassMethod
1520
+     */
1521
+    protected function canAccessShare(IShare $share, bool $checkGroups = true): bool {
1522
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1523
+        if ($share->getPermissions() === 0) {
1524
+            return false;
1525
+        }
1526
+
1527
+        // Owner of the file and the sharer of the file can always get share
1528
+        if ($share->getShareOwner() === $this->userId
1529
+            || $share->getSharedBy() === $this->userId) {
1530
+            return true;
1531
+        }
1532
+
1533
+        // If the share is shared with you, you can access it!
1534
+        if ($share->getShareType() === IShare::TYPE_USER
1535
+            && $share->getSharedWith() === $this->userId) {
1536
+            return true;
1537
+        }
1538
+
1539
+        // Have reshare rights on the shared file/folder ?
1540
+        // Does the currentUser have access to the shared file?
1541
+        $userFolder = $this->rootFolder->getUserFolder($this->userId);
1542
+        $file = $userFolder->getFirstNodeById($share->getNodeId());
1543
+        if ($file && $this->shareProviderResharingRights($this->userId, $share, $file)) {
1544
+            return true;
1545
+        }
1546
+
1547
+        // If in the recipient group, you can see the share
1548
+        if ($checkGroups && $share->getShareType() === IShare::TYPE_GROUP) {
1549
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1550
+            $user = $this->userManager->get($this->userId);
1551
+            if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1552
+                return true;
1553
+            }
1554
+        }
1555
+
1556
+        if ($share->getShareType() === IShare::TYPE_CIRCLE) {
1557
+            // TODO: have a sanity check like above?
1558
+            return true;
1559
+        }
1560
+
1561
+        if ($share->getShareType() === IShare::TYPE_ROOM) {
1562
+            try {
1563
+                return $this->getRoomShareHelper()->canAccessShare($share, $this->userId);
1564
+            } catch (ContainerExceptionInterface $e) {
1565
+                return false;
1566
+            }
1567
+        }
1568
+
1569
+        if ($share->getShareType() === IShare::TYPE_DECK) {
1570
+            try {
1571
+                return $this->getDeckShareHelper()->canAccessShare($share, $this->userId);
1572
+            } catch (ContainerExceptionInterface $e) {
1573
+                return false;
1574
+            }
1575
+        }
1576
+
1577
+        if ($share->getShareType() === IShare::TYPE_SCIENCEMESH) {
1578
+            try {
1579
+                return $this->getSciencemeshShareHelper()->canAccessShare($share, $this->userId);
1580
+            } catch (ContainerExceptionInterface $e) {
1581
+                return false;
1582
+            }
1583
+        }
1584
+
1585
+        return false;
1586
+    }
1587
+
1588
+    /**
1589
+     * Does the user have edit permission on the share
1590
+     *
1591
+     * @param IShare $share the share to check
1592
+     * @return boolean
1593
+     */
1594
+    protected function canEditShare(IShare $share): bool {
1595
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1596
+        if ($share->getPermissions() === 0) {
1597
+            return false;
1598
+        }
1599
+
1600
+        // The owner of the file and the creator of the share
1601
+        // can always edit the share
1602
+        if ($share->getShareOwner() === $this->userId
1603
+            || $share->getSharedBy() === $this->userId
1604
+        ) {
1605
+            return true;
1606
+        }
1607
+
1608
+        $userFolder = $this->rootFolder->getUserFolder($this->userId);
1609
+        $file = $userFolder->getFirstNodeById($share->getNodeId());
1610
+        if ($file?->getMountPoint() instanceof IShareOwnerlessMount && $this->shareProviderResharingRights($this->userId, $share, $file)) {
1611
+            return true;
1612
+        }
1613
+
1614
+        //! we do NOT support some kind of `admin` in groups.
1615
+        //! You cannot edit shares shared to a group you're
1616
+        //! a member of if you're not the share owner or the file owner!
1617
+
1618
+        return false;
1619
+    }
1620
+
1621
+    /**
1622
+     * Does the user have delete permission on the share
1623
+     *
1624
+     * @param IShare $share the share to check
1625
+     * @return boolean
1626
+     */
1627
+    protected function canDeleteShare(IShare $share): bool {
1628
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1629
+        if ($share->getPermissions() === 0) {
1630
+            return false;
1631
+        }
1632
+
1633
+        // if the user is the recipient, i can unshare
1634
+        // the share with self
1635
+        if ($share->getShareType() === IShare::TYPE_USER
1636
+            && $share->getSharedWith() === $this->userId
1637
+        ) {
1638
+            return true;
1639
+        }
1640
+
1641
+        // The owner of the file and the creator of the share
1642
+        // can always delete the share
1643
+        if ($share->getShareOwner() === $this->userId
1644
+            || $share->getSharedBy() === $this->userId
1645
+        ) {
1646
+            return true;
1647
+        }
1648
+
1649
+        $userFolder = $this->rootFolder->getUserFolder($this->userId);
1650
+        $file = $userFolder->getFirstNodeById($share->getNodeId());
1651
+        if ($file?->getMountPoint() instanceof IShareOwnerlessMount && $this->shareProviderResharingRights($this->userId, $share, $file)) {
1652
+            return true;
1653
+        }
1654
+
1655
+        return false;
1656
+    }
1657
+
1658
+    /**
1659
+     * Does the user have delete permission on the share
1660
+     * This differs from the canDeleteShare function as it only
1661
+     * remove the share for the current user. It does NOT
1662
+     * completely delete the share but only the mount point.
1663
+     * It can then be restored from the deleted shares section.
1664
+     *
1665
+     * @param IShare $share the share to check
1666
+     * @return boolean
1667
+     *
1668
+     * @suppress PhanUndeclaredClassMethod
1669
+     */
1670
+    protected function canDeleteShareFromSelf(IShare $share): bool {
1671
+        if ($share->getShareType() !== IShare::TYPE_GROUP
1672
+            && $share->getShareType() !== IShare::TYPE_ROOM
1673
+            && $share->getShareType() !== IShare::TYPE_DECK
1674
+            && $share->getShareType() !== IShare::TYPE_SCIENCEMESH
1675
+        ) {
1676
+            return false;
1677
+        }
1678
+
1679
+        if ($share->getShareOwner() === $this->userId
1680
+            || $share->getSharedBy() === $this->userId
1681
+        ) {
1682
+            // Delete the whole share, not just for self
1683
+            return false;
1684
+        }
1685
+
1686
+        // If in the recipient group, you can delete the share from self
1687
+        if ($share->getShareType() === IShare::TYPE_GROUP) {
1688
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1689
+            $user = $this->userManager->get($this->userId);
1690
+            if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1691
+                return true;
1692
+            }
1693
+        }
1694
+
1695
+        if ($share->getShareType() === IShare::TYPE_ROOM) {
1696
+            try {
1697
+                return $this->getRoomShareHelper()->canAccessShare($share, $this->userId);
1698
+            } catch (ContainerExceptionInterface $e) {
1699
+                return false;
1700
+            }
1701
+        }
1702
+
1703
+        if ($share->getShareType() === IShare::TYPE_DECK) {
1704
+            try {
1705
+                return $this->getDeckShareHelper()->canAccessShare($share, $this->userId);
1706
+            } catch (ContainerExceptionInterface $e) {
1707
+                return false;
1708
+            }
1709
+        }
1710
+
1711
+        if ($share->getShareType() === IShare::TYPE_SCIENCEMESH) {
1712
+            try {
1713
+                return $this->getSciencemeshShareHelper()->canAccessShare($share, $this->userId);
1714
+            } catch (ContainerExceptionInterface $e) {
1715
+                return false;
1716
+            }
1717
+        }
1718
+
1719
+        return false;
1720
+    }
1721
+
1722
+    /**
1723
+     * Make sure that the passed date is valid ISO 8601
1724
+     * So YYYY-MM-DD
1725
+     * If not throw an exception
1726
+     *
1727
+     * @param string $expireDate
1728
+     *
1729
+     * @throws \Exception
1730
+     * @return \DateTime
1731
+     */
1732
+    private function parseDate(string $expireDate): \DateTime {
1733
+        try {
1734
+            $date = new \DateTime(trim($expireDate, '"'), $this->dateTimeZone->getTimeZone());
1735
+            // Make sure it expires at midnight in owner timezone
1736
+            $date->setTime(0, 0, 0);
1737
+        } catch (\Exception $e) {
1738
+            throw new \Exception($this->l->t('Invalid date. Format must be YYYY-MM-DD'));
1739
+        }
1740
+
1741
+        return $date;
1742
+    }
1743
+
1744
+    /**
1745
+     * Since we have multiple providers but the OCS Share API v1 does
1746
+     * not support this we need to check all backends.
1747
+     *
1748
+     * @param string $id
1749
+     * @return IShare
1750
+     * @throws ShareNotFound
1751
+     */
1752
+    private function getShareById(string $id): IShare {
1753
+        $providers = [
1754
+            'ocinternal' => null, // No type check needed
1755
+            'ocCircleShare' => IShare::TYPE_CIRCLE,
1756
+            'ocMailShare' => IShare::TYPE_EMAIL,
1757
+            'ocRoomShare' => null,
1758
+            'deck' => IShare::TYPE_DECK,
1759
+            'sciencemesh' => IShare::TYPE_SCIENCEMESH,
1760
+        ];
1761
+
1762
+        // Add federated sharing as a provider only if it's allowed
1763
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1764
+            $providers['ocFederatedSharing'] = null; // No type check needed
1765
+        }
1766
+
1767
+        foreach ($providers as $prefix => $type) {
1768
+            try {
1769
+                if ($type === null || $this->shareManager->shareProviderExists($type)) {
1770
+                    return $this->shareManager->getShareById($prefix . ':' . $id, $this->userId);
1771
+                }
1772
+            } catch (ShareNotFound $e) {
1773
+                // Do nothing, continue to next provider
1774
+            } catch (\Exception $e) {
1775
+                $this->logger->warning('Unexpected error in share provider', [
1776
+                    'shareId' => $id,
1777
+                    'provider' => $prefix,
1778
+                    'exception' => $e,
1779
+                ]);
1780
+            }
1781
+        }
1782
+        throw new ShareNotFound();
1783
+    }
1784
+
1785
+    /**
1786
+     * Lock a Node
1787
+     *
1788
+     * @param Node $node
1789
+     * @throws LockedException
1790
+     */
1791
+    private function lock(Node $node) {
1792
+        $node->lock(ILockingProvider::LOCK_SHARED);
1793
+        $this->lockedNode = $node;
1794
+    }
1795
+
1796
+    /**
1797
+     * Cleanup the remaining locks
1798
+     * @throws LockedException
1799
+     */
1800
+    public function cleanup() {
1801
+        if ($this->lockedNode !== null) {
1802
+            $this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1803
+        }
1804
+    }
1805
+
1806
+    /**
1807
+     * Returns the helper of ShareAPIController for room shares.
1808
+     *
1809
+     * If the Talk application is not enabled or the helper is not available
1810
+     * a ContainerExceptionInterface is thrown instead.
1811
+     *
1812
+     * @return \OCA\Talk\Share\Helper\ShareAPIController
1813
+     * @throws ContainerExceptionInterface
1814
+     */
1815
+    private function getRoomShareHelper() {
1816
+        if (!$this->appManager->isEnabledForUser('spreed')) {
1817
+            throw new QueryException();
1818
+        }
1819
+
1820
+        return $this->serverContainer->get('\OCA\Talk\Share\Helper\ShareAPIController');
1821
+    }
1822
+
1823
+    /**
1824
+     * Returns the helper of ShareAPIHelper for deck shares.
1825
+     *
1826
+     * If the Deck application is not enabled or the helper is not available
1827
+     * a ContainerExceptionInterface is thrown instead.
1828
+     *
1829
+     * @return ShareAPIHelper
1830
+     * @throws ContainerExceptionInterface
1831
+     */
1832
+    private function getDeckShareHelper() {
1833
+        if (!$this->appManager->isEnabledForUser('deck')) {
1834
+            throw new QueryException();
1835
+        }
1836
+
1837
+        return $this->serverContainer->get('\OCA\Deck\Sharing\ShareAPIHelper');
1838
+    }
1839
+
1840
+    /**
1841
+     * Returns the helper of ShareAPIHelper for sciencemesh shares.
1842
+     *
1843
+     * If the sciencemesh application is not enabled or the helper is not available
1844
+     * a ContainerExceptionInterface is thrown instead.
1845
+     *
1846
+     * @return ShareAPIHelper
1847
+     * @throws ContainerExceptionInterface
1848
+     */
1849
+    private function getSciencemeshShareHelper() {
1850
+        if (!$this->appManager->isEnabledForUser('sciencemesh')) {
1851
+            throw new QueryException();
1852
+        }
1853
+
1854
+        return $this->serverContainer->get('\OCA\ScienceMesh\Sharing\ShareAPIHelper');
1855
+    }
1856
+
1857
+    /**
1858
+     * @param string $viewer
1859
+     * @param Node $node
1860
+     * @param bool $reShares
1861
+     *
1862
+     * @return IShare[]
1863
+     */
1864
+    private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1865
+        $providers = [
1866
+            IShare::TYPE_USER,
1867
+            IShare::TYPE_GROUP,
1868
+            IShare::TYPE_LINK,
1869
+            IShare::TYPE_EMAIL,
1870
+            IShare::TYPE_CIRCLE,
1871
+            IShare::TYPE_ROOM,
1872
+            IShare::TYPE_DECK,
1873
+            IShare::TYPE_SCIENCEMESH
1874
+        ];
1875
+
1876
+        // Should we assume that the (currentUser) viewer is the owner of the node !?
1877
+        $shares = [];
1878
+        foreach ($providers as $provider) {
1879
+            if (!$this->shareManager->shareProviderExists($provider)) {
1880
+                continue;
1881
+            }
1882
+
1883
+            $providerShares
1884
+                = $this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
1885
+            $shares = array_merge($shares, $providerShares);
1886
+        }
1887
+
1888
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1889
+            $federatedShares = $this->shareManager->getSharesBy(
1890
+                $this->userId, IShare::TYPE_REMOTE, $node, $reShares, -1, 0
1891
+            );
1892
+            $shares = array_merge($shares, $federatedShares);
1893
+        }
1894
+
1895
+        if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1896
+            $federatedShares = $this->shareManager->getSharesBy(
1897
+                $this->userId, IShare::TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
1898
+            );
1899
+            $shares = array_merge($shares, $federatedShares);
1900
+        }
1901
+
1902
+        return $shares;
1903
+    }
1904
+
1905
+
1906
+    /**
1907
+     * @param Node $node
1908
+     *
1909
+     * @throws SharingRightsException
1910
+     */
1911
+    private function confirmSharingRights(Node $node): void {
1912
+        if (!$this->hasResharingRights($this->userId, $node)) {
1913
+            throw new SharingRightsException($this->l->t('No sharing rights on this item'));
1914
+        }
1915
+    }
1916
+
1917
+
1918
+    /**
1919
+     * @param string $viewer
1920
+     * @param Node $node
1921
+     *
1922
+     * @return bool
1923
+     */
1924
+    private function hasResharingRights($viewer, $node): bool {
1925
+        if ($viewer === $node->getOwner()->getUID()) {
1926
+            return true;
1927
+        }
1928
+
1929
+        foreach ([$node, $node->getParent()] as $node) {
1930
+            $shares = $this->getSharesFromNode($viewer, $node, true);
1931
+            foreach ($shares as $share) {
1932
+                try {
1933
+                    if ($this->shareProviderResharingRights($viewer, $share, $node)) {
1934
+                        return true;
1935
+                    }
1936
+                } catch (InvalidPathException|NotFoundException $e) {
1937
+                }
1938
+            }
1939
+        }
1940
+
1941
+        return false;
1942
+    }
1943
+
1944
+
1945
+    /**
1946
+     * Returns if we can find resharing rights in an IShare object for a specific user.
1947
+     *
1948
+     * @suppress PhanUndeclaredClassMethod
1949
+     *
1950
+     * @param string $userId
1951
+     * @param IShare $share
1952
+     * @param Node $node
1953
+     *
1954
+     * @return bool
1955
+     * @throws NotFoundException
1956
+     * @throws InvalidPathException
1957
+     */
1958
+    private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1959
+        if ($share->getShareOwner() === $userId) {
1960
+            return true;
1961
+        }
1962
+
1963
+        // we check that current user have parent resharing rights on the current file
1964
+        if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
1965
+            return true;
1966
+        }
1967
+
1968
+        if ((Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1969
+            return false;
1970
+        }
1971
+
1972
+        if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() === $userId) {
1973
+            return true;
1974
+        }
1975
+
1976
+        if ($share->getShareType() === IShare::TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1977
+            return true;
1978
+        }
1979
+
1980
+        if ($share->getShareType() === IShare::TYPE_CIRCLE && Server::get(IAppManager::class)->isEnabledForUser('circles')
1981
+            && class_exists('\OCA\Circles\Api\v1\Circles')) {
1982
+            $hasCircleId = (str_ends_with($share->getSharedWith(), ']'));
1983
+            $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1984
+            $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1985
+            if ($shareWithLength === false) {
1986
+                $sharedWith = substr($share->getSharedWith(), $shareWithStart);
1987
+            } else {
1988
+                $sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1989
+            }
1990
+            try {
1991
+                $member = Circles::getMember($sharedWith, $userId, 1);
1992
+                if ($member->getLevel() >= 4) {
1993
+                    return true;
1994
+                }
1995
+                return false;
1996
+            } catch (ContainerExceptionInterface $e) {
1997
+                return false;
1998
+            }
1999
+        }
2000
+
2001
+        return false;
2002
+    }
2003
+
2004
+    /**
2005
+     * Get all the shares for the current user
2006
+     *
2007
+     * @param Node|null $path
2008
+     * @param boolean $reshares
2009
+     * @return IShare[]
2010
+     */
2011
+    private function getAllShares(?Node $path = null, bool $reshares = false) {
2012
+        // Get all shares
2013
+        $userShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_USER, $path, $reshares, -1, 0);
2014
+        $groupShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_GROUP, $path, $reshares, -1, 0);
2015
+        $linkShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_LINK, $path, $reshares, -1, 0);
2016
+
2017
+        // EMAIL SHARES
2018
+        $mailShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_EMAIL, $path, $reshares, -1, 0);
2019
+
2020
+        // TEAM SHARES
2021
+        $circleShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_CIRCLE, $path, $reshares, -1, 0);
2022
+
2023
+        // TALK SHARES
2024
+        $roomShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_ROOM, $path, $reshares, -1, 0);
2025
+
2026
+        // DECK SHARES
2027
+        $deckShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_DECK, $path, $reshares, -1, 0);
2028
+
2029
+        // SCIENCEMESH SHARES
2030
+        $sciencemeshShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_SCIENCEMESH, $path, $reshares, -1, 0);
2031
+
2032
+        // FEDERATION
2033
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
2034
+            $federatedShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_REMOTE, $path, $reshares, -1, 0);
2035
+        } else {
2036
+            $federatedShares = [];
2037
+        }
2038
+        if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
2039
+            $federatedGroupShares = $this->shareManager->getSharesBy($this->userId, IShare::TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
2040
+        } else {
2041
+            $federatedGroupShares = [];
2042
+        }
2043
+
2044
+        return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $deckShares, $sciencemeshShares, $federatedShares, $federatedGroupShares);
2045
+    }
2046
+
2047
+
2048
+    /**
2049
+     * merging already formatted shares.
2050
+     * We'll make an associative array to easily detect duplicate Ids.
2051
+     * Keys _needs_ to be removed after all shares are retrieved and merged.
2052
+     *
2053
+     * @param array $shares
2054
+     * @param array $newShares
2055
+     */
2056
+    private function mergeFormattedShares(array &$shares, array $newShares) {
2057
+        foreach ($newShares as $newShare) {
2058
+            if (!array_key_exists($newShare['id'], $shares)) {
2059
+                $shares[$newShare['id']] = $newShare;
2060
+            }
2061
+        }
2062
+    }
2063
+
2064
+    /**
2065
+     * @param IShare $share
2066
+     * @param string|null $attributesString
2067
+     * @return IShare modified share
2068
+     */
2069
+    private function setShareAttributes(IShare $share, ?string $attributesString) {
2070
+        $newShareAttributes = null;
2071
+        if ($attributesString !== null) {
2072
+            $newShareAttributes = $this->shareManager->newShare()->newAttributes();
2073
+            $formattedShareAttributes = \json_decode($attributesString, true);
2074
+            if (is_array($formattedShareAttributes)) {
2075
+                foreach ($formattedShareAttributes as $formattedAttr) {
2076
+                    $newShareAttributes->setAttribute(
2077
+                        $formattedAttr['scope'],
2078
+                        $formattedAttr['key'],
2079
+                        $formattedAttr['value'],
2080
+                    );
2081
+                }
2082
+            } else {
2083
+                throw new OCSBadRequestException($this->l->t('Invalid share attributes provided: "%s"', [$attributesString]));
2084
+            }
2085
+        }
2086
+        $share->setAttributes($newShareAttributes);
2087
+
2088
+        return $share;
2089
+    }
2090
+
2091
+    private function checkInheritedAttributes(IShare $share): void {
2092
+        if (!$share->getSharedBy()) {
2093
+            return; // Probably in a test
2094
+        }
2095
+
2096
+        $canDownload = false;
2097
+        $hideDownload = true;
2098
+
2099
+        $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
2100
+        $nodes = $userFolder->getById($share->getNodeId());
2101
+        foreach ($nodes as $node) {
2102
+            // Owner always can download it - so allow it and break
2103
+            if ($node->getOwner()?->getUID() === $share->getSharedBy()) {
2104
+                $canDownload = true;
2105
+                $hideDownload = false;
2106
+                break;
2107
+            }
2108
+
2109
+            if ($node->getStorage()->instanceOfStorage(SharedStorage::class)) {
2110
+                $storage = $node->getStorage();
2111
+                if ($storage instanceof Wrapper) {
2112
+                    $storage = $storage->getInstanceOfStorage(SharedStorage::class);
2113
+                    if ($storage === null) {
2114
+                        throw new \RuntimeException('Should not happen, instanceOfStorage but getInstanceOfStorage return null');
2115
+                    }
2116
+                } else {
2117
+                    throw new \RuntimeException('Should not happen, instanceOfStorage but not a wrapper');
2118
+                }
2119
+
2120
+                /** @var SharedStorage $storage */
2121
+                $originalShare = $storage->getShare();
2122
+                $inheritedAttributes = $originalShare->getAttributes();
2123
+                // hide if hidden and also the current share enforces hide (can only be false if one share is false or user is owner)
2124
+                $hideDownload = $hideDownload && $originalShare->getHideDownload();
2125
+                // allow download if already allowed by previous share or when the current share allows downloading
2126
+                $canDownload = $canDownload || $inheritedAttributes === null || $inheritedAttributes->getAttribute('permissions', 'download') !== false;
2127
+            } elseif ($node->getStorage()->instanceOfStorage(Storage::class)) {
2128
+                $canDownload = true; // in case of federation storage, we can expect the download to be activated by default
2129
+            }
2130
+        }
2131
+
2132
+        if ($hideDownload || !$canDownload) {
2133
+            $share->setHideDownload(true);
2134
+
2135
+            if (!$canDownload) {
2136
+                $attributes = $share->getAttributes() ?? $share->newAttributes();
2137
+                $attributes->setAttribute('permissions', 'download', false);
2138
+                $share->setAttributes($attributes);
2139
+            }
2140
+        }
2141
+    }
2142
+
2143
+    /**
2144
+     * Send a mail notification again for a share.
2145
+     * The mail_send option must be enabled for the given share.
2146
+     * @param string $id the share ID
2147
+     * @param string $password the password to check against. Necessary for password protected shares.
2148
+     * @throws OCSNotFoundException Share not found
2149
+     * @throws OCSForbiddenException You are not allowed to send mail notifications
2150
+     * @throws OCSBadRequestException Invalid request or wrong password
2151
+     * @throws OCSException Error while sending mail notification
2152
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
2153
+     *
2154
+     * 200: The email notification was sent successfully
2155
+     */
2156
+    #[NoAdminRequired]
2157
+    #[UserRateLimit(limit: 10, period: 600)]
2158
+    public function sendShareEmail(string $id, $password = ''): DataResponse {
2159
+        try {
2160
+            $share = $this->getShareById($id);
2161
+
2162
+            if (!$this->canAccessShare($share, false)) {
2163
+                throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
2164
+            }
2165
+
2166
+            if (!$this->canEditShare($share)) {
2167
+                throw new OCSForbiddenException($this->l->t('You are not allowed to send mail notifications'));
2168
+            }
2169
+
2170
+            // For mail and link shares, the user must be
2171
+            // the owner of the share, not only the file owner.
2172
+            if ($share->getShareType() === IShare::TYPE_EMAIL
2173
+                || $share->getShareType() === IShare::TYPE_LINK) {
2174
+                if ($share->getSharedBy() !== $this->userId) {
2175
+                    throw new OCSForbiddenException($this->l->t('You are not allowed to send mail notifications'));
2176
+                }
2177
+            }
2178
+
2179
+            try {
2180
+                $provider = $this->factory->getProviderForType($share->getShareType());
2181
+                if (!($provider instanceof IShareProviderWithNotification)) {
2182
+                    throw new OCSBadRequestException($this->l->t('No mail notification configured for this share type'));
2183
+                }
2184
+
2185
+                // Circumvent the password encrypted data by
2186
+                // setting the password clear. We're not storing
2187
+                // the password clear, it is just a temporary
2188
+                // object manipulation. The password will stay
2189
+                // encrypted in the database.
2190
+                if ($share->getPassword() !== null && $share->getPassword() !== $password) {
2191
+                    if (!$this->shareManager->checkPassword($share, $password)) {
2192
+                        throw new OCSBadRequestException($this->l->t('Wrong password'));
2193
+                    }
2194
+                    $share = $share->setPassword($password);
2195
+                }
2196
+
2197
+                $provider->sendMailNotification($share);
2198
+                return new DataResponse();
2199
+            } catch (Exception $e) {
2200
+                $this->logger->error($e->getMessage(), ['exception' => $e]);
2201
+                throw new OCSException($this->l->t('Error while sending mail notification'));
2202
+            }
2203
+
2204
+        } catch (ShareNotFound $e) {
2205
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist'));
2206
+        }
2207
+    }
2208
+
2209
+    /**
2210
+     * Get a unique share token
2211
+     *
2212
+     * @throws OCSException Failed to generate a unique token
2213
+     *
2214
+     * @return DataResponse<Http::STATUS_OK, array{token: string}, array{}>
2215
+     *
2216
+     * 200: Token generated successfully
2217
+     */
2218
+    #[ApiRoute(verb: 'GET', url: '/api/v1/token')]
2219
+    #[NoAdminRequired]
2220
+    public function generateToken(): DataResponse {
2221
+        try {
2222
+            $token = $this->shareManager->generateToken();
2223
+            return new DataResponse([
2224
+                'token' => $token,
2225
+            ]);
2226
+        } catch (ShareTokenException $e) {
2227
+            throw new OCSException($this->l->t('Failed to generate a unique token'));
2228
+        }
2229
+    }
2230
+
2231
+    /**
2232
+     * Populate the result set with file tags
2233
+     *
2234
+     * @psalm-template T of array{tags?: list<string>, file_source: int, ...array<string, mixed>}
2235
+     * @param list<T> $fileList
2236
+     * @return list<T> file list populated with tags
2237
+     */
2238
+    private function populateTags(array $fileList): array {
2239
+        $tagger = $this->tagManager->load('files');
2240
+        $tags = $tagger->getTagsForObjects(array_map(static fn (array $fileData) => $fileData['file_source'], $fileList));
2241
+
2242
+        if (!is_array($tags)) {
2243
+            throw new \UnexpectedValueException('$tags must be an array');
2244
+        }
2245
+
2246
+        // Set empty tag array
2247
+        foreach ($fileList as &$fileData) {
2248
+            $fileData['tags'] = [];
2249
+        }
2250
+        unset($fileData);
2251
+
2252
+        if (!empty($tags)) {
2253
+            foreach ($tags as $fileId => $fileTags) {
2254
+                foreach ($fileList as &$fileData) {
2255
+                    if ($fileId !== $fileData['file_source']) {
2256
+                        continue;
2257
+                    }
2258
+
2259
+                    $fileData['tags'] = $fileTags;
2260
+                }
2261
+                unset($fileData);
2262
+            }
2263
+        }
2264
+
2265
+        return $fileList;
2266
+    }
2267 2267
 }
Please login to merge, or discard this patch.
apps/files_sharing/tests/ApiTest.php 1 patch
Indentation   +1439 added lines, -1439 removed lines patch added patch discarded remove patch
@@ -50,1456 +50,1456 @@
 block discarded – undo
50 50
  * TODO: convert to real integration tests
51 51
  */
52 52
 class ApiTest extends TestCase {
53
-	use EmailValidatorTrait;
54
-
55
-	public const TEST_FOLDER_NAME = '/folder_share_api_test';
56
-	public const APP_NAME = 'files_sharing';
57
-
58
-	private static $tempStorage;
59
-
60
-	private Folder $userFolder;
61
-	private string $subsubfolder;
62
-	protected IAppConfig&MockObject $appConfig;
63
-
64
-	protected function setUp(): void {
65
-		parent::setUp();
66
-
67
-		Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups', 'no');
68
-		Server::get(IConfig::class)->setAppValue('core', 'shareapi_expire_after_n_days', '7');
69
-
70
-		Filesystem::getLoader()->removeStorageWrapper('sharing_mask');
71
-
72
-		$this->folder = self::TEST_FOLDER_NAME;
73
-		$this->subfolder = '/subfolder_share_api_test';
74
-		$this->subsubfolder = '/subsubfolder_share_api_test';
75
-
76
-		$this->filename = '/share-api-test.txt';
77
-
78
-		// save file with content
79
-		$this->view->file_put_contents($this->filename, $this->data);
80
-		$this->view->mkdir($this->folder);
81
-		$this->view->mkdir($this->folder . $this->subfolder);
82
-		$this->view->mkdir($this->folder . $this->subfolder . $this->subsubfolder);
83
-		$this->view->file_put_contents($this->folder . $this->filename, $this->data);
84
-		$this->view->file_put_contents($this->folder . $this->subfolder . $this->filename, $this->data);
85
-		$mount = $this->view->getMount($this->filename);
86
-		$mount->getStorage()->getScanner()->scan('', Scanner::SCAN_RECURSIVE);
87
-
88
-		$this->userFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1);
89
-
90
-		$this->appConfig = $this->createMock(IAppConfig::class);
91
-	}
92
-
93
-	protected function tearDown(): void {
94
-		if ($this->view instanceof View) {
95
-			$this->view->unlink($this->filename);
96
-			$this->view->deleteAll($this->folder);
97
-		}
98
-
99
-		self::$tempStorage = null;
100
-
101
-		parent::tearDown();
102
-	}
103
-
104
-	/**
105
-	 * @param string $userId The userId of the caller
106
-	 * @return ShareAPIController
107
-	 */
108
-	private function createOCS($userId) {
109
-		$l = $this->getMockBuilder(IL10N::class)->getMock();
110
-		$l->method('t')
111
-			->willReturnCallback(function ($text, $parameters = []) {
112
-				return vsprintf($text, $parameters);
113
-			});
114
-		$config = $this->createMock(IConfig::class);
115
-		$appManager = $this->createMock(IAppManager::class);
116
-		$serverContainer = $this->createMock(ContainerInterface::class);
117
-		$userStatusManager = $this->createMock(IUserStatusManager::class);
118
-		$previewManager = $this->createMock(IPreview::class);
119
-		$dateTimeZone = $this->createMock(IDateTimeZone::class);
120
-		$logger = $this->createMock(LoggerInterface::class);
121
-		$providerFactory = $this->createMock(IProviderFactory::class);
122
-		$mailer = $this->createMock(IMailer::class);
123
-		$tagManager = $this->createMock(ITagManager::class);
124
-		$trustedServers = $this->createMock(TrustedServers::class);
125
-		$dateTimeZone->method('getTimeZone')->willReturn(new \DateTimeZone(date_default_timezone_get()));
126
-
127
-		return new ShareAPIController(
128
-			self::APP_NAME,
129
-			$this->getMockBuilder(IRequest::class)->getMock(),
130
-			$this->shareManager,
131
-			Server::get(IGroupManager::class),
132
-			Server::get(IUserManager::class),
133
-			Server::get(IRootFolder::class),
134
-			Server::get(IURLGenerator::class),
135
-			$l,
136
-			$config,
137
-			$this->appConfig,
138
-			$appManager,
139
-			$serverContainer,
140
-			$userStatusManager,
141
-			$previewManager,
142
-			$dateTimeZone,
143
-			$logger,
144
-			$providerFactory,
145
-			$mailer,
146
-			$tagManager,
147
-			$this->getEmailValidatorWithStrictEmailCheck(),
148
-			$trustedServers,
149
-			$userId,
150
-		);
151
-	}
152
-
153
-	public function testCreateShareUserFile(): void {
154
-		$this->setUp(); // for some reasons phpunit refuses to do this for us only for this test
155
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
156
-		$result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
157
-		$ocs->cleanup();
158
-
159
-		$data = $result->getData();
160
-		$this->assertEquals(19, $data['permissions']);
161
-		$this->assertEmpty($data['expiration']);
162
-
163
-		$this->shareManager->getShareById('ocinternal:' . $data['id']);
164
-
165
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
166
-		$ocs->deleteShare($data['id']);
167
-
168
-		$ocs->cleanup();
169
-	}
170
-
171
-	public function testCreateShareUserFolder(): void {
172
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
173
-		$result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
174
-		$ocs->cleanup();
175
-
176
-		$data = $result->getData();
177
-		$this->assertEquals(31, $data['permissions']);
178
-		$this->assertEmpty($data['expiration']);
179
-
180
-		$this->shareManager->getShareById('ocinternal:' . $data['id']);
181
-
182
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
183
-		$ocs->deleteShare($data['id']);
184
-		$ocs->cleanup();
185
-	}
186
-
187
-
188
-	public function testCreateShareGroupFile(): void {
189
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
190
-		$result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_GROUP, self::TEST_FILES_SHARING_API_GROUP1);
191
-		$ocs->cleanup();
192
-
193
-		$data = $result->getData();
194
-		$this->assertEquals(19, $data['permissions']);
195
-		$this->assertEmpty($data['expiration']);
196
-
197
-		$this->shareManager->getShareById('ocinternal:' . $data['id']);
198
-
199
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
200
-		$ocs->deleteShare($data['id']);
201
-		$ocs->cleanup();
202
-	}
203
-
204
-	public function testCreateShareGroupFolder(): void {
205
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
206
-		$result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_GROUP, self::TEST_FILES_SHARING_API_GROUP1);
207
-		$ocs->cleanup();
208
-
209
-		$data = $result->getData();
210
-		$this->assertEquals(31, $data['permissions']);
211
-		$this->assertEmpty($data['expiration']);
212
-
213
-		$this->shareManager->getShareById('ocinternal:' . $data['id']);
214
-
215
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
216
-		$ocs->deleteShare($data['id']);
217
-		$ocs->cleanup();
218
-	}
219
-
220
-	/**
221
-	 * @group RoutingWeirdness
222
-	 */
223
-	public function testCreateShareLink(): void {
224
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
225
-		$result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK);
226
-		$ocs->cleanup();
227
-
228
-		$data = $result->getData();
229
-		$this->assertEquals(Constants::PERMISSION_ALL,
230
-			$data['permissions']);
231
-		$this->assertEmpty($data['expiration']);
232
-		$this->assertTrue(is_string($data['token']));
233
-
234
-		// check for correct link
235
-		$url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']);
236
-		$this->assertEquals($url, $data['url']);
237
-
238
-		$this->shareManager->getShareById('ocinternal:' . $data['id']);
239
-
240
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
241
-		$ocs->deleteShare($data['id']);
242
-		$ocs->cleanup();
243
-	}
244
-
245
-	/**
246
-	 * @group RoutingWeirdness
247
-	 */
248
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataAllowFederationOnPublicShares')]
249
-	public function testCreateShareLinkPublicUpload(array $appConfig, int $permissions): void {
250
-		$this->appConfig->method('getValueBool')
251
-			->willReturnMap([$appConfig]);
252
-
253
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
254
-		$result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true');
255
-		$ocs->cleanup();
256
-
257
-		$data = $result->getData();
258
-		$this->assertEquals(
259
-			Constants::PERMISSION_READ
260
-			| Constants::PERMISSION_CREATE
261
-			| Constants::PERMISSION_UPDATE
262
-			| Constants::PERMISSION_DELETE
263
-			| $permissions,
264
-			$data['permissions']
265
-		);
266
-		$this->assertEmpty($data['expiration']);
267
-		$this->assertTrue(is_string($data['token']));
268
-
269
-		// check for correct link
270
-		$url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']);
271
-		$this->assertEquals($url, $data['url']);
272
-
273
-		$this->shareManager->getShareById('ocinternal:' . $data['id']);
274
-
275
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
276
-		$ocs->deleteShare($data['id']);
277
-		$ocs->cleanup();
278
-	}
279
-
280
-	public function testEnforceLinkPassword(): void {
281
-		$password = md5(time());
282
-		$config = Server::get(IConfig::class);
283
-		$config->setAppValue('core', 'shareapi_enforce_links_password', 'yes');
284
-
285
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
286
-		try {
287
-			$ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK);
288
-			$this->fail();
289
-		} catch (OCSForbiddenException $e) {
290
-		}
291
-		$ocs->cleanup();
292
-
293
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
294
-		try {
295
-			$ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '');
296
-			$this->fail();
297
-		} catch (OCSForbiddenException $e) {
298
-		}
299
-		$ocs->cleanup();
300
-
301
-		// share with password should succeed
302
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
303
-		$result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', $password);
304
-		$ocs->cleanup();
305
-
306
-		$data = $result->getData();
307
-
308
-		// setting new password should succeed
309
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
310
-		$ocs->updateShare($data['id'], null, $password);
311
-		$ocs->cleanup();
312
-
313
-		// removing password should fail
314
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
315
-		try {
316
-			$ocs->updateShare($data['id']);
317
-			$this->fail();
318
-		} catch (OCSBadRequestException $e) {
319
-		}
320
-		$ocs->cleanup();
321
-
322
-		// cleanup
323
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
324
-		$ocs->deleteShare($data['id']);
325
-		$ocs->cleanup();
326
-
327
-		$config->setAppValue('core', 'shareapi_enforce_links_password', 'no');
328
-		$this->addToAssertionCount(1);
329
-	}
330
-
331
-	/**
332
-	 * @medium
333
-	 */
334
-	public function testSharePermissions(): void {
335
-		// sharing file to a user should work if shareapi_exclude_groups is set
336
-		// to no
337
-		Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups', 'no');
338
-
339
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
340
-		$result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
341
-		$ocs->cleanup();
342
-
343
-		$data = $result->getData();
344
-
345
-		$this->shareManager->getShareById('ocinternal:' . $data['id']);
346
-
347
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
348
-		$ocs->deleteShare($data['id']);
349
-		$ocs->cleanup();
350
-
351
-		// exclude groups, but not the group the user belongs to. Sharing should still work
352
-		Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups', 'yes');
353
-		Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups_list', 'admin,group1,group2');
354
-
355
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
356
-		$result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
357
-		$ocs->cleanup();
358
-
359
-		$data = $result->getData();
360
-
361
-		$this->shareManager->getShareById('ocinternal:' . $data['id']);
362
-
363
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
364
-		$ocs->deleteShare($data['id']);
365
-		$ocs->cleanup();
366
-
367
-		// now we exclude the group the user belongs to ('group'), sharing should fail now
368
-		Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups_list', 'admin,group');
369
-
370
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
371
-		$ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
372
-		$ocs->cleanup();
373
-
374
-		// cleanup
375
-		Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups', 'no');
376
-		Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups_list', '');
377
-
378
-		$this->addToAssertionCount(1);
379
-	}
380
-
381
-
382
-	/**
383
-	 * @medium
384
-	 */
385
-	public function testGetAllShares(): void {
386
-		$node = $this->userFolder->get($this->filename);
387
-
388
-		$share = $this->shareManager->newShare();
389
-		$share->setNode($node)
390
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
391
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
392
-			->setShareType(IShare::TYPE_USER)
393
-			->setPermissions(19);
394
-
395
-		$share = $this->shareManager->createShare($share);
396
-
397
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
398
-		$result = $ocs->getShares();
399
-		$ocs->cleanup();
400
-
401
-		$this->assertTrue(count($result->getData()) === 1);
402
-
403
-		$this->shareManager->deleteShare($share);
404
-	}
405
-
406
-	public function testGetAllSharesWithMe(): void {
407
-		$this->loginAsUser(self::TEST_FILES_SHARING_API_USER2);
408
-		$this->logout();
409
-
410
-		$node1 = $this->userFolder->get($this->filename);
411
-		$share1 = $this->shareManager->newShare();
412
-		$share1->setNode($node1)
413
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
414
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
415
-			->setShareType(IShare::TYPE_USER)
416
-			->setPermissions(19);
417
-		$share1 = $this->shareManager->createShare($share1);
418
-		$share1->setStatus(IShare::STATUS_ACCEPTED);
419
-		$this->shareManager->updateShare($share1);
420
-
421
-		$node2 = $this->userFolder->get($this->folder);
422
-		$share2 = $this->shareManager->newShare();
423
-		$share2->setNode($node2)
424
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
425
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
426
-			->setShareType(IShare::TYPE_USER)
427
-			->setPermissions(31);
428
-		$share2 = $this->shareManager->createShare($share2);
429
-		$share2->setStatus(IShare::STATUS_ACCEPTED);
430
-		$this->shareManager->updateShare($share2);
431
-
432
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
433
-		$result = $ocs->getShares('true');
434
-		$ocs->cleanup();
435
-
436
-		$this->assertCount(2, $result->getData());
437
-
438
-		$this->shareManager->deleteShare($share1);
439
-		$this->shareManager->deleteShare($share2);
440
-	}
441
-
442
-	/**
443
-	 * @medium
444
-	 * @group RoutingWeirdness
445
-	 */
446
-	public function testPublicLinkUrl(): void {
447
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
448
-		$result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK);
449
-		$ocs->cleanup();
450
-
451
-		$data = $result->getData();
452
-
453
-		// check if we have a token
454
-		$this->assertTrue(is_string($data['token']));
455
-		$id = $data['id'];
456
-
457
-		// check for correct link
458
-		$url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']);
459
-		$this->assertEquals($url, $data['url']);
460
-
461
-		// check for link in getall shares
462
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
463
-		$result = $ocs->getShares();
464
-		$ocs->cleanup();
465
-
466
-		$data = $result->getData();
467
-		$this->assertEquals($url, current($data)['url']);
468
-
469
-		// check for path
470
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
471
-		$result = $ocs->getShares();
472
-		$ocs->cleanup();
473
-
474
-		$data = $result->getData();
475
-		$this->assertEquals($url, current($data)['url']);
476
-
477
-		// check in share id
478
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
479
-		$result = $ocs->getShare($id);
480
-		$ocs->cleanup();
481
-
482
-		$data = $result->getData();
483
-		$this->assertEquals($url, current($data)['url']);
484
-
485
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
486
-		$ocs->deleteShare($id);
487
-		$ocs->cleanup();
488
-	}
489
-
490
-	/**
491
-	 * @medium
492
-	 * @depends testCreateShareUserFile
493
-	 * @depends testCreateShareLink
494
-	 */
495
-	public function testGetShareFromSource(): void {
496
-		$node = $this->userFolder->get($this->filename);
497
-		$share = $this->shareManager->newShare();
498
-		$share->setNode($node)
499
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
500
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
501
-			->setShareType(IShare::TYPE_USER)
502
-			->setPermissions(19);
503
-		$share1 = $this->shareManager->createShare($share);
504
-
505
-		$share = $this->shareManager->newShare();
506
-		$share->setNode($node)
507
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
508
-			->setShareType(IShare::TYPE_LINK)
509
-			->setPermissions(1);
510
-		$share2 = $this->shareManager->createShare($share);
511
-
512
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
513
-		$result = $ocs->getShares();
514
-		$ocs->cleanup();
515
-
516
-		// test should return one share created from testCreateShare()
517
-		$this->assertTrue(count($result->getData()) === 2);
518
-
519
-		$this->shareManager->deleteShare($share1);
520
-		$this->shareManager->deleteShare($share2);
521
-	}
522
-
523
-	/**
524
-	 * @medium
525
-	 * @depends testCreateShareUserFile
526
-	 * @depends testCreateShareLink
527
-	 */
528
-	public function testGetShareFromSourceWithReshares(): void {
529
-		$node = $this->userFolder->get($this->filename);
530
-		$share1 = $this->shareManager->newShare();
531
-		$share1->setNode($node)
532
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
533
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
534
-			->setShareType(IShare::TYPE_USER)
535
-			->setPermissions(19);
536
-		$share1 = $this->shareManager->createShare($share1);
537
-
538
-		$share2 = $this->shareManager->newShare();
539
-		$share2->setNode($node)
540
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
541
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER3)
542
-			->setShareType(IShare::TYPE_USER)
543
-			->setPermissions(19);
544
-		$share2 = $this->shareManager->createShare($share2);
545
-
546
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
547
-		$result = $ocs->getShares();
548
-		$ocs->cleanup();
549
-
550
-		// test should return one share
551
-		$this->assertTrue(count($result->getData()) === 1);
552
-
553
-		// now also ask for the reshares
554
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
555
-		$result = $ocs->getShares('false', 'true', 'false', $this->filename);
556
-		$ocs->cleanup();
557
-
558
-		// now we should get two shares, the initial share and the reshare
559
-		$this->assertCount(2, $result->getData());
560
-
561
-		$this->shareManager->deleteShare($share1);
562
-		$this->shareManager->deleteShare($share2);
563
-	}
564
-
565
-	/**
566
-	 * @medium
567
-	 * @depends testCreateShareUserFile
568
-	 */
569
-	public function testGetShareFromId(): void {
570
-		$node = $this->userFolder->get($this->filename);
571
-		$share1 = $this->shareManager->newShare();
572
-		$share1->setNode($node)
573
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
574
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
575
-			->setShareType(IShare::TYPE_USER)
576
-			->setPermissions(19);
577
-		$share1 = $this->shareManager->createShare($share1);
578
-
579
-		// call getShare() with share ID
580
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
581
-		$result = $ocs->getShare($share1->getId());
582
-		$ocs->cleanup();
583
-
584
-		// test should return one share created from testCreateShare()
585
-		$this->assertEquals(1, count($result->getData()));
586
-
587
-		$this->shareManager->deleteShare($share1);
588
-	}
589
-
590
-	/**
591
-	 * @medium
592
-	 */
593
-	public function testGetShareFromFolder(): void {
594
-		$node1 = $this->userFolder->get($this->filename);
595
-		$share1 = $this->shareManager->newShare();
596
-		$share1->setNode($node1)
597
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
598
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
599
-			->setShareType(IShare::TYPE_USER)
600
-			->setPermissions(19);
601
-		$share1 = $this->shareManager->createShare($share1);
602
-
603
-		$node2 = $this->userFolder->get($this->folder . '/' . $this->filename);
604
-		$share2 = $this->shareManager->newShare();
605
-		$share2->setNode($node2)
606
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
607
-			->setShareType(IShare::TYPE_LINK)
608
-			->setPermissions(1);
609
-		$share2 = $this->shareManager->createShare($share2);
610
-
611
-
612
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
613
-		$result = $ocs->getShares('false', 'false', 'true', $this->folder);
614
-		$ocs->cleanup();
615
-
616
-		// test should return one share within $this->folder
617
-		$this->assertTrue(count($result->getData()) === 1);
618
-
619
-		$this->shareManager->deleteShare($share1);
620
-		$this->shareManager->deleteShare($share2);
621
-	}
622
-
623
-	public function testGetShareFromFolderWithFile(): void {
624
-		$node1 = $this->userFolder->get($this->filename);
625
-		$share1 = $this->shareManager->newShare();
626
-		$share1->setNode($node1)
627
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
628
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
629
-			->setShareType(IShare::TYPE_USER)
630
-			->setPermissions(19);
631
-		$share1 = $this->shareManager->createShare($share1);
632
-
633
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
634
-		try {
635
-			$ocs->getShares('false', 'false', 'true', $this->filename);
636
-			$this->fail();
637
-		} catch (OCSBadRequestException $e) {
638
-			$this->assertEquals('Not a directory', $e->getMessage());
639
-		}
640
-		$ocs->cleanup();
641
-
642
-		$this->shareManager->deleteShare($share1);
643
-	}
644
-
645
-	/**
646
-	 * share a folder, than reshare a file within the shared folder and check if we construct the correct path
647
-	 * @medium
648
-	 */
649
-	public function testGetShareFromFolderReshares(): void {
650
-		$node1 = $this->userFolder->get($this->folder);
651
-		$share1 = $this->shareManager->newShare();
652
-		$share1->setNode($node1)
653
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
654
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
655
-			->setShareType(IShare::TYPE_USER)
656
-			->setPermissions(31);
657
-		$share1 = $this->shareManager->createShare($share1);
658
-		$share1->setStatus(IShare::STATUS_ACCEPTED);
659
-		$this->shareManager->updateShare($share1);
660
-
661
-		$node2 = $this->userFolder->get($this->folder . '/' . $this->filename);
662
-		$share2 = $this->shareManager->newShare();
663
-		$share2->setNode($node2)
664
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
665
-			->setShareType(IShare::TYPE_LINK)
666
-			->setPermissions(1);
667
-		$share2 = $this->shareManager->createShare($share2);
668
-		$share2->setStatus(IShare::STATUS_ACCEPTED);
669
-		$this->shareManager->updateShare($share2);
670
-
671
-		$node3 = $this->userFolder->get($this->folder . '/' . $this->subfolder . '/' . $this->filename);
672
-		$share3 = $this->shareManager->newShare();
673
-		$share3->setNode($node3)
674
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
675
-			->setShareType(IShare::TYPE_LINK)
676
-			->setPermissions(1);
677
-		$share3 = $this->shareManager->createShare($share3);
678
-		$share3->setStatus(IShare::STATUS_ACCEPTED);
679
-		$this->shareManager->updateShare($share3);
680
-
681
-		$testValues = [
682
-			['query' => $this->folder,
683
-				'expectedResult' => $this->folder . $this->filename],
684
-			['query' => $this->folder . $this->subfolder,
685
-				'expectedResult' => $this->folder . $this->subfolder . $this->filename],
686
-		];
687
-
688
-		foreach ($testValues as $value) {
689
-			$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
690
-			$result = $ocs->getShares('false', 'false', 'true', $value['query']);
691
-			$ocs->cleanup();
692
-
693
-			// test should return one share within $this->folder
694
-			$data = $result->getData();
695
-
696
-			$this->assertEquals($value['expectedResult'], $data[0]['path']);
697
-		}
698
-
699
-		// cleanup
700
-		$this->shareManager->deleteShare($share1);
701
-		$this->shareManager->deleteShare($share2);
702
-		$this->shareManager->deleteShare($share3);
703
-	}
704
-
705
-	/**
706
-	 * reshare a sub folder and check if we get the correct path
707
-	 * @medium
708
-	 */
709
-	public function testGetShareFromSubFolderReShares(): void {
710
-		$node1 = $this->userFolder->get($this->folder . $this->subfolder);
711
-		$share1 = $this->shareManager->newShare();
712
-		$share1->setNode($node1)
713
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
714
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
715
-			->setShareType(IShare::TYPE_USER)
716
-			->setPermissions(31);
717
-		$share1 = $this->shareManager->createShare($share1);
718
-		$share1->setStatus(IShare::STATUS_ACCEPTED);
719
-		$this->shareManager->updateShare($share1);
720
-
721
-		$node2 = Server::get(IRootFolder::class)->getUserFolder(self::TEST_FILES_SHARING_API_USER2)->get($this->subfolder);
722
-		$share2 = $this->shareManager->newShare();
723
-		$share2->setNode($node2)
724
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
725
-			->setShareType(IShare::TYPE_LINK)
726
-			->setPermissions(1);
727
-		$share2 = $this->shareManager->createShare($share2);
728
-		$share2->setStatus(IShare::STATUS_ACCEPTED);
729
-		$this->shareManager->updateShare($share2);
730
-
731
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
732
-		$result = $ocs->getShares();
733
-		$ocs->cleanup();
734
-
735
-		// test should return one share within $this->folder
736
-		$data = $result->getData();
737
-
738
-		// we should get exactly one result
739
-		$this->assertCount(1, $data);
740
-
741
-		$this->assertEquals($this->subfolder, $data[0]['path']);
742
-
743
-		$this->shareManager->deleteShare($share2);
744
-		$this->shareManager->deleteShare($share1);
745
-	}
746
-
747
-	/**
748
-	 * test re-re-share of folder if the path gets constructed correctly
749
-	 * @medium
750
-	 */
751
-	public function XtestGetShareFromFolderReReShares() {
752
-		$node1 = $this->userFolder->get($this->folder . $this->subfolder);
753
-		$share1 = $this->shareManager->newShare();
754
-		$share1->setNode($node1)
755
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
756
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
757
-			->setShareType(IShare::TYPE_USER)
758
-			->setPermissions(31);
759
-		$share1 = $this->shareManager->createShare($share1);
760
-
761
-		$node2 = $this->userFolder->get($this->folder . $this->subfolder . $this->subsubfolder);
762
-		$share2 = $this->shareManager->newShare();
763
-		$share2->setNode($node2)
764
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
765
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER3)
766
-			->setShareType(IShare::TYPE_USER)
767
-			->setPermissions(31);
768
-		$share2 = $this->shareManager->createShare($share2);
769
-
770
-		$share3 = $this->shareManager->newShare();
771
-		$share3->setNode($node2)
772
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER3)
773
-			->setShareType(IShare::TYPE_LINK)
774
-			->setPermissions(1);
775
-		$share3 = $this->shareManager->createShare($share3);
776
-
777
-		/*
53
+    use EmailValidatorTrait;
54
+
55
+    public const TEST_FOLDER_NAME = '/folder_share_api_test';
56
+    public const APP_NAME = 'files_sharing';
57
+
58
+    private static $tempStorage;
59
+
60
+    private Folder $userFolder;
61
+    private string $subsubfolder;
62
+    protected IAppConfig&MockObject $appConfig;
63
+
64
+    protected function setUp(): void {
65
+        parent::setUp();
66
+
67
+        Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups', 'no');
68
+        Server::get(IConfig::class)->setAppValue('core', 'shareapi_expire_after_n_days', '7');
69
+
70
+        Filesystem::getLoader()->removeStorageWrapper('sharing_mask');
71
+
72
+        $this->folder = self::TEST_FOLDER_NAME;
73
+        $this->subfolder = '/subfolder_share_api_test';
74
+        $this->subsubfolder = '/subsubfolder_share_api_test';
75
+
76
+        $this->filename = '/share-api-test.txt';
77
+
78
+        // save file with content
79
+        $this->view->file_put_contents($this->filename, $this->data);
80
+        $this->view->mkdir($this->folder);
81
+        $this->view->mkdir($this->folder . $this->subfolder);
82
+        $this->view->mkdir($this->folder . $this->subfolder . $this->subsubfolder);
83
+        $this->view->file_put_contents($this->folder . $this->filename, $this->data);
84
+        $this->view->file_put_contents($this->folder . $this->subfolder . $this->filename, $this->data);
85
+        $mount = $this->view->getMount($this->filename);
86
+        $mount->getStorage()->getScanner()->scan('', Scanner::SCAN_RECURSIVE);
87
+
88
+        $this->userFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1);
89
+
90
+        $this->appConfig = $this->createMock(IAppConfig::class);
91
+    }
92
+
93
+    protected function tearDown(): void {
94
+        if ($this->view instanceof View) {
95
+            $this->view->unlink($this->filename);
96
+            $this->view->deleteAll($this->folder);
97
+        }
98
+
99
+        self::$tempStorage = null;
100
+
101
+        parent::tearDown();
102
+    }
103
+
104
+    /**
105
+     * @param string $userId The userId of the caller
106
+     * @return ShareAPIController
107
+     */
108
+    private function createOCS($userId) {
109
+        $l = $this->getMockBuilder(IL10N::class)->getMock();
110
+        $l->method('t')
111
+            ->willReturnCallback(function ($text, $parameters = []) {
112
+                return vsprintf($text, $parameters);
113
+            });
114
+        $config = $this->createMock(IConfig::class);
115
+        $appManager = $this->createMock(IAppManager::class);
116
+        $serverContainer = $this->createMock(ContainerInterface::class);
117
+        $userStatusManager = $this->createMock(IUserStatusManager::class);
118
+        $previewManager = $this->createMock(IPreview::class);
119
+        $dateTimeZone = $this->createMock(IDateTimeZone::class);
120
+        $logger = $this->createMock(LoggerInterface::class);
121
+        $providerFactory = $this->createMock(IProviderFactory::class);
122
+        $mailer = $this->createMock(IMailer::class);
123
+        $tagManager = $this->createMock(ITagManager::class);
124
+        $trustedServers = $this->createMock(TrustedServers::class);
125
+        $dateTimeZone->method('getTimeZone')->willReturn(new \DateTimeZone(date_default_timezone_get()));
126
+
127
+        return new ShareAPIController(
128
+            self::APP_NAME,
129
+            $this->getMockBuilder(IRequest::class)->getMock(),
130
+            $this->shareManager,
131
+            Server::get(IGroupManager::class),
132
+            Server::get(IUserManager::class),
133
+            Server::get(IRootFolder::class),
134
+            Server::get(IURLGenerator::class),
135
+            $l,
136
+            $config,
137
+            $this->appConfig,
138
+            $appManager,
139
+            $serverContainer,
140
+            $userStatusManager,
141
+            $previewManager,
142
+            $dateTimeZone,
143
+            $logger,
144
+            $providerFactory,
145
+            $mailer,
146
+            $tagManager,
147
+            $this->getEmailValidatorWithStrictEmailCheck(),
148
+            $trustedServers,
149
+            $userId,
150
+        );
151
+    }
152
+
153
+    public function testCreateShareUserFile(): void {
154
+        $this->setUp(); // for some reasons phpunit refuses to do this for us only for this test
155
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
156
+        $result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
157
+        $ocs->cleanup();
158
+
159
+        $data = $result->getData();
160
+        $this->assertEquals(19, $data['permissions']);
161
+        $this->assertEmpty($data['expiration']);
162
+
163
+        $this->shareManager->getShareById('ocinternal:' . $data['id']);
164
+
165
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
166
+        $ocs->deleteShare($data['id']);
167
+
168
+        $ocs->cleanup();
169
+    }
170
+
171
+    public function testCreateShareUserFolder(): void {
172
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
173
+        $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
174
+        $ocs->cleanup();
175
+
176
+        $data = $result->getData();
177
+        $this->assertEquals(31, $data['permissions']);
178
+        $this->assertEmpty($data['expiration']);
179
+
180
+        $this->shareManager->getShareById('ocinternal:' . $data['id']);
181
+
182
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
183
+        $ocs->deleteShare($data['id']);
184
+        $ocs->cleanup();
185
+    }
186
+
187
+
188
+    public function testCreateShareGroupFile(): void {
189
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
190
+        $result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_GROUP, self::TEST_FILES_SHARING_API_GROUP1);
191
+        $ocs->cleanup();
192
+
193
+        $data = $result->getData();
194
+        $this->assertEquals(19, $data['permissions']);
195
+        $this->assertEmpty($data['expiration']);
196
+
197
+        $this->shareManager->getShareById('ocinternal:' . $data['id']);
198
+
199
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
200
+        $ocs->deleteShare($data['id']);
201
+        $ocs->cleanup();
202
+    }
203
+
204
+    public function testCreateShareGroupFolder(): void {
205
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
206
+        $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_GROUP, self::TEST_FILES_SHARING_API_GROUP1);
207
+        $ocs->cleanup();
208
+
209
+        $data = $result->getData();
210
+        $this->assertEquals(31, $data['permissions']);
211
+        $this->assertEmpty($data['expiration']);
212
+
213
+        $this->shareManager->getShareById('ocinternal:' . $data['id']);
214
+
215
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
216
+        $ocs->deleteShare($data['id']);
217
+        $ocs->cleanup();
218
+    }
219
+
220
+    /**
221
+     * @group RoutingWeirdness
222
+     */
223
+    public function testCreateShareLink(): void {
224
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
225
+        $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK);
226
+        $ocs->cleanup();
227
+
228
+        $data = $result->getData();
229
+        $this->assertEquals(Constants::PERMISSION_ALL,
230
+            $data['permissions']);
231
+        $this->assertEmpty($data['expiration']);
232
+        $this->assertTrue(is_string($data['token']));
233
+
234
+        // check for correct link
235
+        $url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']);
236
+        $this->assertEquals($url, $data['url']);
237
+
238
+        $this->shareManager->getShareById('ocinternal:' . $data['id']);
239
+
240
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
241
+        $ocs->deleteShare($data['id']);
242
+        $ocs->cleanup();
243
+    }
244
+
245
+    /**
246
+     * @group RoutingWeirdness
247
+     */
248
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataAllowFederationOnPublicShares')]
249
+    public function testCreateShareLinkPublicUpload(array $appConfig, int $permissions): void {
250
+        $this->appConfig->method('getValueBool')
251
+            ->willReturnMap([$appConfig]);
252
+
253
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
254
+        $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true');
255
+        $ocs->cleanup();
256
+
257
+        $data = $result->getData();
258
+        $this->assertEquals(
259
+            Constants::PERMISSION_READ
260
+            | Constants::PERMISSION_CREATE
261
+            | Constants::PERMISSION_UPDATE
262
+            | Constants::PERMISSION_DELETE
263
+            | $permissions,
264
+            $data['permissions']
265
+        );
266
+        $this->assertEmpty($data['expiration']);
267
+        $this->assertTrue(is_string($data['token']));
268
+
269
+        // check for correct link
270
+        $url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']);
271
+        $this->assertEquals($url, $data['url']);
272
+
273
+        $this->shareManager->getShareById('ocinternal:' . $data['id']);
274
+
275
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
276
+        $ocs->deleteShare($data['id']);
277
+        $ocs->cleanup();
278
+    }
279
+
280
+    public function testEnforceLinkPassword(): void {
281
+        $password = md5(time());
282
+        $config = Server::get(IConfig::class);
283
+        $config->setAppValue('core', 'shareapi_enforce_links_password', 'yes');
284
+
285
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
286
+        try {
287
+            $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK);
288
+            $this->fail();
289
+        } catch (OCSForbiddenException $e) {
290
+        }
291
+        $ocs->cleanup();
292
+
293
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
294
+        try {
295
+            $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '');
296
+            $this->fail();
297
+        } catch (OCSForbiddenException $e) {
298
+        }
299
+        $ocs->cleanup();
300
+
301
+        // share with password should succeed
302
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
303
+        $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', $password);
304
+        $ocs->cleanup();
305
+
306
+        $data = $result->getData();
307
+
308
+        // setting new password should succeed
309
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
310
+        $ocs->updateShare($data['id'], null, $password);
311
+        $ocs->cleanup();
312
+
313
+        // removing password should fail
314
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
315
+        try {
316
+            $ocs->updateShare($data['id']);
317
+            $this->fail();
318
+        } catch (OCSBadRequestException $e) {
319
+        }
320
+        $ocs->cleanup();
321
+
322
+        // cleanup
323
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
324
+        $ocs->deleteShare($data['id']);
325
+        $ocs->cleanup();
326
+
327
+        $config->setAppValue('core', 'shareapi_enforce_links_password', 'no');
328
+        $this->addToAssertionCount(1);
329
+    }
330
+
331
+    /**
332
+     * @medium
333
+     */
334
+    public function testSharePermissions(): void {
335
+        // sharing file to a user should work if shareapi_exclude_groups is set
336
+        // to no
337
+        Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups', 'no');
338
+
339
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
340
+        $result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
341
+        $ocs->cleanup();
342
+
343
+        $data = $result->getData();
344
+
345
+        $this->shareManager->getShareById('ocinternal:' . $data['id']);
346
+
347
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
348
+        $ocs->deleteShare($data['id']);
349
+        $ocs->cleanup();
350
+
351
+        // exclude groups, but not the group the user belongs to. Sharing should still work
352
+        Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups', 'yes');
353
+        Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups_list', 'admin,group1,group2');
354
+
355
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
356
+        $result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
357
+        $ocs->cleanup();
358
+
359
+        $data = $result->getData();
360
+
361
+        $this->shareManager->getShareById('ocinternal:' . $data['id']);
362
+
363
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
364
+        $ocs->deleteShare($data['id']);
365
+        $ocs->cleanup();
366
+
367
+        // now we exclude the group the user belongs to ('group'), sharing should fail now
368
+        Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups_list', 'admin,group');
369
+
370
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
371
+        $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
372
+        $ocs->cleanup();
373
+
374
+        // cleanup
375
+        Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups', 'no');
376
+        Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups_list', '');
377
+
378
+        $this->addToAssertionCount(1);
379
+    }
380
+
381
+
382
+    /**
383
+     * @medium
384
+     */
385
+    public function testGetAllShares(): void {
386
+        $node = $this->userFolder->get($this->filename);
387
+
388
+        $share = $this->shareManager->newShare();
389
+        $share->setNode($node)
390
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
391
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
392
+            ->setShareType(IShare::TYPE_USER)
393
+            ->setPermissions(19);
394
+
395
+        $share = $this->shareManager->createShare($share);
396
+
397
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
398
+        $result = $ocs->getShares();
399
+        $ocs->cleanup();
400
+
401
+        $this->assertTrue(count($result->getData()) === 1);
402
+
403
+        $this->shareManager->deleteShare($share);
404
+    }
405
+
406
+    public function testGetAllSharesWithMe(): void {
407
+        $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2);
408
+        $this->logout();
409
+
410
+        $node1 = $this->userFolder->get($this->filename);
411
+        $share1 = $this->shareManager->newShare();
412
+        $share1->setNode($node1)
413
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
414
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
415
+            ->setShareType(IShare::TYPE_USER)
416
+            ->setPermissions(19);
417
+        $share1 = $this->shareManager->createShare($share1);
418
+        $share1->setStatus(IShare::STATUS_ACCEPTED);
419
+        $this->shareManager->updateShare($share1);
420
+
421
+        $node2 = $this->userFolder->get($this->folder);
422
+        $share2 = $this->shareManager->newShare();
423
+        $share2->setNode($node2)
424
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
425
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
426
+            ->setShareType(IShare::TYPE_USER)
427
+            ->setPermissions(31);
428
+        $share2 = $this->shareManager->createShare($share2);
429
+        $share2->setStatus(IShare::STATUS_ACCEPTED);
430
+        $this->shareManager->updateShare($share2);
431
+
432
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
433
+        $result = $ocs->getShares('true');
434
+        $ocs->cleanup();
435
+
436
+        $this->assertCount(2, $result->getData());
437
+
438
+        $this->shareManager->deleteShare($share1);
439
+        $this->shareManager->deleteShare($share2);
440
+    }
441
+
442
+    /**
443
+     * @medium
444
+     * @group RoutingWeirdness
445
+     */
446
+    public function testPublicLinkUrl(): void {
447
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
448
+        $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK);
449
+        $ocs->cleanup();
450
+
451
+        $data = $result->getData();
452
+
453
+        // check if we have a token
454
+        $this->assertTrue(is_string($data['token']));
455
+        $id = $data['id'];
456
+
457
+        // check for correct link
458
+        $url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']);
459
+        $this->assertEquals($url, $data['url']);
460
+
461
+        // check for link in getall shares
462
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
463
+        $result = $ocs->getShares();
464
+        $ocs->cleanup();
465
+
466
+        $data = $result->getData();
467
+        $this->assertEquals($url, current($data)['url']);
468
+
469
+        // check for path
470
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
471
+        $result = $ocs->getShares();
472
+        $ocs->cleanup();
473
+
474
+        $data = $result->getData();
475
+        $this->assertEquals($url, current($data)['url']);
476
+
477
+        // check in share id
478
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
479
+        $result = $ocs->getShare($id);
480
+        $ocs->cleanup();
481
+
482
+        $data = $result->getData();
483
+        $this->assertEquals($url, current($data)['url']);
484
+
485
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
486
+        $ocs->deleteShare($id);
487
+        $ocs->cleanup();
488
+    }
489
+
490
+    /**
491
+     * @medium
492
+     * @depends testCreateShareUserFile
493
+     * @depends testCreateShareLink
494
+     */
495
+    public function testGetShareFromSource(): void {
496
+        $node = $this->userFolder->get($this->filename);
497
+        $share = $this->shareManager->newShare();
498
+        $share->setNode($node)
499
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
500
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
501
+            ->setShareType(IShare::TYPE_USER)
502
+            ->setPermissions(19);
503
+        $share1 = $this->shareManager->createShare($share);
504
+
505
+        $share = $this->shareManager->newShare();
506
+        $share->setNode($node)
507
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
508
+            ->setShareType(IShare::TYPE_LINK)
509
+            ->setPermissions(1);
510
+        $share2 = $this->shareManager->createShare($share);
511
+
512
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
513
+        $result = $ocs->getShares();
514
+        $ocs->cleanup();
515
+
516
+        // test should return one share created from testCreateShare()
517
+        $this->assertTrue(count($result->getData()) === 2);
518
+
519
+        $this->shareManager->deleteShare($share1);
520
+        $this->shareManager->deleteShare($share2);
521
+    }
522
+
523
+    /**
524
+     * @medium
525
+     * @depends testCreateShareUserFile
526
+     * @depends testCreateShareLink
527
+     */
528
+    public function testGetShareFromSourceWithReshares(): void {
529
+        $node = $this->userFolder->get($this->filename);
530
+        $share1 = $this->shareManager->newShare();
531
+        $share1->setNode($node)
532
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
533
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
534
+            ->setShareType(IShare::TYPE_USER)
535
+            ->setPermissions(19);
536
+        $share1 = $this->shareManager->createShare($share1);
537
+
538
+        $share2 = $this->shareManager->newShare();
539
+        $share2->setNode($node)
540
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
541
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER3)
542
+            ->setShareType(IShare::TYPE_USER)
543
+            ->setPermissions(19);
544
+        $share2 = $this->shareManager->createShare($share2);
545
+
546
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
547
+        $result = $ocs->getShares();
548
+        $ocs->cleanup();
549
+
550
+        // test should return one share
551
+        $this->assertTrue(count($result->getData()) === 1);
552
+
553
+        // now also ask for the reshares
554
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
555
+        $result = $ocs->getShares('false', 'true', 'false', $this->filename);
556
+        $ocs->cleanup();
557
+
558
+        // now we should get two shares, the initial share and the reshare
559
+        $this->assertCount(2, $result->getData());
560
+
561
+        $this->shareManager->deleteShare($share1);
562
+        $this->shareManager->deleteShare($share2);
563
+    }
564
+
565
+    /**
566
+     * @medium
567
+     * @depends testCreateShareUserFile
568
+     */
569
+    public function testGetShareFromId(): void {
570
+        $node = $this->userFolder->get($this->filename);
571
+        $share1 = $this->shareManager->newShare();
572
+        $share1->setNode($node)
573
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
574
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
575
+            ->setShareType(IShare::TYPE_USER)
576
+            ->setPermissions(19);
577
+        $share1 = $this->shareManager->createShare($share1);
578
+
579
+        // call getShare() with share ID
580
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
581
+        $result = $ocs->getShare($share1->getId());
582
+        $ocs->cleanup();
583
+
584
+        // test should return one share created from testCreateShare()
585
+        $this->assertEquals(1, count($result->getData()));
586
+
587
+        $this->shareManager->deleteShare($share1);
588
+    }
589
+
590
+    /**
591
+     * @medium
592
+     */
593
+    public function testGetShareFromFolder(): void {
594
+        $node1 = $this->userFolder->get($this->filename);
595
+        $share1 = $this->shareManager->newShare();
596
+        $share1->setNode($node1)
597
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
598
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
599
+            ->setShareType(IShare::TYPE_USER)
600
+            ->setPermissions(19);
601
+        $share1 = $this->shareManager->createShare($share1);
602
+
603
+        $node2 = $this->userFolder->get($this->folder . '/' . $this->filename);
604
+        $share2 = $this->shareManager->newShare();
605
+        $share2->setNode($node2)
606
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
607
+            ->setShareType(IShare::TYPE_LINK)
608
+            ->setPermissions(1);
609
+        $share2 = $this->shareManager->createShare($share2);
610
+
611
+
612
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
613
+        $result = $ocs->getShares('false', 'false', 'true', $this->folder);
614
+        $ocs->cleanup();
615
+
616
+        // test should return one share within $this->folder
617
+        $this->assertTrue(count($result->getData()) === 1);
618
+
619
+        $this->shareManager->deleteShare($share1);
620
+        $this->shareManager->deleteShare($share2);
621
+    }
622
+
623
+    public function testGetShareFromFolderWithFile(): void {
624
+        $node1 = $this->userFolder->get($this->filename);
625
+        $share1 = $this->shareManager->newShare();
626
+        $share1->setNode($node1)
627
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
628
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
629
+            ->setShareType(IShare::TYPE_USER)
630
+            ->setPermissions(19);
631
+        $share1 = $this->shareManager->createShare($share1);
632
+
633
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
634
+        try {
635
+            $ocs->getShares('false', 'false', 'true', $this->filename);
636
+            $this->fail();
637
+        } catch (OCSBadRequestException $e) {
638
+            $this->assertEquals('Not a directory', $e->getMessage());
639
+        }
640
+        $ocs->cleanup();
641
+
642
+        $this->shareManager->deleteShare($share1);
643
+    }
644
+
645
+    /**
646
+     * share a folder, than reshare a file within the shared folder and check if we construct the correct path
647
+     * @medium
648
+     */
649
+    public function testGetShareFromFolderReshares(): void {
650
+        $node1 = $this->userFolder->get($this->folder);
651
+        $share1 = $this->shareManager->newShare();
652
+        $share1->setNode($node1)
653
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
654
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
655
+            ->setShareType(IShare::TYPE_USER)
656
+            ->setPermissions(31);
657
+        $share1 = $this->shareManager->createShare($share1);
658
+        $share1->setStatus(IShare::STATUS_ACCEPTED);
659
+        $this->shareManager->updateShare($share1);
660
+
661
+        $node2 = $this->userFolder->get($this->folder . '/' . $this->filename);
662
+        $share2 = $this->shareManager->newShare();
663
+        $share2->setNode($node2)
664
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
665
+            ->setShareType(IShare::TYPE_LINK)
666
+            ->setPermissions(1);
667
+        $share2 = $this->shareManager->createShare($share2);
668
+        $share2->setStatus(IShare::STATUS_ACCEPTED);
669
+        $this->shareManager->updateShare($share2);
670
+
671
+        $node3 = $this->userFolder->get($this->folder . '/' . $this->subfolder . '/' . $this->filename);
672
+        $share3 = $this->shareManager->newShare();
673
+        $share3->setNode($node3)
674
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
675
+            ->setShareType(IShare::TYPE_LINK)
676
+            ->setPermissions(1);
677
+        $share3 = $this->shareManager->createShare($share3);
678
+        $share3->setStatus(IShare::STATUS_ACCEPTED);
679
+        $this->shareManager->updateShare($share3);
680
+
681
+        $testValues = [
682
+            ['query' => $this->folder,
683
+                'expectedResult' => $this->folder . $this->filename],
684
+            ['query' => $this->folder . $this->subfolder,
685
+                'expectedResult' => $this->folder . $this->subfolder . $this->filename],
686
+        ];
687
+
688
+        foreach ($testValues as $value) {
689
+            $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
690
+            $result = $ocs->getShares('false', 'false', 'true', $value['query']);
691
+            $ocs->cleanup();
692
+
693
+            // test should return one share within $this->folder
694
+            $data = $result->getData();
695
+
696
+            $this->assertEquals($value['expectedResult'], $data[0]['path']);
697
+        }
698
+
699
+        // cleanup
700
+        $this->shareManager->deleteShare($share1);
701
+        $this->shareManager->deleteShare($share2);
702
+        $this->shareManager->deleteShare($share3);
703
+    }
704
+
705
+    /**
706
+     * reshare a sub folder and check if we get the correct path
707
+     * @medium
708
+     */
709
+    public function testGetShareFromSubFolderReShares(): void {
710
+        $node1 = $this->userFolder->get($this->folder . $this->subfolder);
711
+        $share1 = $this->shareManager->newShare();
712
+        $share1->setNode($node1)
713
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
714
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
715
+            ->setShareType(IShare::TYPE_USER)
716
+            ->setPermissions(31);
717
+        $share1 = $this->shareManager->createShare($share1);
718
+        $share1->setStatus(IShare::STATUS_ACCEPTED);
719
+        $this->shareManager->updateShare($share1);
720
+
721
+        $node2 = Server::get(IRootFolder::class)->getUserFolder(self::TEST_FILES_SHARING_API_USER2)->get($this->subfolder);
722
+        $share2 = $this->shareManager->newShare();
723
+        $share2->setNode($node2)
724
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
725
+            ->setShareType(IShare::TYPE_LINK)
726
+            ->setPermissions(1);
727
+        $share2 = $this->shareManager->createShare($share2);
728
+        $share2->setStatus(IShare::STATUS_ACCEPTED);
729
+        $this->shareManager->updateShare($share2);
730
+
731
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
732
+        $result = $ocs->getShares();
733
+        $ocs->cleanup();
734
+
735
+        // test should return one share within $this->folder
736
+        $data = $result->getData();
737
+
738
+        // we should get exactly one result
739
+        $this->assertCount(1, $data);
740
+
741
+        $this->assertEquals($this->subfolder, $data[0]['path']);
742
+
743
+        $this->shareManager->deleteShare($share2);
744
+        $this->shareManager->deleteShare($share1);
745
+    }
746
+
747
+    /**
748
+     * test re-re-share of folder if the path gets constructed correctly
749
+     * @medium
750
+     */
751
+    public function XtestGetShareFromFolderReReShares() {
752
+        $node1 = $this->userFolder->get($this->folder . $this->subfolder);
753
+        $share1 = $this->shareManager->newShare();
754
+        $share1->setNode($node1)
755
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
756
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
757
+            ->setShareType(IShare::TYPE_USER)
758
+            ->setPermissions(31);
759
+        $share1 = $this->shareManager->createShare($share1);
760
+
761
+        $node2 = $this->userFolder->get($this->folder . $this->subfolder . $this->subsubfolder);
762
+        $share2 = $this->shareManager->newShare();
763
+        $share2->setNode($node2)
764
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
765
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER3)
766
+            ->setShareType(IShare::TYPE_USER)
767
+            ->setPermissions(31);
768
+        $share2 = $this->shareManager->createShare($share2);
769
+
770
+        $share3 = $this->shareManager->newShare();
771
+        $share3->setNode($node2)
772
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER3)
773
+            ->setShareType(IShare::TYPE_LINK)
774
+            ->setPermissions(1);
775
+        $share3 = $this->shareManager->createShare($share3);
776
+
777
+        /*
778 778
 		 * Test as recipient
779 779
 		 */
780
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER3);
781
-		$result = $ocs->getShares();
782
-		$ocs->cleanup();
780
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER3);
781
+        $result = $ocs->getShares();
782
+        $ocs->cleanup();
783 783
 
784
-		// test should return one share within $this->folder
785
-		$data = $result->getData();
784
+        // test should return one share within $this->folder
785
+        $data = $result->getData();
786 786
 
787
-		// we should get exactly one result
788
-		$this->assertCount(1, $data);
789
-		$this->assertEquals($this->subsubfolder, $data[0]['path']);
787
+        // we should get exactly one result
788
+        $this->assertCount(1, $data);
789
+        $this->assertEquals($this->subsubfolder, $data[0]['path']);
790 790
 
791
-		/*
791
+        /*
792 792
 		 * Test for first owner/initiator
793 793
 		 */
794
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
795
-		$result = $ocs->getShares();
796
-		$ocs->cleanup();
794
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
795
+        $result = $ocs->getShares();
796
+        $ocs->cleanup();
797 797
 
798
-		// test should return one share within $this->folder
799
-		$data = $result->getData();
798
+        // test should return one share within $this->folder
799
+        $data = $result->getData();
800 800
 
801
-		// we should get exactly one result
802
-		$this->assertCount(1, $data);
803
-		$this->assertEquals($this->folder . $this->subfolder, $data[0]['path']);
801
+        // we should get exactly one result
802
+        $this->assertCount(1, $data);
803
+        $this->assertEquals($this->folder . $this->subfolder, $data[0]['path']);
804 804
 
805
-		/*
805
+        /*
806 806
 		 * Test for second initiator
807 807
 		 */
808
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
809
-		$result = $ocs->getShares();
810
-		$ocs->cleanup();
811
-
812
-		// test should return one share within $this->folder
813
-		$data = $result->getData();
814
-
815
-		// we should get exactly one result
816
-		$this->assertCount(1, $data);
817
-		$this->assertEquals($this->subfolder . $this->subsubfolder, $data[0]['path']);
818
-
819
-		$this->shareManager->deleteShare($share1);
820
-		$this->shareManager->deleteShare($share2);
821
-		$this->shareManager->deleteShare($share3);
822
-	}
823
-
824
-	/**
825
-	 * test multiple shared folder if the path gets constructed correctly
826
-	 * @medium
827
-	 */
828
-	public function testGetShareMultipleSharedFolder(): void {
829
-		$this->setUp();
830
-		$node1 = $this->userFolder->get($this->folder . $this->subfolder);
831
-		$share1 = $this->shareManager->newShare();
832
-		$share1->setNode($node1)
833
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
834
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
835
-			->setShareType(IShare::TYPE_USER)
836
-			->setPermissions(31);
837
-		$share1 = $this->shareManager->createShare($share1);
838
-		$share1->setStatus(IShare::STATUS_ACCEPTED);
839
-		$this->shareManager->updateShare($share1);
840
-
841
-		$node2 = $this->userFolder->get($this->folder);
842
-		$share2 = $this->shareManager->newShare();
843
-		$share2->setNode($node2)
844
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
845
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
846
-			->setShareType(IShare::TYPE_USER)
847
-			->setPermissions(31);
848
-		$share2 = $this->shareManager->createShare($share2);
849
-		$share2->setStatus(IShare::STATUS_ACCEPTED);
850
-		$this->shareManager->updateShare($share2);
851
-
852
-		$share3 = $this->shareManager->newShare();
853
-		$share3->setNode($node1)
854
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
855
-			->setShareType(IShare::TYPE_LINK)
856
-			->setPermissions(1);
857
-		$share3 = $this->shareManager->createShare($share3);
858
-		$share3->setStatus(IShare::STATUS_ACCEPTED);
859
-		$this->shareManager->updateShare($share3);
860
-
861
-		// $request = $this->createRequest(['path' => $this->subfolder]);
862
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
863
-		$result1 = $ocs->getShares('false', 'false', 'false', $this->subfolder);
864
-		$ocs->cleanup();
865
-
866
-		// test should return one share within $this->folder
867
-		$data1 = $result1->getData();
868
-		$this->assertCount(1, $data1);
869
-		$s1 = reset($data1);
870
-
871
-		//$request = $this->createRequest(['path' => $this->folder.$this->subfolder]);
872
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
873
-		$result2 = $ocs->getShares('false', 'false', 'false', $this->folder . $this->subfolder);
874
-		$ocs->cleanup();
875
-
876
-		// test should return one share within $this->folder
877
-		$data2 = $result2->getData();
878
-		$this->assertCount(1, $data2);
879
-		$s2 = reset($data2);
880
-
881
-		$this->assertEquals($this->subfolder, $s1['path']);
882
-		$this->assertEquals($this->folder . $this->subfolder, $s2['path']);
883
-
884
-		$this->shareManager->deleteShare($share1);
885
-		$this->shareManager->deleteShare($share2);
886
-		$this->shareManager->deleteShare($share3);
887
-	}
888
-
889
-	/**
890
-	 * test re-re-share of folder if the path gets constructed correctly
891
-	 * @medium
892
-	 */
893
-	public function testGetShareFromFileReReShares(): void {
894
-		$node1 = $this->userFolder->get($this->folder . $this->subfolder);
895
-		$share1 = $this->shareManager->newShare();
896
-		$share1->setNode($node1)
897
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
898
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
899
-			->setShareType(IShare::TYPE_USER)
900
-			->setPermissions(31);
901
-		$share1 = $this->shareManager->createShare($share1);
902
-		$share1->setStatus(IShare::STATUS_ACCEPTED);
903
-		$this->shareManager->updateShare($share1);
904
-
905
-		$user2Folder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER2);
906
-		$node2 = $user2Folder->get($this->subfolder . $this->filename);
907
-		$share2 = $this->shareManager->newShare();
908
-		$share2->setNode($node2)
909
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
910
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER3)
911
-			->setShareType(IShare::TYPE_USER)
912
-			->setPermissions(19);
913
-		$share2 = $this->shareManager->createShare($share2);
914
-		$share2->setStatus(IShare::STATUS_ACCEPTED);
915
-		$this->shareManager->updateShare($share2);
916
-
917
-		$user3Folder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER3);
918
-		$node3 = $user3Folder->get($this->filename);
919
-		$share3 = $this->shareManager->newShare();
920
-		$share3->setNode($node3)
921
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER3)
922
-			->setShareType(IShare::TYPE_LINK)
923
-			->setPermissions(1);
924
-		$share3 = $this->shareManager->createShare($share3);
925
-		$share3->setStatus(IShare::STATUS_ACCEPTED);
926
-		$this->shareManager->updateShare($share3);
927
-
928
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER3);
929
-		$result = $ocs->getShares();
930
-		$ocs->cleanup();
931
-
932
-		// test should return one share within $this->folder
933
-		$data = $result->getData();
934
-
935
-		// we should get exactly one result
936
-		$this->assertCount(1, $data);
937
-
938
-		$this->assertEquals($this->filename, $data[0]['path']);
939
-
940
-		$this->shareManager->deleteShare($share1);
941
-		$this->shareManager->deleteShare($share2);
942
-		$this->shareManager->deleteShare($share3);
943
-	}
944
-
945
-	/**
946
-	 * @medium
947
-	 */
948
-	public function testGetShareFromUnknownId(): void {
949
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER3);
950
-		try {
951
-			$ocs->getShare(0);
952
-			$this->fail();
953
-		} catch (OCSNotFoundException $e) {
954
-			$this->assertEquals('Wrong share ID, share does not exist', $e->getMessage());
955
-		}
956
-		$ocs->cleanup();
957
-	}
958
-
959
-	/**
960
-	 * @medium
961
-	 * @depends testCreateShareUserFile
962
-	 * @depends testCreateShareLink
963
-	 */
964
-	public function testUpdateShare(): void {
965
-		$password = md5(time());
966
-
967
-		$node1 = $this->userFolder->get($this->filename);
968
-		$share1 = $this->shareManager->newShare();
969
-		$share1->setNode($node1)
970
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
971
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
972
-			->setShareType(IShare::TYPE_USER)
973
-			->setPermissions(19)
974
-			->setAttributes($this->shareManager->newShare()->newAttributes());
975
-
976
-		$this->assertNotNull($share1->getAttributes());
977
-		$share1 = $this->shareManager->createShare($share1);
978
-		$this->assertEquals(19, $share1->getPermissions());
979
-
980
-		$share2 = $this->shareManager->newShare();
981
-		$share2->setNode($node1)
982
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
983
-			->setShareType(IShare::TYPE_LINK)
984
-			->setPermissions(1);
985
-		$share2 = $this->shareManager->createShare($share2);
986
-		$this->assertEquals(1, $share2->getPermissions());
987
-
988
-		// update permissions
989
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
990
-		$ocs->updateShare(
991
-			$share1->getId(), 1, null, null, null, null, null, null, null,
992
-			'[{"scope": "app1", "key": "attr1", "value": true}]'
993
-		);
994
-		$ocs->cleanup();
995
-
996
-		$share1 = $this->shareManager->getShareById('ocinternal:' . $share1->getId());
997
-		$this->assertEquals(1, $share1->getPermissions());
998
-		$this->assertEquals(true, $share1->getAttributes()->getAttribute('app1', 'attr1'));
999
-
1000
-		// update password for link share
1001
-		$this->assertNull($share2->getPassword());
1002
-
1003
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1004
-		$ocs->updateShare($share2->getId(), null, $password);
1005
-		$ocs->cleanup();
1006
-
1007
-		$share2 = $this->shareManager->getShareById('ocinternal:' . $share2->getId());
1008
-		$this->assertNotNull($share2->getPassword());
1009
-
1010
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1011
-		$ocs->updateShare($share2->getId(), null, '');
1012
-		$ocs->cleanup();
1013
-
1014
-		$share2 = $this->shareManager->getShareById('ocinternal:' . $share2->getId());
1015
-		$this->assertNull($share2->getPassword());
1016
-
1017
-		$this->shareManager->deleteShare($share1);
1018
-		$this->shareManager->deleteShare($share2);
1019
-	}
1020
-
1021
-	/**
1022
-	 * @medium
1023
-	 */
1024
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataAllowFederationOnPublicShares')]
1025
-	public function testUpdateShareUpload(array $appConfig, int $permissions): void {
1026
-		$this->appConfig->method('getValueBool')->willReturnMap([
1027
-			$appConfig,
1028
-		]);
1029
-
1030
-		$node1 = $this->userFolder->get($this->folder);
1031
-		$share1 = $this->shareManager->newShare();
1032
-		$share1->setNode($node1)
1033
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
1034
-			->setShareType(IShare::TYPE_LINK)
1035
-			->setPermissions(1);
1036
-		$share1 = $this->shareManager->createShare($share1);
1037
-
1038
-		// update public upload
1039
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1040
-		$ocs->updateShare($share1->getId(), null, null, null, 'true');
1041
-		$ocs->cleanup();
1042
-
1043
-		$share1 = $this->shareManager->getShareById($share1->getFullId());
1044
-		$this->assertEquals(
1045
-			Constants::PERMISSION_READ
1046
-			| Constants::PERMISSION_CREATE
1047
-			| Constants::PERMISSION_UPDATE
1048
-			| Constants::PERMISSION_DELETE
1049
-			| $permissions,
1050
-			$share1->getPermissions()
1051
-		);
1052
-
1053
-		// cleanup
1054
-		$this->shareManager->deleteShare($share1);
1055
-	}
1056
-
1057
-	public static function dataAllowFederationOnPublicShares(): array {
1058
-		return [
1059
-			[['core', ConfigLexicon::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES, false, false], 0],
1060
-			[['core', ConfigLexicon::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES, false, true], Constants::PERMISSION_SHARE],
1061
-		];
1062
-	}
1063
-
1064
-	/**
1065
-	 * @medium
1066
-	 */
1067
-	public function testUpdateShareExpireDate(): void {
1068
-		$node1 = $this->userFolder->get($this->folder);
1069
-		$share1 = $this->shareManager->newShare();
1070
-		$share1->setNode($node1)
1071
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
1072
-			->setShareType(IShare::TYPE_LINK)
1073
-			->setPermissions(1);
1074
-		$share1 = $this->shareManager->createShare($share1);
1075
-		$share1->setStatus(IShare::STATUS_ACCEPTED);
1076
-		$this->shareManager->updateShare($share1);
1077
-
1078
-		$config = Server::get(IConfig::class);
1079
-
1080
-		// enforce expire date, by default 7 days after the file was shared
1081
-		$config->setAppValue('core', 'shareapi_default_expire_date', 'yes');
1082
-		$config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes');
1083
-
1084
-		$dateWithinRange = new \DateTime();
1085
-		$dateWithinRange->add(new \DateInterval('P6D'));
1086
-
1087
-		$dateOutOfRange = new \DateTime();
1088
-		$dateOutOfRange->add(new \DateInterval('P8D'));
1089
-
1090
-		// update expire date to a valid value
1091
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1092
-		$ocs->updateShare($share1->getId(), null, null, null, null, $dateWithinRange->format('Y-m-d'));
1093
-		$ocs->cleanup();
1094
-
1095
-		$share1 = $this->shareManager->getShareById($share1->getFullId());
1096
-
1097
-		// date should be changed
1098
-		$dateWithinRange->setTime(0, 0, 0);
1099
-		$dateWithinRange->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1100
-		$this->assertEquals($dateWithinRange, $share1->getExpirationDate());
1101
-
1102
-		// update expire date to a value out of range
1103
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1104
-		try {
1105
-			$ocs->updateShare($share1->getId());
1106
-			$this->fail();
1107
-		} catch (OCSBadRequestException $e) {
1108
-		}
1109
-		$ocs->cleanup();
1110
-
1111
-		$share1 = $this->shareManager->getShareById($share1->getFullId());
1112
-
1113
-		// date shouldn't be changed
1114
-		$this->assertEquals($dateWithinRange, $share1->getExpirationDate());
1115
-
1116
-		// Try to remove expire date
1117
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1118
-		try {
1119
-			$ocs->updateShare($share1->getId());
1120
-			$this->fail();
1121
-		} catch (OCSBadRequestException $e) {
1122
-		}
1123
-		$ocs->cleanup();
1124
-
1125
-		$share1 = $this->shareManager->getShareById($share1->getFullId());
1126
-
1127
-
1128
-		// date shouldn't be changed
1129
-		$this->assertEquals($dateWithinRange, $share1->getExpirationDate());
1130
-		// cleanup
1131
-		$config->setAppValue('core', 'shareapi_default_expire_date', 'no');
1132
-		$config->setAppValue('core', 'shareapi_enforce_expire_date', 'no');
1133
-		$this->shareManager->deleteShare($share1);
1134
-	}
1135
-
1136
-	/**
1137
-	 * @medium
1138
-	 * @depends testCreateShareUserFile
1139
-	 */
1140
-	public function testDeleteShare(): void {
1141
-		$node1 = $this->userFolder->get($this->filename);
1142
-		$share1 = $this->shareManager->newShare();
1143
-		$share1->setNode($node1)
1144
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
1145
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
1146
-			->setShareType(IShare::TYPE_USER)
1147
-			->setPermissions(19);
1148
-		$share1 = $this->shareManager->createShare($share1);
1149
-
1150
-		$share2 = $this->shareManager->newShare();
1151
-		$share2->setNode($node1)
1152
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
1153
-			->setShareType(IShare::TYPE_LINK)
1154
-			->setPermissions(1);
1155
-		$share2 = $this->shareManager->createShare($share2);
1156
-
1157
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1158
-		$ocs->deleteShare($share1->getId());
1159
-		$ocs->cleanup();
1160
-
1161
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1162
-		$ocs->deleteShare($share2->getId());
1163
-		$ocs->cleanup();
1164
-
1165
-		$this->assertEmpty($this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER2, IShare::TYPE_USER));
1166
-		$this->assertEmpty($this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER2, IShare::TYPE_LINK));
1167
-	}
1168
-
1169
-	/**
1170
-	 * test unshare of a reshared file
1171
-	 */
1172
-	public function testDeleteReshare(): void {
1173
-		$node1 = $this->userFolder->get($this->folder);
1174
-		$share1 = $this->shareManager->newShare();
1175
-		$share1->setNode($node1)
1176
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
1177
-			->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
1178
-			->setShareType(IShare::TYPE_USER)
1179
-			->setPermissions(31);
1180
-		$share1 = $this->shareManager->createShare($share1);
1181
-		$share1->setStatus(IShare::STATUS_ACCEPTED);
1182
-		$this->shareManager->updateShare($share1);
1183
-
1184
-		$user2folder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER2);
1185
-		$node2 = $user2folder->get($this->folder . '/' . $this->filename);
1186
-		$share2 = $this->shareManager->newShare();
1187
-		$share2->setNode($node2)
1188
-			->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
1189
-			->setShareType(IShare::TYPE_LINK)
1190
-			->setPermissions(1);
1191
-		$share2 = $this->shareManager->createShare($share2);
1192
-		$share2->setStatus(IShare::STATUS_ACCEPTED);
1193
-		$this->shareManager->updateShare($share2);
1194
-
1195
-		// test if we can unshare the link again
1196
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
1197
-		$ocs->deleteShare($share2->getId());
1198
-		$ocs->cleanup();
1199
-
1200
-		$this->shareManager->deleteShare($share1);
1201
-		$this->addToAssertionCount(1);
1202
-	}
1203
-
1204
-	/**
1205
-	 * share a folder which contains a share mount point, should be forbidden
1206
-	 */
1207
-	public function testShareFolderWithAMountPoint(): void {
1208
-		// user 1 shares a folder with user2
1209
-		self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
1210
-
1211
-		$share = $this->share(
1212
-			IShare::TYPE_USER,
1213
-			$this->folder,
1214
-			self::TEST_FILES_SHARING_API_USER1,
1215
-			self::TEST_FILES_SHARING_API_USER2,
1216
-			Constants::PERMISSION_ALL
1217
-		);
1218
-		$share->setStatus(IShare::STATUS_ACCEPTED);
1219
-		$this->shareManager->updateShare($share);
1220
-
1221
-		// user2 shares a file from the folder as link
1222
-		self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
1223
-
1224
-		$view = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
1225
-		$view->mkdir('localDir');
1226
-
1227
-		// move mount point to the folder "localDir"
1228
-		$result = $view->rename($this->folder, 'localDir/' . $this->folder);
1229
-		$this->assertTrue($result !== false);
1230
-
1231
-		// try to share "localDir"
1232
-		$fileInfo2 = $view->getFileInfo('localDir');
1233
-
1234
-		$this->assertTrue($fileInfo2 instanceof FileInfo);
1235
-
1236
-		$pass = true;
1237
-		try {
1238
-			$this->share(
1239
-				IShare::TYPE_USER,
1240
-				'localDir',
1241
-				self::TEST_FILES_SHARING_API_USER2,
1242
-				self::TEST_FILES_SHARING_API_USER3,
1243
-				Constants::PERMISSION_ALL
1244
-			);
1245
-		} catch (\Exception $e) {
1246
-			$pass = false;
1247
-		}
1248
-
1249
-		$this->assertFalse($pass);
1250
-
1251
-		//cleanup
1252
-
1253
-		$result = $view->rename('localDir/' . $this->folder, $this->folder);
1254
-		$this->assertTrue($result !== false);
1255
-		$view->unlink('localDir');
1256
-
1257
-		self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
1258
-
1259
-		$this->shareManager->deleteShare($share);
1260
-	}
1261
-
1262
-	/**
1263
-	 * Post init mount points hook for mounting simulated ext storage
1264
-	 */
1265
-	public static function initTestMountPointsHook($data) {
1266
-		if ($data['user'] === self::TEST_FILES_SHARING_API_USER1) {
1267
-			Filesystem::mount(self::$tempStorage, [], '/' . self::TEST_FILES_SHARING_API_USER1 . '/files' . self::TEST_FOLDER_NAME);
1268
-		}
1269
-	}
1270
-
1271
-	/**
1272
-	 * Tests mounting a folder that is an external storage mount point.
1273
-	 */
1274
-	public function testShareStorageMountPoint(): void {
1275
-		$tempStorage = new Temporary([]);
1276
-		$tempStorage->file_put_contents('test.txt', 'abcdef');
1277
-		$tempStorage->getScanner()->scan('');
1278
-
1279
-		$this->registerMount(self::TEST_FILES_SHARING_API_USER1, $tempStorage, self::TEST_FILES_SHARING_API_USER1 . '/files' . self::TEST_FOLDER_NAME);
1280
-
1281
-		// logging in will auto-mount the temp storage for user1 as well
1282
-		self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
1283
-
1284
-		// user 1 shares the mount point folder with user2
1285
-		$share = $this->share(
1286
-			IShare::TYPE_USER,
1287
-			$this->folder,
1288
-			self::TEST_FILES_SHARING_API_USER1,
1289
-			self::TEST_FILES_SHARING_API_USER2,
1290
-			Constants::PERMISSION_ALL
1291
-		);
1292
-		$share->setStatus(IShare::STATUS_ACCEPTED);
1293
-		$this->shareManager->updateShare($share);
1294
-
1295
-		// user2: check that mount point name appears correctly
1296
-		self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
1297
-
1298
-		$view = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
1299
-
1300
-		$this->assertTrue($view->file_exists($this->folder));
1301
-		$this->assertTrue($view->file_exists($this->folder . '/test.txt'));
1302
-
1303
-		self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
1304
-
1305
-		$this->shareManager->deleteShare($share);
1306
-
1307
-		\OC_Hook::clear('OC_Filesystem', 'post_initMountPoints');
1308
-		\OC_Hook::clear('\OCA\Files_Sharing\Tests\ApiTest', 'initTestMountPointsHook');
1309
-	}
1310
-
1311
-	public static function datesProvider() {
1312
-		$date = new \DateTime();
1313
-		$date->setTime(0, 0);
1314
-		$date->add(new \DateInterval('P5D'));
1315
-		$date->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1316
-
1317
-		return [
1318
-			[$date->format('Y-m-d H:i:s'), true],
1319
-			['abc', false],
1320
-			[$date->format('Y-m-d H:i:s') . 'xyz', false],
1321
-		];
1322
-	}
1323
-
1324
-	/**
1325
-	 * Make sure only ISO 8601 dates are accepted
1326
-	 *
1327
-	 * @group RoutingWeirdness
1328
-	 */
1329
-	#[\PHPUnit\Framework\Attributes\DataProvider('datesProvider')]
1330
-	public function testPublicLinkExpireDate($date, $valid): void {
1331
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1332
-
1333
-		try {
1334
-			$result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, $date);
1335
-			$this->assertTrue($valid);
1336
-		} catch (OCSNotFoundException $e) {
1337
-			$this->assertFalse($valid);
1338
-			$this->assertEquals('Invalid date. Format must be YYYY-MM-DD', $e->getMessage());
1339
-			$ocs->cleanup();
1340
-			return;
1341
-		}
1342
-		$ocs->cleanup();
1343
-
1344
-		$data = $result->getData();
1345
-		$this->assertTrue(is_string($data['token']));
1346
-		$this->assertEquals(substr($date, 0, 10), substr($data['expiration'], 0, 10));
1347
-
1348
-		// check for correct link
1349
-		$url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']);
1350
-		$this->assertEquals($url, $data['url']);
1351
-
1352
-		$share = $this->shareManager->getShareById('ocinternal:' . $data['id']);
1353
-
1354
-		$this->assertEquals($date, $share->getExpirationDate()->format('Y-m-d H:i:s'));
1355
-
1356
-		$this->shareManager->deleteShare($share);
1357
-	}
1358
-
1359
-	/**
1360
-	 * @group RoutingWeirdness
1361
-	 */
1362
-	public function testCreatePublicLinkExpireDateValid(): void {
1363
-		$config = Server::get(IConfig::class);
1364
-
1365
-		// enforce expire date, by default 7 days after the file was shared
1366
-		$config->setAppValue('core', 'shareapi_default_expire_date', 'yes');
1367
-		$config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes');
1368
-
1369
-		$date = new \DateTime();
1370
-		$date->add(new \DateInterval('P5D'));
1371
-
1372
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1373
-		$result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, $date->format('Y-m-d'));
1374
-		$ocs->cleanup();
1375
-
1376
-		$data = $result->getData();
1377
-		$this->assertTrue(is_string($data['token']));
1378
-		$this->assertEquals($date->format('Y-m-d 00:00:00'), $data['expiration']);
1379
-
1380
-		// check for correct link
1381
-		$url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']);
1382
-		$this->assertEquals($url, $data['url']);
1383
-
1384
-		$share = $this->shareManager->getShareById('ocinternal:' . $data['id']);
1385
-		$date->setTime(0, 0, 0);
1386
-		$this->assertEquals($date, $share->getExpirationDate());
1387
-
1388
-		$this->shareManager->deleteShare($share);
1389
-
1390
-		$config->setAppValue('core', 'shareapi_default_expire_date', 'no');
1391
-		$config->setAppValue('core', 'shareapi_enforce_expire_date', 'no');
1392
-	}
1393
-
1394
-	public function testCreatePublicLinkExpireDateInvalidFuture(): void {
1395
-		$config = Server::get(IConfig::class);
1396
-
1397
-		// enforce expire date, by default 7 days after the file was shared
1398
-		$config->setAppValue('core', 'shareapi_default_expire_date', 'yes');
1399
-		$config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes');
1400
-
1401
-		$date = new \DateTime();
1402
-		$date->add(new \DateInterval('P8D'));
1403
-
1404
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1405
-
1406
-		try {
1407
-			$ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, $date->format('Y-m-d'));
1408
-			$this->fail();
1409
-		} catch (OCSException $e) {
1410
-			$this->assertEquals(404, $e->getCode());
1411
-			$this->assertEquals('Cannot set expiration date more than 7 days in the future', $e->getMessage());
1412
-		}
1413
-		$ocs->cleanup();
1414
-
1415
-		$config->setAppValue('core', 'shareapi_default_expire_date', 'no');
1416
-		$config->setAppValue('core', 'shareapi_enforce_expire_date', 'no');
1417
-	}
1418
-
1419
-	public function XtestCreatePublicLinkExpireDateInvalidPast() {
1420
-		$config = Server::get(IConfig::class);
1421
-
1422
-		$date = new \DateTime();
1423
-		$date->sub(new \DateInterval('P8D'));
1424
-
1425
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1426
-
1427
-		try {
1428
-			$ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, $date->format('Y-m-d'));
1429
-			$this->fail();
1430
-		} catch (OCSException $e) {
1431
-			$this->assertEquals(404, $e->getCode());
1432
-			$this->assertEquals('Expiration date is in the past', $e->getMessage());
1433
-		}
1434
-		$ocs->cleanup();
1435
-
1436
-		$config->setAppValue('core', 'shareapi_default_expire_date', 'no');
1437
-		$config->setAppValue('core', 'shareapi_enforce_expire_date', 'no');
1438
-	}
1439
-
1440
-	/**
1441
-	 * test for no invisible shares
1442
-	 * See: https://github.com/owncloud/core/issues/22295
1443
-	 */
1444
-	public function testInvisibleSharesUser(): void {
1445
-		// simulate a post request
1446
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1447
-		$result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
1448
-		$ocs->cleanup();
1449
-		$data = $result->getData();
808
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
809
+        $result = $ocs->getShares();
810
+        $ocs->cleanup();
811
+
812
+        // test should return one share within $this->folder
813
+        $data = $result->getData();
814
+
815
+        // we should get exactly one result
816
+        $this->assertCount(1, $data);
817
+        $this->assertEquals($this->subfolder . $this->subsubfolder, $data[0]['path']);
818
+
819
+        $this->shareManager->deleteShare($share1);
820
+        $this->shareManager->deleteShare($share2);
821
+        $this->shareManager->deleteShare($share3);
822
+    }
823
+
824
+    /**
825
+     * test multiple shared folder if the path gets constructed correctly
826
+     * @medium
827
+     */
828
+    public function testGetShareMultipleSharedFolder(): void {
829
+        $this->setUp();
830
+        $node1 = $this->userFolder->get($this->folder . $this->subfolder);
831
+        $share1 = $this->shareManager->newShare();
832
+        $share1->setNode($node1)
833
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
834
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
835
+            ->setShareType(IShare::TYPE_USER)
836
+            ->setPermissions(31);
837
+        $share1 = $this->shareManager->createShare($share1);
838
+        $share1->setStatus(IShare::STATUS_ACCEPTED);
839
+        $this->shareManager->updateShare($share1);
840
+
841
+        $node2 = $this->userFolder->get($this->folder);
842
+        $share2 = $this->shareManager->newShare();
843
+        $share2->setNode($node2)
844
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
845
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
846
+            ->setShareType(IShare::TYPE_USER)
847
+            ->setPermissions(31);
848
+        $share2 = $this->shareManager->createShare($share2);
849
+        $share2->setStatus(IShare::STATUS_ACCEPTED);
850
+        $this->shareManager->updateShare($share2);
851
+
852
+        $share3 = $this->shareManager->newShare();
853
+        $share3->setNode($node1)
854
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
855
+            ->setShareType(IShare::TYPE_LINK)
856
+            ->setPermissions(1);
857
+        $share3 = $this->shareManager->createShare($share3);
858
+        $share3->setStatus(IShare::STATUS_ACCEPTED);
859
+        $this->shareManager->updateShare($share3);
860
+
861
+        // $request = $this->createRequest(['path' => $this->subfolder]);
862
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
863
+        $result1 = $ocs->getShares('false', 'false', 'false', $this->subfolder);
864
+        $ocs->cleanup();
865
+
866
+        // test should return one share within $this->folder
867
+        $data1 = $result1->getData();
868
+        $this->assertCount(1, $data1);
869
+        $s1 = reset($data1);
870
+
871
+        //$request = $this->createRequest(['path' => $this->folder.$this->subfolder]);
872
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
873
+        $result2 = $ocs->getShares('false', 'false', 'false', $this->folder . $this->subfolder);
874
+        $ocs->cleanup();
875
+
876
+        // test should return one share within $this->folder
877
+        $data2 = $result2->getData();
878
+        $this->assertCount(1, $data2);
879
+        $s2 = reset($data2);
880
+
881
+        $this->assertEquals($this->subfolder, $s1['path']);
882
+        $this->assertEquals($this->folder . $this->subfolder, $s2['path']);
883
+
884
+        $this->shareManager->deleteShare($share1);
885
+        $this->shareManager->deleteShare($share2);
886
+        $this->shareManager->deleteShare($share3);
887
+    }
888
+
889
+    /**
890
+     * test re-re-share of folder if the path gets constructed correctly
891
+     * @medium
892
+     */
893
+    public function testGetShareFromFileReReShares(): void {
894
+        $node1 = $this->userFolder->get($this->folder . $this->subfolder);
895
+        $share1 = $this->shareManager->newShare();
896
+        $share1->setNode($node1)
897
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
898
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
899
+            ->setShareType(IShare::TYPE_USER)
900
+            ->setPermissions(31);
901
+        $share1 = $this->shareManager->createShare($share1);
902
+        $share1->setStatus(IShare::STATUS_ACCEPTED);
903
+        $this->shareManager->updateShare($share1);
904
+
905
+        $user2Folder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER2);
906
+        $node2 = $user2Folder->get($this->subfolder . $this->filename);
907
+        $share2 = $this->shareManager->newShare();
908
+        $share2->setNode($node2)
909
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
910
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER3)
911
+            ->setShareType(IShare::TYPE_USER)
912
+            ->setPermissions(19);
913
+        $share2 = $this->shareManager->createShare($share2);
914
+        $share2->setStatus(IShare::STATUS_ACCEPTED);
915
+        $this->shareManager->updateShare($share2);
916
+
917
+        $user3Folder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER3);
918
+        $node3 = $user3Folder->get($this->filename);
919
+        $share3 = $this->shareManager->newShare();
920
+        $share3->setNode($node3)
921
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER3)
922
+            ->setShareType(IShare::TYPE_LINK)
923
+            ->setPermissions(1);
924
+        $share3 = $this->shareManager->createShare($share3);
925
+        $share3->setStatus(IShare::STATUS_ACCEPTED);
926
+        $this->shareManager->updateShare($share3);
927
+
928
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER3);
929
+        $result = $ocs->getShares();
930
+        $ocs->cleanup();
931
+
932
+        // test should return one share within $this->folder
933
+        $data = $result->getData();
934
+
935
+        // we should get exactly one result
936
+        $this->assertCount(1, $data);
937
+
938
+        $this->assertEquals($this->filename, $data[0]['path']);
939
+
940
+        $this->shareManager->deleteShare($share1);
941
+        $this->shareManager->deleteShare($share2);
942
+        $this->shareManager->deleteShare($share3);
943
+    }
944
+
945
+    /**
946
+     * @medium
947
+     */
948
+    public function testGetShareFromUnknownId(): void {
949
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER3);
950
+        try {
951
+            $ocs->getShare(0);
952
+            $this->fail();
953
+        } catch (OCSNotFoundException $e) {
954
+            $this->assertEquals('Wrong share ID, share does not exist', $e->getMessage());
955
+        }
956
+        $ocs->cleanup();
957
+    }
958
+
959
+    /**
960
+     * @medium
961
+     * @depends testCreateShareUserFile
962
+     * @depends testCreateShareLink
963
+     */
964
+    public function testUpdateShare(): void {
965
+        $password = md5(time());
966
+
967
+        $node1 = $this->userFolder->get($this->filename);
968
+        $share1 = $this->shareManager->newShare();
969
+        $share1->setNode($node1)
970
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
971
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
972
+            ->setShareType(IShare::TYPE_USER)
973
+            ->setPermissions(19)
974
+            ->setAttributes($this->shareManager->newShare()->newAttributes());
975
+
976
+        $this->assertNotNull($share1->getAttributes());
977
+        $share1 = $this->shareManager->createShare($share1);
978
+        $this->assertEquals(19, $share1->getPermissions());
979
+
980
+        $share2 = $this->shareManager->newShare();
981
+        $share2->setNode($node1)
982
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
983
+            ->setShareType(IShare::TYPE_LINK)
984
+            ->setPermissions(1);
985
+        $share2 = $this->shareManager->createShare($share2);
986
+        $this->assertEquals(1, $share2->getPermissions());
987
+
988
+        // update permissions
989
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
990
+        $ocs->updateShare(
991
+            $share1->getId(), 1, null, null, null, null, null, null, null,
992
+            '[{"scope": "app1", "key": "attr1", "value": true}]'
993
+        );
994
+        $ocs->cleanup();
995
+
996
+        $share1 = $this->shareManager->getShareById('ocinternal:' . $share1->getId());
997
+        $this->assertEquals(1, $share1->getPermissions());
998
+        $this->assertEquals(true, $share1->getAttributes()->getAttribute('app1', 'attr1'));
999
+
1000
+        // update password for link share
1001
+        $this->assertNull($share2->getPassword());
1002
+
1003
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1004
+        $ocs->updateShare($share2->getId(), null, $password);
1005
+        $ocs->cleanup();
1006
+
1007
+        $share2 = $this->shareManager->getShareById('ocinternal:' . $share2->getId());
1008
+        $this->assertNotNull($share2->getPassword());
1009
+
1010
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1011
+        $ocs->updateShare($share2->getId(), null, '');
1012
+        $ocs->cleanup();
1013
+
1014
+        $share2 = $this->shareManager->getShareById('ocinternal:' . $share2->getId());
1015
+        $this->assertNull($share2->getPassword());
1016
+
1017
+        $this->shareManager->deleteShare($share1);
1018
+        $this->shareManager->deleteShare($share2);
1019
+    }
1020
+
1021
+    /**
1022
+     * @medium
1023
+     */
1024
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataAllowFederationOnPublicShares')]
1025
+    public function testUpdateShareUpload(array $appConfig, int $permissions): void {
1026
+        $this->appConfig->method('getValueBool')->willReturnMap([
1027
+            $appConfig,
1028
+        ]);
1029
+
1030
+        $node1 = $this->userFolder->get($this->folder);
1031
+        $share1 = $this->shareManager->newShare();
1032
+        $share1->setNode($node1)
1033
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
1034
+            ->setShareType(IShare::TYPE_LINK)
1035
+            ->setPermissions(1);
1036
+        $share1 = $this->shareManager->createShare($share1);
1037
+
1038
+        // update public upload
1039
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1040
+        $ocs->updateShare($share1->getId(), null, null, null, 'true');
1041
+        $ocs->cleanup();
1042
+
1043
+        $share1 = $this->shareManager->getShareById($share1->getFullId());
1044
+        $this->assertEquals(
1045
+            Constants::PERMISSION_READ
1046
+            | Constants::PERMISSION_CREATE
1047
+            | Constants::PERMISSION_UPDATE
1048
+            | Constants::PERMISSION_DELETE
1049
+            | $permissions,
1050
+            $share1->getPermissions()
1051
+        );
1052
+
1053
+        // cleanup
1054
+        $this->shareManager->deleteShare($share1);
1055
+    }
1056
+
1057
+    public static function dataAllowFederationOnPublicShares(): array {
1058
+        return [
1059
+            [['core', ConfigLexicon::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES, false, false], 0],
1060
+            [['core', ConfigLexicon::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES, false, true], Constants::PERMISSION_SHARE],
1061
+        ];
1062
+    }
1063
+
1064
+    /**
1065
+     * @medium
1066
+     */
1067
+    public function testUpdateShareExpireDate(): void {
1068
+        $node1 = $this->userFolder->get($this->folder);
1069
+        $share1 = $this->shareManager->newShare();
1070
+        $share1->setNode($node1)
1071
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
1072
+            ->setShareType(IShare::TYPE_LINK)
1073
+            ->setPermissions(1);
1074
+        $share1 = $this->shareManager->createShare($share1);
1075
+        $share1->setStatus(IShare::STATUS_ACCEPTED);
1076
+        $this->shareManager->updateShare($share1);
1077
+
1078
+        $config = Server::get(IConfig::class);
1079
+
1080
+        // enforce expire date, by default 7 days after the file was shared
1081
+        $config->setAppValue('core', 'shareapi_default_expire_date', 'yes');
1082
+        $config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes');
1083
+
1084
+        $dateWithinRange = new \DateTime();
1085
+        $dateWithinRange->add(new \DateInterval('P6D'));
1086
+
1087
+        $dateOutOfRange = new \DateTime();
1088
+        $dateOutOfRange->add(new \DateInterval('P8D'));
1089
+
1090
+        // update expire date to a valid value
1091
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1092
+        $ocs->updateShare($share1->getId(), null, null, null, null, $dateWithinRange->format('Y-m-d'));
1093
+        $ocs->cleanup();
1094
+
1095
+        $share1 = $this->shareManager->getShareById($share1->getFullId());
1096
+
1097
+        // date should be changed
1098
+        $dateWithinRange->setTime(0, 0, 0);
1099
+        $dateWithinRange->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1100
+        $this->assertEquals($dateWithinRange, $share1->getExpirationDate());
1101
+
1102
+        // update expire date to a value out of range
1103
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1104
+        try {
1105
+            $ocs->updateShare($share1->getId());
1106
+            $this->fail();
1107
+        } catch (OCSBadRequestException $e) {
1108
+        }
1109
+        $ocs->cleanup();
1110
+
1111
+        $share1 = $this->shareManager->getShareById($share1->getFullId());
1112
+
1113
+        // date shouldn't be changed
1114
+        $this->assertEquals($dateWithinRange, $share1->getExpirationDate());
1115
+
1116
+        // Try to remove expire date
1117
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1118
+        try {
1119
+            $ocs->updateShare($share1->getId());
1120
+            $this->fail();
1121
+        } catch (OCSBadRequestException $e) {
1122
+        }
1123
+        $ocs->cleanup();
1124
+
1125
+        $share1 = $this->shareManager->getShareById($share1->getFullId());
1126
+
1127
+
1128
+        // date shouldn't be changed
1129
+        $this->assertEquals($dateWithinRange, $share1->getExpirationDate());
1130
+        // cleanup
1131
+        $config->setAppValue('core', 'shareapi_default_expire_date', 'no');
1132
+        $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no');
1133
+        $this->shareManager->deleteShare($share1);
1134
+    }
1135
+
1136
+    /**
1137
+     * @medium
1138
+     * @depends testCreateShareUserFile
1139
+     */
1140
+    public function testDeleteShare(): void {
1141
+        $node1 = $this->userFolder->get($this->filename);
1142
+        $share1 = $this->shareManager->newShare();
1143
+        $share1->setNode($node1)
1144
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
1145
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
1146
+            ->setShareType(IShare::TYPE_USER)
1147
+            ->setPermissions(19);
1148
+        $share1 = $this->shareManager->createShare($share1);
1149
+
1150
+        $share2 = $this->shareManager->newShare();
1151
+        $share2->setNode($node1)
1152
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
1153
+            ->setShareType(IShare::TYPE_LINK)
1154
+            ->setPermissions(1);
1155
+        $share2 = $this->shareManager->createShare($share2);
1156
+
1157
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1158
+        $ocs->deleteShare($share1->getId());
1159
+        $ocs->cleanup();
1160
+
1161
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1162
+        $ocs->deleteShare($share2->getId());
1163
+        $ocs->cleanup();
1164
+
1165
+        $this->assertEmpty($this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER2, IShare::TYPE_USER));
1166
+        $this->assertEmpty($this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER2, IShare::TYPE_LINK));
1167
+    }
1168
+
1169
+    /**
1170
+     * test unshare of a reshared file
1171
+     */
1172
+    public function testDeleteReshare(): void {
1173
+        $node1 = $this->userFolder->get($this->folder);
1174
+        $share1 = $this->shareManager->newShare();
1175
+        $share1->setNode($node1)
1176
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER1)
1177
+            ->setSharedWith(self::TEST_FILES_SHARING_API_USER2)
1178
+            ->setShareType(IShare::TYPE_USER)
1179
+            ->setPermissions(31);
1180
+        $share1 = $this->shareManager->createShare($share1);
1181
+        $share1->setStatus(IShare::STATUS_ACCEPTED);
1182
+        $this->shareManager->updateShare($share1);
1183
+
1184
+        $user2folder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER2);
1185
+        $node2 = $user2folder->get($this->folder . '/' . $this->filename);
1186
+        $share2 = $this->shareManager->newShare();
1187
+        $share2->setNode($node2)
1188
+            ->setSharedBy(self::TEST_FILES_SHARING_API_USER2)
1189
+            ->setShareType(IShare::TYPE_LINK)
1190
+            ->setPermissions(1);
1191
+        $share2 = $this->shareManager->createShare($share2);
1192
+        $share2->setStatus(IShare::STATUS_ACCEPTED);
1193
+        $this->shareManager->updateShare($share2);
1194
+
1195
+        // test if we can unshare the link again
1196
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
1197
+        $ocs->deleteShare($share2->getId());
1198
+        $ocs->cleanup();
1199
+
1200
+        $this->shareManager->deleteShare($share1);
1201
+        $this->addToAssertionCount(1);
1202
+    }
1203
+
1204
+    /**
1205
+     * share a folder which contains a share mount point, should be forbidden
1206
+     */
1207
+    public function testShareFolderWithAMountPoint(): void {
1208
+        // user 1 shares a folder with user2
1209
+        self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
1210
+
1211
+        $share = $this->share(
1212
+            IShare::TYPE_USER,
1213
+            $this->folder,
1214
+            self::TEST_FILES_SHARING_API_USER1,
1215
+            self::TEST_FILES_SHARING_API_USER2,
1216
+            Constants::PERMISSION_ALL
1217
+        );
1218
+        $share->setStatus(IShare::STATUS_ACCEPTED);
1219
+        $this->shareManager->updateShare($share);
1220
+
1221
+        // user2 shares a file from the folder as link
1222
+        self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
1223
+
1224
+        $view = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
1225
+        $view->mkdir('localDir');
1226
+
1227
+        // move mount point to the folder "localDir"
1228
+        $result = $view->rename($this->folder, 'localDir/' . $this->folder);
1229
+        $this->assertTrue($result !== false);
1230
+
1231
+        // try to share "localDir"
1232
+        $fileInfo2 = $view->getFileInfo('localDir');
1233
+
1234
+        $this->assertTrue($fileInfo2 instanceof FileInfo);
1235
+
1236
+        $pass = true;
1237
+        try {
1238
+            $this->share(
1239
+                IShare::TYPE_USER,
1240
+                'localDir',
1241
+                self::TEST_FILES_SHARING_API_USER2,
1242
+                self::TEST_FILES_SHARING_API_USER3,
1243
+                Constants::PERMISSION_ALL
1244
+            );
1245
+        } catch (\Exception $e) {
1246
+            $pass = false;
1247
+        }
1248
+
1249
+        $this->assertFalse($pass);
1250
+
1251
+        //cleanup
1252
+
1253
+        $result = $view->rename('localDir/' . $this->folder, $this->folder);
1254
+        $this->assertTrue($result !== false);
1255
+        $view->unlink('localDir');
1256
+
1257
+        self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
1258
+
1259
+        $this->shareManager->deleteShare($share);
1260
+    }
1261
+
1262
+    /**
1263
+     * Post init mount points hook for mounting simulated ext storage
1264
+     */
1265
+    public static function initTestMountPointsHook($data) {
1266
+        if ($data['user'] === self::TEST_FILES_SHARING_API_USER1) {
1267
+            Filesystem::mount(self::$tempStorage, [], '/' . self::TEST_FILES_SHARING_API_USER1 . '/files' . self::TEST_FOLDER_NAME);
1268
+        }
1269
+    }
1270
+
1271
+    /**
1272
+     * Tests mounting a folder that is an external storage mount point.
1273
+     */
1274
+    public function testShareStorageMountPoint(): void {
1275
+        $tempStorage = new Temporary([]);
1276
+        $tempStorage->file_put_contents('test.txt', 'abcdef');
1277
+        $tempStorage->getScanner()->scan('');
1278
+
1279
+        $this->registerMount(self::TEST_FILES_SHARING_API_USER1, $tempStorage, self::TEST_FILES_SHARING_API_USER1 . '/files' . self::TEST_FOLDER_NAME);
1280
+
1281
+        // logging in will auto-mount the temp storage for user1 as well
1282
+        self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
1283
+
1284
+        // user 1 shares the mount point folder with user2
1285
+        $share = $this->share(
1286
+            IShare::TYPE_USER,
1287
+            $this->folder,
1288
+            self::TEST_FILES_SHARING_API_USER1,
1289
+            self::TEST_FILES_SHARING_API_USER2,
1290
+            Constants::PERMISSION_ALL
1291
+        );
1292
+        $share->setStatus(IShare::STATUS_ACCEPTED);
1293
+        $this->shareManager->updateShare($share);
1294
+
1295
+        // user2: check that mount point name appears correctly
1296
+        self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
1297
+
1298
+        $view = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
1299
+
1300
+        $this->assertTrue($view->file_exists($this->folder));
1301
+        $this->assertTrue($view->file_exists($this->folder . '/test.txt'));
1302
+
1303
+        self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
1304
+
1305
+        $this->shareManager->deleteShare($share);
1306
+
1307
+        \OC_Hook::clear('OC_Filesystem', 'post_initMountPoints');
1308
+        \OC_Hook::clear('\OCA\Files_Sharing\Tests\ApiTest', 'initTestMountPointsHook');
1309
+    }
1310
+
1311
+    public static function datesProvider() {
1312
+        $date = new \DateTime();
1313
+        $date->setTime(0, 0);
1314
+        $date->add(new \DateInterval('P5D'));
1315
+        $date->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1316
+
1317
+        return [
1318
+            [$date->format('Y-m-d H:i:s'), true],
1319
+            ['abc', false],
1320
+            [$date->format('Y-m-d H:i:s') . 'xyz', false],
1321
+        ];
1322
+    }
1323
+
1324
+    /**
1325
+     * Make sure only ISO 8601 dates are accepted
1326
+     *
1327
+     * @group RoutingWeirdness
1328
+     */
1329
+    #[\PHPUnit\Framework\Attributes\DataProvider('datesProvider')]
1330
+    public function testPublicLinkExpireDate($date, $valid): void {
1331
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1332
+
1333
+        try {
1334
+            $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, $date);
1335
+            $this->assertTrue($valid);
1336
+        } catch (OCSNotFoundException $e) {
1337
+            $this->assertFalse($valid);
1338
+            $this->assertEquals('Invalid date. Format must be YYYY-MM-DD', $e->getMessage());
1339
+            $ocs->cleanup();
1340
+            return;
1341
+        }
1342
+        $ocs->cleanup();
1343
+
1344
+        $data = $result->getData();
1345
+        $this->assertTrue(is_string($data['token']));
1346
+        $this->assertEquals(substr($date, 0, 10), substr($data['expiration'], 0, 10));
1347
+
1348
+        // check for correct link
1349
+        $url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']);
1350
+        $this->assertEquals($url, $data['url']);
1351
+
1352
+        $share = $this->shareManager->getShareById('ocinternal:' . $data['id']);
1353
+
1354
+        $this->assertEquals($date, $share->getExpirationDate()->format('Y-m-d H:i:s'));
1355
+
1356
+        $this->shareManager->deleteShare($share);
1357
+    }
1358
+
1359
+    /**
1360
+     * @group RoutingWeirdness
1361
+     */
1362
+    public function testCreatePublicLinkExpireDateValid(): void {
1363
+        $config = Server::get(IConfig::class);
1364
+
1365
+        // enforce expire date, by default 7 days after the file was shared
1366
+        $config->setAppValue('core', 'shareapi_default_expire_date', 'yes');
1367
+        $config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes');
1368
+
1369
+        $date = new \DateTime();
1370
+        $date->add(new \DateInterval('P5D'));
1371
+
1372
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1373
+        $result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, $date->format('Y-m-d'));
1374
+        $ocs->cleanup();
1375
+
1376
+        $data = $result->getData();
1377
+        $this->assertTrue(is_string($data['token']));
1378
+        $this->assertEquals($date->format('Y-m-d 00:00:00'), $data['expiration']);
1379
+
1380
+        // check for correct link
1381
+        $url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']);
1382
+        $this->assertEquals($url, $data['url']);
1383
+
1384
+        $share = $this->shareManager->getShareById('ocinternal:' . $data['id']);
1385
+        $date->setTime(0, 0, 0);
1386
+        $this->assertEquals($date, $share->getExpirationDate());
1387
+
1388
+        $this->shareManager->deleteShare($share);
1389
+
1390
+        $config->setAppValue('core', 'shareapi_default_expire_date', 'no');
1391
+        $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no');
1392
+    }
1393
+
1394
+    public function testCreatePublicLinkExpireDateInvalidFuture(): void {
1395
+        $config = Server::get(IConfig::class);
1396
+
1397
+        // enforce expire date, by default 7 days after the file was shared
1398
+        $config->setAppValue('core', 'shareapi_default_expire_date', 'yes');
1399
+        $config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes');
1400
+
1401
+        $date = new \DateTime();
1402
+        $date->add(new \DateInterval('P8D'));
1403
+
1404
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1405
+
1406
+        try {
1407
+            $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, $date->format('Y-m-d'));
1408
+            $this->fail();
1409
+        } catch (OCSException $e) {
1410
+            $this->assertEquals(404, $e->getCode());
1411
+            $this->assertEquals('Cannot set expiration date more than 7 days in the future', $e->getMessage());
1412
+        }
1413
+        $ocs->cleanup();
1414
+
1415
+        $config->setAppValue('core', 'shareapi_default_expire_date', 'no');
1416
+        $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no');
1417
+    }
1418
+
1419
+    public function XtestCreatePublicLinkExpireDateInvalidPast() {
1420
+        $config = Server::get(IConfig::class);
1421
+
1422
+        $date = new \DateTime();
1423
+        $date->sub(new \DateInterval('P8D'));
1424
+
1425
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1426
+
1427
+        try {
1428
+            $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, $date->format('Y-m-d'));
1429
+            $this->fail();
1430
+        } catch (OCSException $e) {
1431
+            $this->assertEquals(404, $e->getCode());
1432
+            $this->assertEquals('Expiration date is in the past', $e->getMessage());
1433
+        }
1434
+        $ocs->cleanup();
1435
+
1436
+        $config->setAppValue('core', 'shareapi_default_expire_date', 'no');
1437
+        $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no');
1438
+    }
1439
+
1440
+    /**
1441
+     * test for no invisible shares
1442
+     * See: https://github.com/owncloud/core/issues/22295
1443
+     */
1444
+    public function testInvisibleSharesUser(): void {
1445
+        // simulate a post request
1446
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1447
+        $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
1448
+        $ocs->cleanup();
1449
+        $data = $result->getData();
1450 1450
 
1451
-		$topId = $data['id'];
1452
-
1453
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
1454
-		$ocs->acceptShare($topId);
1455
-		$ocs->cleanup();
1456
-
1457
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
1458
-		$ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK);
1459
-		$ocs->cleanup();
1460
-
1461
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1462
-		$ocs->deleteShare($topId);
1463
-		$ocs->cleanup();
1464
-
1465
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1466
-		$result = $ocs->getShares();
1467
-		$ocs->cleanup();
1468
-
1469
-		$this->assertEmpty($result->getData());
1470
-	}
1471
-
1472
-	/**
1473
-	 * test for no invisible shares
1474
-	 * See: https://github.com/owncloud/core/issues/22295
1475
-	 */
1476
-	public function testInvisibleSharesGroup(): void {
1477
-		// simulate a post request
1478
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1479
-		$result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_GROUP, self::TEST_FILES_SHARING_API_GROUP1);
1480
-		$ocs->cleanup();
1481
-		$data = $result->getData();
1482
-
1483
-		$topId = $data['id'];
1484
-
1485
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
1486
-		$ocs->acceptShare($topId);
1487
-		$ocs->cleanup();
1488
-
1489
-		\OC_Util::tearDownFS();
1490
-
1491
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
1492
-		$ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK);
1493
-		$ocs->cleanup();
1494
-
1495
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1496
-		$ocs->deleteShare($topId);
1497
-		$ocs->cleanup();
1498
-
1499
-		$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1500
-		$result = $ocs->getShares();
1501
-		$ocs->cleanup();
1502
-
1503
-		$this->assertEmpty($result->getData());
1504
-	}
1451
+        $topId = $data['id'];
1452
+
1453
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
1454
+        $ocs->acceptShare($topId);
1455
+        $ocs->cleanup();
1456
+
1457
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
1458
+        $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK);
1459
+        $ocs->cleanup();
1460
+
1461
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1462
+        $ocs->deleteShare($topId);
1463
+        $ocs->cleanup();
1464
+
1465
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1466
+        $result = $ocs->getShares();
1467
+        $ocs->cleanup();
1468
+
1469
+        $this->assertEmpty($result->getData());
1470
+    }
1471
+
1472
+    /**
1473
+     * test for no invisible shares
1474
+     * See: https://github.com/owncloud/core/issues/22295
1475
+     */
1476
+    public function testInvisibleSharesGroup(): void {
1477
+        // simulate a post request
1478
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1479
+        $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_GROUP, self::TEST_FILES_SHARING_API_GROUP1);
1480
+        $ocs->cleanup();
1481
+        $data = $result->getData();
1482
+
1483
+        $topId = $data['id'];
1484
+
1485
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
1486
+        $ocs->acceptShare($topId);
1487
+        $ocs->cleanup();
1488
+
1489
+        \OC_Util::tearDownFS();
1490
+
1491
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
1492
+        $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK);
1493
+        $ocs->cleanup();
1494
+
1495
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1496
+        $ocs->deleteShare($topId);
1497
+        $ocs->cleanup();
1498
+
1499
+        $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
1500
+        $result = $ocs->getShares();
1501
+        $ocs->cleanup();
1502
+
1503
+        $this->assertEmpty($result->getData());
1504
+    }
1505 1505
 }
Please login to merge, or discard this patch.
apps/files_sharing/tests/Controller/ShareAPIControllerTest.php 1 patch
Indentation   +5355 added lines, -5355 removed lines patch added patch discarded remove patch
@@ -63,517 +63,517 @@  discard block
 block discarded – undo
63 63
  * @group DB
64 64
  */
65 65
 class ShareAPIControllerTest extends TestCase {
66
-	use EmailValidatorTrait;
67
-
68
-	private string $appName = 'files_sharing';
69
-	private string $currentUser;
70
-
71
-	private ShareAPIController $ocs;
72
-
73
-	private IManager&MockObject $shareManager;
74
-	private IGroupManager&MockObject $groupManager;
75
-	private IUserManager&MockObject $userManager;
76
-	private IRequest&MockObject $request;
77
-	private IRootFolder&MockObject $rootFolder;
78
-	private IURLGenerator&MockObject $urlGenerator;
79
-	private IL10N&MockObject $l;
80
-	private IConfig&MockObject $config;
81
-	private IAppConfig&MockObject $appConfig;
82
-	private IAppManager&MockObject $appManager;
83
-	private ContainerInterface&MockObject $serverContainer;
84
-	private IUserStatusManager&MockObject $userStatusManager;
85
-	private IPreview&MockObject $previewManager;
86
-	private IDateTimeZone&MockObject $dateTimeZone;
87
-	private LoggerInterface&MockObject $logger;
88
-	private IProviderFactory&MockObject $factory;
89
-	private IMailer&MockObject $mailer;
90
-	private ITagManager&MockObject $tagManager;
91
-	private TrustedServers&MockObject $trustedServers;
92
-
93
-	protected function setUp(): void {
94
-		$this->shareManager = $this->createMock(IManager::class);
95
-		$this->shareManager
96
-			->expects($this->any())
97
-			->method('shareApiEnabled')
98
-			->willReturn(true);
99
-		$this->shareManager
100
-			->expects($this->any())
101
-			->method('shareProviderExists')->willReturn(true);
102
-		$this->groupManager = $this->createMock(IGroupManager::class);
103
-		$this->userManager = $this->createMock(IUserManager::class);
104
-		$this->request = $this->createMock(IRequest::class);
105
-		$this->rootFolder = $this->createMock(IRootFolder::class);
106
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
107
-		$this->currentUser = 'currentUser';
108
-
109
-		$this->l = $this->createMock(IL10N::class);
110
-		$this->l->method('t')
111
-			->willReturnCallback(function ($text, $parameters = []) {
112
-				return vsprintf($text, $parameters);
113
-			});
114
-		$this->config = $this->createMock(IConfig::class);
115
-		$this->appConfig = $this->createMock(IAppConfig::class);
116
-		$this->appManager = $this->createMock(IAppManager::class);
117
-		$this->serverContainer = $this->createMock(ContainerInterface::class);
118
-		$this->userStatusManager = $this->createMock(IUserStatusManager::class);
119
-		$this->previewManager = $this->createMock(IPreview::class);
120
-		$this->previewManager->method('isAvailable')
121
-			->willReturnCallback(function ($fileInfo) {
122
-				return $fileInfo->getMimeType() === 'mimeWithPreview';
123
-			});
124
-		$this->dateTimeZone = $this->createMock(IDateTimeZone::class);
125
-		$this->logger = $this->createMock(LoggerInterface::class);
126
-		$this->factory = $this->createMock(IProviderFactory::class);
127
-		$this->mailer = $this->createMock(IMailer::class);
128
-		$this->tagManager = $this->createMock(ITagManager::class);
129
-		$this->trustedServers = $this->createMock(TrustedServers::class);
130
-
131
-		$this->ocs = new ShareAPIController(
132
-			$this->appName,
133
-			$this->request,
134
-			$this->shareManager,
135
-			$this->groupManager,
136
-			$this->userManager,
137
-			$this->rootFolder,
138
-			$this->urlGenerator,
139
-			$this->l,
140
-			$this->config,
141
-			$this->appConfig,
142
-			$this->appManager,
143
-			$this->serverContainer,
144
-			$this->userStatusManager,
145
-			$this->previewManager,
146
-			$this->dateTimeZone,
147
-			$this->logger,
148
-			$this->factory,
149
-			$this->mailer,
150
-			$this->tagManager,
151
-			$this->getEmailValidatorWithStrictEmailCheck(),
152
-			$this->trustedServers,
153
-			$this->currentUser,
154
-		);
155
-
156
-	}
157
-
158
-	/**
159
-	 * @return ShareAPIController&MockObject
160
-	 */
161
-	private function mockFormatShare() {
162
-		return $this->getMockBuilder(ShareAPIController::class)
163
-			->setConstructorArgs([
164
-				$this->appName,
165
-				$this->request,
166
-				$this->shareManager,
167
-				$this->groupManager,
168
-				$this->userManager,
169
-				$this->rootFolder,
170
-				$this->urlGenerator,
171
-				$this->l,
172
-				$this->config,
173
-				$this->appConfig,
174
-				$this->appManager,
175
-				$this->serverContainer,
176
-				$this->userStatusManager,
177
-				$this->previewManager,
178
-				$this->dateTimeZone,
179
-				$this->logger,
180
-				$this->factory,
181
-				$this->mailer,
182
-				$this->tagManager,
183
-				$this->getEmailValidatorWithStrictEmailCheck(),
184
-				$this->trustedServers,
185
-				$this->currentUser,
186
-			])->onlyMethods(['formatShare'])
187
-			->getMock();
188
-	}
189
-
190
-	private function newShare() {
191
-		return Server::get(IManager::class)->newShare();
192
-	}
193
-
194
-
195
-	private function mockShareAttributes() {
196
-		$formattedShareAttributes = [
197
-			[
198
-				'scope' => 'permissions',
199
-				'key' => 'download',
200
-				'value' => true
201
-			]
202
-		];
203
-
204
-		$shareAttributes = $this->createMock(IShareAttributes::class);
205
-		$shareAttributes->method('toArray')->willReturn($formattedShareAttributes);
206
-		$shareAttributes->method('getAttribute')->with('permissions', 'download')->willReturn(true);
207
-
208
-		// send both IShare attributes class and expected json string
209
-		return [$shareAttributes, \json_encode($formattedShareAttributes)];
210
-	}
211
-
212
-	public function testDeleteShareShareNotFound(): void {
213
-		$this->expectException(OCSNotFoundException::class);
214
-		$this->expectExceptionMessage('Wrong share ID, share does not exist');
215
-
216
-		$this->shareManager
217
-			->expects($this->exactly(7))
218
-			->method('getShareById')
219
-			->willReturnCallback(function ($id): void {
220
-				if ($id === 'ocinternal:42' || $id === 'ocRoomShare:42' || $id === 'ocFederatedSharing:42' || $id === 'ocCircleShare:42' || $id === 'ocMailShare:42' || $id === 'deck:42' || $id === 'sciencemesh:42') {
221
-					throw new ShareNotFound();
222
-				} else {
223
-					throw new \Exception();
224
-				}
225
-			});
226
-
227
-		$this->shareManager->method('outgoingServer2ServerSharesAllowed')->willReturn(true);
228
-
229
-		$this->ocs->deleteShare(42);
230
-	}
231
-
232
-	public function testDeleteShare(): void {
233
-		$node = $this->getMockBuilder(File::class)->getMock();
234
-
235
-		$share = $this->newShare();
236
-		$share->setSharedBy($this->currentUser)
237
-			->setNode($node);
238
-		$this->shareManager
239
-			->expects($this->once())
240
-			->method('getShareById')
241
-			->with('ocinternal:42')
242
-			->willReturn($share);
243
-		$this->shareManager
244
-			->expects($this->once())
245
-			->method('deleteShare')
246
-			->with($share);
247
-
248
-		$node->expects($this->once())
249
-			->method('lock')
250
-			->with(ILockingProvider::LOCK_SHARED);
251
-
252
-		$expected = new DataResponse();
253
-		$result = $this->ocs->deleteShare(42);
254
-
255
-		$this->assertInstanceOf(get_class($expected), $result);
256
-		$this->assertEquals($expected->getData(), $result->getData());
257
-	}
258
-
259
-
260
-	public function testDeleteShareLocked(): void {
261
-		$this->expectException(OCSNotFoundException::class);
262
-		$this->expectExceptionMessage('Could not delete share');
263
-
264
-		$node = $this->getMockBuilder(File::class)->getMock();
265
-		$node->method('getId')->willReturn(1);
266
-
267
-		$share = $this->newShare();
268
-		$share->setNode($node);
269
-
270
-		$userFolder = $this->getMockBuilder(Folder::class)->getMock();
271
-		$this->rootFolder->method('getUserFolder')
272
-			->with($this->currentUser)
273
-			->willReturn($userFolder);
274
-
275
-		$userFolder->method('getById')
276
-			->with($share->getNodeId())
277
-			->willReturn([$node]);
278
-
279
-		$this->shareManager
280
-			->expects($this->once())
281
-			->method('getShareById')
282
-			->with('ocinternal:42')
283
-			->willReturn($share);
284
-
285
-		$this->shareManager
286
-			->expects($this->never())
287
-			->method('deleteShare')
288
-			->with($share);
289
-
290
-		$node->expects($this->once())
291
-			->method('lock')
292
-			->with(ILockingProvider::LOCK_SHARED)
293
-			->willThrowException(new LockedException('mypath'));
294
-
295
-		$this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteFromSelf', [$share]));
296
-		$this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteShare', [$share]));
297
-
298
-		$this->ocs->deleteShare(42);
299
-	}
300
-
301
-	/**
302
-	 * You can always remove a share that was shared with you
303
-	 */
304
-	public function testDeleteShareWithMe(): void {
305
-		$node = $this->getMockBuilder(File::class)->getMock();
306
-
307
-		$share = $this->newShare();
308
-		$share->setSharedWith($this->currentUser)
309
-			->setShareType(IShare::TYPE_USER)
310
-			->setNode($node);
311
-
312
-		$this->shareManager
313
-			->expects($this->once())
314
-			->method('getShareById')
315
-			->with('ocinternal:42')
316
-			->willReturn($share);
317
-
318
-		$this->shareManager
319
-			->expects($this->once())
320
-			->method('deleteShare')
321
-			->with($share);
322
-
323
-		$node->expects($this->once())
324
-			->method('lock')
325
-			->with(ILockingProvider::LOCK_SHARED);
326
-
327
-		$this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteFromSelf', [$share]));
328
-		$this->assertTrue($this->invokePrivate($this->ocs, 'canDeleteShare', [$share]));
329
-
330
-		$this->ocs->deleteShare(42);
331
-	}
332
-
333
-	/**
334
-	 * You can always delete a share you own
335
-	 */
336
-	public function testDeleteShareOwner(): void {
337
-		$node = $this->getMockBuilder(File::class)->getMock();
338
-
339
-		$share = $this->newShare();
340
-		$share->setSharedBy($this->currentUser)
341
-			->setNode($node);
342
-
343
-		$this->shareManager
344
-			->expects($this->once())
345
-			->method('getShareById')
346
-			->with('ocinternal:42')
347
-			->willReturn($share);
348
-
349
-		$this->shareManager
350
-			->expects($this->once())
351
-			->method('deleteShare')
352
-			->with($share);
353
-
354
-		$node->expects($this->once())
355
-			->method('lock')
356
-			->with(ILockingProvider::LOCK_SHARED);
357
-
358
-		$this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteFromSelf', [$share]));
359
-		$this->assertTrue($this->invokePrivate($this->ocs, 'canDeleteShare', [$share]));
360
-
361
-		$this->ocs->deleteShare(42);
362
-	}
363
-
364
-	/**
365
-	 * You can always delete a share when you own
366
-	 * the file path it belong to
367
-	 */
368
-	public function testDeleteShareFileOwner(): void {
369
-		$node = $this->getMockBuilder(File::class)->getMock();
370
-		$node->method('getId')->willReturn(1);
371
-
372
-		$share = $this->newShare();
373
-		$share->setShareOwner($this->currentUser)
374
-			->setNode($node);
375
-
376
-		$this->shareManager
377
-			->expects($this->once())
378
-			->method('getShareById')
379
-			->with('ocinternal:42')
380
-			->willReturn($share);
381
-
382
-		$this->shareManager
383
-			->expects($this->once())
384
-			->method('deleteShare')
385
-			->with($share);
386
-
387
-		$node->expects($this->once())
388
-			->method('lock')
389
-			->with(ILockingProvider::LOCK_SHARED);
390
-
391
-		$this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteFromSelf', [$share]));
392
-		$this->assertTrue($this->invokePrivate($this->ocs, 'canDeleteShare', [$share]));
393
-
394
-		$this->ocs->deleteShare(42);
395
-	}
396
-
397
-	/**
398
-	 * You can remove (the mountpoint, not the share)
399
-	 * a share if you're in the group the share is shared with
400
-	 */
401
-	public function testDeleteSharedWithMyGroup(): void {
402
-		$node = $this->getMockBuilder(File::class)->getMock();
403
-		$node->method('getId')->willReturn(1);
404
-
405
-		$share = $this->newShare();
406
-		$share->setShareType(IShare::TYPE_GROUP)
407
-			->setSharedWith('group')
408
-			->setNode($node);
409
-
410
-		$this->shareManager
411
-			->expects($this->once())
412
-			->method('getShareById')
413
-			->with('ocinternal:42')
414
-			->willReturn($share);
415
-
416
-		// canDeleteShareFromSelf
417
-		$user = $this->createMock(IUser::class);
418
-		$group = $this->getMockBuilder(IGroup::class)->getMock();
419
-		$this->groupManager
420
-			->method('get')
421
-			->with('group')
422
-			->willReturn($group);
423
-		$this->userManager
424
-			->method('get')
425
-			->with($this->currentUser)
426
-			->willReturn($user);
427
-		$group->method('inGroup')
428
-			->with($user)
429
-			->willReturn(true);
430
-
431
-		$node->expects($this->once())
432
-			->method('lock')
433
-			->with(ILockingProvider::LOCK_SHARED);
434
-
435
-		$userFolder = $this->getMockBuilder(Folder::class)->getMock();
436
-		$this->rootFolder->method('getUserFolder')
437
-			->with($this->currentUser)
438
-			->willReturn($userFolder);
439
-
440
-		$userFolder->method('getById')
441
-			->with($share->getNodeId())
442
-			->willReturn([$share->getNode()]);
443
-
444
-		$this->shareManager->expects($this->once())
445
-			->method('deleteFromSelf')
446
-			->with($share, $this->currentUser);
447
-
448
-		$this->shareManager->expects($this->never())
449
-			->method('deleteShare');
450
-
451
-		$this->assertTrue($this->invokePrivate($this->ocs, 'canDeleteShareFromSelf', [$share]));
452
-		$this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteShare', [$share]));
453
-
454
-		$this->ocs->deleteShare(42);
455
-	}
456
-
457
-	/**
458
-	 * You cannot remove a share if you're not
459
-	 * in the group the share is shared with
460
-	 */
461
-	public function testDeleteSharedWithGroupIDontBelongTo(): void {
462
-		$this->expectException(OCSNotFoundException::class);
463
-		$this->expectExceptionMessage('Wrong share ID, share does not exist');
464
-
465
-		$node = $this->getMockBuilder(File::class)->getMock();
466
-		$node->method('getId')->willReturn(42);
467
-
468
-		$share = $this->newShare();
469
-		$share->setShareType(IShare::TYPE_GROUP)
470
-			->setSharedWith('group')
471
-			->setNode($node);
472
-
473
-		$this->shareManager
474
-			->expects($this->once())
475
-			->method('getShareById')
476
-			->with('ocinternal:42')
477
-			->willReturn($share);
478
-
479
-		// canDeleteShareFromSelf
480
-		$user = $this->createMock(IUser::class);
481
-		$group = $this->getMockBuilder(IGroup::class)->getMock();
482
-		$this->groupManager
483
-			->method('get')
484
-			->with('group')
485
-			->willReturn($group);
486
-		$this->userManager
487
-			->method('get')
488
-			->with($this->currentUser)
489
-			->willReturn($user);
490
-		$group->method('inGroup')
491
-			->with($user)
492
-			->willReturn(false);
493
-
494
-		$node->expects($this->once())
495
-			->method('lock')
496
-			->with(ILockingProvider::LOCK_SHARED);
497
-
498
-		$userFolder = $this->getMockBuilder(Folder::class)->getMock();
499
-		$this->rootFolder->method('getUserFolder')
500
-			->with($this->currentUser)
501
-			->willReturn($userFolder);
502
-
503
-		$userFolder->method('getById')
504
-			->with($share->getNodeId())
505
-			->willReturn([$share->getNode()]);
506
-
507
-		$this->shareManager->expects($this->never())
508
-			->method('deleteFromSelf');
509
-
510
-		$this->shareManager->expects($this->never())
511
-			->method('deleteShare');
512
-
513
-		$this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteShareFromSelf', [$share]));
514
-		$this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteShare', [$share]));
515
-
516
-		$this->ocs->deleteShare(42);
517
-	}
518
-
519
-	public function testDeleteShareOwnerless(): void {
520
-		$ocs = $this->mockFormatShare();
521
-
522
-		$mount = $this->createMock(IShareOwnerlessMount::class);
523
-
524
-		$file = $this->createMock(File::class);
525
-		$file
526
-			->expects($this->exactly(2))
527
-			->method('getPermissions')
528
-			->willReturn(Constants::PERMISSION_SHARE);
529
-		$file
530
-			->expects($this->once())
531
-			->method('getMountPoint')
532
-			->willReturn($mount);
533
-
534
-		$userFolder = $this->createMock(Folder::class);
535
-		$userFolder->method('getById')
536
-			->with(2)
537
-			->willReturn([$file]);
538
-		$userFolder->method('getFirstNodeById')
539
-			->with(2)
540
-			->willReturn($file);
541
-
542
-		$this->rootFolder
543
-			->method('getUserFolder')
544
-			->with($this->currentUser)
545
-			->willReturn($userFolder);
546
-
547
-		$share = $this->createMock(IShare::class);
548
-		$share
549
-			->expects($this->once())
550
-			->method('getNode')
551
-			->willReturn($file);
552
-		$share
553
-			->expects($this->exactly(2))
554
-			->method('getNodeId')
555
-			->willReturn(2);
556
-		$share
557
-			->expects($this->exactly(2))
558
-			->method('getPermissions')
559
-			->willReturn(Constants::PERMISSION_SHARE);
560
-
561
-		$this->shareManager
562
-			->expects($this->once())
563
-			->method('getShareById')
564
-			->with('ocinternal:1', $this->currentUser)
565
-			->willReturn($share);
566
-
567
-		$this->shareManager
568
-			->expects($this->once())
569
-			->method('deleteShare')
570
-			->with($share);
571
-
572
-		$result = $ocs->deleteShare(1);
573
-		$this->assertInstanceOf(DataResponse::class, $result);
574
-	}
575
-
576
-	/*
66
+    use EmailValidatorTrait;
67
+
68
+    private string $appName = 'files_sharing';
69
+    private string $currentUser;
70
+
71
+    private ShareAPIController $ocs;
72
+
73
+    private IManager&MockObject $shareManager;
74
+    private IGroupManager&MockObject $groupManager;
75
+    private IUserManager&MockObject $userManager;
76
+    private IRequest&MockObject $request;
77
+    private IRootFolder&MockObject $rootFolder;
78
+    private IURLGenerator&MockObject $urlGenerator;
79
+    private IL10N&MockObject $l;
80
+    private IConfig&MockObject $config;
81
+    private IAppConfig&MockObject $appConfig;
82
+    private IAppManager&MockObject $appManager;
83
+    private ContainerInterface&MockObject $serverContainer;
84
+    private IUserStatusManager&MockObject $userStatusManager;
85
+    private IPreview&MockObject $previewManager;
86
+    private IDateTimeZone&MockObject $dateTimeZone;
87
+    private LoggerInterface&MockObject $logger;
88
+    private IProviderFactory&MockObject $factory;
89
+    private IMailer&MockObject $mailer;
90
+    private ITagManager&MockObject $tagManager;
91
+    private TrustedServers&MockObject $trustedServers;
92
+
93
+    protected function setUp(): void {
94
+        $this->shareManager = $this->createMock(IManager::class);
95
+        $this->shareManager
96
+            ->expects($this->any())
97
+            ->method('shareApiEnabled')
98
+            ->willReturn(true);
99
+        $this->shareManager
100
+            ->expects($this->any())
101
+            ->method('shareProviderExists')->willReturn(true);
102
+        $this->groupManager = $this->createMock(IGroupManager::class);
103
+        $this->userManager = $this->createMock(IUserManager::class);
104
+        $this->request = $this->createMock(IRequest::class);
105
+        $this->rootFolder = $this->createMock(IRootFolder::class);
106
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
107
+        $this->currentUser = 'currentUser';
108
+
109
+        $this->l = $this->createMock(IL10N::class);
110
+        $this->l->method('t')
111
+            ->willReturnCallback(function ($text, $parameters = []) {
112
+                return vsprintf($text, $parameters);
113
+            });
114
+        $this->config = $this->createMock(IConfig::class);
115
+        $this->appConfig = $this->createMock(IAppConfig::class);
116
+        $this->appManager = $this->createMock(IAppManager::class);
117
+        $this->serverContainer = $this->createMock(ContainerInterface::class);
118
+        $this->userStatusManager = $this->createMock(IUserStatusManager::class);
119
+        $this->previewManager = $this->createMock(IPreview::class);
120
+        $this->previewManager->method('isAvailable')
121
+            ->willReturnCallback(function ($fileInfo) {
122
+                return $fileInfo->getMimeType() === 'mimeWithPreview';
123
+            });
124
+        $this->dateTimeZone = $this->createMock(IDateTimeZone::class);
125
+        $this->logger = $this->createMock(LoggerInterface::class);
126
+        $this->factory = $this->createMock(IProviderFactory::class);
127
+        $this->mailer = $this->createMock(IMailer::class);
128
+        $this->tagManager = $this->createMock(ITagManager::class);
129
+        $this->trustedServers = $this->createMock(TrustedServers::class);
130
+
131
+        $this->ocs = new ShareAPIController(
132
+            $this->appName,
133
+            $this->request,
134
+            $this->shareManager,
135
+            $this->groupManager,
136
+            $this->userManager,
137
+            $this->rootFolder,
138
+            $this->urlGenerator,
139
+            $this->l,
140
+            $this->config,
141
+            $this->appConfig,
142
+            $this->appManager,
143
+            $this->serverContainer,
144
+            $this->userStatusManager,
145
+            $this->previewManager,
146
+            $this->dateTimeZone,
147
+            $this->logger,
148
+            $this->factory,
149
+            $this->mailer,
150
+            $this->tagManager,
151
+            $this->getEmailValidatorWithStrictEmailCheck(),
152
+            $this->trustedServers,
153
+            $this->currentUser,
154
+        );
155
+
156
+    }
157
+
158
+    /**
159
+     * @return ShareAPIController&MockObject
160
+     */
161
+    private function mockFormatShare() {
162
+        return $this->getMockBuilder(ShareAPIController::class)
163
+            ->setConstructorArgs([
164
+                $this->appName,
165
+                $this->request,
166
+                $this->shareManager,
167
+                $this->groupManager,
168
+                $this->userManager,
169
+                $this->rootFolder,
170
+                $this->urlGenerator,
171
+                $this->l,
172
+                $this->config,
173
+                $this->appConfig,
174
+                $this->appManager,
175
+                $this->serverContainer,
176
+                $this->userStatusManager,
177
+                $this->previewManager,
178
+                $this->dateTimeZone,
179
+                $this->logger,
180
+                $this->factory,
181
+                $this->mailer,
182
+                $this->tagManager,
183
+                $this->getEmailValidatorWithStrictEmailCheck(),
184
+                $this->trustedServers,
185
+                $this->currentUser,
186
+            ])->onlyMethods(['formatShare'])
187
+            ->getMock();
188
+    }
189
+
190
+    private function newShare() {
191
+        return Server::get(IManager::class)->newShare();
192
+    }
193
+
194
+
195
+    private function mockShareAttributes() {
196
+        $formattedShareAttributes = [
197
+            [
198
+                'scope' => 'permissions',
199
+                'key' => 'download',
200
+                'value' => true
201
+            ]
202
+        ];
203
+
204
+        $shareAttributes = $this->createMock(IShareAttributes::class);
205
+        $shareAttributes->method('toArray')->willReturn($formattedShareAttributes);
206
+        $shareAttributes->method('getAttribute')->with('permissions', 'download')->willReturn(true);
207
+
208
+        // send both IShare attributes class and expected json string
209
+        return [$shareAttributes, \json_encode($formattedShareAttributes)];
210
+    }
211
+
212
+    public function testDeleteShareShareNotFound(): void {
213
+        $this->expectException(OCSNotFoundException::class);
214
+        $this->expectExceptionMessage('Wrong share ID, share does not exist');
215
+
216
+        $this->shareManager
217
+            ->expects($this->exactly(7))
218
+            ->method('getShareById')
219
+            ->willReturnCallback(function ($id): void {
220
+                if ($id === 'ocinternal:42' || $id === 'ocRoomShare:42' || $id === 'ocFederatedSharing:42' || $id === 'ocCircleShare:42' || $id === 'ocMailShare:42' || $id === 'deck:42' || $id === 'sciencemesh:42') {
221
+                    throw new ShareNotFound();
222
+                } else {
223
+                    throw new \Exception();
224
+                }
225
+            });
226
+
227
+        $this->shareManager->method('outgoingServer2ServerSharesAllowed')->willReturn(true);
228
+
229
+        $this->ocs->deleteShare(42);
230
+    }
231
+
232
+    public function testDeleteShare(): void {
233
+        $node = $this->getMockBuilder(File::class)->getMock();
234
+
235
+        $share = $this->newShare();
236
+        $share->setSharedBy($this->currentUser)
237
+            ->setNode($node);
238
+        $this->shareManager
239
+            ->expects($this->once())
240
+            ->method('getShareById')
241
+            ->with('ocinternal:42')
242
+            ->willReturn($share);
243
+        $this->shareManager
244
+            ->expects($this->once())
245
+            ->method('deleteShare')
246
+            ->with($share);
247
+
248
+        $node->expects($this->once())
249
+            ->method('lock')
250
+            ->with(ILockingProvider::LOCK_SHARED);
251
+
252
+        $expected = new DataResponse();
253
+        $result = $this->ocs->deleteShare(42);
254
+
255
+        $this->assertInstanceOf(get_class($expected), $result);
256
+        $this->assertEquals($expected->getData(), $result->getData());
257
+    }
258
+
259
+
260
+    public function testDeleteShareLocked(): void {
261
+        $this->expectException(OCSNotFoundException::class);
262
+        $this->expectExceptionMessage('Could not delete share');
263
+
264
+        $node = $this->getMockBuilder(File::class)->getMock();
265
+        $node->method('getId')->willReturn(1);
266
+
267
+        $share = $this->newShare();
268
+        $share->setNode($node);
269
+
270
+        $userFolder = $this->getMockBuilder(Folder::class)->getMock();
271
+        $this->rootFolder->method('getUserFolder')
272
+            ->with($this->currentUser)
273
+            ->willReturn($userFolder);
274
+
275
+        $userFolder->method('getById')
276
+            ->with($share->getNodeId())
277
+            ->willReturn([$node]);
278
+
279
+        $this->shareManager
280
+            ->expects($this->once())
281
+            ->method('getShareById')
282
+            ->with('ocinternal:42')
283
+            ->willReturn($share);
284
+
285
+        $this->shareManager
286
+            ->expects($this->never())
287
+            ->method('deleteShare')
288
+            ->with($share);
289
+
290
+        $node->expects($this->once())
291
+            ->method('lock')
292
+            ->with(ILockingProvider::LOCK_SHARED)
293
+            ->willThrowException(new LockedException('mypath'));
294
+
295
+        $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteFromSelf', [$share]));
296
+        $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteShare', [$share]));
297
+
298
+        $this->ocs->deleteShare(42);
299
+    }
300
+
301
+    /**
302
+     * You can always remove a share that was shared with you
303
+     */
304
+    public function testDeleteShareWithMe(): void {
305
+        $node = $this->getMockBuilder(File::class)->getMock();
306
+
307
+        $share = $this->newShare();
308
+        $share->setSharedWith($this->currentUser)
309
+            ->setShareType(IShare::TYPE_USER)
310
+            ->setNode($node);
311
+
312
+        $this->shareManager
313
+            ->expects($this->once())
314
+            ->method('getShareById')
315
+            ->with('ocinternal:42')
316
+            ->willReturn($share);
317
+
318
+        $this->shareManager
319
+            ->expects($this->once())
320
+            ->method('deleteShare')
321
+            ->with($share);
322
+
323
+        $node->expects($this->once())
324
+            ->method('lock')
325
+            ->with(ILockingProvider::LOCK_SHARED);
326
+
327
+        $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteFromSelf', [$share]));
328
+        $this->assertTrue($this->invokePrivate($this->ocs, 'canDeleteShare', [$share]));
329
+
330
+        $this->ocs->deleteShare(42);
331
+    }
332
+
333
+    /**
334
+     * You can always delete a share you own
335
+     */
336
+    public function testDeleteShareOwner(): void {
337
+        $node = $this->getMockBuilder(File::class)->getMock();
338
+
339
+        $share = $this->newShare();
340
+        $share->setSharedBy($this->currentUser)
341
+            ->setNode($node);
342
+
343
+        $this->shareManager
344
+            ->expects($this->once())
345
+            ->method('getShareById')
346
+            ->with('ocinternal:42')
347
+            ->willReturn($share);
348
+
349
+        $this->shareManager
350
+            ->expects($this->once())
351
+            ->method('deleteShare')
352
+            ->with($share);
353
+
354
+        $node->expects($this->once())
355
+            ->method('lock')
356
+            ->with(ILockingProvider::LOCK_SHARED);
357
+
358
+        $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteFromSelf', [$share]));
359
+        $this->assertTrue($this->invokePrivate($this->ocs, 'canDeleteShare', [$share]));
360
+
361
+        $this->ocs->deleteShare(42);
362
+    }
363
+
364
+    /**
365
+     * You can always delete a share when you own
366
+     * the file path it belong to
367
+     */
368
+    public function testDeleteShareFileOwner(): void {
369
+        $node = $this->getMockBuilder(File::class)->getMock();
370
+        $node->method('getId')->willReturn(1);
371
+
372
+        $share = $this->newShare();
373
+        $share->setShareOwner($this->currentUser)
374
+            ->setNode($node);
375
+
376
+        $this->shareManager
377
+            ->expects($this->once())
378
+            ->method('getShareById')
379
+            ->with('ocinternal:42')
380
+            ->willReturn($share);
381
+
382
+        $this->shareManager
383
+            ->expects($this->once())
384
+            ->method('deleteShare')
385
+            ->with($share);
386
+
387
+        $node->expects($this->once())
388
+            ->method('lock')
389
+            ->with(ILockingProvider::LOCK_SHARED);
390
+
391
+        $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteFromSelf', [$share]));
392
+        $this->assertTrue($this->invokePrivate($this->ocs, 'canDeleteShare', [$share]));
393
+
394
+        $this->ocs->deleteShare(42);
395
+    }
396
+
397
+    /**
398
+     * You can remove (the mountpoint, not the share)
399
+     * a share if you're in the group the share is shared with
400
+     */
401
+    public function testDeleteSharedWithMyGroup(): void {
402
+        $node = $this->getMockBuilder(File::class)->getMock();
403
+        $node->method('getId')->willReturn(1);
404
+
405
+        $share = $this->newShare();
406
+        $share->setShareType(IShare::TYPE_GROUP)
407
+            ->setSharedWith('group')
408
+            ->setNode($node);
409
+
410
+        $this->shareManager
411
+            ->expects($this->once())
412
+            ->method('getShareById')
413
+            ->with('ocinternal:42')
414
+            ->willReturn($share);
415
+
416
+        // canDeleteShareFromSelf
417
+        $user = $this->createMock(IUser::class);
418
+        $group = $this->getMockBuilder(IGroup::class)->getMock();
419
+        $this->groupManager
420
+            ->method('get')
421
+            ->with('group')
422
+            ->willReturn($group);
423
+        $this->userManager
424
+            ->method('get')
425
+            ->with($this->currentUser)
426
+            ->willReturn($user);
427
+        $group->method('inGroup')
428
+            ->with($user)
429
+            ->willReturn(true);
430
+
431
+        $node->expects($this->once())
432
+            ->method('lock')
433
+            ->with(ILockingProvider::LOCK_SHARED);
434
+
435
+        $userFolder = $this->getMockBuilder(Folder::class)->getMock();
436
+        $this->rootFolder->method('getUserFolder')
437
+            ->with($this->currentUser)
438
+            ->willReturn($userFolder);
439
+
440
+        $userFolder->method('getById')
441
+            ->with($share->getNodeId())
442
+            ->willReturn([$share->getNode()]);
443
+
444
+        $this->shareManager->expects($this->once())
445
+            ->method('deleteFromSelf')
446
+            ->with($share, $this->currentUser);
447
+
448
+        $this->shareManager->expects($this->never())
449
+            ->method('deleteShare');
450
+
451
+        $this->assertTrue($this->invokePrivate($this->ocs, 'canDeleteShareFromSelf', [$share]));
452
+        $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteShare', [$share]));
453
+
454
+        $this->ocs->deleteShare(42);
455
+    }
456
+
457
+    /**
458
+     * You cannot remove a share if you're not
459
+     * in the group the share is shared with
460
+     */
461
+    public function testDeleteSharedWithGroupIDontBelongTo(): void {
462
+        $this->expectException(OCSNotFoundException::class);
463
+        $this->expectExceptionMessage('Wrong share ID, share does not exist');
464
+
465
+        $node = $this->getMockBuilder(File::class)->getMock();
466
+        $node->method('getId')->willReturn(42);
467
+
468
+        $share = $this->newShare();
469
+        $share->setShareType(IShare::TYPE_GROUP)
470
+            ->setSharedWith('group')
471
+            ->setNode($node);
472
+
473
+        $this->shareManager
474
+            ->expects($this->once())
475
+            ->method('getShareById')
476
+            ->with('ocinternal:42')
477
+            ->willReturn($share);
478
+
479
+        // canDeleteShareFromSelf
480
+        $user = $this->createMock(IUser::class);
481
+        $group = $this->getMockBuilder(IGroup::class)->getMock();
482
+        $this->groupManager
483
+            ->method('get')
484
+            ->with('group')
485
+            ->willReturn($group);
486
+        $this->userManager
487
+            ->method('get')
488
+            ->with($this->currentUser)
489
+            ->willReturn($user);
490
+        $group->method('inGroup')
491
+            ->with($user)
492
+            ->willReturn(false);
493
+
494
+        $node->expects($this->once())
495
+            ->method('lock')
496
+            ->with(ILockingProvider::LOCK_SHARED);
497
+
498
+        $userFolder = $this->getMockBuilder(Folder::class)->getMock();
499
+        $this->rootFolder->method('getUserFolder')
500
+            ->with($this->currentUser)
501
+            ->willReturn($userFolder);
502
+
503
+        $userFolder->method('getById')
504
+            ->with($share->getNodeId())
505
+            ->willReturn([$share->getNode()]);
506
+
507
+        $this->shareManager->expects($this->never())
508
+            ->method('deleteFromSelf');
509
+
510
+        $this->shareManager->expects($this->never())
511
+            ->method('deleteShare');
512
+
513
+        $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteShareFromSelf', [$share]));
514
+        $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteShare', [$share]));
515
+
516
+        $this->ocs->deleteShare(42);
517
+    }
518
+
519
+    public function testDeleteShareOwnerless(): void {
520
+        $ocs = $this->mockFormatShare();
521
+
522
+        $mount = $this->createMock(IShareOwnerlessMount::class);
523
+
524
+        $file = $this->createMock(File::class);
525
+        $file
526
+            ->expects($this->exactly(2))
527
+            ->method('getPermissions')
528
+            ->willReturn(Constants::PERMISSION_SHARE);
529
+        $file
530
+            ->expects($this->once())
531
+            ->method('getMountPoint')
532
+            ->willReturn($mount);
533
+
534
+        $userFolder = $this->createMock(Folder::class);
535
+        $userFolder->method('getById')
536
+            ->with(2)
537
+            ->willReturn([$file]);
538
+        $userFolder->method('getFirstNodeById')
539
+            ->with(2)
540
+            ->willReturn($file);
541
+
542
+        $this->rootFolder
543
+            ->method('getUserFolder')
544
+            ->with($this->currentUser)
545
+            ->willReturn($userFolder);
546
+
547
+        $share = $this->createMock(IShare::class);
548
+        $share
549
+            ->expects($this->once())
550
+            ->method('getNode')
551
+            ->willReturn($file);
552
+        $share
553
+            ->expects($this->exactly(2))
554
+            ->method('getNodeId')
555
+            ->willReturn(2);
556
+        $share
557
+            ->expects($this->exactly(2))
558
+            ->method('getPermissions')
559
+            ->willReturn(Constants::PERMISSION_SHARE);
560
+
561
+        $this->shareManager
562
+            ->expects($this->once())
563
+            ->method('getShareById')
564
+            ->with('ocinternal:1', $this->currentUser)
565
+            ->willReturn($share);
566
+
567
+        $this->shareManager
568
+            ->expects($this->once())
569
+            ->method('deleteShare')
570
+            ->with($share);
571
+
572
+        $result = $ocs->deleteShare(1);
573
+        $this->assertInstanceOf(DataResponse::class, $result);
574
+    }
575
+
576
+    /*
577 577
 	 * FIXME: Enable once we have a federated Share Provider
578 578
 
579 579
 	public function testGetGetShareNotExists() {
@@ -588,4848 +588,4848 @@  discard block
 block discarded – undo
588 588
 	}
589 589
 	*/
590 590
 
591
-	public function createShare(
592
-		int $id,
593
-		int $shareType,
594
-		?string $sharedWith,
595
-		string $sharedBy,
596
-		string $shareOwner,
597
-		File|Folder|null $node,
598
-		int $permissions,
599
-		int $shareTime,
600
-		?\DateTime $expiration,
601
-		int $parent,
602
-		string $target,
603
-		int $mail_send,
604
-		string $note = '',
605
-		?string $token = null,
606
-		?string $password = null,
607
-		string $label = '',
608
-		?IShareAttributes $attributes = null,
609
-	): MockObject {
610
-		$share = $this->createMock(IShare::class);
611
-		$share->method('getId')->willReturn($id);
612
-		$share->method('getShareType')->willReturn($shareType);
613
-		$share->method('getSharedWith')->willReturn($sharedWith);
614
-		$share->method('getSharedBy')->willReturn($sharedBy);
615
-		$share->method('getShareOwner')->willReturn($shareOwner);
616
-		$share->method('getNode')->willReturn($node);
617
-		$share->method('getPermissions')->willReturn($permissions);
618
-		$share->method('getNote')->willReturn($note);
619
-		$share->method('getLabel')->willReturn($label);
620
-		$share->method('getAttributes')->willReturn($attributes);
621
-		$time = new \DateTime();
622
-		$time->setTimestamp($shareTime);
623
-		$share->method('getShareTime')->willReturn($time);
624
-		$share->method('getExpirationDate')->willReturn($expiration);
625
-		$share->method('getTarget')->willReturn($target);
626
-		$share->method('getMailSend')->willReturn($mail_send);
627
-		$share->method('getToken')->willReturn($token);
628
-		$share->method('getPassword')->willReturn($password);
629
-
630
-		if ($shareType === IShare::TYPE_USER
631
-			|| $shareType === IShare::TYPE_GROUP
632
-			|| $shareType === IShare::TYPE_LINK) {
633
-			$share->method('getFullId')->willReturn('ocinternal:' . $id);
634
-		}
635
-
636
-		return $share;
637
-	}
638
-
639
-	public static function dataGetShare(): array {
640
-		$data = [];
641
-
642
-		$file = [
643
-			'class' => File::class,
644
-			'id' => 1,
645
-			'path' => 'file',
646
-			'mimeType' => 'myMimeType',
647
-		];
648
-
649
-		$folder = [
650
-			'class' => Folder::class,
651
-			'id' => 2,
652
-			'path' => 'folder',
653
-			'mimeType' => 'myFolderMimeType',
654
-		];
655
-
656
-		// File shared with user
657
-		$share = [
658
-			100,
659
-			IShare::TYPE_USER,
660
-			'userId',
661
-			'initiatorId',
662
-			'ownerId',
663
-			$file,
664
-			4,
665
-			5,
666
-			null,
667
-			6,
668
-			'target',
669
-			0,
670
-			'personal note',
671
-			null,
672
-			null,
673
-			'',
674
-			[],
675
-		];
676
-		$expected = [
677
-			'id' => 100,
678
-			'share_type' => IShare::TYPE_USER,
679
-			'share_with' => 'userId',
680
-			'share_with_displayname' => 'userDisplay',
681
-			'share_with_displayname_unique' => '[email protected]',
682
-			'uid_owner' => 'initiatorId',
683
-			'displayname_owner' => 'initiatorDisplay',
684
-			'item_type' => 'file',
685
-			'item_source' => 1,
686
-			'file_source' => 1,
687
-			'file_target' => 'target',
688
-			'file_parent' => 3,
689
-			'token' => null,
690
-			'expiration' => null,
691
-			'permissions' => 4,
692
-			'stime' => 5,
693
-			'parent' => null,
694
-			'storage_id' => 'STORAGE',
695
-			'path' => 'file',
696
-			'storage' => 101,
697
-			'mail_send' => 0,
698
-			'uid_file_owner' => 'ownerId',
699
-			'note' => 'personal note',
700
-			'label' => '',
701
-			'displayname_file_owner' => 'ownerDisplay',
702
-			'mimetype' => 'myMimeType',
703
-			'has_preview' => false,
704
-			'hide_download' => 0,
705
-			'can_edit' => false,
706
-			'can_delete' => false,
707
-			'item_size' => 123465,
708
-			'item_mtime' => 1234567890,
709
-			'item_permissions' => 4,
710
-			'is-mount-root' => false,
711
-			'mount-type' => '',
712
-		];
713
-		$data['File shared with user'] = [$share, $expected, true];
714
-
715
-		// Folder shared with group
716
-		$share = [
717
-			101,
718
-			IShare::TYPE_GROUP,
719
-			'groupId',
720
-			'initiatorId',
721
-			'ownerId',
722
-			$folder,
723
-			4,
724
-			5,
725
-			null,
726
-			6,
727
-			'target',
728
-			0,
729
-			'personal note',
730
-			null,
731
-			null,
732
-			'',
733
-			[],
734
-		];
735
-		$expected = [
736
-			'id' => 101,
737
-			'share_type' => IShare::TYPE_GROUP,
738
-			'share_with' => 'groupId',
739
-			'share_with_displayname' => 'groupId',
740
-			'uid_owner' => 'initiatorId',
741
-			'displayname_owner' => 'initiatorDisplay',
742
-			'item_type' => 'folder',
743
-			'item_source' => 2,
744
-			'file_source' => 2,
745
-			'file_target' => 'target',
746
-			'file_parent' => 3,
747
-			'token' => null,
748
-			'expiration' => null,
749
-			'permissions' => 4,
750
-			'stime' => 5,
751
-			'parent' => null,
752
-			'storage_id' => 'STORAGE',
753
-			'path' => 'folder',
754
-			'storage' => 101,
755
-			'mail_send' => 0,
756
-			'uid_file_owner' => 'ownerId',
757
-			'note' => 'personal note',
758
-			'label' => '',
759
-			'displayname_file_owner' => 'ownerDisplay',
760
-			'mimetype' => 'myFolderMimeType',
761
-			'has_preview' => false,
762
-			'hide_download' => 0,
763
-			'can_edit' => false,
764
-			'can_delete' => false,
765
-			'item_size' => 123465,
766
-			'item_mtime' => 1234567890,
767
-			'item_permissions' => 4,
768
-			'is-mount-root' => false,
769
-			'mount-type' => '',
770
-		];
771
-		$data['Folder shared with group'] = [$share, $expected, true];
772
-
773
-		// File shared by link with Expire
774
-		$expire = \DateTime::createFromFormat('Y-m-d h:i:s', '2000-01-02 01:02:03');
775
-		$share = [
776
-			101,
777
-			IShare::TYPE_LINK,
778
-			null,
779
-			'initiatorId',
780
-			'ownerId',
781
-			$folder,
782
-			4,
783
-			5,
784
-			$expire,
785
-			6,
786
-			'target',
787
-			0,
788
-			'personal note',
789
-			'token',
790
-			'password',
791
-			'first link share'
792
-		];
793
-		$expected = [
794
-			'id' => 101,
795
-			'share_type' => IShare::TYPE_LINK,
796
-			'password' => 'password',
797
-			'share_with' => 'password',
798
-			'share_with_displayname' => '(Shared link)',
799
-			'send_password_by_talk' => false,
800
-			'uid_owner' => 'initiatorId',
801
-			'displayname_owner' => 'initiatorDisplay',
802
-			'item_type' => 'folder',
803
-			'item_source' => 2,
804
-			'file_source' => 2,
805
-			'file_target' => 'target',
806
-			'file_parent' => 3,
807
-			'token' => 'token',
808
-			'expiration' => '2000-01-02 00:00:00',
809
-			'permissions' => 4,
810
-			'attributes' => null,
811
-			'stime' => 5,
812
-			'parent' => null,
813
-			'storage_id' => 'STORAGE',
814
-			'path' => 'folder',
815
-			'storage' => 101,
816
-			'mail_send' => 0,
817
-			'url' => 'url',
818
-			'uid_file_owner' => 'ownerId',
819
-			'note' => 'personal note',
820
-			'label' => 'first link share',
821
-			'displayname_file_owner' => 'ownerDisplay',
822
-			'mimetype' => 'myFolderMimeType',
823
-			'has_preview' => false,
824
-			'hide_download' => 0,
825
-			'can_edit' => false,
826
-			'can_delete' => false,
827
-			'item_size' => 123465,
828
-			'item_mtime' => 1234567890,
829
-			'item_permissions' => 4,
830
-			'is-mount-root' => false,
831
-			'mount-type' => '',
832
-		];
833
-		$data['File shared by link with Expire'] = [$share, $expected, false];
834
-
835
-		return $data;
836
-	}
837
-
838
-	#[DataProvider('dataGetShare')]
839
-	public function testGetShare(array $shareParams, array $result, bool $attributes): void {
840
-
841
-		$cache = $this->createMock(ICache::class);
842
-		$cache->method('getNumericStorageId')->willReturn(101);
843
-
844
-		$storage = $this->createMock(IStorage::class);
845
-		$storage->method('getId')->willReturn('STORAGE');
846
-		$storage->method('getCache')->willReturn($cache);
847
-
848
-		$parentFolder = $this->createMock(Folder::class);
849
-		$parentFolder->method('getId')->willReturn(3);
850
-
851
-		$mountPoint = $this->createMock(IMountPoint::class);
852
-		$mountPoint->method('getMountType')->willReturn('');
853
-
854
-		$nodeParams = $shareParams[5];
855
-		$node = $this->createMock($nodeParams['class']);
856
-		$node->method('getId')->willReturn($nodeParams['id']);
857
-		$node->method('getPath')->willReturn($nodeParams['path']);
858
-		$node->method('getStorage')->willReturn($storage);
859
-		$node->method('getParent')->willReturn($parentFolder);
860
-		$node->method('getSize')->willReturn(123465);
861
-		$node->method('getMTime')->willReturn(1234567890);
862
-		$node->method('getMimeType')->willReturn($nodeParams['mimeType']);
863
-		$node->method('getMountPoint')->willReturn($mountPoint);
864
-
865
-		$shareParams[5] = $node;
866
-
867
-		if ($attributes) {
868
-			[$shareAttributes, $shareAttributesReturnJson] = $this->mockShareAttributes();
869
-			$result['attributes'] = $shareAttributesReturnJson;
870
-			$shareParams[16] = $shareAttributes;
871
-		}
872
-
873
-		$share = $this->createShare(...$shareParams);
874
-		/** @var ShareAPIController&MockObject $ocs */
875
-		$ocs = $this->getMockBuilder(ShareAPIController::class)
876
-			->setConstructorArgs([
877
-				$this->appName,
878
-				$this->request,
879
-				$this->shareManager,
880
-				$this->groupManager,
881
-				$this->userManager,
882
-				$this->rootFolder,
883
-				$this->urlGenerator,
884
-				$this->l,
885
-				$this->config,
886
-				$this->appConfig,
887
-				$this->appManager,
888
-				$this->serverContainer,
889
-				$this->userStatusManager,
890
-				$this->previewManager,
891
-				$this->dateTimeZone,
892
-				$this->logger,
893
-				$this->factory,
894
-				$this->mailer,
895
-				$this->tagManager,
896
-				$this->getEmailValidatorWithStrictEmailCheck(),
897
-				$this->trustedServers,
898
-				$this->currentUser,
899
-			])
900
-			->onlyMethods(['canAccessShare'])
901
-			->getMock();
902
-
903
-		$ocs->expects($this->any())
904
-			->method('canAccessShare')
905
-			->willReturn(true);
906
-
907
-		$this->shareManager
908
-			->expects($this->any())
909
-			->method('getShareById')
910
-			->with($share->getFullId(), 'currentUser')
911
-			->willReturn($share);
912
-
913
-		$userFolder = $this->getMockBuilder(Folder::class)->getMock();
914
-		$userFolder
915
-			->method('getRelativePath')
916
-			->willReturnArgument(0);
917
-
918
-		$userFolder->method('getById')
919
-			->with($share->getNodeId())
920
-			->willReturn([$share->getNode()]);
921
-		$userFolder->method('getFirstNodeById')
922
-			->with($share->getNodeId())
923
-			->willReturn($share->getNode());
924
-
925
-		$this->rootFolder->method('getUserFolder')
926
-			->with($this->currentUser)
927
-			->willReturn($userFolder);
928
-
929
-		$this->urlGenerator
930
-			->method('linkToRouteAbsolute')
931
-			->willReturn('url');
932
-
933
-		$initiator = $this->getMockBuilder(IUser::class)->getMock();
934
-		$initiator->method('getUID')->willReturn('initiatorId');
935
-		$initiator->method('getDisplayName')->willReturn('initiatorDisplay');
936
-
937
-		$owner = $this->getMockBuilder(IUser::class)->getMock();
938
-		$owner->method('getUID')->willReturn('ownerId');
939
-		$owner->method('getDisplayName')->willReturn('ownerDisplay');
940
-
941
-		$user = $this->getMockBuilder(IUser::class)->getMock();
942
-		$user->method('getUID')->willReturn('userId');
943
-		$user->method('getDisplayName')->willReturn('userDisplay');
944
-		$user->method('getSystemEMailAddress')->willReturn('[email protected]');
945
-
946
-		$group = $this->getMockBuilder(IGroup::class)->getMock();
947
-		$group->method('getGID')->willReturn('groupId');
948
-
949
-		$this->userManager->method('get')->willReturnMap([
950
-			['userId', $user],
951
-			['initiatorId', $initiator],
952
-			['ownerId', $owner],
953
-		]);
954
-		$this->groupManager->method('get')->willReturnMap([
955
-			['group', $group],
956
-		]);
957
-		$this->dateTimeZone->method('getTimezone')->willReturn(new \DateTimeZone('UTC'));
958
-
959
-		$data = $ocs->getShare((string)$share->getId())->getData()[0];
960
-		$this->assertEquals($result, $data);
961
-	}
962
-
963
-
964
-	public function testGetShareInvalidNode(): void {
965
-		$this->expectException(OCSNotFoundException::class);
966
-		$this->expectExceptionMessage('Wrong share ID, share does not exist');
967
-
968
-		$share = Server::get(IManager::class)->newShare();
969
-		$share->setSharedBy('initiator')
970
-			->setSharedWith('recipient')
971
-			->setShareOwner('owner');
972
-
973
-		$this->shareManager
974
-			->expects($this->once())
975
-			->method('getShareById')
976
-			->with('ocinternal:42', 'currentUser')
977
-			->willReturn($share);
978
-
979
-		$userFolder = $this->getMockBuilder(Folder::class)->getMock();
980
-		$this->rootFolder->method('getUserFolder')
981
-			->with($this->currentUser)
982
-			->willReturn($userFolder);
983
-
984
-		$this->ocs->getShare('42');
985
-	}
986
-
987
-	public static function dataGetShares(): array {
988
-		$file1 = [
989
-			'class' => File::class,
990
-			'methods' => [
991
-				'getName' => 'file1',
992
-			]
993
-		];
994
-		$file2 = [
995
-			'class' => File::class,
996
-			'methods' => [
997
-				'getName' => 'file2',
998
-			]
999
-		];
1000
-
1001
-		$folder = [
1002
-			'class' => Folder::class,
1003
-			'methods' => [
1004
-				'getDirectoryListing' => [$file1, $file2]
1005
-			]
1006
-		];
1007
-
1008
-		$file1UserShareOwner = [
1009
-			'type' => IShare::TYPE_USER,
1010
-			'sharedWith' => 'recipient',
1011
-			'sharedBy' => 'initiator',
1012
-			'owner' => 'currentUser',
1013
-			'node' => $file1,
1014
-			'id' => 4,
1015
-		];
1016
-
1017
-		$file1UserShareOwnerExpected = [
1018
-			'id' => 4,
1019
-			'share_type' => IShare::TYPE_USER,
1020
-		];
1021
-
1022
-		$file1UserShareInitiator = [
1023
-			'type' => IShare::TYPE_USER,
1024
-			'sharedWith' => 'recipient',
1025
-			'sharedBy' => 'currentUser',
1026
-			'owner' => 'owner',
1027
-			'node' => $file1,
1028
-			'id' => 8,
1029
-		];
1030
-
1031
-		$file1UserShareInitiatorExpected = [
1032
-			'id' => 8,
1033
-			'share_type' => IShare::TYPE_USER,
1034
-		];
1035
-
1036
-		$file1UserShareRecipient = [
1037
-			'type' => IShare::TYPE_USER,
1038
-			'sharedWith' => 'currentUser',
1039
-			'sharedBy' => 'initiator',
1040
-			'owner' => 'owner',
1041
-			'node' => $file1,
1042
-			'id' => 15,
1043
-		];
1044
-
1045
-		$file1UserShareRecipientExpected = [
1046
-			'id' => 15,
1047
-			'share_type' => IShare::TYPE_USER,
1048
-		];
1049
-
1050
-		$file1UserShareOther = [
1051
-			'type' => IShare::TYPE_USER,
1052
-			'sharedWith' => 'recipient',
1053
-			'sharedBy' => 'initiator',
1054
-			'owner' => 'owner',
1055
-			'node' => $file1,
1056
-			'id' => 16,
1057
-		];
1058
-
1059
-		$file1UserShareOtherExpected = [
1060
-			'id' => 16,
1061
-			'share_type' => IShare::TYPE_USER,
1062
-		];
1063
-
1064
-		$file1GroupShareOwner = [
1065
-			'type' => IShare::TYPE_GROUP,
1066
-			'sharedWith' => 'recipient',
1067
-			'sharedBy' => 'initiator',
1068
-			'owner' => 'currentUser',
1069
-			'node' => $file1,
1070
-			'id' => 23,
1071
-		];
1072
-
1073
-		$file1GroupShareOwnerExpected = [
1074
-			'id' => 23,
1075
-			'share_type' => IShare::TYPE_GROUP,
1076
-		];
1077
-
1078
-		$file1GroupShareRecipient = [
1079
-			'type' => IShare::TYPE_GROUP,
1080
-			'sharedWith' => 'currentUserGroup',
1081
-			'sharedBy' => 'initiator',
1082
-			'owner' => 'owner',
1083
-			'node' => $file1,
1084
-			'id' => 42,
1085
-		];
1086
-
1087
-		$file1GroupShareRecipientExpected = [
1088
-			'id' => 42,
1089
-			'share_type' => IShare::TYPE_GROUP,
1090
-		];
1091
-
1092
-		$file1GroupShareOther = [
1093
-			'type' => IShare::TYPE_GROUP,
1094
-			'sharedWith' => 'recipient',
1095
-			'sharedBy' => 'initiator',
1096
-			'owner' => 'owner',
1097
-			'node' => $file1,
1098
-			'id' => 108,
1099
-		];
1100
-
1101
-		$file1LinkShareOwner = [
1102
-			'type' => IShare::TYPE_LINK,
1103
-			'sharedWith' => 'recipient',
1104
-			'sharedBy' => 'initiator',
1105
-			'owner' => 'currentUser',
1106
-			'node' => $file1,
1107
-			'id' => 415,
1108
-		];
1109
-
1110
-		$file1LinkShareOwnerExpected = [
1111
-			'id' => 415,
1112
-			'share_type' => IShare::TYPE_LINK,
1113
-		];
1114
-
1115
-		$file1EmailShareOwner = [
1116
-			'type' => IShare::TYPE_EMAIL,
1117
-			'sharedWith' => 'recipient',
1118
-			'sharedBy' => 'initiator',
1119
-			'owner' => 'currentUser',
1120
-			'node' => $file1,
1121
-			'id' => 416,
1122
-		];
1123
-
1124
-		$file1EmailShareOwnerExpected = [
1125
-			'id' => 416,
1126
-			'share_type' => IShare::TYPE_EMAIL,
1127
-		];
1128
-
1129
-		$file1CircleShareOwner = [
1130
-			'type' => IShare::TYPE_CIRCLE,
1131
-			'sharedWith' => 'recipient',
1132
-			'sharedBy' => 'initiator',
1133
-			'owner' => 'currentUser',
1134
-			'node' => $file1,
1135
-			'id' => 423,
1136
-		];
1137
-
1138
-		$file1CircleShareOwnerExpected = [
1139
-			'id' => 423,
1140
-			'share_type' => IShare::TYPE_CIRCLE,
1141
-		];
1142
-
1143
-		$file1RoomShareOwner = [
1144
-			'type' => IShare::TYPE_ROOM,
1145
-			'sharedWith' => 'recipient',
1146
-			'sharedBy' => 'initiator',
1147
-			'owner' => 'currentUser',
1148
-			'node' => $file1,
1149
-			'id' => 442,
1150
-		];
1151
-
1152
-		$file1RoomShareOwnerExpected = [
1153
-			'id' => 442,
1154
-			'share_type' => IShare::TYPE_ROOM,
1155
-		];
1156
-
1157
-		$file1RemoteShareOwner = [
1158
-			'type' => IShare::TYPE_REMOTE,
1159
-			'sharedWith' => 'recipient',
1160
-			'sharedBy' => 'initiator',
1161
-			'owner' => 'currentUser',
1162
-			'expirationDate' => new \DateTime('2000-01-01T01:02:03'),
1163
-			'node' => $file1,
1164
-			'id' => 815,
1165
-		];
1166
-
1167
-		$file1RemoteShareOwnerExpected = [
1168
-			'id' => 815,
1169
-			'share_type' => IShare::TYPE_REMOTE,
1170
-		];
1171
-
1172
-		$file1RemoteGroupShareOwner = [
1173
-			'type' => IShare::TYPE_REMOTE_GROUP,
1174
-			'sharedWith' => 'recipient',
1175
-			'sharedBy' => 'initiator',
1176
-			'owner' => 'currentUser',
1177
-			'expirationDate' => new \DateTime('2000-01-01T01:02:03'),
1178
-			'node' => $file1,
1179
-			'id' => 816,
1180
-		];
1181
-
1182
-		$file1RemoteGroupShareOwnerExpected = [
1183
-			'id' => 816,
1184
-			'share_type' => IShare::TYPE_REMOTE_GROUP,
1185
-		];
1186
-
1187
-		$file2UserShareOwner = [
1188
-			'type' => IShare::TYPE_USER,
1189
-			'sharedWith' => 'recipient',
1190
-			'sharedBy' => 'initiator',
1191
-			'owner' => 'currentUser',
1192
-			'node' => $file2,
1193
-			'id' => 823,
1194
-		];
1195
-
1196
-		$file2UserShareOwnerExpected = [
1197
-			'id' => 823,
1198
-			'share_type' => IShare::TYPE_USER,
1199
-		];
1200
-
1201
-		$data = [
1202
-			[
1203
-				[
1204
-					'node' => $file1,
1205
-				],
1206
-				[
1207
-					'file1' => [
1208
-						IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareOwner, $file1UserShareOwner],
1209
-					],
1210
-				],
1211
-				[
1212
-				],
1213
-				[
1214
-					$file1UserShareOwnerExpected
1215
-				]
1216
-			],
1217
-			[
1218
-				[
1219
-					'node' => $file1,
1220
-				],
1221
-				[
1222
-					'file1' => [
1223
-						IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareRecipient],
1224
-					],
1225
-				],
1226
-				[
1227
-				],
1228
-				[
1229
-					$file1UserShareOwnerExpected,
1230
-				]
1231
-			],
1232
-			[
1233
-				[
1234
-					'node' => $file1,
1235
-				],
1236
-				[
1237
-					'file1' => [
1238
-						IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareRecipient, $file1UserShareInitiator, $file1UserShareOther],
1239
-					],
1240
-				],
1241
-				[
1242
-				],
1243
-				[
1244
-					$file1UserShareOwnerExpected,
1245
-					$file1UserShareInitiatorExpected,
1246
-					$file1UserShareOtherExpected,
1247
-				]
1248
-			],
1249
-			[
1250
-				[
1251
-					'node' => $file1,
1252
-				],
1253
-				[
1254
-					'file1' => [
1255
-						IShare::TYPE_USER => [$file1UserShareRecipient, $file1UserShareInitiator, $file1UserShareOther],
1256
-					],
1257
-				],
1258
-				[
1259
-				],
1260
-				[
1261
-					$file1UserShareInitiatorExpected,
1262
-				]
1263
-			],
1264
-			[
1265
-				[
1266
-					'node' => $file1,
1267
-				],
1268
-				[
1269
-					'file1' => [
1270
-						IShare::TYPE_USER => [$file1UserShareOwner],
1271
-						IShare::TYPE_GROUP => [$file1GroupShareRecipient],
1272
-					],
1273
-				],
1274
-				[
1275
-				],
1276
-				[
1277
-					$file1UserShareOwnerExpected,
1278
-					$file1GroupShareRecipientExpected,
1279
-				]
1280
-			],
1281
-			[
1282
-				[
1283
-					'node' => $file1,
1284
-				],
1285
-				[
1286
-					'file1' => [
1287
-						IShare::TYPE_USER => [$file1UserShareOwner],
1288
-						IShare::TYPE_GROUP => [$file1GroupShareOwner],
1289
-						IShare::TYPE_LINK => [$file1LinkShareOwner],
1290
-						IShare::TYPE_EMAIL => [$file1EmailShareOwner],
1291
-						IShare::TYPE_CIRCLE => [$file1CircleShareOwner],
1292
-						IShare::TYPE_ROOM => [$file1RoomShareOwner],
1293
-						IShare::TYPE_REMOTE => [$file1RemoteShareOwner],
1294
-						IShare::TYPE_REMOTE_GROUP => [$file1RemoteGroupShareOwner],
1295
-					],
1296
-				],
1297
-				[
1298
-				],
1299
-				[
1300
-					$file1UserShareOwnerExpected,
1301
-					$file1GroupShareOwnerExpected,
1302
-					$file1LinkShareOwnerExpected,
1303
-					$file1EmailShareOwnerExpected,
1304
-					$file1CircleShareOwnerExpected,
1305
-					$file1RoomShareOwnerExpected,
1306
-				]
1307
-			],
1308
-			[
1309
-				[
1310
-					'node' => $file1,
1311
-				],
1312
-				[
1313
-					'file1' => [
1314
-						IShare::TYPE_USER => [$file1UserShareOwner],
1315
-						IShare::TYPE_GROUP => [$file1GroupShareOwner],
1316
-						IShare::TYPE_LINK => [$file1LinkShareOwner],
1317
-						IShare::TYPE_EMAIL => [$file1EmailShareOwner],
1318
-						IShare::TYPE_CIRCLE => [$file1CircleShareOwner],
1319
-						IShare::TYPE_ROOM => [$file1RoomShareOwner],
1320
-						IShare::TYPE_REMOTE => [$file1RemoteShareOwner],
1321
-						IShare::TYPE_REMOTE_GROUP => [$file1RemoteGroupShareOwner],
1322
-					],
1323
-				],
1324
-				[
1325
-					IShare::TYPE_REMOTE => true,
1326
-					IShare::TYPE_REMOTE_GROUP => true,
1327
-				],
1328
-				[
1329
-					$file1UserShareOwnerExpected,
1330
-					$file1GroupShareOwnerExpected,
1331
-					$file1LinkShareOwnerExpected,
1332
-					$file1EmailShareOwnerExpected,
1333
-					$file1CircleShareOwnerExpected,
1334
-					$file1RoomShareOwnerExpected,
1335
-					$file1RemoteShareOwnerExpected,
1336
-					$file1RemoteGroupShareOwnerExpected,
1337
-				]
1338
-			],
1339
-			[
1340
-				[
1341
-					'node' => $folder,
1342
-					'subfiles' => 'true',
1343
-				],
1344
-				[
1345
-					'file1' => [
1346
-						IShare::TYPE_USER => [$file1UserShareOwner],
1347
-					],
1348
-					'file2' => [
1349
-						IShare::TYPE_USER => [$file2UserShareOwner],
1350
-					],
1351
-				],
1352
-				[
1353
-				],
1354
-				[
1355
-					$file1UserShareOwnerExpected,
1356
-					$file2UserShareOwnerExpected,
1357
-				]
1358
-			],
1359
-			[
1360
-				[
1361
-					'node' => $folder,
1362
-					'subfiles' => 'true',
1363
-				],
1364
-				[
1365
-					'file1' => [
1366
-						IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareOwner, $file1UserShareOwner],
1367
-					],
1368
-				],
1369
-				[
1370
-				],
1371
-				[
1372
-					$file1UserShareOwnerExpected,
1373
-				]
1374
-			],
1375
-			[
1376
-				[
1377
-					'node' => $folder,
1378
-					'subfiles' => 'true',
1379
-				],
1380
-				[
1381
-					'file1' => [
1382
-						IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareRecipient],
1383
-					],
1384
-				],
1385
-				[
1386
-				],
1387
-				[
1388
-					$file1UserShareOwnerExpected
1389
-				]
1390
-			],
1391
-			[
1392
-				[
1393
-					'node' => $folder,
1394
-					'subfiles' => 'true',
1395
-				],
1396
-				[
1397
-					'file1' => [
1398
-						IShare::TYPE_USER => [$file1UserShareRecipient, $file1UserShareInitiator, $file1UserShareOther],
1399
-					],
1400
-					'file2' => [
1401
-						IShare::TYPE_USER => [$file2UserShareOwner],
1402
-					],
1403
-				],
1404
-				[
1405
-				],
1406
-				[
1407
-					$file1UserShareInitiatorExpected,
1408
-					$file1UserShareOtherExpected,
1409
-					$file2UserShareOwnerExpected,
1410
-				]
1411
-			],
1412
-			// This might not happen in a real environment, as the combination
1413
-			// of shares does not seem to be possible on a folder without
1414
-			// resharing rights; if the folder has resharing rights then the
1415
-			// share with others would be included too in the results.
1416
-			[
1417
-				[
1418
-					'node' => $folder,
1419
-					'subfiles' => 'true',
1420
-				],
1421
-				[
1422
-					'file1' => [
1423
-						IShare::TYPE_USER => [$file1UserShareRecipient, $file1UserShareInitiator, $file1UserShareOther],
1424
-					],
1425
-				],
1426
-				[
1427
-				],
1428
-				[
1429
-					$file1UserShareInitiatorExpected,
1430
-				]
1431
-			],
1432
-			[
1433
-				[
1434
-					'node' => $folder,
1435
-					'subfiles' => 'true',
1436
-				],
1437
-				[
1438
-					'file1' => [
1439
-						IShare::TYPE_USER => [$file1UserShareOwner],
1440
-						IShare::TYPE_GROUP => [$file1GroupShareRecipient],
1441
-					],
1442
-				],
1443
-				[
1444
-				],
1445
-				[
1446
-					$file1UserShareOwnerExpected,
1447
-					$file1GroupShareRecipientExpected,
1448
-				]
1449
-			],
1450
-			[
1451
-				[
1452
-					'node' => $folder,
1453
-					'subfiles' => 'true',
1454
-				],
1455
-				[
1456
-					'file1' => [
1457
-						IShare::TYPE_USER => [$file1UserShareOwner],
1458
-						IShare::TYPE_GROUP => [$file1GroupShareOwner],
1459
-						IShare::TYPE_LINK => [$file1LinkShareOwner],
1460
-						IShare::TYPE_EMAIL => [$file1EmailShareOwner],
1461
-						IShare::TYPE_CIRCLE => [$file1CircleShareOwner],
1462
-						IShare::TYPE_ROOM => [$file1RoomShareOwner],
1463
-						IShare::TYPE_REMOTE => [$file1RemoteShareOwner],
1464
-						IShare::TYPE_REMOTE_GROUP => [$file1RemoteGroupShareOwner],
1465
-					],
1466
-				],
1467
-				[
1468
-				],
1469
-				[
1470
-					$file1UserShareOwnerExpected,
1471
-					$file1GroupShareOwnerExpected,
1472
-					$file1LinkShareOwnerExpected,
1473
-					$file1EmailShareOwnerExpected,
1474
-					$file1CircleShareOwnerExpected,
1475
-					$file1RoomShareOwnerExpected,
1476
-				]
1477
-			],
1478
-			[
1479
-				[
1480
-					'node' => $folder,
1481
-					'subfiles' => 'true',
1482
-				],
1483
-				[
1484
-					'file1' => [
1485
-						IShare::TYPE_USER => [$file1UserShareOwner],
1486
-						IShare::TYPE_GROUP => [$file1GroupShareOwner],
1487
-						IShare::TYPE_LINK => [$file1LinkShareOwner],
1488
-						IShare::TYPE_EMAIL => [$file1EmailShareOwner],
1489
-						IShare::TYPE_CIRCLE => [$file1CircleShareOwner],
1490
-						IShare::TYPE_ROOM => [$file1RoomShareOwner],
1491
-						IShare::TYPE_REMOTE => [$file1RemoteShareOwner],
1492
-						IShare::TYPE_REMOTE_GROUP => [$file1RemoteGroupShareOwner],
1493
-					],
1494
-				],
1495
-				[
1496
-					IShare::TYPE_REMOTE => true,
1497
-					IShare::TYPE_REMOTE_GROUP => true,
1498
-				],
1499
-				[
1500
-					$file1UserShareOwnerExpected,
1501
-					$file1GroupShareOwnerExpected,
1502
-					$file1LinkShareOwnerExpected,
1503
-					$file1EmailShareOwnerExpected,
1504
-					$file1CircleShareOwnerExpected,
1505
-					$file1RoomShareOwnerExpected,
1506
-					$file1RemoteShareOwnerExpected,
1507
-					$file1RemoteGroupShareOwnerExpected,
1508
-				]
1509
-			],
1510
-		];
1511
-
1512
-		return $data;
1513
-	}
1514
-
1515
-	private function mockSimpleNode(string $class, array $methods): MockObject {
1516
-		$node = $this->createMock($class);
1517
-		foreach ($methods as $method => $return) {
1518
-			if ($method === 'getDirectoryListing') {
1519
-				$return = array_map(
1520
-					fn ($nodeParams) => $this->mockSimpleNode(...$nodeParams),
1521
-					$return
1522
-				);
1523
-			}
1524
-			$node->method($method)->willReturn($return);
1525
-		}
1526
-		return $node;
1527
-	}
1528
-
1529
-	#[DataProvider('dataGetShares')]
1530
-	public function testGetShares(array $getSharesParameters, array $shares, array $extraShareTypes, array $expected): void {
1531
-		$shares = array_map(
1532
-			fn ($sharesByType) => array_map(
1533
-				fn ($shareList) => array_map(
1534
-					function (array $shareParams): IShare {
1535
-						$share = Server::get(IManager::class)->newShare();
1536
-						$share->setShareType($shareParams['type'])
1537
-							->setSharedBy($shareParams['sharedBy'])
1538
-							->setShareOwner($shareParams['owner'])
1539
-							->setPermissions(Constants::PERMISSION_READ)
1540
-							->setId($shareParams['id']);
1541
-						if (isset($shareParams['sharedWith'])) {
1542
-							$share->setSharedWith($shareParams['sharedWith']);
1543
-						}
1544
-						if (isset($shareParams['sharedWithDisplayName'])) {
1545
-							$share->setSharedWithDisplayName($shareParams['sharedWithDisplayName']);
1546
-						}
1547
-						if (isset($shareParams['sharedWithAvatar'])) {
1548
-							$share->setSharedWithAvatar($shareParams['sharedWithAvatar']);
1549
-						}
1550
-						if (isset($shareParams['attributes'])) {
1551
-							$shareAttributes = $this->createMock(IShareAttributes::class);
1552
-							$shareAttributes->method('toArray')->willReturn($shareParams['attributes']);
1553
-							$shareAttributes->method('getAttribute')->with('permissions', 'download')->willReturn(true);
1554
-							$share->setAttributes($shareAttributes);
1555
-
1556
-							$expects['attributes'] = \json_encode($shareParams['attributes']);
1557
-						}
1558
-						if (isset($shareParams['node'])) {
1559
-							$node = $this->mockSimpleNode(...$shareParams['node']);
1560
-							$share->setNode($node);
1561
-						}
1562
-						if (isset($shareParams['note'])) {
1563
-							$share->setNote($shareParams['note']);
1564
-						}
1565
-						if (isset($shareParams['expirationDate'])) {
1566
-							$share->setExpirationDate($shareParams['expirationDate']);
1567
-						}
1568
-						if (isset($shareParams['token'])) {
1569
-							$share->setToken($shareParams['token']);
1570
-						}
1571
-						if (isset($shareParams['label'])) {
1572
-							$share->setLabel($shareParams['label']);
1573
-						}
1574
-						if (isset($shareParams['password'])) {
1575
-							$share->setPassword($shareParams['password']);
1576
-						}
1577
-						if (isset($shareParams['sendPasswordByTalk'])) {
1578
-							$share->setSendPasswordByTalk($shareParams['sendPasswordByTalk']);
1579
-						}
1580
-						return $share;
1581
-					},
1582
-					$shareList
1583
-				),
1584
-				$sharesByType
1585
-			),
1586
-			$shares
1587
-		);
1588
-
1589
-		/** @var ShareAPIController&MockObject $ocs */
1590
-		$ocs = $this->getMockBuilder(ShareAPIController::class)
1591
-			->setConstructorArgs([
1592
-				$this->appName,
1593
-				$this->request,
1594
-				$this->shareManager,
1595
-				$this->groupManager,
1596
-				$this->userManager,
1597
-				$this->rootFolder,
1598
-				$this->urlGenerator,
1599
-				$this->l,
1600
-				$this->config,
1601
-				$this->appConfig,
1602
-				$this->appManager,
1603
-				$this->serverContainer,
1604
-				$this->userStatusManager,
1605
-				$this->previewManager,
1606
-				$this->dateTimeZone,
1607
-				$this->logger,
1608
-				$this->factory,
1609
-				$this->mailer,
1610
-				$this->tagManager,
1611
-				$this->getEmailValidatorWithStrictEmailCheck(),
1612
-				$this->trustedServers,
1613
-				$this->currentUser,
1614
-			])
1615
-			->onlyMethods(['formatShare'])
1616
-			->getMock();
1617
-
1618
-		$ocs->method('formatShare')
1619
-			->willReturnCallback(
1620
-				function ($share) {
1621
-					return [
1622
-						'id' => $share->getId(),
1623
-						'share_type' => $share->getShareType()
1624
-					];
1625
-				}
1626
-			);
1627
-
1628
-		$userFolder = $this->getMockBuilder(Folder::class)->getMock();
1629
-		$userFolder->method('get')
1630
-			->with('path')
1631
-			->willReturn($this->mockSimpleNode(...$getSharesParameters['node']));
1632
-
1633
-		$this->rootFolder->method('getUserFolder')
1634
-			->with($this->currentUser)
1635
-			->willReturn($userFolder);
1636
-
1637
-		$this->shareManager
1638
-			->method('getSharesBy')
1639
-			->willReturnCallback(
1640
-				function ($user, $shareType, $node) use ($shares) {
1641
-					if (!isset($shares[$node->getName()]) || !isset($shares[$node->getName()][$shareType])) {
1642
-						return [];
1643
-					}
1644
-					return $shares[$node->getName()][$shareType];
1645
-				}
1646
-			);
1647
-
1648
-		$this->shareManager
1649
-			->method('outgoingServer2ServerSharesAllowed')
1650
-			->willReturn($extraShareTypes[ISHARE::TYPE_REMOTE] ?? false);
1651
-
1652
-		$this->shareManager
1653
-			->method('outgoingServer2ServerGroupSharesAllowed')
1654
-			->willReturn($extraShareTypes[ISHARE::TYPE_REMOTE_GROUP] ?? false);
1655
-
1656
-		$this->groupManager
1657
-			->method('isInGroup')
1658
-			->willReturnCallback(
1659
-				function ($user, $group) {
1660
-					return $group === 'currentUserGroup';
1661
-				}
1662
-			);
1663
-
1664
-		$result = $ocs->getShares(
1665
-			$getSharesParameters['sharedWithMe'] ?? 'false',
1666
-			$getSharesParameters['reshares'] ?? 'false',
1667
-			$getSharesParameters['subfiles'] ?? 'false',
1668
-			'path'
1669
-		);
1670
-
1671
-		$this->assertEquals($expected, $result->getData());
1672
-	}
1673
-
1674
-	public function testCanAccessShareAsOwner(): void {
1675
-		$share = $this->createMock(IShare::class);
1676
-		$share->method('getShareOwner')->willReturn($this->currentUser);
1677
-		$this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1678
-	}
1679
-
1680
-	public function testCanAccessShareAsSharer(): void {
1681
-		$share = $this->createMock(IShare::class);
1682
-		$share->method('getSharedBy')->willReturn($this->currentUser);
1683
-		$this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1684
-	}
1685
-
1686
-	public function testCanAccessShareAsSharee(): void {
1687
-		$share = $this->createMock(IShare::class);
1688
-		$share->method('getShareType')->willReturn(IShare::TYPE_USER);
1689
-		$share->method('getSharedWith')->willReturn($this->currentUser);
1690
-		$this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1691
-	}
1692
-
1693
-	public function testCannotAccessLinkShare(): void {
1694
-		$share = $this->createMock(IShare::class);
1695
-		$share->method('getShareType')->willReturn(IShare::TYPE_LINK);
1696
-		$share->method('getNodeId')->willReturn(42);
1697
-
1698
-		$userFolder = $this->createMock(Folder::class);
1699
-		$this->rootFolder->method('getUserFolder')
1700
-			->with($this->currentUser)
1701
-			->willReturn($userFolder);
1702
-
1703
-		$this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1704
-	}
1705
-
1706
-	#[DataProvider('dataCanAccessShareWithPermissions')]
1707
-	public function testCanAccessShareWithPermissions(int $permissions, bool $expected): void {
1708
-		$share = $this->createMock(IShare::class);
1709
-		$share->method('getShareType')->willReturn(IShare::TYPE_USER);
1710
-		$share->method('getSharedWith')->willReturn($this->createMock(IUser::class));
1711
-		$share->method('getNodeId')->willReturn(42);
1712
-
1713
-		$file = $this->createMock(File::class);
1714
-
1715
-		$userFolder = $this->getMockBuilder(Folder::class)->getMock();
1716
-		$userFolder->method('getFirstNodeById')
1717
-			->with($share->getNodeId())
1718
-			->willReturn($file);
1719
-		$userFolder->method('getById')
1720
-			->with($share->getNodeId())
1721
-			->willReturn([$file]);
1722
-		$this->rootFolder->method('getUserFolder')
1723
-			->with($this->currentUser)
1724
-			->willReturn($userFolder);
1725
-
1726
-		$file->method('getPermissions')
1727
-			->willReturn($permissions);
1728
-
1729
-		if ($expected) {
1730
-			$this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1731
-		} else {
1732
-			$this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1733
-		}
1734
-	}
1735
-
1736
-	public static function dataCanAccessShareWithPermissions(): array {
1737
-		return [
1738
-			[Constants::PERMISSION_SHARE, true],
1739
-			[Constants::PERMISSION_READ, false],
1740
-			[Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, true],
1741
-		];
1742
-	}
1743
-
1744
-	#[DataProvider('dataCanAccessShareAsGroupMember')]
1745
-	public function testCanAccessShareAsGroupMember(string $group, bool $expected): void {
1746
-		$share = $this->createMock(IShare::class);
1747
-		$share->method('getShareType')->willReturn(IShare::TYPE_GROUP);
1748
-		$share->method('getSharedWith')->willReturn($group);
1749
-		$share->method('getNodeId')->willReturn(42);
1750
-
1751
-		$file = $this->createMock(File::class);
1752
-
1753
-		$userFolder = $this->createMock(Folder::class);
1754
-		$userFolder->method('getFirstNodeById')
1755
-			->with($share->getNodeId())
1756
-			->willReturn($file);
1757
-		$userFolder->method('getById')
1758
-			->with($share->getNodeId())
1759
-			->willReturn([$file]);
1760
-		$this->rootFolder->method('getUserFolder')
1761
-			->with($this->currentUser)
1762
-			->willReturn($userFolder);
1763
-
1764
-		$user = $this->createMock(IUser::class);
1765
-		$this->userManager->method('get')
1766
-			->with($this->currentUser)
1767
-			->willReturn($user);
1768
-
1769
-		$group = $this->createMock(IGroup::class);
1770
-		$group->method('inGroup')->with($user)->willReturn(true);
1771
-		$group2 = $this->createMock(IGroup::class);
1772
-		$group2->method('inGroup')->with($user)->willReturn(false);
1773
-
1774
-		$this->groupManager->method('get')->willReturnMap([
1775
-			['group', $group],
1776
-			['group2', $group2],
1777
-			['group-null', null],
1778
-		]);
1779
-
1780
-		if ($expected) {
1781
-			$this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1782
-		} else {
1783
-			$this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1784
-		}
1785
-	}
1786
-
1787
-	public static function dataCanAccessShareAsGroupMember(): array {
1788
-		return [
1789
-			['group', true],
1790
-			['group2', false],
1791
-			['group-null', false],
1792
-		];
1793
-	}
1794
-
1795
-	public static function dataCanAccessRoomShare(): array {
1796
-		return [
1797
-			[false, false, false],
1798
-			[false, false, true],
1799
-			[true, true, true],
1800
-			[false, true, false],
1801
-		];
1802
-	}
1803
-
1804
-	#[DataProvider('dataCanAccessRoomShare')]
1805
-	public function testCanAccessRoomShare(
1806
-		bool $expected,
1807
-		bool $helperAvailable,
1808
-		bool $canAccessShareByHelper,
1809
-	): void {
1810
-		$share = $this->createMock(IShare::class);
1811
-		$share->method('getShareType')->willReturn(IShare::TYPE_ROOM);
1812
-		$share->method('getSharedWith')->willReturn('recipientRoom');
1813
-
1814
-		$userFolder = $this->getMockBuilder(Folder::class)->getMock();
1815
-		$this->rootFolder->method('getUserFolder')
1816
-			->with($this->currentUser)
1817
-			->willReturn($userFolder);
1818
-
1819
-		$userFolder->method('getById')
1820
-			->with($share->getNodeId())
1821
-			->willReturn([$share->getNode()]);
1822
-
1823
-		if (!$helperAvailable) {
1824
-			$this->appManager->method('isEnabledForUser')
1825
-				->with('spreed')
1826
-				->willReturn(false);
1827
-		} else {
1828
-			$this->appManager->method('isEnabledForUser')
1829
-				->with('spreed')
1830
-				->willReturn(true);
1831
-
1832
-			// This is not possible anymore with PHPUnit 10+
1833
-			// as `setMethods` was removed and now real reflection is used, thus the class needs to exist.
1834
-			// $helper = $this->getMockBuilder('\OCA\Talk\Share\Helper\ShareAPIController')
1835
-			$helper = $this->getMockBuilder(\stdClass::class)
1836
-				->addMethods(['canAccessShare'])
1837
-				->getMock();
1838
-			$helper->method('canAccessShare')
1839
-				->with($share, $this->currentUser)
1840
-				->willReturn($canAccessShareByHelper);
1841
-
1842
-			$this->serverContainer->method('get')
1843
-				->with('\OCA\Talk\Share\Helper\ShareAPIController')
1844
-				->willReturn($helper);
1845
-		}
1846
-
1847
-		$this->assertEquals($expected, $this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1848
-	}
1849
-
1850
-
1851
-	public function testCreateShareNoPath(): void {
1852
-		$this->expectException(OCSNotFoundException::class);
1853
-		$this->expectExceptionMessage('Please specify a file or folder path');
1854
-
1855
-		$this->ocs->createShare();
1856
-	}
1857
-
1858
-
1859
-	public function testCreateShareInvalidPath(): void {
1860
-		$this->expectException(OCSNotFoundException::class);
1861
-		$this->expectExceptionMessage('Wrong path, file/folder does not exist');
1862
-
1863
-		$userFolder = $this->getMockBuilder(Folder::class)->getMock();
1864
-		$this->rootFolder->expects($this->once())
1865
-			->method('getUserFolder')
1866
-			->with('currentUser')
1867
-			->willReturn($userFolder);
1868
-
1869
-		$userFolder->expects($this->once())
1870
-			->method('get')
1871
-			->with('invalid-path')
1872
-			->willThrowException(new NotFoundException());
1873
-
1874
-		$this->ocs->createShare('invalid-path');
1875
-	}
1876
-
1877
-	public function testCreateShareInvalidShareType(): void {
1878
-		$this->expectException(OCSBadRequestException::class);
1879
-		$this->expectExceptionMessage('Unknown share type');
1880
-
1881
-		$share = $this->newShare();
1882
-		$this->shareManager->method('newShare')->willReturn($share);
1883
-
1884
-		[$userFolder, $file] = $this->getNonSharedUserFile();
1885
-		$this->rootFolder->expects($this->atLeastOnce())
1886
-			->method('getUserFolder')
1887
-			->with('currentUser')
1888
-			->willReturn($userFolder);
1889
-
1890
-		$userFolder->expects($this->atLeastOnce())
1891
-			->method('get')
1892
-			->with('valid-path')
1893
-			->willReturn($file);
1894
-		$userFolder->method('getById')
1895
-			->willReturn([]);
1896
-
1897
-		$file->expects($this->once())
1898
-			->method('lock')
1899
-			->with(ILockingProvider::LOCK_SHARED);
1900
-
1901
-		$this->ocs->createShare('valid-path', 31);
1902
-	}
1903
-
1904
-	public function testCreateShareUserNoShareWith(): void {
1905
-		$this->expectException(OCSNotFoundException::class);
1906
-		$this->expectExceptionMessage('Please specify a valid account to share with');
1907
-
1908
-		$share = $this->newShare();
1909
-		$this->shareManager->method('newShare')->willReturn($share);
1910
-
1911
-		[$userFolder, $path] = $this->getNonSharedUserFile();
1912
-		$this->rootFolder->method('getUserFolder')
1913
-			->with('currentUser')
1914
-			->willReturn($userFolder);
1915
-
1916
-		$userFolder->expects($this->once())
1917
-			->method('get')
1918
-			->with('valid-path')
1919
-			->willReturn($path);
1920
-		$userFolder->method('getById')
1921
-			->willReturn([]);
1922
-
1923
-		$path->expects($this->once())
1924
-			->method('lock')
1925
-			->with(ILockingProvider::LOCK_SHARED);
1926
-
1927
-		$this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_USER);
1928
-	}
1929
-
1930
-
1931
-	public function testCreateShareUserNoValidShareWith(): void {
1932
-		$this->expectException(OCSNotFoundException::class);
1933
-		$this->expectExceptionMessage('Please specify a valid account to share with');
1934
-
1935
-		$share = $this->newShare();
1936
-		$this->shareManager->method('newShare')->willReturn($share);
1937
-
1938
-		[$userFolder, $path] = $this->getNonSharedUserFile();
1939
-		$this->rootFolder->method('getUserFolder')
1940
-			->with('currentUser')
1941
-			->willReturn($userFolder);
1942
-
1943
-		$userFolder->expects($this->once())
1944
-			->method('get')
1945
-			->with('valid-path')
1946
-			->willReturn($path);
1947
-		$userFolder->method('getById')
1948
-			->willReturn([]);
1949
-		$path->expects($this->once())
1950
-			->method('lock')
1951
-			->with(ILockingProvider::LOCK_SHARED);
1952
-		$this->userManager->method('userExists')
1953
-			->with('invalidUser')
1954
-			->willReturn(false);
1955
-
1956
-		$this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_USER, 'invalidUser');
1957
-	}
1958
-
1959
-	public function testCreateShareUser(): void {
1960
-		$share = $this->newShare();
1961
-		$this->shareManager->method('newShare')->willReturn($share);
1962
-
1963
-		/** @var ShareAPIController $ocs */
1964
-		$ocs = $this->getMockBuilder(ShareAPIController::class)
1965
-			->setConstructorArgs([
1966
-				$this->appName,
1967
-				$this->request,
1968
-				$this->shareManager,
1969
-				$this->groupManager,
1970
-				$this->userManager,
1971
-				$this->rootFolder,
1972
-				$this->urlGenerator,
1973
-				$this->l,
1974
-				$this->config,
1975
-				$this->appConfig,
1976
-				$this->appManager,
1977
-				$this->serverContainer,
1978
-				$this->userStatusManager,
1979
-				$this->previewManager,
1980
-				$this->dateTimeZone,
1981
-				$this->logger,
1982
-				$this->factory,
1983
-				$this->mailer,
1984
-				$this->tagManager,
1985
-				$this->getEmailValidatorWithStrictEmailCheck(),
1986
-				$this->trustedServers,
1987
-				$this->currentUser,
1988
-			])->onlyMethods(['formatShare'])
1989
-			->getMock();
1990
-
1991
-		[$userFolder, $path] = $this->getNonSharedUserFile();
1992
-		$this->rootFolder->expects($this->exactly(2))
1993
-			->method('getUserFolder')
1994
-			->with('currentUser')
1995
-			->willReturn($userFolder);
1996
-
1997
-		$userFolder->expects($this->once())
1998
-			->method('get')
1999
-			->with('valid-path')
2000
-			->willReturn($path);
2001
-		$userFolder->method('getById')
2002
-			->willReturn([]);
2003
-
2004
-		$this->userManager->method('userExists')->with('validUser')->willReturn(true);
2005
-
2006
-		$path->expects($this->once())
2007
-			->method('lock')
2008
-			->with(ILockingProvider::LOCK_SHARED);
2009
-
2010
-		$this->shareManager->method('createShare')
2011
-			->with($this->callback(function (IShare $share) use ($path) {
2012
-				return $share->getNode() === $path
2013
-					&& $share->getPermissions() === (
2014
-						Constants::PERMISSION_ALL
2015
-						& ~Constants::PERMISSION_DELETE
2016
-						& ~Constants::PERMISSION_CREATE
2017
-					)
2018
-					&& $share->getShareType() === IShare::TYPE_USER
2019
-					&& $share->getSharedWith() === 'validUser'
2020
-					&& $share->getSharedBy() === 'currentUser';
2021
-			}))
2022
-			->willReturnArgument(0);
2023
-
2024
-		$expected = new DataResponse([]);
2025
-		$result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_USER, 'validUser');
2026
-
2027
-		$this->assertInstanceOf(get_class($expected), $result);
2028
-		$this->assertEquals($expected->getData(), $result->getData());
2029
-	}
2030
-
2031
-
2032
-	public function testCreateShareGroupNoValidShareWith(): void {
2033
-		$this->expectException(OCSNotFoundException::class);
2034
-		$this->expectExceptionMessage('Please specify a valid group');
2035
-
2036
-		$share = $this->newShare();
2037
-		$this->shareManager->method('newShare')->willReturn($share);
2038
-		$this->shareManager->method('createShare')->willReturnArgument(0);
2039
-		$this->shareManager->method('allowGroupSharing')->willReturn(true);
2040
-
2041
-		[$userFolder, $path] = $this->getNonSharedUserFile();
2042
-		$this->rootFolder->method('getUserFolder')
2043
-			->with('currentUser')
2044
-			->willReturn($userFolder);
2045
-
2046
-		$userFolder->expects($this->once())
2047
-			->method('get')
2048
-			->with('valid-path')
2049
-			->willReturn($path);
2050
-		$userFolder->method('getById')
2051
-			->willReturn([]);
2052
-
2053
-		$path->expects($this->once())
2054
-			->method('lock')
2055
-			->with(ILockingProvider::LOCK_SHARED);
2056
-
2057
-		$this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_GROUP, 'invalidGroup');
2058
-	}
2059
-
2060
-	public function testCreateShareGroup(): void {
2061
-		$share = $this->newShare();
2062
-		$this->shareManager->method('newShare')->willReturn($share);
2063
-
2064
-		/** @var ShareAPIController&MockObject $ocs */
2065
-		$ocs = $this->getMockBuilder(ShareAPIController::class)
2066
-			->setConstructorArgs([
2067
-				$this->appName,
2068
-				$this->request,
2069
-				$this->shareManager,
2070
-				$this->groupManager,
2071
-				$this->userManager,
2072
-				$this->rootFolder,
2073
-				$this->urlGenerator,
2074
-				$this->l,
2075
-				$this->config,
2076
-				$this->appConfig,
2077
-				$this->appManager,
2078
-				$this->serverContainer,
2079
-				$this->userStatusManager,
2080
-				$this->previewManager,
2081
-				$this->dateTimeZone,
2082
-				$this->logger,
2083
-				$this->factory,
2084
-				$this->mailer,
2085
-				$this->tagManager,
2086
-				$this->getEmailValidatorWithStrictEmailCheck(),
2087
-				$this->trustedServers,
2088
-				$this->currentUser,
2089
-			])->onlyMethods(['formatShare'])
2090
-			->getMock();
2091
-
2092
-		$this->request
2093
-			->method('getParam')
2094
-			->willReturnMap([
2095
-				['path', null, 'valid-path'],
2096
-				['permissions', null, Constants::PERMISSION_ALL],
2097
-				['shareType', '-1', IShare::TYPE_GROUP],
2098
-				['shareWith', null, 'validGroup'],
2099
-			]);
2100
-
2101
-		[$userFolder, $path] = $this->getNonSharedUserFolder();
2102
-		$this->rootFolder->expects($this->exactly(2))
2103
-			->method('getUserFolder')
2104
-			->with('currentUser')
2105
-			->willReturn($userFolder);
2106
-
2107
-		$userFolder->expects($this->once())
2108
-			->method('get')
2109
-			->with('valid-path')
2110
-			->willReturn($path);
2111
-		$userFolder->method('getById')
2112
-			->willReturn([]);
2113
-
2114
-		$this->groupManager->method('groupExists')->with('validGroup')->willReturn(true);
2115
-
2116
-		$this->shareManager->expects($this->once())
2117
-			->method('allowGroupSharing')
2118
-			->willReturn(true);
2119
-
2120
-		$path->expects($this->once())
2121
-			->method('lock')
2122
-			->with(ILockingProvider::LOCK_SHARED);
2123
-
2124
-		$this->shareManager->method('createShare')
2125
-			->with($this->callback(function (IShare $share) use ($path) {
2126
-				return $share->getNode() === $path
2127
-				&& $share->getPermissions() === Constants::PERMISSION_ALL
2128
-				&& $share->getShareType() === IShare::TYPE_GROUP
2129
-				&& $share->getSharedWith() === 'validGroup'
2130
-				&& $share->getSharedBy() === 'currentUser';
2131
-			}))
2132
-			->willReturnArgument(0);
2133
-
2134
-		$expected = new DataResponse([]);
2135
-		$result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_GROUP, 'validGroup');
2136
-
2137
-		$this->assertInstanceOf(get_class($expected), $result);
2138
-		$this->assertEquals($expected->getData(), $result->getData());
2139
-	}
2140
-
2141
-
2142
-	public function testCreateShareGroupNotAllowed(): void {
2143
-		$this->expectException(OCSNotFoundException::class);
2144
-		$this->expectExceptionMessage('Group sharing is disabled by the administrator');
2145
-
2146
-		$share = $this->newShare();
2147
-		$this->shareManager->method('newShare')->willReturn($share);
2148
-
2149
-		[$userFolder, $path] = $this->getNonSharedUserFolder();
2150
-		$this->rootFolder->method('getUserFolder')
2151
-			->with('currentUser')
2152
-			->willReturn($userFolder);
2153
-
2154
-		$userFolder->expects($this->once())
2155
-			->method('get')
2156
-			->with('valid-path')
2157
-			->willReturn($path);
2158
-		$userFolder->method('getById')
2159
-			->willReturn([]);
2160
-
2161
-		$this->groupManager->method('groupExists')->with('validGroup')->willReturn(true);
2162
-
2163
-		$this->shareManager->expects($this->once())
2164
-			->method('allowGroupSharing')
2165
-			->willReturn(false);
2166
-
2167
-		$this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_GROUP, 'invalidGroup');
2168
-	}
2169
-
2170
-
2171
-	public function testCreateShareLinkNoLinksAllowed(): void {
2172
-		$this->expectException(OCSNotFoundException::class);
2173
-		$this->expectExceptionMessage('Public link sharing is disabled by the administrator');
2174
-
2175
-		$this->request
2176
-			->method('getParam')
2177
-			->willReturnMap([
2178
-				['path', null, 'valid-path'],
2179
-				['shareType', '-1', IShare::TYPE_LINK],
2180
-			]);
2181
-
2182
-		$path = $this->getMockBuilder(Folder::class)->getMock();
2183
-		$path->method('getId')->willReturn(42);
2184
-		$storage = $this->createMock(IStorage::class);
2185
-		$storage->method('instanceOfStorage')
2186
-			->willReturnMap([
2187
-				['OCA\Files_Sharing\External\Storage', false],
2188
-				['OCA\Files_Sharing\SharedStorage', false],
2189
-			]);
2190
-		$path->method('getStorage')->willReturn($storage);
2191
-		$this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2192
-		$this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2193
-		$this->rootFolder->method('getById')
2194
-			->willReturn([]);
2195
-
2196
-		$this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2197
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2198
-		$this->shareManager->method('shareApiAllowLinks')->willReturn(false);
2199
-
2200
-		$this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK);
2201
-	}
2202
-
2203
-
2204
-	public function testCreateShareLinkNoPublicUpload(): void {
2205
-		$this->expectException(OCSForbiddenException::class);
2206
-		$this->expectExceptionMessage('Public upload disabled by the administrator');
2207
-
2208
-		$path = $this->getMockBuilder(Folder::class)->getMock();
2209
-		$path->method('getId')->willReturn(42);
2210
-		$storage = $this->createMock(IStorage::class);
2211
-		$storage->method('instanceOfStorage')
2212
-			->willReturnMap([
2213
-				['OCA\Files_Sharing\External\Storage', false],
2214
-				['OCA\Files_Sharing\SharedStorage', false],
2215
-			]);
2216
-		$path->method('getStorage')->willReturn($storage);
2217
-		$this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2218
-		$this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2219
-		$this->rootFolder->method('getById')
2220
-			->willReturn([]);
2221
-
2222
-		$this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2223
-		$this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2224
-
2225
-		$this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true');
2226
-	}
2227
-
2228
-
2229
-	public function testCreateShareLinkPublicUploadFile(): void {
2230
-		$this->expectException(OCSBadRequestException::class);
2231
-		$this->expectExceptionMessage('Public upload is only possible for publicly shared folders');
2232
-
2233
-		$storage = $this->createMock(IStorage::class);
2234
-		$storage->method('instanceOfStorage')
2235
-			->willReturnMap([
2236
-				['OCA\Files_Sharing\External\Storage', false],
2237
-				['OCA\Files_Sharing\SharedStorage', false],
2238
-			]);
2239
-
2240
-		$file = $this->createMock(File::class);
2241
-		$file->method('getId')->willReturn(42);
2242
-		$file->method('getStorage')->willReturn($storage);
2243
-
2244
-		$this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2245
-		$this->rootFolder->method('get')->with('valid-path')->willReturn($file);
2246
-		$this->rootFolder->method('getById')
2247
-			->willReturn([]);
2248
-
2249
-		$this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2250
-		$this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2251
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2252
-
2253
-		$this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true');
2254
-	}
2255
-
2256
-	public function testCreateShareLinkPublicUploadFolder(): void {
2257
-		$ocs = $this->mockFormatShare();
2258
-
2259
-		$path = $this->getMockBuilder(Folder::class)->getMock();
2260
-		$path->method('getId')->willReturn(1);
2261
-		$storage = $this->createMock(IStorage::class);
2262
-		$storage->method('instanceOfStorage')
2263
-			->willReturnMap([
2264
-				['OCA\Files_Sharing\External\Storage', false],
2265
-				['OCA\Files_Sharing\SharedStorage', false],
2266
-			]);
2267
-		$path->method('getStorage')->willReturn($storage);
2268
-		$this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2269
-		$this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2270
-		$this->rootFolder->method('getById')
2271
-			->willReturn([]);
2272
-
2273
-		$this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2274
-		$this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2275
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2276
-
2277
-		$this->shareManager->expects($this->once())->method('createShare')->with(
2278
-			$this->callback(function (IShare $share) use ($path) {
2279
-				return $share->getNode() === $path
2280
-					&& $share->getShareType() === IShare::TYPE_LINK
2281
-					&& $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
2282
-					&& $share->getSharedBy() === 'currentUser'
2283
-					&& $share->getPassword() === null
2284
-					&& $share->getExpirationDate() === null;
2285
-			})
2286
-		)->willReturnArgument(0);
2287
-
2288
-		$expected = new DataResponse([]);
2289
-		$result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true', '', null, '');
2290
-
2291
-		$this->assertInstanceOf(get_class($expected), $result);
2292
-		$this->assertEquals($expected->getData(), $result->getData());
2293
-	}
2294
-
2295
-	public function testCreateShareLinkPassword(): void {
2296
-		$ocs = $this->mockFormatShare();
2297
-
2298
-		$path = $this->getMockBuilder(Folder::class)->getMock();
2299
-		$path->method('getId')->willReturn(42);
2300
-		$storage = $this->createMock(IStorage::class);
2301
-		$storage->method('instanceOfStorage')
2302
-			->willReturnMap([
2303
-				['OCA\Files_Sharing\External\Storage', false],
2304
-				['OCA\Files_Sharing\SharedStorage', false],
2305
-			]);
2306
-		$path->method('getStorage')->willReturn($storage);
2307
-		$this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2308
-		$this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2309
-		$this->rootFolder->method('getById')
2310
-			->willReturn([]);
2311
-
2312
-		$this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2313
-		$this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2314
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2315
-
2316
-		$this->shareManager->expects($this->once())->method('createShare')->with(
2317
-			$this->callback(function (IShare $share) use ($path) {
2318
-				return $share->getNode() === $path
2319
-				&& $share->getShareType() === IShare::TYPE_LINK
2320
-				&& $share->getPermissions() === Constants::PERMISSION_READ // publicUpload was set to false
2321
-				&& $share->getSharedBy() === 'currentUser'
2322
-				&& $share->getPassword() === 'password'
2323
-				&& $share->getExpirationDate() === null;
2324
-			})
2325
-		)->willReturnArgument(0);
2326
-
2327
-		$expected = new DataResponse([]);
2328
-		$result = $ocs->createShare('valid-path', Constants::PERMISSION_READ, IShare::TYPE_LINK, null, 'false', 'password', null, '');
2329
-
2330
-		$this->assertInstanceOf(get_class($expected), $result);
2331
-		$this->assertEquals($expected->getData(), $result->getData());
2332
-	}
2333
-
2334
-	public function testCreateShareLinkSendPasswordByTalk(): void {
2335
-		$ocs = $this->mockFormatShare();
2336
-
2337
-		$path = $this->getMockBuilder(Folder::class)->getMock();
2338
-		$path->method('getId')->willReturn(42);
2339
-		$storage = $this->createMock(IStorage::class);
2340
-		$storage->method('instanceOfStorage')
2341
-			->willReturnMap([
2342
-				['OCA\Files_Sharing\External\Storage', false],
2343
-				['OCA\Files_Sharing\SharedStorage', false],
2344
-			]);
2345
-		$path->method('getStorage')->willReturn($storage);
2346
-		$this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2347
-		$this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2348
-		$this->rootFolder->method('getById')
2349
-			->willReturn([]);
2350
-
2351
-		$this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2352
-		$this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2353
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2354
-
2355
-		$this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(true);
2356
-
2357
-		$this->shareManager->expects($this->once())->method('createShare')->with(
2358
-			$this->callback(function (IShare $share) use ($path) {
2359
-				return $share->getNode() === $path
2360
-				&& $share->getShareType() === IShare::TYPE_LINK
2361
-				&& $share->getPermissions() === (Constants::PERMISSION_ALL & ~(Constants::PERMISSION_SHARE))
2362
-				&& $share->getSharedBy() === 'currentUser'
2363
-				&& $share->getPassword() === 'password'
2364
-				&& $share->getSendPasswordByTalk() === true
2365
-				&& $share->getExpirationDate() === null;
2366
-			})
2367
-		)->willReturnArgument(0);
2368
-
2369
-		$expected = new DataResponse([]);
2370
-		$result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true', 'password', 'true', '');
2371
-
2372
-		$this->assertInstanceOf(get_class($expected), $result);
2373
-		$this->assertEquals($expected->getData(), $result->getData());
2374
-	}
2375
-
2376
-
2377
-	public function testCreateShareLinkSendPasswordByTalkWithTalkDisabled(): void {
2378
-		$this->expectException(OCSForbiddenException::class);
2379
-		$this->expectExceptionMessage('Sharing valid-path sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled');
2380
-
2381
-		$ocs = $this->mockFormatShare();
2382
-
2383
-		$path = $this->getMockBuilder(Folder::class)->getMock();
2384
-		$path->method('getId')->willReturn(42);
2385
-		$storage = $this->createMock(IStorage::class);
2386
-		$storage->method('instanceOfStorage')
2387
-			->willReturnMap([
2388
-				['OCA\Files_Sharing\External\Storage', false],
2389
-				['OCA\Files_Sharing\SharedStorage', false],
2390
-			]);
2391
-		$path->method('getStorage')->willReturn($storage);
2392
-		$path->method('getPath')->willReturn('valid-path');
2393
-		$this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2394
-		$this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2395
-		$this->rootFolder->method('getById')
2396
-			->willReturn([]);
2397
-
2398
-		$this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2399
-		$this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2400
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2401
-
2402
-		$this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(false);
2403
-
2404
-		$this->shareManager->expects($this->never())->method('createShare');
2405
-
2406
-		$ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', 'password', 'true', '');
2407
-	}
2408
-
2409
-	public function testCreateShareValidExpireDate(): void {
2410
-		$ocs = $this->mockFormatShare();
2411
-
2412
-		$this->request
2413
-			->method('getParam')
2414
-			->willReturnMap([
2415
-				['path', null, 'valid-path'],
2416
-				['shareType', '-1', IShare::TYPE_LINK],
2417
-				['publicUpload', null, 'false'],
2418
-				['expireDate', '', '2000-01-01'],
2419
-				['password', '', ''],
2420
-			]);
2421
-
2422
-		$path = $this->getMockBuilder(Folder::class)->getMock();
2423
-		$path->method('getId')->willReturn(42);
2424
-		$storage = $this->createMock(IStorage::class);
2425
-		$storage->method('instanceOfStorage')
2426
-			->willReturnMap([
2427
-				['OCA\Files_Sharing\External\Storage', false],
2428
-				['OCA\Files_Sharing\SharedStorage', false],
2429
-			]);
2430
-		$path->method('getStorage')->willReturn($storage);
2431
-		$this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2432
-		$this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2433
-		$this->rootFolder->method('getById')
2434
-			->willReturn([]);
2435
-
2436
-		$this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2437
-		$this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2438
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2439
-
2440
-		$this->shareManager->expects($this->once())->method('createShare')->with(
2441
-			$this->callback(function (IShare $share) use ($path) {
2442
-				$date = new \DateTime('2000-01-01');
2443
-				$date->setTime(0, 0, 0);
2444
-
2445
-				return $share->getNode() === $path
2446
-				&& $share->getShareType() === IShare::TYPE_LINK
2447
-				&& $share->getPermissions() === Constants::PERMISSION_READ | Constants::PERMISSION_SHARE
2448
-				&& $share->getSharedBy() === 'currentUser'
2449
-				&& $share->getPassword() === null
2450
-				&& $share->getExpirationDate() == $date;
2451
-			})
2452
-		)->willReturnArgument(0);
2453
-
2454
-		$expected = new DataResponse([]);
2455
-		$result = $ocs->createShare('valid-path', null, IShare::TYPE_LINK, null, 'false', '', null, '2000-01-01');
2456
-
2457
-		$this->assertInstanceOf(get_class($expected), $result);
2458
-		$this->assertEquals($expected->getData(), $result->getData());
2459
-	}
2460
-
2461
-
2462
-	public function testCreateShareInvalidExpireDate(): void {
2463
-		$this->expectException(OCSNotFoundException::class);
2464
-		$this->expectExceptionMessage('Invalid date. Format must be YYYY-MM-DD');
2465
-
2466
-		$ocs = $this->mockFormatShare();
2467
-
2468
-		$path = $this->getMockBuilder(Folder::class)->getMock();
2469
-		$path->method('getId')->willReturn(42);
2470
-		$storage = $this->createMock(IStorage::class);
2471
-		$storage->method('instanceOfStorage')
2472
-			->willReturnMap([
2473
-				['OCA\Files_Sharing\External\Storage', false],
2474
-				['OCA\Files_Sharing\SharedStorage', false],
2475
-			]);
2476
-		$path->method('getStorage')->willReturn($storage);
2477
-		$this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2478
-		$this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2479
-		$this->rootFolder->method('getById')
2480
-			->willReturn([]);
2481
-
2482
-		$this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2483
-		$this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2484
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2485
-
2486
-		$ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, 'a1b2d3');
2487
-	}
2488
-
2489
-	public function testCreateShareRemote(): void {
2490
-		$share = $this->newShare();
2491
-		$this->shareManager->method('newShare')->willReturn($share);
2492
-
2493
-		/** @var ShareAPIController $ocs */
2494
-		$ocs = $this->getMockBuilder(ShareAPIController::class)
2495
-			->setConstructorArgs([
2496
-				$this->appName,
2497
-				$this->request,
2498
-				$this->shareManager,
2499
-				$this->groupManager,
2500
-				$this->userManager,
2501
-				$this->rootFolder,
2502
-				$this->urlGenerator,
2503
-				$this->l,
2504
-				$this->config,
2505
-				$this->appConfig,
2506
-				$this->appManager,
2507
-				$this->serverContainer,
2508
-				$this->userStatusManager,
2509
-				$this->previewManager,
2510
-				$this->dateTimeZone,
2511
-				$this->logger,
2512
-				$this->factory,
2513
-				$this->mailer,
2514
-				$this->tagManager,
2515
-				$this->getEmailValidatorWithStrictEmailCheck(),
2516
-				$this->trustedServers,
2517
-				$this->currentUser,
2518
-			])->onlyMethods(['formatShare'])
2519
-			->getMock();
2520
-
2521
-		[$userFolder, $path] = $this->getNonSharedUserFile();
2522
-		$this->rootFolder->expects($this->exactly(2))
2523
-			->method('getUserFolder')
2524
-			->with('currentUser')
2525
-			->willReturn($userFolder);
2526
-
2527
-		$userFolder->expects($this->once())
2528
-			->method('get')
2529
-			->with('valid-path')
2530
-			->willReturn($path);
2531
-		$userFolder->method('getById')
2532
-			->willReturn([]);
2533
-
2534
-		$this->userManager->method('userExists')->with('validUser')->willReturn(true);
2535
-
2536
-		$path->expects($this->once())
2537
-			->method('lock')
2538
-			->with(ILockingProvider::LOCK_SHARED);
2539
-
2540
-		$this->shareManager->method('createShare')
2541
-			->with($this->callback(function (IShare $share) use ($path) {
2542
-				return $share->getNode() === $path
2543
-					&& $share->getPermissions() === (
2544
-						Constants::PERMISSION_ALL
2545
-						& ~Constants::PERMISSION_DELETE
2546
-						& ~Constants::PERMISSION_CREATE
2547
-					)
2548
-					&& $share->getShareType() === IShare::TYPE_REMOTE
2549
-					&& $share->getSharedWith() === '[email protected]'
2550
-					&& $share->getSharedBy() === 'currentUser';
2551
-			}))
2552
-			->willReturnArgument(0);
2553
-
2554
-		$this->shareManager->method('outgoingServer2ServerSharesAllowed')->willReturn(true);
2555
-
2556
-		$expected = new DataResponse([]);
2557
-		$result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_REMOTE, '[email protected]');
2558
-
2559
-		$this->assertInstanceOf(get_class($expected), $result);
2560
-		$this->assertEquals($expected->getData(), $result->getData());
2561
-	}
2562
-
2563
-	public function testCreateShareRemoteGroup(): void {
2564
-		$share = $this->newShare();
2565
-		$this->shareManager->method('newShare')->willReturn($share);
2566
-
2567
-		/** @var ShareAPIController $ocs */
2568
-		$ocs = $this->getMockBuilder(ShareAPIController::class)
2569
-			->setConstructorArgs([
2570
-				$this->appName,
2571
-				$this->request,
2572
-				$this->shareManager,
2573
-				$this->groupManager,
2574
-				$this->userManager,
2575
-				$this->rootFolder,
2576
-				$this->urlGenerator,
2577
-				$this->l,
2578
-				$this->config,
2579
-				$this->appConfig,
2580
-				$this->appManager,
2581
-				$this->serverContainer,
2582
-				$this->userStatusManager,
2583
-				$this->previewManager,
2584
-				$this->dateTimeZone,
2585
-				$this->logger,
2586
-				$this->factory,
2587
-				$this->mailer,
2588
-				$this->tagManager,
2589
-				$this->getEmailValidatorWithStrictEmailCheck(),
2590
-				$this->trustedServers,
2591
-				$this->currentUser,
2592
-			])->onlyMethods(['formatShare'])
2593
-			->getMock();
2594
-
2595
-		[$userFolder, $path] = $this->getNonSharedUserFile();
2596
-		$this->rootFolder->expects($this->exactly(2))
2597
-			->method('getUserFolder')
2598
-			->with('currentUser')
2599
-			->willReturn($userFolder);
2600
-
2601
-		$userFolder->expects($this->once())
2602
-			->method('get')
2603
-			->with('valid-path')
2604
-			->willReturn($path);
2605
-		$userFolder->method('getById')
2606
-			->willReturn([]);
2607
-
2608
-		$this->userManager->method('userExists')->with('validUser')->willReturn(true);
2609
-
2610
-		$path->expects($this->once())
2611
-			->method('lock')
2612
-			->with(ILockingProvider::LOCK_SHARED);
2613
-
2614
-		$this->shareManager->method('createShare')
2615
-			->with($this->callback(function (IShare $share) use ($path) {
2616
-				return $share->getNode() === $path
2617
-					&& $share->getPermissions() === (
2618
-						Constants::PERMISSION_ALL
2619
-						& ~Constants::PERMISSION_DELETE
2620
-						& ~Constants::PERMISSION_CREATE
2621
-					)
2622
-					&& $share->getShareType() === IShare::TYPE_REMOTE_GROUP
2623
-					&& $share->getSharedWith() === '[email protected]'
2624
-					&& $share->getSharedBy() === 'currentUser';
2625
-			}))
2626
-			->willReturnArgument(0);
2627
-
2628
-		$this->shareManager->method('outgoingServer2ServerGroupSharesAllowed')->willReturn(true);
2629
-
2630
-		$expected = new DataResponse([]);
2631
-		$result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_REMOTE_GROUP, '[email protected]');
2632
-
2633
-		$this->assertInstanceOf(get_class($expected), $result);
2634
-		$this->assertEquals($expected->getData(), $result->getData());
2635
-	}
2636
-
2637
-	public function testCreateShareRoom(): void {
2638
-		$ocs = $this->mockFormatShare();
2639
-
2640
-		$share = $this->newShare();
2641
-		$this->shareManager->method('newShare')->willReturn($share);
2642
-
2643
-		[$userFolder, $path] = $this->getNonSharedUserFile();
2644
-		$this->rootFolder->expects($this->exactly(2))
2645
-			->method('getUserFolder')
2646
-			->with('currentUser')
2647
-			->willReturn($userFolder);
2648
-
2649
-		$userFolder->expects($this->once())
2650
-			->method('get')
2651
-			->with('valid-path')
2652
-			->willReturn($path);
2653
-		$userFolder->method('getById')
2654
-			->willReturn([]);
2655
-
2656
-		$path->expects($this->once())
2657
-			->method('lock')
2658
-			->with(ILockingProvider::LOCK_SHARED);
2659
-
2660
-		$this->appManager->method('isEnabledForUser')
2661
-			->with('spreed')
2662
-			->willReturn(true);
2663
-
2664
-		// This is not possible anymore with PHPUnit 10+
2665
-		// as `setMethods` was removed and now real reflection is used, thus the class needs to exist.
2666
-		// $helper = $this->getMockBuilder('\OCA\Talk\Share\Helper\ShareAPIController')
2667
-		$helper = $this->getMockBuilder(\stdClass::class)
2668
-			->addMethods(['createShare'])
2669
-			->getMock();
2670
-		$helper->method('createShare')
2671
-			->with(
2672
-				$share,
2673
-				'recipientRoom',
2674
-				Constants::PERMISSION_ALL
2675
-				& ~Constants::PERMISSION_DELETE
2676
-				& ~Constants::PERMISSION_CREATE,
2677
-				''
2678
-			)->willReturnCallback(
2679
-				function ($share): void {
2680
-					$share->setSharedWith('recipientRoom');
2681
-					$share->setPermissions(Constants::PERMISSION_ALL);
2682
-				}
2683
-			);
2684
-
2685
-		$this->serverContainer->method('get')
2686
-			->with('\OCA\Talk\Share\Helper\ShareAPIController')
2687
-			->willReturn($helper);
2688
-
2689
-		$this->shareManager->method('createShare')
2690
-			->with($this->callback(function (IShare $share) use ($path) {
2691
-				return $share->getNode() === $path
2692
-					&& $share->getPermissions() === Constants::PERMISSION_ALL
2693
-					&& $share->getShareType() === IShare::TYPE_ROOM
2694
-					&& $share->getSharedWith() === 'recipientRoom'
2695
-					&& $share->getSharedBy() === 'currentUser';
2696
-			}))
2697
-			->willReturnArgument(0);
2698
-
2699
-		$expected = new DataResponse([]);
2700
-		$result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_ROOM, 'recipientRoom');
2701
-
2702
-		$this->assertInstanceOf(get_class($expected), $result);
2703
-		$this->assertEquals($expected->getData(), $result->getData());
2704
-	}
2705
-
2706
-
2707
-	public function testCreateShareRoomHelperNotAvailable(): void {
2708
-		$this->expectException(OCSForbiddenException::class);
2709
-		$this->expectExceptionMessage('Sharing valid-path failed because the back end does not support room shares');
2710
-
2711
-		$ocs = $this->mockFormatShare();
2712
-
2713
-		$share = $this->newShare();
2714
-		$this->shareManager->method('newShare')->willReturn($share);
2715
-
2716
-		[$userFolder, $path] = $this->getNonSharedUserFolder();
2717
-		$this->rootFolder->method('getUserFolder')
2718
-			->with('currentUser')
2719
-			->willReturn($userFolder);
2720
-
2721
-		$path->method('getPath')->willReturn('valid-path');
2722
-		$userFolder->expects($this->once())
2723
-			->method('get')
2724
-			->with('valid-path')
2725
-			->willReturn($path);
2726
-		$userFolder->method('getById')
2727
-			->willReturn([]);
2728
-
2729
-		$path->expects($this->once())
2730
-			->method('lock')
2731
-			->with(ILockingProvider::LOCK_SHARED);
2732
-
2733
-		$this->appManager->method('isEnabledForUser')
2734
-			->with('spreed')
2735
-			->willReturn(false);
2736
-
2737
-		$this->shareManager->expects($this->never())->method('createShare');
2738
-
2739
-		$ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_ROOM, 'recipientRoom');
2740
-	}
2741
-
2742
-
2743
-	public function testCreateShareRoomHelperThrowException(): void {
2744
-		$this->expectException(OCSNotFoundException::class);
2745
-		$this->expectExceptionMessage('Exception thrown by the helper');
2746
-
2747
-		$ocs = $this->mockFormatShare();
2748
-
2749
-		$share = $this->newShare();
2750
-		$share->setSharedBy('currentUser');
2751
-		$this->shareManager->method('newShare')->willReturn($share);
2752
-
2753
-		[$userFolder, $path] = $this->getNonSharedUserFile();
2754
-		$this->rootFolder->method('getUserFolder')
2755
-			->with('currentUser')
2756
-			->willReturn($userFolder);
2757
-
2758
-		$userFolder->expects($this->once())
2759
-			->method('get')
2760
-			->with('valid-path')
2761
-			->willReturn($path);
2762
-		$userFolder->method('getById')
2763
-			->willReturn([]);
2764
-
2765
-		$path->expects($this->once())
2766
-			->method('lock')
2767
-			->with(ILockingProvider::LOCK_SHARED);
2768
-
2769
-		$this->appManager->method('isEnabledForUser')
2770
-			->with('spreed')
2771
-			->willReturn(true);
2772
-
2773
-		// This is not possible anymore with PHPUnit 10+
2774
-		// as `setMethods` was removed and now real reflection is used, thus the class needs to exist.
2775
-		// $helper = $this->getMockBuilder('\OCA\Talk\Share\Helper\ShareAPIController')
2776
-		$helper = $this->getMockBuilder(\stdClass::class)
2777
-			->addMethods(['createShare'])
2778
-			->getMock();
2779
-		$helper->method('createShare')
2780
-			->with(
2781
-				$share,
2782
-				'recipientRoom',
2783
-				Constants::PERMISSION_ALL & ~(Constants::PERMISSION_CREATE | Constants::PERMISSION_DELETE),
2784
-				''
2785
-			)->willReturnCallback(
2786
-				function ($share): void {
2787
-					throw new OCSNotFoundException('Exception thrown by the helper');
2788
-				}
2789
-			);
2790
-
2791
-		$this->serverContainer->method('get')
2792
-			->with('\OCA\Talk\Share\Helper\ShareAPIController')
2793
-			->willReturn($helper);
2794
-
2795
-		$this->shareManager->expects($this->never())->method('createShare');
2796
-
2797
-		$ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_ROOM, 'recipientRoom');
2798
-	}
2799
-
2800
-	/**
2801
-	 * Test for https://github.com/owncloud/core/issues/22587
2802
-	 * TODO: Remove once proper solution is in place
2803
-	 */
2804
-	public function testCreateReshareOfFederatedMountNoDeletePermissions(): void {
2805
-		$share = Server::get(IManager::class)->newShare();
2806
-		$this->shareManager->method('newShare')->willReturn($share);
2807
-
2808
-		/** @var ShareAPIController&MockObject $ocs */
2809
-		$ocs = $this->getMockBuilder(ShareAPIController::class)
2810
-			->setConstructorArgs([
2811
-				$this->appName,
2812
-				$this->request,
2813
-				$this->shareManager,
2814
-				$this->groupManager,
2815
-				$this->userManager,
2816
-				$this->rootFolder,
2817
-				$this->urlGenerator,
2818
-				$this->l,
2819
-				$this->config,
2820
-				$this->appConfig,
2821
-				$this->appManager,
2822
-				$this->serverContainer,
2823
-				$this->userStatusManager,
2824
-				$this->previewManager,
2825
-				$this->dateTimeZone,
2826
-				$this->logger,
2827
-				$this->factory,
2828
-				$this->mailer,
2829
-				$this->tagManager,
2830
-				$this->getEmailValidatorWithStrictEmailCheck(),
2831
-				$this->trustedServers,
2832
-				$this->currentUser,
2833
-			])->onlyMethods(['formatShare'])
2834
-			->getMock();
2835
-
2836
-		$userFolder = $this->getMockBuilder(Folder::class)->getMock();
2837
-		$this->rootFolder->expects($this->exactly(2))
2838
-			->method('getUserFolder')
2839
-			->with('currentUser')
2840
-			->willReturn($userFolder);
2841
-
2842
-		$path = $this->getMockBuilder(Folder::class)->getMock();
2843
-		$path->method('getId')->willReturn(42);
2844
-
2845
-		$storage = $this->createMock(IStorage::class);
2846
-		$storage->method('instanceOfStorage')
2847
-			->willReturnMap([
2848
-				['OCA\Files_Sharing\External\Storage', true],
2849
-				['OCA\Files_Sharing\SharedStorage', false],
2850
-			]);
2851
-		$userFolder->method('getStorage')->willReturn($storage);
2852
-		$path->method('getStorage')->willReturn($storage);
2853
-
2854
-		$path->method('getPermissions')->willReturn(Constants::PERMISSION_READ);
2855
-		$userFolder->expects($this->once())
2856
-			->method('get')
2857
-			->with('valid-path')
2858
-			->willReturn($path);
2859
-		$userFolder->method('getById')
2860
-			->willReturn([]);
2861
-
2862
-		$this->userManager->method('userExists')->with('validUser')->willReturn(true);
2863
-
2864
-		$this->shareManager
2865
-			->expects($this->once())
2866
-			->method('createShare')
2867
-			->with($this->callback(function (IShare $share) {
2868
-				return $share->getPermissions() === Constants::PERMISSION_READ;
2869
-			}))
2870
-			->willReturnArgument(0);
2871
-
2872
-		$ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_USER, 'validUser');
2873
-	}
2874
-
2875
-
2876
-	public function testUpdateShareCantAccess(): void {
2877
-		$this->expectException(OCSNotFoundException::class);
2878
-		$this->expectExceptionMessage('Wrong share ID, share does not exist');
2879
-
2880
-		[$userFolder, $node] = $this->getNonSharedUserFolder();
2881
-		$share = $this->newShare();
2882
-		$share->setNode($node);
2883
-
2884
-		$node->expects($this->once())
2885
-			->method('lock')
2886
-			->with(ILockingProvider::LOCK_SHARED);
2887
-
2888
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
2889
-
2890
-		$this->rootFolder->method('getUserFolder')
2891
-			->with($this->currentUser)
2892
-			->willReturn($userFolder);
2893
-
2894
-		$userFolder->method('getById')
2895
-			->with($share->getNodeId())
2896
-			->willReturn([$share->getNode()]);
2897
-
2898
-		$this->ocs->updateShare(42);
2899
-	}
2900
-
2901
-
2902
-	public function testUpdateNoParametersLink(): void {
2903
-		$this->expectException(OCSBadRequestException::class);
2904
-		$this->expectExceptionMessage('Wrong or no update parameter given');
2905
-
2906
-		$node = $this->getMockBuilder(Folder::class)->getMock();
2907
-		$share = $this->newShare();
2908
-		$share->setPermissions(Constants::PERMISSION_ALL)
2909
-			->setSharedBy($this->currentUser)
2910
-			->setShareType(IShare::TYPE_LINK)
2911
-			->setNode($node);
2912
-
2913
-		$node->expects($this->once())
2914
-			->method('lock')
2915
-			->with(ILockingProvider::LOCK_SHARED);
2916
-
2917
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
2918
-
2919
-		$this->ocs->updateShare(42);
2920
-	}
2921
-
2922
-
2923
-	public function testUpdateNoParametersOther(): void {
2924
-		$this->expectException(OCSBadRequestException::class);
2925
-		$this->expectExceptionMessage('Wrong or no update parameter given');
2926
-
2927
-		$node = $this->getMockBuilder(Folder::class)->getMock();
2928
-		$share = $this->newShare();
2929
-		$share->setPermissions(Constants::PERMISSION_ALL)
2930
-			->setSharedBy($this->currentUser)
2931
-			->setShareType(IShare::TYPE_GROUP)
2932
-			->setNode($node);
2933
-
2934
-		$node->expects($this->once())
2935
-			->method('lock')
2936
-			->with(ILockingProvider::LOCK_SHARED);
2937
-
2938
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
2939
-
2940
-		$this->ocs->updateShare(42);
2941
-	}
2942
-
2943
-	public function testUpdateLinkShareClear(): void {
2944
-		$ocs = $this->mockFormatShare();
2945
-
2946
-		[$userFolder, $node] = $this->getNonSharedUserFolder();
2947
-		$node->method('getId')
2948
-			->willReturn(42);
2949
-		$share = $this->newShare();
2950
-		$share->setPermissions(Constants::PERMISSION_ALL)
2951
-			->setSharedBy($this->currentUser)
2952
-			->setShareType(IShare::TYPE_LINK)
2953
-			->setPassword('password')
2954
-			->setExpirationDate(new \DateTime())
2955
-			->setNote('note')
2956
-			->setLabel('label')
2957
-			->setHideDownload(true)
2958
-			->setPermissions(Constants::PERMISSION_ALL)
2959
-			->setNode($node);
2960
-
2961
-		$node->expects($this->once())
2962
-			->method('lock')
2963
-			->with(ILockingProvider::LOCK_SHARED);
2964
-
2965
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
2966
-
2967
-		$this->shareManager->expects($this->once())->method('updateShare')->with(
2968
-			$this->callback(function (IShare $share) {
2969
-				return $share->getPermissions() === Constants::PERMISSION_READ
2970
-				&& $share->getPassword() === null
2971
-				&& $share->getExpirationDate() === null
2972
-				// Once set a note or a label are never back to null, only to an
2973
-				// empty string.
2974
-				&& $share->getNote() === ''
2975
-				&& $share->getLabel() === ''
2976
-				&& $share->getHideDownload() === false;
2977
-			})
2978
-		)->willReturnArgument(0);
2979
-
2980
-		$this->shareManager->method('getSharedWith')
2981
-			->willReturn([]);
2982
-
2983
-		$this->rootFolder->method('getUserFolder')
2984
-			->with($this->currentUser)
2985
-			->willReturn($userFolder);
2986
-
2987
-		$userFolder->method('getById')
2988
-			->with(42)
2989
-			->willReturn([$node]);
2990
-		$userFolder->method('getFirstNodeById')
2991
-			->with(42)
2992
-			->willReturn($node);
2993
-
2994
-		$mountPoint = $this->createMock(IMountPoint::class);
2995
-		$node->method('getMountPoint')
2996
-			->willReturn($mountPoint);
2997
-		$mountPoint->method('getStorageRootId')
2998
-			->willReturn(42);
2999
-
3000
-		$expected = new DataResponse([]);
3001
-		$result = $ocs->updateShare(42, null, '', null, 'false', '', '', '', 'false');
3002
-
3003
-		$this->assertInstanceOf(get_class($expected), $result);
3004
-		$this->assertEquals($expected->getData(), $result->getData());
3005
-	}
3006
-
3007
-	public function testUpdateLinkShareSet(): void {
3008
-		$ocs = $this->mockFormatShare();
3009
-
3010
-		[$userFolder, $folder] = $this->getNonSharedUserFolder();
3011
-		$folder->method('getId')
3012
-			->willReturn(42);
3013
-
3014
-		$share = Server::get(IManager::class)->newShare();
3015
-		$share->setPermissions(Constants::PERMISSION_ALL)
3016
-			->setSharedBy($this->currentUser)
3017
-			->setShareType(IShare::TYPE_LINK)
3018
-			->setNode($folder);
3019
-
3020
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3021
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3022
-
3023
-		$this->shareManager->expects($this->once())->method('updateShare')->with(
3024
-			$this->callback(function (IShare $share) {
3025
-				$date = new \DateTime('2000-01-01');
3026
-				$date->setTime(0, 0, 0);
3027
-
3028
-				return $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
3029
-				&& $share->getPassword() === 'password'
3030
-				&& $share->getExpirationDate() == $date
3031
-				&& $share->getNote() === 'note'
3032
-				&& $share->getLabel() === 'label'
3033
-				&& $share->getHideDownload() === true;
3034
-			})
3035
-		)->willReturnArgument(0);
3036
-
3037
-		$this->shareManager->method('getSharedWith')
3038
-			->willReturn([]);
3039
-
3040
-		$this->rootFolder->method('getUserFolder')
3041
-			->with($this->currentUser)
3042
-			->willReturn($userFolder);
3043
-
3044
-		$userFolder->method('getById')
3045
-			->with(42)
3046
-			->willReturn([$folder]);
3047
-
3048
-		$mountPoint = $this->createMock(IMountPoint::class);
3049
-		$folder->method('getMountPoint')
3050
-			->willReturn($mountPoint);
3051
-		$mountPoint->method('getStorageRootId')
3052
-			->willReturn(42);
3053
-
3054
-		$expected = new DataResponse([]);
3055
-		$result = $ocs->updateShare(42, null, 'password', null, 'true', '2000-01-01', 'note', 'label', 'true');
3056
-
3057
-		$this->assertInstanceOf(get_class($expected), $result);
3058
-		$this->assertEquals($expected->getData(), $result->getData());
3059
-	}
3060
-
3061
-	#[DataProvider('publicUploadParamsProvider')]
3062
-	public function testUpdateLinkShareEnablePublicUpload($permissions, $publicUpload, $expireDate, $password): void {
3063
-		$ocs = $this->mockFormatShare();
3064
-
3065
-		[$userFolder, $folder] = $this->getNonSharedUserFolder();
3066
-		$folder->method('getId')
3067
-			->willReturn(42);
3068
-
3069
-		$share = Server::get(IManager::class)->newShare();
3070
-		$share->setPermissions(Constants::PERMISSION_ALL)
3071
-			->setSharedBy($this->currentUser)
3072
-			->setShareType(IShare::TYPE_LINK)
3073
-			->setPassword('password')
3074
-			->setNode($folder);
3075
-
3076
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3077
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3078
-		$this->shareManager->method('getSharedWith')->willReturn([]);
3079
-
3080
-		$this->shareManager->expects($this->once())->method('updateShare')->with(
3081
-			$this->callback(function (IShare $share) {
3082
-				return $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
3083
-				&& $share->getPassword() === 'password'
3084
-				&& $share->getExpirationDate() === null;
3085
-			})
3086
-		)->willReturnArgument(0);
3087
-
3088
-		$this->rootFolder->method('getUserFolder')
3089
-			->with($this->currentUser)
3090
-			->willReturn($userFolder);
3091
-
3092
-		$userFolder->method('getById')
3093
-			->with(42)
3094
-			->willReturn([$folder]);
3095
-
3096
-		$mountPoint = $this->createMock(IMountPoint::class);
3097
-		$folder->method('getMountPoint')
3098
-			->willReturn($mountPoint);
3099
-		$mountPoint->method('getStorageRootId')
3100
-			->willReturn(42);
3101
-
3102
-		$expected = new DataResponse([]);
3103
-		$result = $ocs->updateShare(42, $permissions, $password, null, $publicUpload, $expireDate);
3104
-
3105
-		$this->assertInstanceOf(get_class($expected), $result);
3106
-		$this->assertEquals($expected->getData(), $result->getData());
3107
-	}
3108
-
3109
-
3110
-	public static function publicLinkValidPermissionsProvider() {
3111
-		return [
3112
-			[Constants::PERMISSION_CREATE],
3113
-			[Constants::PERMISSION_READ],
3114
-			[Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE],
3115
-			[Constants::PERMISSION_READ | Constants::PERMISSION_DELETE],
3116
-			[Constants::PERMISSION_READ | Constants::PERMISSION_CREATE],
3117
-		];
3118
-	}
3119
-
3120
-	#[DataProvider('publicLinkValidPermissionsProvider')]
3121
-	public function testUpdateLinkShareSetCRUDPermissions($permissions): void {
3122
-		$ocs = $this->mockFormatShare();
3123
-
3124
-		[$userFolder, $folder] = $this->getNonSharedUserFolder();
3125
-		$folder->method('getId')
3126
-			->willReturn(42);
3127
-
3128
-		$share = Server::get(IManager::class)->newShare();
3129
-		$share->setPermissions(Constants::PERMISSION_ALL)
3130
-			->setSharedBy($this->currentUser)
3131
-			->setShareType(IShare::TYPE_LINK)
3132
-			->setPassword('password')
3133
-			->setNode($folder);
3134
-
3135
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3136
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3137
-		$this->shareManager->method('getSharedWith')->willReturn([]);
3138
-
3139
-		$this->shareManager
3140
-			->expects($this->any())
3141
-			->method('updateShare')
3142
-			->willReturnArgument(0);
3143
-
3144
-		$this->rootFolder->method('getUserFolder')
3145
-			->with($this->currentUser)
3146
-			->willReturn($userFolder);
3147
-
3148
-		$userFolder->method('getById')
3149
-			->with(42)
3150
-			->willReturn([$folder]);
3151
-
3152
-		$mountPoint = $this->createMock(IMountPoint::class);
3153
-		$folder->method('getMountPoint')
3154
-			->willReturn($mountPoint);
3155
-		$mountPoint->method('getStorageRootId')
3156
-			->willReturn(42);
3157
-
3158
-		$expected = new DataResponse([]);
3159
-		$result = $ocs->updateShare(42, $permissions, 'password', null, null, null);
3160
-
3161
-		$this->assertInstanceOf(get_class($expected), $result);
3162
-		$this->assertEquals($expected->getData(), $result->getData());
3163
-	}
3164
-
3165
-	public static function publicLinkInvalidPermissionsProvider1() {
3166
-		return [
3167
-			[Constants::PERMISSION_DELETE],
3168
-			[Constants::PERMISSION_UPDATE],
3169
-			[Constants::PERMISSION_SHARE],
3170
-		];
3171
-	}
3172
-
3173
-	#[DataProvider('publicLinkInvalidPermissionsProvider1')]
3174
-	public function testUpdateLinkShareSetInvalidCRUDPermissions1($permissions): void {
3175
-		$this->expectException(OCSBadRequestException::class);
3176
-		$this->expectExceptionMessage('Share must at least have READ or CREATE permissions');
3177
-
3178
-		$this->testUpdateLinkShareSetCRUDPermissions($permissions, null);
3179
-	}
3180
-
3181
-	public static function publicLinkInvalidPermissionsProvider2() {
3182
-		return [
3183
-			[Constants::PERMISSION_CREATE | Constants::PERMISSION_DELETE],
3184
-			[Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE],
3185
-		];
3186
-	}
3187
-
3188
-	#[DataProvider('publicLinkInvalidPermissionsProvider2')]
3189
-	public function testUpdateLinkShareSetInvalidCRUDPermissions2($permissions): void {
3190
-		$this->expectException(OCSBadRequestException::class);
3191
-		$this->expectExceptionMessage('Share must have READ permission if UPDATE or DELETE permission is set');
3192
-
3193
-		$this->testUpdateLinkShareSetCRUDPermissions($permissions);
3194
-	}
3195
-
3196
-	public function testUpdateLinkShareInvalidDate(): void {
3197
-		$this->expectException(OCSBadRequestException::class);
3198
-		$this->expectExceptionMessage('Invalid date. Format must be YYYY-MM-DD');
3199
-
3200
-		$ocs = $this->mockFormatShare();
3201
-		[$userFolder, $folder] = $this->getNonSharedUserFolder();
3202
-		$userFolder->method('getById')
3203
-			->with(42)
3204
-			->willReturn([$folder]);
3205
-		$this->rootFolder->method('getUserFolder')
3206
-			->with($this->currentUser)
3207
-			->willReturn($userFolder);
3208
-
3209
-		$folder->method('getId')
3210
-			->willReturn(42);
3211
-
3212
-		$share = Server::get(IManager::class)->newShare();
3213
-		$share->setPermissions(Constants::PERMISSION_ALL)
3214
-			->setSharedBy($this->currentUser)
3215
-			->setShareType(IShare::TYPE_LINK)
3216
-			->setNode($folder);
3217
-
3218
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3219
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3220
-
3221
-		$ocs->updateShare(42, null, 'password', null, 'true', '2000-01-a');
3222
-	}
3223
-
3224
-	public static function publicUploadParamsProvider() {
3225
-		return [
3226
-			[null, 'true', null, 'password'],
3227
-			// legacy had no delete
3228
-			[
3229
-				Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE,
3230
-				'true', null, 'password'
3231
-			],
3232
-			// correct
3233
-			[
3234
-				Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE,
3235
-				null, null, 'password'
3236
-			],
3237
-		];
3238
-	}
3239
-
3240
-	#[DataProvider('publicUploadParamsProvider')]
3241
-	public function testUpdateLinkSharePublicUploadNotAllowed($permissions, $publicUpload, $expireDate, $password): void {
3242
-		$this->expectException(OCSForbiddenException::class);
3243
-		$this->expectExceptionMessage('Public upload disabled by the administrator');
3244
-
3245
-		$ocs = $this->mockFormatShare();
3246
-		[$userFolder, $folder] = $this->getNonSharedUserFolder();
3247
-		$userFolder->method('getById')
3248
-			->with(42)
3249
-			->willReturn([$folder]);
3250
-		$this->rootFolder->method('getUserFolder')
3251
-			->with($this->currentUser)
3252
-			->willReturn($userFolder);
3253
-
3254
-		$folder->method('getId')->willReturn(42);
3255
-
3256
-		$share = Server::get(IManager::class)->newShare();
3257
-		$share->setPermissions(Constants::PERMISSION_ALL)
3258
-			->setSharedBy($this->currentUser)
3259
-			->setShareType(IShare::TYPE_LINK)
3260
-			->setNode($folder);
3261
-
3262
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3263
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(false);
3264
-
3265
-		$ocs->updateShare(42, $permissions, $password, null, $publicUpload, $expireDate);
3266
-	}
3267
-
3268
-
3269
-	public function testUpdateLinkSharePublicUploadOnFile(): void {
3270
-		$this->expectException(OCSBadRequestException::class);
3271
-		$this->expectExceptionMessage('Public upload is only possible for publicly shared folders');
3272
-
3273
-		$ocs = $this->mockFormatShare();
3274
-
3275
-		$file = $this->getMockBuilder(File::class)->getMock();
3276
-		$file->method('getId')
3277
-			->willReturn(42);
3278
-		[$userFolder, $folder] = $this->getNonSharedUserFolder();
3279
-		$userFolder->method('getById')
3280
-			->with(42)
3281
-			->willReturn([$folder]);
3282
-		$this->rootFolder->method('getUserFolder')
3283
-			->with($this->currentUser)
3284
-			->willReturn($userFolder);
3285
-
3286
-		$share = Server::get(IManager::class)->newShare();
3287
-		$share->setPermissions(Constants::PERMISSION_ALL)
3288
-			->setSharedBy($this->currentUser)
3289
-			->setShareType(IShare::TYPE_LINK)
3290
-			->setNode($file);
3291
-
3292
-		$this->shareManager
3293
-			->method('getShareById')
3294
-			->with('ocinternal:42')
3295
-			->willReturn($share);
3296
-		$this->shareManager
3297
-			->method('shareApiLinkAllowPublicUpload')
3298
-			->willReturn(true);
3299
-		$this->shareManager
3300
-			->method('updateShare')
3301
-			->with($share)
3302
-			->willThrowException(new \InvalidArgumentException('File shares cannot have create or delete permissions'));
3303
-
3304
-		$ocs->updateShare(42, null, 'password', null, 'true', '');
3305
-	}
3306
-
3307
-	public function testUpdateLinkSharePasswordDoesNotChangeOther(): void {
3308
-		$ocs = $this->mockFormatShare();
3309
-
3310
-		$date = new \DateTime('2000-01-01');
3311
-		$date->setTime(0, 0, 0);
3312
-
3313
-		[$userFolder, $node] = $this->getNonSharedUserFolder();
3314
-		$node->method('getId')->willReturn(42);
3315
-		$userFolder->method('getById')
3316
-			->with(42)
3317
-			->willReturn([$node]);
3318
-		$this->rootFolder->method('getUserFolder')
3319
-			->with($this->currentUser)
3320
-			->willReturn($userFolder);
3321
-		$share = $this->newShare();
3322
-		$share->setPermissions(Constants::PERMISSION_ALL)
3323
-			->setSharedBy($this->currentUser)
3324
-			->setShareType(IShare::TYPE_LINK)
3325
-			->setPassword('password')
3326
-			->setSendPasswordByTalk(true)
3327
-			->setExpirationDate($date)
3328
-			->setNote('note')
3329
-			->setLabel('label')
3330
-			->setHideDownload(true)
3331
-			->setPermissions(Constants::PERMISSION_ALL)
3332
-			->setNode($node);
3333
-
3334
-		$node->expects($this->once())
3335
-			->method('lock')
3336
-			->with(ILockingProvider::LOCK_SHARED);
3337
-
3338
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3339
-
3340
-		$this->shareManager->expects($this->once())->method('updateShare')->with(
3341
-			$this->callback(function (IShare $share) use ($date) {
3342
-				return $share->getPermissions() === Constants::PERMISSION_ALL
3343
-				&& $share->getPassword() === 'newpassword'
3344
-				&& $share->getSendPasswordByTalk() === true
3345
-				&& $share->getExpirationDate() === $date
3346
-				&& $share->getNote() === 'note'
3347
-				&& $share->getLabel() === 'label'
3348
-				&& $share->getHideDownload() === true;
3349
-			})
3350
-		)->willReturnArgument(0);
3351
-
3352
-		$expected = new DataResponse([]);
3353
-		$result = $ocs->updateShare(42, null, 'newpassword', null, null, null, null, null, null);
3354
-
3355
-		$this->assertInstanceOf(get_class($expected), $result);
3356
-		$this->assertEquals($expected->getData(), $result->getData());
3357
-	}
3358
-
3359
-	public function testUpdateLinkShareSendPasswordByTalkDoesNotChangeOther(): void {
3360
-		$ocs = $this->mockFormatShare();
3361
-
3362
-		$date = new \DateTime('2000-01-01');
3363
-		$date->setTime(0, 0, 0);
3364
-
3365
-		[$userFolder, $node] = $this->getNonSharedUserFolder();
3366
-		$userFolder->method('getById')
3367
-			->with(42)
3368
-			->willReturn([$node]);
3369
-		$this->rootFolder->method('getUserFolder')
3370
-			->with($this->currentUser)
3371
-			->willReturn($userFolder);
3372
-		$node->method('getId')->willReturn(42);
3373
-		$share = $this->newShare();
3374
-		$share->setPermissions(Constants::PERMISSION_ALL)
3375
-			->setSharedBy($this->currentUser)
3376
-			->setShareType(IShare::TYPE_LINK)
3377
-			->setPassword('password')
3378
-			->setSendPasswordByTalk(false)
3379
-			->setExpirationDate($date)
3380
-			->setNote('note')
3381
-			->setLabel('label')
3382
-			->setHideDownload(true)
3383
-			->setPermissions(Constants::PERMISSION_ALL)
3384
-			->setNode($node);
3385
-
3386
-		$node->expects($this->once())
3387
-			->method('lock')
3388
-			->with(ILockingProvider::LOCK_SHARED);
3389
-
3390
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3391
-
3392
-		$this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(true);
3393
-
3394
-		$this->shareManager->expects($this->once())->method('updateShare')->with(
3395
-			$this->callback(function (IShare $share) use ($date) {
3396
-				return $share->getPermissions() === Constants::PERMISSION_ALL
3397
-				&& $share->getPassword() === 'password'
3398
-				&& $share->getSendPasswordByTalk() === true
3399
-				&& $share->getExpirationDate() === $date
3400
-				&& $share->getNote() === 'note'
3401
-				&& $share->getLabel() === 'label'
3402
-				&& $share->getHideDownload() === true;
3403
-			})
3404
-		)->willReturnArgument(0);
3405
-
3406
-		$expected = new DataResponse([]);
3407
-		$result = $ocs->updateShare(42, null, null, 'true', null, null, null, null, null);
3408
-
3409
-		$this->assertInstanceOf(get_class($expected), $result);
3410
-		$this->assertEquals($expected->getData(), $result->getData());
3411
-	}
3412
-
3413
-
3414
-	public function testUpdateLinkShareSendPasswordByTalkWithTalkDisabledDoesNotChangeOther(): void {
3415
-		$this->expectException(OCSForbiddenException::class);
3416
-		$this->expectExceptionMessage('"Sending the password by Nextcloud Talk" for sharing a file or folder failed because Nextcloud Talk is not enabled.');
3417
-
3418
-		$ocs = $this->mockFormatShare();
3419
-
3420
-		$date = new \DateTime('2000-01-01');
3421
-		$date->setTime(0, 0, 0);
3422
-
3423
-		[$userFolder, $node] = $this->getNonSharedUserFolder();
3424
-		$userFolder->method('getById')
3425
-			->with(42)
3426
-			->willReturn([$node]);
3427
-		$this->rootFolder->method('getUserFolder')
3428
-			->with($this->currentUser)
3429
-			->willReturn($userFolder);
3430
-		$node->method('getId')->willReturn(42);
3431
-		$share = $this->newShare();
3432
-		$share->setPermissions(Constants::PERMISSION_ALL)
3433
-			->setSharedBy($this->currentUser)
3434
-			->setShareType(IShare::TYPE_LINK)
3435
-			->setPassword('password')
3436
-			->setSendPasswordByTalk(false)
3437
-			->setExpirationDate($date)
3438
-			->setNote('note')
3439
-			->setLabel('label')
3440
-			->setHideDownload(true)
3441
-			->setPermissions(Constants::PERMISSION_ALL)
3442
-			->setNode($node);
3443
-
3444
-		$node->expects($this->once())
3445
-			->method('lock')
3446
-			->with(ILockingProvider::LOCK_SHARED);
3447
-
3448
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3449
-
3450
-		$this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(false);
3451
-
3452
-		$this->shareManager->expects($this->never())->method('updateShare');
3453
-
3454
-		$ocs->updateShare(42, null, null, 'true', null, null, null, null, null);
3455
-	}
3456
-
3457
-	public function testUpdateLinkShareDoNotSendPasswordByTalkDoesNotChangeOther(): void {
3458
-		$ocs = $this->mockFormatShare();
3459
-
3460
-		$date = new \DateTime('2000-01-01');
3461
-		$date->setTime(0, 0, 0);
3462
-
3463
-		[$userFolder, $node] = $this->getNonSharedUserFolder();
3464
-		$userFolder->method('getById')
3465
-			->with(42)
3466
-			->willReturn([$node]);
3467
-		$this->rootFolder->method('getUserFolder')
3468
-			->with($this->currentUser)
3469
-			->willReturn($userFolder);
3470
-		$node->method('getId')->willReturn(42);
3471
-		$share = $this->newShare();
3472
-		$share->setPermissions(Constants::PERMISSION_ALL)
3473
-			->setSharedBy($this->currentUser)
3474
-			->setShareType(IShare::TYPE_LINK)
3475
-			->setPassword('password')
3476
-			->setSendPasswordByTalk(true)
3477
-			->setExpirationDate($date)
3478
-			->setNote('note')
3479
-			->setLabel('label')
3480
-			->setHideDownload(true)
3481
-			->setPermissions(Constants::PERMISSION_ALL)
3482
-			->setNode($node);
3483
-
3484
-		$node->expects($this->once())
3485
-			->method('lock')
3486
-			->with(ILockingProvider::LOCK_SHARED);
3487
-
3488
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3489
-
3490
-		$this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(true);
3491
-
3492
-		$this->shareManager->expects($this->once())->method('updateShare')->with(
3493
-			$this->callback(function (IShare $share) use ($date) {
3494
-				return $share->getPermissions() === Constants::PERMISSION_ALL
3495
-				&& $share->getPassword() === 'password'
3496
-				&& $share->getSendPasswordByTalk() === false
3497
-				&& $share->getExpirationDate() === $date
3498
-				&& $share->getNote() === 'note'
3499
-				&& $share->getLabel() === 'label'
3500
-				&& $share->getHideDownload() === true;
3501
-			})
3502
-		)->willReturnArgument(0);
3503
-
3504
-		$expected = new DataResponse([]);
3505
-		$result = $ocs->updateShare(42, null, null, 'false', null, null, null, null, null);
3506
-
3507
-		$this->assertInstanceOf(get_class($expected), $result);
3508
-		$this->assertEquals($expected->getData(), $result->getData());
3509
-	}
3510
-
3511
-	public function testUpdateLinkShareDoNotSendPasswordByTalkWithTalkDisabledDoesNotChangeOther(): void {
3512
-		$ocs = $this->mockFormatShare();
3513
-
3514
-		$date = new \DateTime('2000-01-01');
3515
-		$date->setTime(0, 0, 0);
3516
-
3517
-		[$userFolder, $node] = $this->getNonSharedUserFolder();
3518
-		$node->method('getId')
3519
-			->willReturn(42);
3520
-
3521
-		$share = $this->newShare();
3522
-		$share->setPermissions(Constants::PERMISSION_ALL)
3523
-			->setSharedBy($this->currentUser)
3524
-			->setShareType(IShare::TYPE_LINK)
3525
-			->setPassword('password')
3526
-			->setSendPasswordByTalk(true)
3527
-			->setExpirationDate($date)
3528
-			->setNote('note')
3529
-			->setLabel('label')
3530
-			->setHideDownload(true)
3531
-			->setPermissions(Constants::PERMISSION_ALL)
3532
-			->setNode($node);
3533
-
3534
-		$node->expects($this->once())
3535
-			->method('lock')
3536
-			->with(ILockingProvider::LOCK_SHARED);
3537
-
3538
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3539
-
3540
-		$this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(false);
3541
-
3542
-		$this->shareManager->expects($this->once())->method('updateShare')->with(
3543
-			$this->callback(function (IShare $share) use ($date) {
3544
-				return $share->getPermissions() === Constants::PERMISSION_ALL
3545
-				&& $share->getPassword() === 'password'
3546
-				&& $share->getSendPasswordByTalk() === false
3547
-				&& $share->getExpirationDate() === $date
3548
-				&& $share->getNote() === 'note'
3549
-				&& $share->getLabel() === 'label'
3550
-				&& $share->getHideDownload() === true;
3551
-			})
3552
-		)->willReturnArgument(0);
3553
-
3554
-		$this->rootFolder->method('getUserFolder')
3555
-			->with($this->currentUser)
3556
-			->willReturn($userFolder);
3557
-
3558
-		$userFolder->method('getById')
3559
-			->with(42)
3560
-			->willReturn([$node]);
3561
-
3562
-		$mountPoint = $this->createMock(IMountPoint::class);
3563
-		$node->method('getMountPoint')
3564
-			->willReturn($mountPoint);
3565
-		$mountPoint->method('getStorageRootId')
3566
-			->willReturn(42);
3567
-
3568
-		$mountPoint = $this->createMock(IMountPoint::class);
3569
-		$node->method('getMountPoint')
3570
-			->willReturn($mountPoint);
3571
-		$mountPoint->method('getStorageRootId')
3572
-			->willReturn(42);
3573
-
3574
-		$expected = new DataResponse([]);
3575
-		$result = $ocs->updateShare(42, null, null, 'false', null, null, null, null, null);
3576
-
3577
-		$this->assertInstanceOf(get_class($expected), $result);
3578
-		$this->assertEquals($expected->getData(), $result->getData());
3579
-	}
3580
-
3581
-	public function testUpdateLinkShareExpireDateDoesNotChangeOther(): void {
3582
-		$ocs = $this->mockFormatShare();
3583
-
3584
-		[$userFolder, $node] = $this->getNonSharedUserFolder();
3585
-		$node->method('getId')
3586
-			->willReturn(42);
3587
-
3588
-		$share = $this->newShare();
3589
-		$share->setPermissions(Constants::PERMISSION_ALL)
3590
-			->setSharedBy($this->currentUser)
3591
-			->setShareType(IShare::TYPE_LINK)
3592
-			->setPassword('password')
3593
-			->setSendPasswordByTalk(true)
3594
-			->setExpirationDate(new \DateTime())
3595
-			->setNote('note')
3596
-			->setLabel('label')
3597
-			->setHideDownload(true)
3598
-			->setPermissions(Constants::PERMISSION_ALL)
3599
-			->setNode($node);
3600
-
3601
-		$node->expects($this->once())
3602
-			->method('lock')
3603
-			->with(ILockingProvider::LOCK_SHARED);
3604
-
3605
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3606
-
3607
-		$this->shareManager->expects($this->once())->method('updateShare')->with(
3608
-			$this->callback(function (IShare $share) {
3609
-				$date = new \DateTime('2010-12-23');
3610
-				$date->setTime(0, 0, 0);
3611
-
3612
-				return $share->getPermissions() === Constants::PERMISSION_ALL
3613
-				&& $share->getPassword() === 'password'
3614
-				&& $share->getSendPasswordByTalk() === true
3615
-				&& $share->getExpirationDate() == $date
3616
-				&& $share->getNote() === 'note'
3617
-				&& $share->getLabel() === 'label'
3618
-				&& $share->getHideDownload() === true;
3619
-			})
3620
-		)->willReturnArgument(0);
3621
-
3622
-		$this->rootFolder->method('getUserFolder')
3623
-			->with($this->currentUser)
3624
-			->willReturn($userFolder);
3625
-
3626
-		$userFolder->method('getById')
3627
-			->with(42)
3628
-			->willReturn([$node]);
3629
-
3630
-		$mountPoint = $this->createMock(IMountPoint::class);
3631
-		$node->method('getMountPoint')
3632
-			->willReturn($mountPoint);
3633
-		$mountPoint->method('getStorageRootId')
3634
-			->willReturn(42);
3635
-
3636
-		$expected = new DataResponse([]);
3637
-		$result = $ocs->updateShare(42, null, null, null, null, '2010-12-23', null, null, null);
3638
-
3639
-		$this->assertInstanceOf(get_class($expected), $result);
3640
-		$this->assertEquals($expected->getData(), $result->getData());
3641
-	}
3642
-
3643
-	public function testUpdateLinkSharePublicUploadDoesNotChangeOther(): void {
3644
-		$ocs = $this->mockFormatShare();
3645
-
3646
-		$date = new \DateTime('2000-01-01');
3647
-
3648
-		[$userFolder, $folder] = $this->getNonSharedUserFolder();
3649
-		$folder->method('getId')
3650
-			->willReturn(42);
3651
-
3652
-		$share = Server::get(IManager::class)->newShare();
3653
-		$share->setPermissions(Constants::PERMISSION_ALL)
3654
-			->setSharedBy($this->currentUser)
3655
-			->setShareType(IShare::TYPE_LINK)
3656
-			->setPassword('password')
3657
-			->setSendPasswordByTalk(true)
3658
-			->setExpirationDate($date)
3659
-			->setNote('note')
3660
-			->setLabel('label')
3661
-			->setHideDownload(true)
3662
-			->setPermissions(Constants::PERMISSION_ALL)
3663
-			->setNode($folder);
3664
-
3665
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3666
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3667
-
3668
-		$this->shareManager->expects($this->once())->method('updateShare')->with(
3669
-			$this->callback(function (IShare $share) use ($date) {
3670
-				return $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
3671
-				&& $share->getPassword() === 'password'
3672
-				&& $share->getSendPasswordByTalk() === true
3673
-				&& $share->getExpirationDate() === $date
3674
-				&& $share->getNote() === 'note'
3675
-				&& $share->getLabel() === 'label'
3676
-				&& $share->getHideDownload() === true;
3677
-			})
3678
-		)->willReturnArgument(0);
3679
-
3680
-		$this->shareManager->method('getSharedWith')
3681
-			->willReturn([]);
3682
-
3683
-		$this->rootFolder->method('getUserFolder')
3684
-			->with($this->currentUser)
3685
-			->willReturn($userFolder);
3686
-
3687
-		$userFolder->method('getById')
3688
-			->with(42)
3689
-			->willReturn([$folder]);
3690
-
3691
-		$mountPoint = $this->createMock(IMountPoint::class);
3692
-		$folder->method('getMountPoint')
3693
-			->willReturn($mountPoint);
3694
-		$mountPoint->method('getStorageRootId')
3695
-			->willReturn(42);
3696
-
3697
-		$expected = new DataResponse([]);
3698
-		$result = $ocs->updateShare(42, null, null, null, 'true', null, null, null, null);
3699
-
3700
-		$this->assertInstanceOf(get_class($expected), $result);
3701
-		$this->assertEquals($expected->getData(), $result->getData());
3702
-	}
3703
-
3704
-	public function testUpdateLinkSharePermissions(): void {
3705
-		$ocs = $this->mockFormatShare();
3706
-
3707
-		$date = new \DateTime('2000-01-01');
3708
-
3709
-		[$userFolder, $folder] = $this->getNonSharedUserFolder();
3710
-		$folder->method('getId')
3711
-			->willReturn(42);
3712
-
3713
-		$share = Server::get(IManager::class)->newShare();
3714
-		$share->setPermissions(Constants::PERMISSION_ALL)
3715
-			->setSharedBy($this->currentUser)
3716
-			->setShareType(IShare::TYPE_LINK)
3717
-			->setPassword('password')
3718
-			->setSendPasswordByTalk(true)
3719
-			->setExpirationDate($date)
3720
-			->setNote('note')
3721
-			->setLabel('label')
3722
-			->setHideDownload(true)
3723
-			->setPermissions(Constants::PERMISSION_ALL)
3724
-			->setNode($folder);
3725
-
3726
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3727
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3728
-
3729
-		$this->shareManager->expects($this->once())->method('updateShare')->with(
3730
-			$this->callback(function (IShare $share) use ($date): bool {
3731
-				return $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
3732
-				&& $share->getPassword() === 'password'
3733
-				&& $share->getSendPasswordByTalk() === true
3734
-				&& $share->getExpirationDate() === $date
3735
-				&& $share->getNote() === 'note'
3736
-				&& $share->getLabel() === 'label'
3737
-				&& $share->getHideDownload() === true;
3738
-			})
3739
-		)->willReturnArgument(0);
3740
-
3741
-		$this->shareManager->method('getSharedWith')->willReturn([]);
3742
-
3743
-		$this->rootFolder->method('getUserFolder')
3744
-			->with($this->currentUser)
3745
-			->willReturn($userFolder);
3746
-
3747
-		$userFolder->method('getById')
3748
-			->with(42)
3749
-			->willReturn([$folder]);
3750
-
3751
-		$mountPoint = $this->createMock(IMountPoint::class);
3752
-		$folder->method('getMountPoint')
3753
-			->willReturn($mountPoint);
3754
-		$mountPoint->method('getStorageRootId')
3755
-			->willReturn(42);
3756
-
3757
-		$expected = new DataResponse([]);
3758
-		$result = $ocs->updateShare(42, 7, null, null, 'true', null, null, null, null);
3759
-
3760
-		$this->assertInstanceOf(get_class($expected), $result);
3761
-		$this->assertEquals($expected->getData(), $result->getData());
3762
-	}
3763
-
3764
-	public function testUpdateLinkSharePermissionsShare(): void {
3765
-		$ocs = $this->mockFormatShare();
3766
-
3767
-		$date = new \DateTime('2000-01-01');
3768
-
3769
-		[$userFolder, $folder] = $this->getNonSharedUserFolder();
3770
-		$folder->method('getId')
3771
-			->willReturn(42);
3772
-
3773
-		$share = Server::get(IManager::class)->newShare();
3774
-		$share->setPermissions(Constants::PERMISSION_ALL)
3775
-			->setSharedBy($this->currentUser)
3776
-			->setShareType(IShare::TYPE_LINK)
3777
-			->setPassword('password')
3778
-			->setSendPasswordByTalk(true)
3779
-			->setExpirationDate($date)
3780
-			->setNote('note')
3781
-			->setLabel('label')
3782
-			->setHideDownload(true)
3783
-			->setPermissions(Constants::PERMISSION_READ)
3784
-			->setNode($folder);
3785
-
3786
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3787
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3788
-
3789
-		$this->shareManager->expects($this->once())
3790
-			->method('updateShare')
3791
-			->with(
3792
-				$this->callback(function (IShare $share) use ($date) {
3793
-					return $share->getPermissions() === Constants::PERMISSION_ALL
3794
-						&& $share->getPassword() === 'password'
3795
-						&& $share->getSendPasswordByTalk() === true
3796
-						&& $share->getExpirationDate() === $date
3797
-						&& $share->getNote() === 'note'
3798
-						&& $share->getLabel() === 'label'
3799
-						&& $share->getHideDownload() === true;
3800
-				})
3801
-			)->willReturnArgument(0);
3802
-
3803
-		$this->rootFolder->method('getUserFolder')
3804
-			->with($this->currentUser)
3805
-			->willReturn($userFolder);
3806
-
3807
-		$userFolder->method('getById')
3808
-			->with(42)
3809
-			->willReturn([$folder]);
3810
-
3811
-		$mountPoint = $this->createMock(IMountPoint::class);
3812
-		$folder->method('getMountPoint')
3813
-			->willReturn($mountPoint);
3814
-		$mountPoint->method('getStorageRootId')
3815
-			->willReturn(42);
3816
-
3817
-		$this->shareManager->method('getSharedWith')->willReturn([]);
3818
-
3819
-		$expected = new DataResponse([]);
3820
-		$result = $ocs->updateShare(42, Constants::PERMISSION_ALL, null, null, null, null, null, null, null);
3821
-
3822
-		$this->assertInstanceOf(get_class($expected), $result);
3823
-		$this->assertEquals($expected->getData(), $result->getData());
3824
-	}
3825
-
3826
-	public function testUpdateOtherPermissions(): void {
3827
-		$ocs = $this->mockFormatShare();
3828
-
3829
-		[$userFolder, $file] = $this->getNonSharedUserFolder();
3830
-		$file->method('getId')
3831
-			->willReturn(42);
3832
-
3833
-		$share = Server::get(IManager::class)->newShare();
3834
-		$share->setPermissions(Constants::PERMISSION_ALL)
3835
-			->setSharedBy($this->currentUser)
3836
-			->setShareType(IShare::TYPE_USER)
3837
-			->setNode($file);
3838
-
3839
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3840
-		$this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3841
-
3842
-		$this->shareManager->expects($this->once())->method('updateShare')->with(
3843
-			$this->callback(function (IShare $share) {
3844
-				return $share->getPermissions() === Constants::PERMISSION_ALL;
3845
-			})
3846
-		)->willReturnArgument(0);
3847
-
3848
-		$this->shareManager->method('getSharedWith')->willReturn([]);
3849
-
3850
-		[$userFolder, $folder] = $this->getNonSharedUserFolder();
3851
-		$this->rootFolder->method('getUserFolder')
3852
-			->with($this->currentUser)
3853
-			->willReturn($userFolder);
3854
-
3855
-		$userFolder->method('getById')
3856
-			->with(42)
3857
-			->willReturn([$file]);
3858
-
3859
-		$mountPoint = $this->createMock(IMountPoint::class);
3860
-		$file->method('getMountPoint')
3861
-			->willReturn($mountPoint);
3862
-		$mountPoint->method('getStorageRootId')
3863
-			->willReturn(42);
3864
-
3865
-		$expected = new DataResponse([]);
3866
-		$result = $ocs->updateShare(42, 31, null, null, null, null);
3867
-
3868
-		$this->assertInstanceOf(get_class($expected), $result);
3869
-		$this->assertEquals($expected->getData(), $result->getData());
3870
-	}
3871
-
3872
-	public function testUpdateShareCannotIncreasePermissions(): void {
3873
-		$ocs = $this->mockFormatShare();
3874
-
3875
-		[$userFolder, $folder] = $this->getNonSharedUserFolder();
3876
-		$folder->method('getId')
3877
-			->willReturn(42);
3878
-
3879
-		$share = Server::get(IManager::class)->newShare();
3880
-		$share
3881
-			->setId(42)
3882
-			->setSharedBy($this->currentUser)
3883
-			->setShareOwner('anotheruser')
3884
-			->setShareType(IShare::TYPE_GROUP)
3885
-			->setSharedWith('group1')
3886
-			->setPermissions(Constants::PERMISSION_READ)
3887
-			->setNode($folder);
3888
-
3889
-		// note: updateShare will modify the received instance but getSharedWith will reread from the database,
3890
-		// so their values will be different
3891
-		$incomingShare = Server::get(IManager::class)->newShare();
3892
-		$incomingShare
3893
-			->setId(42)
3894
-			->setSharedBy($this->currentUser)
3895
-			->setShareOwner('anotheruser')
3896
-			->setShareType(IShare::TYPE_GROUP)
3897
-			->setSharedWith('group1')
3898
-			->setPermissions(Constants::PERMISSION_READ)
3899
-			->setNode($folder);
3900
-
3901
-		$this->request
3902
-			->method('getParam')
3903
-			->willReturnMap([
3904
-				['permissions', null, '31'],
3905
-			]);
3906
-
3907
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3908
-
3909
-		$this->shareManager->expects($this->any())
3910
-			->method('getSharedWith')
3911
-			->willReturnMap([
3912
-				['currentUser', IShare::TYPE_USER, $share->getNode(), -1, 0, []],
3913
-				['currentUser', IShare::TYPE_GROUP, $share->getNode(), -1, 0, [$incomingShare]],
3914
-				['currentUser', IShare::TYPE_ROOM, $share->getNode(), -1, 0, []]
3915
-			]);
3916
-
3917
-		$this->rootFolder->method('getUserFolder')
3918
-			->with($this->currentUser)
3919
-			->willReturn($userFolder);
3920
-
3921
-		$userFolder->method('getById')
3922
-			->with(42)
3923
-			->willReturn([$folder]);
3924
-		$userFolder->method('getFirstNodeById')
3925
-			->with(42)
3926
-			->willReturn($folder);
3927
-
3928
-		$mountPoint = $this->createMock(IMountPoint::class);
3929
-		$folder->method('getMountPoint')
3930
-			->willReturn($mountPoint);
3931
-		$mountPoint->method('getStorageRootId')
3932
-			->willReturn(42);
3933
-
3934
-		$this->shareManager->expects($this->once())
3935
-			->method('updateShare')
3936
-			->with($share)
3937
-			->willThrowException(new GenericShareException('Cannot increase permissions of path/file', 'Cannot increase permissions of path/file', 404));
3938
-
3939
-		try {
3940
-			$ocs->updateShare(42, 31);
3941
-			$this->fail();
3942
-		} catch (OCSException $e) {
3943
-			$this->assertEquals('Cannot increase permissions of path/file', $e->getMessage());
3944
-		}
3945
-	}
3946
-
3947
-	public function testUpdateShareCanIncreasePermissionsIfOwner(): void {
3948
-		$ocs = $this->mockFormatShare();
3949
-
3950
-		[$userFolder, $folder] = $this->getNonSharedUserFolder();
3951
-		$folder->method('getId')
3952
-			->willReturn(42);
3953
-
3954
-		$share = Server::get(IManager::class)->newShare();
3955
-		$share
3956
-			->setId(42)
3957
-			->setSharedBy($this->currentUser)
3958
-			->setShareOwner($this->currentUser)
3959
-			->setShareType(IShare::TYPE_GROUP)
3960
-			->setSharedWith('group1')
3961
-			->setPermissions(Constants::PERMISSION_READ)
3962
-			->setNode($folder);
3963
-
3964
-		// note: updateShare will modify the received instance but getSharedWith will reread from the database,
3965
-		// so their values will be different
3966
-		$incomingShare = Server::get(IManager::class)->newShare();
3967
-		$incomingShare
3968
-			->setId(42)
3969
-			->setSharedBy($this->currentUser)
3970
-			->setShareOwner($this->currentUser)
3971
-			->setShareType(IShare::TYPE_GROUP)
3972
-			->setSharedWith('group1')
3973
-			->setPermissions(Constants::PERMISSION_READ)
3974
-			->setNode($folder);
3975
-
3976
-		$this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3977
-
3978
-		$this->shareManager->expects($this->any())
3979
-			->method('getSharedWith')
3980
-			->willReturnMap([
3981
-				['currentUser', IShare::TYPE_USER, $share->getNode(), -1, 0, []],
3982
-				['currentUser', IShare::TYPE_GROUP, $share->getNode(), -1, 0, [$incomingShare]]
3983
-			]);
3984
-
3985
-		$this->shareManager->expects($this->once())
3986
-			->method('updateShare')
3987
-			->with($share)
3988
-			->willReturn($share);
3989
-
3990
-		$this->rootFolder->method('getUserFolder')
3991
-			->with($this->currentUser)
3992
-			->willReturn($userFolder);
3993
-
3994
-		$userFolder->method('getById')
3995
-			->with(42)
3996
-			->willReturn([$folder]);
3997
-
3998
-		$mountPoint = $this->createMock(IMountPoint::class);
3999
-		$folder->method('getMountPoint')
4000
-			->willReturn($mountPoint);
4001
-		$mountPoint->method('getStorageRootId')
4002
-			->willReturn(42);
4003
-
4004
-		$result = $ocs->updateShare(42, 31);
4005
-		$this->assertInstanceOf(DataResponse::class, $result);
4006
-	}
4007
-
4008
-	public function testUpdateShareOwnerless(): void {
4009
-		$ocs = $this->mockFormatShare();
4010
-
4011
-		$mount = $this->createMock(IShareOwnerlessMount::class);
4012
-
4013
-		$file = $this->createMock(File::class);
4014
-		$file
4015
-			->expects($this->exactly(2))
4016
-			->method('getPermissions')
4017
-			->willReturn(Constants::PERMISSION_SHARE);
4018
-		$file
4019
-			->expects($this->once())
4020
-			->method('getMountPoint')
4021
-			->willReturn($mount);
4022
-
4023
-		$userFolder = $this->createMock(Folder::class);
4024
-		$userFolder->method('getById')
4025
-			->with(2)
4026
-			->willReturn([$file]);
4027
-		$userFolder->method('getFirstNodeById')
4028
-			->with(2)
4029
-			->willReturn($file);
4030
-
4031
-		$this->rootFolder
4032
-			->method('getUserFolder')
4033
-			->with($this->currentUser)
4034
-			->willReturn($userFolder);
4035
-
4036
-		$share = $this->createMock(IShare::class);
4037
-		$share
4038
-			->expects($this->once())
4039
-			->method('getNode')
4040
-			->willReturn($file);
4041
-		$share
4042
-			->expects($this->exactly(2))
4043
-			->method('getNodeId')
4044
-			->willReturn(2);
4045
-		$share
4046
-			->expects($this->exactly(2))
4047
-			->method('getPermissions')
4048
-			->willReturn(Constants::PERMISSION_SHARE);
4049
-
4050
-		$this->shareManager
4051
-			->expects($this->once())
4052
-			->method('getShareById')
4053
-			->with('ocinternal:1', $this->currentUser)
4054
-			->willReturn($share);
4055
-
4056
-		$this->shareManager
4057
-			->expects($this->once())
4058
-			->method('updateShare')
4059
-			->with($share)
4060
-			->willReturn($share);
4061
-
4062
-		$result = $ocs->updateShare(1, Constants::PERMISSION_ALL);
4063
-		$this->assertInstanceOf(DataResponse::class, $result);
4064
-	}
4065
-
4066
-	public static function dataFormatShare(): array {
4067
-		$owner = ['getDisplayName' => 'ownerDN'];
4068
-		$initiator = ['getDisplayName' => 'initiatorDN'];
4069
-		$recipient = [
4070
-			'getDisplayName' => 'recipientDN',
4071
-			'getSystemEMailAddress' => 'recipient'
4072
-		];
4073
-
4074
-		$folder = [
4075
-			'class' => Folder::class,
4076
-			'mimeType' => 'myFolderMimeType',
4077
-			'path' => 'folder',
4078
-			'id' => 2,
4079
-		];
4080
-		$file = [
4081
-			'class' => File::class,
4082
-			'mimeType' => 'myMimeType',
4083
-			'path' => 'file',
4084
-			'id' => 3,
4085
-		];
4086
-		$fileWithPreview = [
4087
-			'class' => File::class,
4088
-			'mimeType' => 'mimeWithPreview',
4089
-			'path' => 'fileWithPreview',
4090
-			'id' => 4,
4091
-		];
4092
-
4093
-		$result = [];
4094
-
4095
-		$share = [
4096
-			'type' => IShare::TYPE_USER,
4097
-			'owner' => 'owner',
4098
-			'sharedWith' => 'recipient',
4099
-			'attributes' => [
4100
-				'scope' => 'permissions',
4101
-				'key' => 'download',
4102
-				'value' => true
4103
-			],
4104
-			'node' => $file,
4105
-			'note' => 'personal note',
4106
-		];
4107
-
4108
-		// User backend down
4109
-		$result[] = [
4110
-			[
4111
-				'id' => '42',
4112
-				'share_type' => IShare::TYPE_USER,
4113
-				'uid_owner' => 'initiator',
4114
-				'displayname_owner' => 'initiator',
4115
-				'permissions' => 1,
4116
-				'stime' => 946684862,
4117
-				'parent' => null,
4118
-				'expiration' => null,
4119
-				'token' => null,
4120
-				'uid_file_owner' => 'owner',
4121
-				'displayname_file_owner' => 'owner',
4122
-				'path' => 'file',
4123
-				'item_type' => 'file',
4124
-				'storage_id' => 'storageId',
4125
-				'storage' => 100,
4126
-				'item_source' => 3,
4127
-				'file_source' => 3,
4128
-				'file_parent' => 1,
4129
-				'file_target' => 'myTarget',
4130
-				'share_with' => 'recipient',
4131
-				'share_with_displayname' => 'recipient',
4132
-				'share_with_displayname_unique' => 'recipient',
4133
-				'note' => 'personal note',
4134
-				'label' => '',
4135
-				'mail_send' => 0,
4136
-				'mimetype' => 'myMimeType',
4137
-				'has_preview' => false,
4138
-				'hide_download' => 0,
4139
-				'can_edit' => false,
4140
-				'can_delete' => false,
4141
-				'item_size' => 123456,
4142
-				'item_mtime' => 1234567890,
4143
-				'is-mount-root' => false,
4144
-				'mount-type' => '',
4145
-				'attributes' => '[{"scope":"permissions","key":"download","value":true}]',
4146
-				'item_permissions' => 1,
4147
-			],
4148
-			$share,
4149
-			[], false
4150
-		];
4151
-		// User backend up
4152
-		$result[] = [
4153
-			[
4154
-				'id' => '42',
4155
-				'share_type' => IShare::TYPE_USER,
4156
-				'uid_owner' => 'initiator',
4157
-				'displayname_owner' => 'initiatorDN',
4158
-				'permissions' => 1,
4159
-				'stime' => 946684862,
4160
-				'parent' => null,
4161
-				'expiration' => null,
4162
-				'token' => null,
4163
-				'uid_file_owner' => 'owner',
4164
-				'displayname_file_owner' => 'ownerDN',
4165
-				'note' => 'personal note',
4166
-				'label' => '',
4167
-				'path' => 'file',
4168
-				'item_type' => 'file',
4169
-				'storage_id' => 'storageId',
4170
-				'storage' => 100,
4171
-				'item_source' => 3,
4172
-				'file_source' => 3,
4173
-				'file_parent' => 1,
4174
-				'file_target' => 'myTarget',
4175
-				'share_with' => 'recipient',
4176
-				'share_with_displayname' => 'recipientDN',
4177
-				'share_with_displayname_unique' => 'recipient',
4178
-				'mail_send' => 0,
4179
-				'mimetype' => 'myMimeType',
4180
-				'has_preview' => false,
4181
-				'hide_download' => 0,
4182
-				'can_edit' => false,
4183
-				'can_delete' => false,
4184
-				'item_size' => 123456,
4185
-				'item_mtime' => 1234567890,
4186
-				'is-mount-root' => false,
4187
-				'mount-type' => '',
4188
-				'attributes' => '[{"scope":"permissions","key":"download","value":true}]',
4189
-				'item_permissions' => 1,
4190
-			], $share, [
4191
-				['owner', $owner],
4192
-				['initiator', $initiator],
4193
-				['recipient', $recipient],
4194
-			], false
4195
-		];
4196
-
4197
-		// Same but no attributes
4198
-		$share = [
4199
-			'type' => IShare::TYPE_USER,
4200
-			'owner' => 'owner',
4201
-			'sharedWith' => 'recipient',
4202
-			'node' => $file,
4203
-			'note' => 'personal note',
4204
-		];
4205
-
4206
-		// User backend down
4207
-		$result[] = [
4208
-			[
4209
-				'id' => '42',
4210
-				'share_type' => IShare::TYPE_USER,
4211
-				'uid_owner' => 'initiator',
4212
-				'displayname_owner' => 'initiator',
4213
-				'permissions' => 1,
4214
-				'attributes' => null,
4215
-				'stime' => 946684862,
4216
-				'parent' => null,
4217
-				'expiration' => null,
4218
-				'token' => null,
4219
-				'uid_file_owner' => 'owner',
4220
-				'displayname_file_owner' => 'owner',
4221
-				'note' => 'personal note',
4222
-				'label' => '',
4223
-				'path' => 'file',
4224
-				'item_type' => 'file',
4225
-				'storage_id' => 'storageId',
4226
-				'storage' => 100,
4227
-				'item_source' => 3,
4228
-				'file_source' => 3,
4229
-				'file_parent' => 1,
4230
-				'file_target' => 'myTarget',
4231
-				'share_with' => 'recipient',
4232
-				'share_with_displayname' => 'recipient',
4233
-				'share_with_displayname_unique' => 'recipient',
4234
-				'mail_send' => 0,
4235
-				'mimetype' => 'myMimeType',
4236
-				'has_preview' => false,
4237
-				'hide_download' => 0,
4238
-				'can_edit' => false,
4239
-				'can_delete' => false,
4240
-				'item_size' => 123456,
4241
-				'item_mtime' => 1234567890,
4242
-				'is-mount-root' => false,
4243
-				'mount-type' => '',
4244
-				'attributes' => null,
4245
-				'item_permissions' => 1,
4246
-			], $share, [], false
4247
-		];
4248
-
4249
-		$share['owner'] = 'currentUser';
4250
-
4251
-		// User backend down
4252
-		$result[] = [
4253
-			[
4254
-				'id' => '42',
4255
-				'share_type' => IShare::TYPE_USER,
4256
-				'uid_owner' => 'initiator',
4257
-				'displayname_owner' => 'initiator',
4258
-				'permissions' => 1,
4259
-				'attributes' => null,
4260
-				'stime' => 946684862,
4261
-				'parent' => null,
4262
-				'expiration' => null,
4263
-				'token' => null,
4264
-				'uid_file_owner' => 'currentUser',
4265
-				'displayname_file_owner' => 'currentUser',
4266
-				'note' => 'personal note',
4267
-				'label' => '',
4268
-				'path' => 'file',
4269
-				'item_type' => 'file',
4270
-				'storage_id' => 'storageId',
4271
-				'storage' => 100,
4272
-				'item_source' => 3,
4273
-				'file_source' => 3,
4274
-				'file_parent' => 1,
4275
-				'file_target' => 'myTarget',
4276
-				'share_with' => 'recipient',
4277
-				'share_with_displayname' => 'recipient',
4278
-				'share_with_displayname_unique' => 'recipient',
4279
-				'mail_send' => 0,
4280
-				'mimetype' => 'myMimeType',
4281
-				'has_preview' => false,
4282
-				'hide_download' => 0,
4283
-				'can_edit' => true,
4284
-				'can_delete' => true,
4285
-				'item_size' => 123456,
4286
-				'item_mtime' => 1234567890,
4287
-				'is-mount-root' => false,
4288
-				'mount-type' => '',
4289
-				'attributes' => null,
4290
-				'item_permissions' => 11,
4291
-			], $share, [], false
4292
-		];
4293
-
4294
-		// with existing group
4295
-		$share = [
4296
-			'type' => IShare::TYPE_GROUP,
4297
-			'owner' => 'owner',
4298
-			'sharedWith' => 'recipientGroup',
4299
-			'node' => $file,
4300
-			'note' => 'personal note',
4301
-		];
4302
-
4303
-		$result[] = [
4304
-			[
4305
-				'id' => '42',
4306
-				'share_type' => IShare::TYPE_GROUP,
4307
-				'uid_owner' => 'initiator',
4308
-				'displayname_owner' => 'initiator',
4309
-				'permissions' => 1,
4310
-				'attributes' => null,
4311
-				'stime' => 946684862,
4312
-				'parent' => null,
4313
-				'expiration' => null,
4314
-				'token' => null,
4315
-				'uid_file_owner' => 'owner',
4316
-				'displayname_file_owner' => 'owner',
4317
-				'note' => 'personal note',
4318
-				'label' => '',
4319
-				'path' => 'file',
4320
-				'item_type' => 'file',
4321
-				'storage_id' => 'storageId',
4322
-				'storage' => 100,
4323
-				'item_source' => 3,
4324
-				'file_source' => 3,
4325
-				'file_parent' => 1,
4326
-				'file_target' => 'myTarget',
4327
-				'share_with' => 'recipientGroup',
4328
-				'share_with_displayname' => 'recipientGroupDisplayName',
4329
-				'mail_send' => 0,
4330
-				'mimetype' => 'myMimeType',
4331
-				'has_preview' => false,
4332
-				'hide_download' => 0,
4333
-				'can_edit' => false,
4334
-				'can_delete' => false,
4335
-				'item_size' => 123456,
4336
-				'item_mtime' => 1234567890,
4337
-				'is-mount-root' => false,
4338
-				'mount-type' => '',
4339
-				'attributes' => null,
4340
-				'item_permissions' => 1,
4341
-			], $share, [], false
4342
-		];
4343
-
4344
-		// with unknown group / no group backend
4345
-		$share['sharedWith'] = 'recipientGroup2';
4346
-
4347
-		$result[] = [
4348
-			[
4349
-				'id' => '42',
4350
-				'share_type' => IShare::TYPE_GROUP,
4351
-				'uid_owner' => 'initiator',
4352
-				'displayname_owner' => 'initiator',
4353
-				'permissions' => 1,
4354
-				'stime' => 946684862,
4355
-				'parent' => null,
4356
-				'expiration' => null,
4357
-				'token' => null,
4358
-				'uid_file_owner' => 'owner',
4359
-				'displayname_file_owner' => 'owner',
4360
-				'note' => 'personal note',
4361
-				'label' => '',
4362
-				'path' => 'file',
4363
-				'item_type' => 'file',
4364
-				'storage_id' => 'storageId',
4365
-				'storage' => 100,
4366
-				'item_source' => 3,
4367
-				'file_source' => 3,
4368
-				'file_parent' => 1,
4369
-				'file_target' => 'myTarget',
4370
-				'share_with' => 'recipientGroup2',
4371
-				'share_with_displayname' => 'recipientGroup2',
4372
-				'mail_send' => 0,
4373
-				'mimetype' => 'myMimeType',
4374
-				'has_preview' => false,
4375
-				'hide_download' => 0,
4376
-				'can_edit' => false,
4377
-				'can_delete' => false,
4378
-				'item_size' => 123456,
4379
-				'item_mtime' => 1234567890,
4380
-				'is-mount-root' => false,
4381
-				'mount-type' => '',
4382
-				'attributes' => null,
4383
-				'item_permissions' => 1,
4384
-			], $share, [], false
4385
-		];
4386
-
4387
-		$share = [
4388
-			'type' => IShare::TYPE_LINK,
4389
-			'owner' => 'owner',
4390
-			'node' => $file,
4391
-			'note' => 'personal note',
4392
-			'password' => 'mypassword',
4393
-			'expirationDate' => new \DateTime('2001-01-02T00:00:00'),
4394
-			'token' => 'myToken',
4395
-			'label' => 'new link share',
4396
-		];
4397
-
4398
-		$result[] = [
4399
-			[
4400
-				'id' => '42',
4401
-				'share_type' => IShare::TYPE_LINK,
4402
-				'uid_owner' => 'initiator',
4403
-				'displayname_owner' => 'initiator',
4404
-				'permissions' => 1,
4405
-				'attributes' => null,
4406
-				'stime' => 946684862,
4407
-				'parent' => null,
4408
-				'expiration' => '2001-01-02 00:00:00',
4409
-				'token' => 'myToken',
4410
-				'uid_file_owner' => 'owner',
4411
-				'displayname_file_owner' => 'owner',
4412
-				'note' => 'personal note',
4413
-				'label' => 'new link share',
4414
-				'path' => 'file',
4415
-				'item_type' => 'file',
4416
-				'storage_id' => 'storageId',
4417
-				'storage' => 100,
4418
-				'item_source' => 3,
4419
-				'file_source' => 3,
4420
-				'file_parent' => 1,
4421
-				'file_target' => 'myTarget',
4422
-				'password' => 'mypassword',
4423
-				'share_with' => 'mypassword',
4424
-				'share_with_displayname' => '(Shared link)',
4425
-				'send_password_by_talk' => false,
4426
-				'mail_send' => 0,
4427
-				'url' => 'myLink',
4428
-				'mimetype' => 'myMimeType',
4429
-				'has_preview' => false,
4430
-				'hide_download' => 0,
4431
-				'can_edit' => false,
4432
-				'can_delete' => false,
4433
-				'item_size' => 123456,
4434
-				'item_mtime' => 1234567890,
4435
-				'is-mount-root' => false,
4436
-				'mount-type' => '',
4437
-				'attributes' => null,
4438
-				'item_permissions' => 1,
4439
-			], $share, [], false
4440
-		];
4441
-
4442
-		$share['sendPasswordByTalk'] = true;
4443
-
4444
-		$result[] = [
4445
-			[
4446
-				'id' => '42',
4447
-				'share_type' => IShare::TYPE_LINK,
4448
-				'uid_owner' => 'initiator',
4449
-				'displayname_owner' => 'initiator',
4450
-				'permissions' => 1,
4451
-				'stime' => 946684862,
4452
-				'parent' => null,
4453
-				'expiration' => '2001-01-02 00:00:00',
4454
-				'token' => 'myToken',
4455
-				'uid_file_owner' => 'owner',
4456
-				'displayname_file_owner' => 'owner',
4457
-				'note' => 'personal note',
4458
-				'label' => 'new link share',
4459
-				'path' => 'file',
4460
-				'item_type' => 'file',
4461
-				'storage_id' => 'storageId',
4462
-				'storage' => 100,
4463
-				'item_source' => 3,
4464
-				'file_source' => 3,
4465
-				'file_parent' => 1,
4466
-				'file_target' => 'myTarget',
4467
-				'password' => 'mypassword',
4468
-				'share_with' => 'mypassword',
4469
-				'share_with_displayname' => '(Shared link)',
4470
-				'send_password_by_talk' => true,
4471
-				'mail_send' => 0,
4472
-				'url' => 'myLink',
4473
-				'mimetype' => 'myMimeType',
4474
-				'has_preview' => false,
4475
-				'hide_download' => 0,
4476
-				'can_edit' => false,
4477
-				'can_delete' => false,
4478
-				'item_size' => 123456,
4479
-				'item_mtime' => 1234567890,
4480
-				'is-mount-root' => false,
4481
-				'mount-type' => '',
4482
-				'attributes' => null,
4483
-				'item_permissions' => 1,
4484
-			], $share, [], false
4485
-		];
4486
-
4487
-		$share = [
4488
-			'type' => IShare::TYPE_REMOTE,
4489
-			'owner' => 'owner',
4490
-			'sharedWith' => '[email protected]',
4491
-			'node' => $folder,
4492
-			'note' => 'personal note',
4493
-			'expirationDate' => new \DateTime('2001-02-03T04:05:06'),
4494
-		];
4495
-
4496
-		$result[] = [
4497
-			[
4498
-				'id' => '42',
4499
-				'share_type' => IShare::TYPE_REMOTE,
4500
-				'uid_owner' => 'initiator',
4501
-				'displayname_owner' => 'initiator',
4502
-				'permissions' => 1,
4503
-				'stime' => 946684862,
4504
-				'parent' => null,
4505
-				'expiration' => '2001-02-03 00:00:00',
4506
-				'token' => null,
4507
-				'uid_file_owner' => 'owner',
4508
-				'displayname_file_owner' => 'owner',
4509
-				'note' => 'personal note',
4510
-				'label' => '',
4511
-				'path' => 'folder',
4512
-				'item_type' => 'folder',
4513
-				'storage_id' => 'storageId',
4514
-				'storage' => 100,
4515
-				'item_source' => 2,
4516
-				'file_source' => 2,
4517
-				'file_parent' => 1,
4518
-				'file_target' => 'myTarget',
4519
-				'share_with' => '[email protected]',
4520
-				'share_with_displayname' => 'foobar',
4521
-				'mail_send' => 0,
4522
-				'mimetype' => 'myFolderMimeType',
4523
-				'has_preview' => false,
4524
-				'hide_download' => 0,
4525
-				'can_edit' => false,
4526
-				'can_delete' => false,
4527
-				'item_size' => 123456,
4528
-				'item_mtime' => 1234567890,
4529
-				'is-mount-root' => false,
4530
-				'mount-type' => '',
4531
-				'attributes' => null,
4532
-				'item_permissions' => 1,
4533
-				'is_trusted_server' => false,
4534
-			], $share, [], false
4535
-		];
4536
-
4537
-		$share = [
4538
-			'type' => IShare::TYPE_REMOTE_GROUP,
4539
-			'owner' => 'owner',
4540
-			'sharedWith' => '[email protected]',
4541
-			'node' => $folder,
4542
-			'note' => 'personal note',
4543
-			'expirationDate' => new \DateTime('2001-02-03T04:05:06'),
4544
-		];
4545
-
4546
-		$result[] = [
4547
-			[
4548
-				'id' => '42',
4549
-				'share_type' => IShare::TYPE_REMOTE_GROUP,
4550
-				'uid_owner' => 'initiator',
4551
-				'displayname_owner' => 'initiator',
4552
-				'permissions' => 1,
4553
-				'stime' => 946684862,
4554
-				'parent' => null,
4555
-				'expiration' => '2001-02-03 00:00:00',
4556
-				'token' => null,
4557
-				'uid_file_owner' => 'owner',
4558
-				'displayname_file_owner' => 'owner',
4559
-				'note' => 'personal note',
4560
-				'label' => '',
4561
-				'path' => 'folder',
4562
-				'item_type' => 'folder',
4563
-				'storage_id' => 'storageId',
4564
-				'storage' => 100,
4565
-				'item_source' => 2,
4566
-				'file_source' => 2,
4567
-				'file_parent' => 1,
4568
-				'file_target' => 'myTarget',
4569
-				'share_with' => '[email protected]',
4570
-				'share_with_displayname' => 'foobar',
4571
-				'mail_send' => 0,
4572
-				'mimetype' => 'myFolderMimeType',
4573
-				'has_preview' => false,
4574
-				'hide_download' => 0,
4575
-				'can_edit' => false,
4576
-				'can_delete' => false,
4577
-				'item_size' => 123456,
4578
-				'item_mtime' => 1234567890,
4579
-				'is-mount-root' => false,
4580
-				'mount-type' => '',
4581
-				'attributes' => null,
4582
-				'item_permissions' => 1,
4583
-				'is_trusted_server' => false,
4584
-			], $share, [], false
4585
-		];
4586
-
4587
-		// Circle with id, display name and avatar set by the Circles app
4588
-		$share = [
4589
-			'type' => IShare::TYPE_CIRCLE,
4590
-			'owner' => 'owner',
4591
-			'sharedWith' => 'Circle (Public circle, circleOwner) [4815162342]',
4592
-			'sharedWithDisplayName' => 'The display name',
4593
-			'sharedWithAvatar' => 'path/to/the/avatar',
4594
-			'node' => $folder,
4595
-		];
4596
-
4597
-		$result[] = [
4598
-			[
4599
-				'id' => '42',
4600
-				'share_type' => IShare::TYPE_CIRCLE,
4601
-				'uid_owner' => 'initiator',
4602
-				'displayname_owner' => 'initiator',
4603
-				'permissions' => 1,
4604
-				'attributes' => null,
4605
-				'stime' => 946684862,
4606
-				'parent' => null,
4607
-				'expiration' => null,
4608
-				'token' => null,
4609
-				'uid_file_owner' => 'owner',
4610
-				'displayname_file_owner' => 'owner',
4611
-				'note' => '',
4612
-				'label' => '',
4613
-				'path' => 'folder',
4614
-				'item_type' => 'folder',
4615
-				'storage_id' => 'storageId',
4616
-				'storage' => 100,
4617
-				'item_source' => 2,
4618
-				'file_source' => 2,
4619
-				'file_parent' => 1,
4620
-				'file_target' => 'myTarget',
4621
-				'share_with' => '4815162342',
4622
-				'share_with_displayname' => 'The display name',
4623
-				'share_with_avatar' => 'path/to/the/avatar',
4624
-				'mail_send' => 0,
4625
-				'mimetype' => 'myFolderMimeType',
4626
-				'has_preview' => false,
4627
-				'hide_download' => 0,
4628
-				'can_edit' => false,
4629
-				'can_delete' => false,
4630
-				'item_size' => 123456,
4631
-				'item_mtime' => 1234567890,
4632
-				'is-mount-root' => false,
4633
-				'mount-type' => '',
4634
-				'attributes' => null,
4635
-				'item_permissions' => 1,
4636
-			], $share, [], false
4637
-		];
4638
-
4639
-		// Circle with id set by the Circles app
4640
-		$share = [
4641
-			'type' => IShare::TYPE_CIRCLE,
4642
-			'owner' => 'owner',
4643
-			'sharedWith' => 'Circle (Public circle, circleOwner) [4815162342]',
4644
-			'node' => $folder,
4645
-		];
4646
-
4647
-		$result[] = [
4648
-			[
4649
-				'id' => '42',
4650
-				'share_type' => IShare::TYPE_CIRCLE,
4651
-				'uid_owner' => 'initiator',
4652
-				'displayname_owner' => 'initiator',
4653
-				'permissions' => 1,
4654
-				'stime' => 946684862,
4655
-				'parent' => null,
4656
-				'expiration' => null,
4657
-				'token' => null,
4658
-				'uid_file_owner' => 'owner',
4659
-				'displayname_file_owner' => 'owner',
4660
-				'note' => '',
4661
-				'label' => '',
4662
-				'path' => 'folder',
4663
-				'item_type' => 'folder',
4664
-				'storage_id' => 'storageId',
4665
-				'storage' => 100,
4666
-				'item_source' => 2,
4667
-				'file_source' => 2,
4668
-				'file_parent' => 1,
4669
-				'file_target' => 'myTarget',
4670
-				'share_with' => '4815162342',
4671
-				'share_with_displayname' => 'Circle (Public circle, circleOwner)',
4672
-				'share_with_avatar' => '',
4673
-				'mail_send' => 0,
4674
-				'mimetype' => 'myFolderMimeType',
4675
-				'has_preview' => false,
4676
-				'hide_download' => 0,
4677
-				'can_edit' => false,
4678
-				'can_delete' => false,
4679
-				'item_size' => 123456,
4680
-				'item_mtime' => 1234567890,
4681
-				'is-mount-root' => false,
4682
-				'mount-type' => '',
4683
-				'attributes' => null,
4684
-				'item_permissions' => 1,
4685
-			], $share, [], false
4686
-		];
4687
-
4688
-		// Circle with id not set by the Circles app
4689
-		$share = [
4690
-			'type' => IShare::TYPE_CIRCLE,
4691
-			'owner' => 'owner',
4692
-			'sharedWith' => 'Circle (Public circle, circleOwner)',
4693
-			'node' => $folder,
4694
-		];
4695
-
4696
-		$result[] = [
4697
-			[
4698
-				'id' => '42',
4699
-				'share_type' => IShare::TYPE_CIRCLE,
4700
-				'uid_owner' => 'initiator',
4701
-				'displayname_owner' => 'initiator',
4702
-				'permissions' => 1,
4703
-				'stime' => 946684862,
4704
-				'parent' => null,
4705
-				'expiration' => null,
4706
-				'token' => null,
4707
-				'uid_file_owner' => 'owner',
4708
-				'displayname_file_owner' => 'owner',
4709
-				'note' => '',
4710
-				'label' => '',
4711
-				'path' => 'folder',
4712
-				'item_type' => 'folder',
4713
-				'storage_id' => 'storageId',
4714
-				'storage' => 100,
4715
-				'item_source' => 2,
4716
-				'file_source' => 2,
4717
-				'file_parent' => 1,
4718
-				'file_target' => 'myTarget',
4719
-				'share_with' => 'Circle',
4720
-				'share_with_displayname' => 'Circle (Public circle, circleOwner)',
4721
-				'share_with_avatar' => '',
4722
-				'mail_send' => 0,
4723
-				'mimetype' => 'myFolderMimeType',
4724
-				'has_preview' => false,
4725
-				'hide_download' => 0,
4726
-				'can_edit' => false,
4727
-				'can_delete' => false,
4728
-				'item_size' => 123456,
4729
-				'item_mtime' => 1234567890,
4730
-				'is-mount-root' => false,
4731
-				'mount-type' => '',
4732
-				'attributes' => null,
4733
-				'item_permissions' => 1,
4734
-			], $share, [], false
4735
-		];
4736
-
4737
-		// No node
4738
-		$share = [
4739
-			'type' => IShare::TYPE_USER,
4740
-			'owner' => 'owner',
4741
-			'sharedWith' => 'recipient',
4742
-			'note' => 'personal note',
4743
-		];
4744
-
4745
-		$result[] = [
4746
-			[], $share, [], true
4747
-		];
4748
-
4749
-		$share = [
4750
-			'type' => IShare::TYPE_EMAIL,
4751
-			'owner' => 'owner',
4752
-			'sharedWith' => '[email protected]',
4753
-			'node' => $folder,
4754
-			'password' => 'password',
4755
-		];
4756
-
4757
-		$result[] = [
4758
-			[
4759
-				'id' => '42',
4760
-				'share_type' => IShare::TYPE_EMAIL,
4761
-				'uid_owner' => 'initiator',
4762
-				'displayname_owner' => 'initiator',
4763
-				'permissions' => 1,
4764
-				'stime' => 946684862,
4765
-				'parent' => null,
4766
-				'expiration' => null,
4767
-				'token' => null,
4768
-				'uid_file_owner' => 'owner',
4769
-				'displayname_file_owner' => 'owner',
4770
-				'note' => '',
4771
-				'label' => '',
4772
-				'path' => 'folder',
4773
-				'item_type' => 'folder',
4774
-				'storage_id' => 'storageId',
4775
-				'storage' => 100,
4776
-				'item_source' => 2,
4777
-				'file_source' => 2,
4778
-				'file_parent' => 1,
4779
-				'file_target' => 'myTarget',
4780
-				'share_with' => '[email protected]',
4781
-				'share_with_displayname' => 'mail display name',
4782
-				'mail_send' => 0,
4783
-				'mimetype' => 'myFolderMimeType',
4784
-				'has_preview' => false,
4785
-				'password' => 'password',
4786
-				'send_password_by_talk' => false,
4787
-				'hide_download' => 0,
4788
-				'can_edit' => false,
4789
-				'can_delete' => false,
4790
-				'password_expiration_time' => null,
4791
-				'item_size' => 123456,
4792
-				'item_mtime' => 1234567890,
4793
-				'is-mount-root' => false,
4794
-				'mount-type' => '',
4795
-				'attributes' => null,
4796
-				'item_permissions' => 1,
4797
-			], $share, [], false
4798
-		];
4799
-
4800
-		$share['sendPasswordByTalk'] = true;
4801
-
4802
-		$result[] = [
4803
-			[
4804
-				'id' => '42',
4805
-				'share_type' => IShare::TYPE_EMAIL,
4806
-				'uid_owner' => 'initiator',
4807
-				'displayname_owner' => 'initiator',
4808
-				'permissions' => 1,
4809
-				'stime' => 946684862,
4810
-				'parent' => null,
4811
-				'expiration' => null,
4812
-				'token' => null,
4813
-				'uid_file_owner' => 'owner',
4814
-				'displayname_file_owner' => 'owner',
4815
-				'note' => '',
4816
-				'label' => '',
4817
-				'path' => 'folder',
4818
-				'item_type' => 'folder',
4819
-				'storage_id' => 'storageId',
4820
-				'storage' => 100,
4821
-				'item_source' => 2,
4822
-				'file_source' => 2,
4823
-				'file_parent' => 1,
4824
-				'file_target' => 'myTarget',
4825
-				'share_with' => '[email protected]',
4826
-				'share_with_displayname' => 'mail display name',
4827
-				'mail_send' => 0,
4828
-				'mimetype' => 'myFolderMimeType',
4829
-				'has_preview' => false,
4830
-				'password' => 'password',
4831
-				'send_password_by_talk' => true,
4832
-				'hide_download' => 0,
4833
-				'can_edit' => false,
4834
-				'can_delete' => false,
4835
-				'password_expiration_time' => null,
4836
-				'item_size' => 123456,
4837
-				'item_mtime' => 1234567890,
4838
-				'is-mount-root' => false,
4839
-				'mount-type' => '',
4840
-				'attributes' => null,
4841
-				'item_permissions' => 1,
4842
-			], $share, [], false
4843
-		];
4844
-
4845
-		// Preview is available
4846
-		$share = [
4847
-			'type' => IShare::TYPE_USER,
4848
-			'owner' => 'currentUser',
4849
-			'sharedWith' => 'recipient',
4850
-			'node' => $fileWithPreview,
4851
-			'note' => 'personal note',
4852
-		];
4853
-
4854
-		$result[] = [
4855
-			[
4856
-				'id' => '42',
4857
-				'share_type' => IShare::TYPE_USER,
4858
-				'uid_owner' => 'initiator',
4859
-				'displayname_owner' => 'initiator',
4860
-				'permissions' => 1,
4861
-				'stime' => 946684862,
4862
-				'parent' => null,
4863
-				'expiration' => null,
4864
-				'token' => null,
4865
-				'uid_file_owner' => 'currentUser',
4866
-				'displayname_file_owner' => 'currentUser',
4867
-				'note' => 'personal note',
4868
-				'label' => '',
4869
-				'path' => 'fileWithPreview',
4870
-				'item_type' => 'file',
4871
-				'storage_id' => 'storageId',
4872
-				'storage' => 100,
4873
-				'item_source' => 4,
4874
-				'file_source' => 4,
4875
-				'file_parent' => 1,
4876
-				'file_target' => 'myTarget',
4877
-				'share_with' => 'recipient',
4878
-				'share_with_displayname' => 'recipient',
4879
-				'share_with_displayname_unique' => 'recipient',
4880
-				'mail_send' => 0,
4881
-				'mimetype' => 'mimeWithPreview',
4882
-				'has_preview' => true,
4883
-				'hide_download' => 0,
4884
-				'can_edit' => true,
4885
-				'can_delete' => true,
4886
-				'item_size' => 123456,
4887
-				'item_mtime' => 1234567890,
4888
-				'is-mount-root' => false,
4889
-				'mount-type' => '',
4890
-				'attributes' => null,
4891
-				'item_permissions' => 11,
4892
-			], $share, [], false
4893
-		];
4894
-
4895
-		return $result;
4896
-	}
4897
-
4898
-	#[DataProvider('dataFormatShare')]
4899
-	public function testFormatShare(
4900
-		array $expects,
4901
-		array $shareParams,
4902
-		array $users,
4903
-		bool $exception,
4904
-	): void {
4905
-		$users = array_map(
4906
-			function ($user) {
4907
-				$mock = $this->createMock(IUser::class);
4908
-				foreach ($user[1] as $method => $return) {
4909
-					$mock->method($method)->willReturn($return);
4910
-				}
4911
-				return [$user[0],$mock];
4912
-			},
4913
-			$users
4914
-		);
4915
-
4916
-		$share = Server::get(IManager::class)->newShare();
4917
-		$share->setShareType($shareParams['type'])
4918
-			->setSharedBy('initiator')
4919
-			->setShareOwner($shareParams['owner'])
4920
-			->setPermissions(Constants::PERMISSION_READ)
4921
-			->setShareTime(new \DateTime('2000-01-01T00:01:02'))
4922
-			->setTarget('myTarget')
4923
-			->setId(42);
4924
-		if (isset($shareParams['sharedWith'])) {
4925
-			$share->setSharedWith($shareParams['sharedWith']);
4926
-		}
4927
-		if (isset($shareParams['sharedWithDisplayName'])) {
4928
-			$share->setSharedWithDisplayName($shareParams['sharedWithDisplayName']);
4929
-		}
4930
-		if (isset($shareParams['sharedWithAvatar'])) {
4931
-			$share->setSharedWithAvatar($shareParams['sharedWithAvatar']);
4932
-		}
4933
-		if (isset($shareParams['attributes'])) {
4934
-			$shareAttributes = $this->createMock(IShareAttributes::class);
4935
-			$shareAttributes->method('toArray')->willReturn($shareParams['attributes']);
4936
-			$shareAttributes->method('getAttribute')->with('permissions', 'download')->willReturn(true);
4937
-			$share->setAttributes($shareAttributes);
4938
-
4939
-			$expects['attributes'] = \json_encode($shareParams['attributes']);
4940
-		}
4941
-		if (isset($shareParams['node'])) {
4942
-			$node = $this->createMock($shareParams['node']['class']);
4943
-
4944
-			$node->method('getMimeType')->willReturn($shareParams['node']['mimeType']);
4945
-
4946
-			$mountPoint = $this->createMock(IMountPoint::class);
4947
-			$mountPoint->method('getMountType')->willReturn('');
4948
-			$node->method('getMountPoint')->willReturn($mountPoint);
4949
-
4950
-			$node->method('getPath')->willReturn($shareParams['node']['path']);
4951
-			$node->method('getId')->willReturn($shareParams['node']['id']);
4952
-
4953
-			$parent = $this->createMock(Folder::class);
4954
-			$parent->method('getId')->willReturn(1);
4955
-			$node->method('getParent')->willReturn($parent);
4956
-
4957
-			$node->method('getSize')->willReturn(123456);
4958
-			$node->method('getMTime')->willReturn(1234567890);
4959
-
4960
-			$cache = $this->createMock(ICache::class);
4961
-			$cache->method('getNumericStorageId')->willReturn(100);
4962
-			$storage = $this->createMock(IStorage::class);
4963
-			$storage->method('getId')->willReturn('storageId');
4964
-			$storage->method('getCache')->willReturn($cache);
4965
-
4966
-			$node->method('getStorage')->willReturn($storage);
4967
-
4968
-			$share->setNode($node);
4969
-		}
4970
-		if (isset($shareParams['note'])) {
4971
-			$share->setNote($shareParams['note']);
4972
-		}
4973
-		if (isset($shareParams['expirationDate'])) {
4974
-			$share->setExpirationDate($shareParams['expirationDate']);
4975
-		}
4976
-		if (isset($shareParams['token'])) {
4977
-			$share->setToken($shareParams['token']);
4978
-		}
4979
-		if (isset($shareParams['label'])) {
4980
-			$share->setLabel($shareParams['label']);
4981
-		}
4982
-		if (isset($shareParams['password'])) {
4983
-			$share->setPassword($shareParams['password']);
4984
-		}
4985
-		if (isset($shareParams['sendPasswordByTalk'])) {
4986
-			$share->setSendPasswordByTalk($shareParams['sendPasswordByTalk']);
4987
-		}
4988
-
4989
-		$this->userManager->method('get')->willReturnMap($users);
4990
-
4991
-		$recipientGroup = $this->createMock(IGroup::class);
4992
-		$recipientGroup->method('getDisplayName')->willReturn('recipientGroupDisplayName');
4993
-		$this->groupManager->method('get')->willReturnMap([
4994
-			['recipientGroup', $recipientGroup],
4995
-		]);
4996
-
4997
-		$this->urlGenerator->method('linkToRouteAbsolute')
4998
-			->with('files_sharing.sharecontroller.showShare', ['token' => 'myToken'])
4999
-			->willReturn('myLink');
5000
-
5001
-		$this->rootFolder->method('getUserFolder')
5002
-			->with($this->currentUser)
5003
-			->willReturnSelf();
5004
-		$this->dateTimeZone->method('getTimezone')->willReturn(new \DateTimeZone('UTC'));
5005
-
5006
-		if (!$exception) {
5007
-			$this->rootFolder->method('getFirstNodeById')
5008
-				->with($share->getNodeId())
5009
-				->willReturn($share->getNode());
5010
-
5011
-			$this->rootFolder->method('getRelativePath')
5012
-				->with($share->getNode()->getPath())
5013
-				->willReturnArgument(0);
5014
-		}
5015
-
5016
-		$cm = $this->createMock(\OCP\Contacts\IManager::class);
5017
-		$this->overwriteService(\OCP\Contacts\IManager::class, $cm);
5018
-
5019
-		$cm->method('search')
5020
-			->willReturnMap([
5021
-				['[email protected]', ['CLOUD'], [
5022
-					'limit' => 1,
5023
-					'enumeration' => false,
5024
-					'strict_search' => true,
5025
-				],
5026
-					[
5027
-						[
5028
-							'CLOUD' => [
5029
-								'[email protected]',
5030
-							],
5031
-							'FN' => 'foobar',
5032
-						],
5033
-					],
5034
-				],
5035
-				['[email protected]', ['EMAIL'], [
5036
-					'limit' => 1,
5037
-					'enumeration' => false,
5038
-					'strict_search' => true,
5039
-				],
5040
-					[
5041
-						[
5042
-							'EMAIL' => [
5043
-								'[email protected]',
5044
-							],
5045
-							'FN' => 'mail display name',
5046
-						],
5047
-					],
5048
-				],
5049
-			]);
5050
-
5051
-		try {
5052
-			$result = $this->invokePrivate($this->ocs, 'formatShare', [$share]);
5053
-			$this->assertFalse($exception);
5054
-			$this->assertEquals($expects, $result);
5055
-		} catch (NotFoundException $e) {
5056
-			$this->assertTrue($exception);
5057
-		}
5058
-	}
5059
-
5060
-	public static function dataFormatRoomShare(): array {
5061
-		$result = [];
5062
-
5063
-		$result[] = [
5064
-			[
5065
-				'id' => '42',
5066
-				'share_type' => IShare::TYPE_ROOM,
5067
-				'uid_owner' => 'initiator',
5068
-				'displayname_owner' => 'initiator',
5069
-				'permissions' => 1,
5070
-				'stime' => 946684862,
5071
-				'parent' => null,
5072
-				'expiration' => null,
5073
-				'token' => null,
5074
-				'uid_file_owner' => 'owner',
5075
-				'displayname_file_owner' => 'owner',
5076
-				'note' => 'personal note',
5077
-				'path' => 'file',
5078
-				'item_type' => 'file',
5079
-				'storage_id' => 'storageId',
5080
-				'storage' => 100,
5081
-				'item_source' => 3,
5082
-				'file_source' => 3,
5083
-				'file_parent' => 1,
5084
-				'file_target' => 'myTarget',
5085
-				'share_with' => 'recipientRoom',
5086
-				'share_with_displayname' => '',
5087
-				'mail_send' => 0,
5088
-				'mimetype' => 'myMimeType',
5089
-				'has_preview' => false,
5090
-				'hide_download' => 0,
5091
-				'label' => '',
5092
-				'can_edit' => false,
5093
-				'can_delete' => false,
5094
-				'item_size' => 123456,
5095
-				'item_mtime' => 1234567890,
5096
-				'is-mount-root' => false,
5097
-				'mount-type' => '',
5098
-				'attributes' => null,
5099
-				'item_permissions' => 1,
5100
-			], false, []
5101
-		];
5102
-
5103
-		$result[] = [
5104
-			[
5105
-				'id' => '42',
5106
-				'share_type' => IShare::TYPE_ROOM,
5107
-				'uid_owner' => 'initiator',
5108
-				'displayname_owner' => 'initiator',
5109
-				'permissions' => 1,
5110
-				'stime' => 946684862,
5111
-				'parent' => null,
5112
-				'expiration' => null,
5113
-				'token' => null,
5114
-				'uid_file_owner' => 'owner',
5115
-				'displayname_file_owner' => 'owner',
5116
-				'note' => 'personal note',
5117
-				'path' => 'file',
5118
-				'item_type' => 'file',
5119
-				'storage_id' => 'storageId',
5120
-				'storage' => 100,
5121
-				'item_source' => 3,
5122
-				'file_source' => 3,
5123
-				'file_parent' => 1,
5124
-				'file_target' => 'myTarget',
5125
-				'share_with' => 'recipientRoom',
5126
-				'share_with_displayname' => 'recipientRoomName',
5127
-				'mail_send' => 0,
5128
-				'mimetype' => 'myMimeType',
5129
-				'has_preview' => false,
5130
-				'hide_download' => 0,
5131
-				'label' => '',
5132
-				'can_edit' => false,
5133
-				'can_delete' => false,
5134
-				'item_size' => 123456,
5135
-				'item_mtime' => 1234567890,
5136
-				'is-mount-root' => false,
5137
-				'mount-type' => '',
5138
-				'attributes' => null,
5139
-				'item_permissions' => 9,
5140
-			], true, [
5141
-				'share_with_displayname' => 'recipientRoomName'
5142
-			]
5143
-		];
5144
-
5145
-		return $result;
5146
-	}
5147
-
5148
-	/**
5149
-	 *
5150
-	 * @param array $expects
5151
-	 * @param IShare $share
5152
-	 * @param bool $helperAvailable
5153
-	 * @param array $formatShareByHelper
5154
-	 */
5155
-	#[DataProvider('dataFormatRoomShare')]
5156
-	public function testFormatRoomShare(array $expects, bool $helperAvailable, array $formatShareByHelper): void {
5157
-		$file = $this->createMock(File::class);
5158
-
5159
-		$file->method('getMimeType')->willReturn('myMimeType');
5160
-		$file->method('getPath')->willReturn('file');
5161
-		$file->method('getId')->willReturn(3);
5162
-
5163
-		$parent = $this->createMock(Folder::class);
5164
-		$parent->method('getId')->willReturn(1);
5165
-		$file->method('getParent')->willReturn($parent);
5166
-
5167
-		$file->method('getSize')->willReturn(123456);
5168
-		$file->method('getMTime')->willReturn(1234567890);
5169
-
5170
-		$mountPoint = $this->createMock(IMountPoint::class);
5171
-		$mountPoint->method('getMountType')->willReturn('');
5172
-		$file->method('getMountPoint')->willReturn($mountPoint);
5173
-
5174
-		$cache = $this->createMock(ICache::class);
5175
-		$cache->method('getNumericStorageId')->willReturn(100);
5176
-		$storage = $this->createMock(IStorage::class);
5177
-		$storage->method('getId')->willReturn('storageId');
5178
-		$storage->method('getCache')->willReturn($cache);
5179
-
5180
-		$file->method('getStorage')->willReturn($storage);
5181
-
5182
-		$share = Server::get(IManager::class)->newShare();
5183
-		$share->setShareType(IShare::TYPE_ROOM)
5184
-			->setSharedWith('recipientRoom')
5185
-			->setSharedBy('initiator')
5186
-			->setShareOwner('owner')
5187
-			->setPermissions(Constants::PERMISSION_READ)
5188
-			->setNode($file)
5189
-			->setShareTime(new \DateTime('2000-01-01T00:01:02'))
5190
-			->setTarget('myTarget')
5191
-			->setNote('personal note')
5192
-			->setId(42);
5193
-
5194
-		$this->rootFolder->method('getUserFolder')
5195
-			->with($this->currentUser)
5196
-			->willReturnSelf();
5197
-
5198
-		$this->rootFolder->method('getFirstNodeById')
5199
-			->with($share->getNodeId())
5200
-			->willReturn($share->getNode());
5201
-
5202
-		$this->rootFolder->method('getRelativePath')
5203
-			->with($share->getNode()->getPath())
5204
-			->willReturnArgument(0);
5205
-
5206
-		if (!$helperAvailable) {
5207
-			$this->appManager->method('isEnabledForUser')
5208
-				->with('spreed')
5209
-				->willReturn(false);
5210
-		} else {
5211
-			$this->appManager->method('isEnabledForUser')
5212
-				->with('spreed')
5213
-				->willReturn(true);
5214
-
5215
-			// This is not possible anymore with PHPUnit 10+
5216
-			// as `setMethods` was removed and now real reflection is used, thus the class needs to exist.
5217
-			// $helper = $this->getMockBuilder('\OCA\Talk\Share\Helper\ShareAPIController')
5218
-			$helper = $this->getMockBuilder(\stdClass::class)
5219
-				->addMethods(['formatShare', 'canAccessShare'])
5220
-				->getMock();
5221
-			$helper->method('formatShare')
5222
-				->with($share)
5223
-				->willReturn($formatShareByHelper);
5224
-			$helper->method('canAccessShare')
5225
-				->with($share)
5226
-				->willReturn(true);
5227
-
5228
-			$this->serverContainer->method('get')
5229
-				->with('\OCA\Talk\Share\Helper\ShareAPIController')
5230
-				->willReturn($helper);
5231
-		}
5232
-
5233
-		$result = $this->invokePrivate($this->ocs, 'formatShare', [$share]);
5234
-		$this->assertEquals($expects, $result);
5235
-	}
5236
-
5237
-	/**
5238
-	 * @return list{Folder, Folder}
5239
-	 */
5240
-	private function getNonSharedUserFolder(): array {
5241
-		$node = $this->getMockBuilder(Folder::class)->getMock();
5242
-		$userFolder = $this->getMockBuilder(Folder::class)->getMock();
5243
-		$storage = $this->createMock(IStorage::class);
5244
-		$storage->method('instanceOfStorage')
5245
-			->willReturnMap([
5246
-				['OCA\Files_Sharing\External\Storage', false],
5247
-				['OCA\Files_Sharing\SharedStorage', false],
5248
-			]);
5249
-		$userFolder->method('getStorage')->willReturn($storage);
5250
-		$node->method('getStorage')->willReturn($storage);
5251
-		$node->method('getId')->willReturn(42);
5252
-		$user = $this->createMock(IUser::class);
5253
-		$user->method('getUID')->willReturn($this->currentUser);
5254
-		$node->method('getOwner')->willReturn($user);
5255
-		return [$userFolder, $node];
5256
-	}
5257
-
5258
-	/**
5259
-	 * @return list{Folder, File}
5260
-	 */
5261
-	private function getNonSharedUserFile(): array {
5262
-		$node = $this->getMockBuilder(File::class)->getMock();
5263
-		$userFolder = $this->getMockBuilder(Folder::class)->getMock();
5264
-		$storage = $this->createMock(IStorage::class);
5265
-		$storage->method('instanceOfStorage')
5266
-			->willReturnMap([
5267
-				['OCA\Files_Sharing\External\Storage', false],
5268
-				['OCA\Files_Sharing\SharedStorage', false],
5269
-			]);
5270
-		$userFolder->method('getStorage')->willReturn($storage);
5271
-		$node->method('getStorage')->willReturn($storage);
5272
-		$node->method('getId')->willReturn(42);
5273
-		return [$userFolder, $node];
5274
-	}
5275
-
5276
-	public function testPopulateTags(): void {
5277
-		$tagger = $this->createMock(ITags::class);
5278
-		$this->tagManager->method('load')
5279
-			->with('files')
5280
-			->willReturn($tagger);
5281
-		$data = [
5282
-			['file_source' => 10],
5283
-			['file_source' => 22, 'foo' => 'bar'],
5284
-			['file_source' => 42, 'x' => 'y'],
5285
-		];
5286
-		$tags = [
5287
-			10 => ['tag3'],
5288
-			42 => ['tag1', 'tag2'],
5289
-		];
5290
-		$tagger->method('getTagsForObjects')
5291
-			->with([10, 22, 42])
5292
-			->willReturn($tags);
5293
-
5294
-		$result = self::invokePrivate($this->ocs, 'populateTags', [$data]);
5295
-		$this->assertSame([
5296
-			['file_source' => 10, 'tags' => ['tag3']],
5297
-			['file_source' => 22, 'foo' => 'bar', 'tags' => []],
5298
-			['file_source' => 42, 'x' => 'y', 'tags' => ['tag1', 'tag2']],
5299
-		], $result);
5300
-	}
5301
-
5302
-	public static function trustedServerProvider(): array {
5303
-		return [
5304
-			'Trusted server' => [true, true],
5305
-			'Untrusted server' => [false, false],
5306
-		];
5307
-	}
5308
-
5309
-	#[DataProvider('trustedServerProvider')]
5310
-	public function testFormatShareWithFederatedShare(bool $isKnownServer, bool $isTrusted): void {
5311
-		$nodeId = 12;
5312
-		$nodePath = '/test.txt';
5313
-
5314
-		$node = $this->createMock(File::class);
5315
-		$node->method('getId')->willReturn($nodeId);
5316
-		$node->method('getPath')->willReturn($nodePath);
5317
-		$node->method('getInternalPath')->willReturn(ltrim($nodePath, '/'));
5318
-		$mountPoint = $this->createMock(IMountPoint::class);
5319
-		$mountPoint->method('getMountType')->willReturn('local');
5320
-		$node->method('getMountPoint')->willReturn($mountPoint);
5321
-		$node->method('getMimetype')->willReturn('text/plain');
5322
-		$storage = $this->createMock(IStorage::class);
5323
-		$storageCache = $this->createMock(ICache::class);
5324
-		$storageCache->method('getNumericStorageId')->willReturn(1);
5325
-		$storage->method('getCache')->willReturn($storageCache);
5326
-		$storage->method('getId')->willReturn('home::shareOwner');
5327
-		$node->method('getStorage')->willReturn($storage);
5328
-		$parent = $this->createMock(Folder::class);
5329
-		$parent->method('getId')->willReturn(2);
5330
-		$node->method('getParent')->willReturn($parent);
5331
-		$node->method('getSize')->willReturn(1234);
5332
-		$node->method('getMTime')->willReturn(1234567890);
5333
-
5334
-		$share = $this->createShare(
5335
-			1,
5336
-			IShare::TYPE_REMOTE,
5337
-			'[email protected]', // shared with
5338
-			'[email protected]',      // shared by
5339
-			'shareOwner',                 // share owner
5340
-			$node,
5341
-			Constants::PERMISSION_READ,
5342
-			time(),
5343
-			null,
5344
-			2,
5345
-			$nodePath,
5346
-			$nodeId
5347
-		);
5348
-
5349
-		$this->previewManager->method('isAvailable')->with($node)->willReturn(false);
5350
-
5351
-		$this->rootFolder->method('getUserFolder')
5352
-			->with($this->currentUser)
5353
-			->willReturnSelf();
5354
-
5355
-		$this->rootFolder->method('getFirstNodeById')
5356
-			->with($share->getNodeId())
5357
-			->willReturn($node);
5358
-
5359
-		$this->rootFolder->method('getRelativePath')
5360
-			->with($node->getPath())
5361
-			->willReturnArgument(0);
5362
-
5363
-		$serverName = 'remoteserver.com';
5364
-		$this->trustedServers->method('isTrustedServer')
5365
-			->with($serverName)
5366
-			->willReturn($isKnownServer);
5367
-
5368
-		$result = $this->invokePrivate($this->ocs, 'formatShare', [$share]);
5369
-
5370
-		$this->assertSame($isTrusted, $result['is_trusted_server']);
5371
-	}
5372
-
5373
-	public function testFormatShareWithFederatedShareWithAtInUsername(): void {
5374
-		$nodeId = 12;
5375
-		$nodePath = '/test.txt';
5376
-
5377
-		$node = $this->createMock(File::class);
5378
-		$node->method('getId')->willReturn($nodeId);
5379
-		$node->method('getPath')->willReturn($nodePath);
5380
-		$node->method('getInternalPath')->willReturn(ltrim($nodePath, '/'));
5381
-		$mountPoint = $this->createMock(IMountPoint::class);
5382
-		$mountPoint->method('getMountType')->willReturn('local');
5383
-		$node->method('getMountPoint')->willReturn($mountPoint);
5384
-		$node->method('getMimetype')->willReturn('text/plain');
5385
-		$storage = $this->createMock(IStorage::class);
5386
-		$storageCache = $this->createMock(ICache::class);
5387
-		$storageCache->method('getNumericStorageId')->willReturn(1);
5388
-		$storage->method('getCache')->willReturn($storageCache);
5389
-		$storage->method('getId')->willReturn('home::shareOwner');
5390
-		$node->method('getStorage')->willReturn($storage);
5391
-		$parent = $this->createMock(Folder::class);
5392
-		$parent->method('getId')->willReturn(2);
5393
-		$node->method('getParent')->willReturn($parent);
5394
-		$node->method('getSize')->willReturn(1234);
5395
-		$node->method('getMTime')->willReturn(1234567890);
5396
-
5397
-		$share = $this->createShare(
5398
-			1,
5399
-			IShare::TYPE_REMOTE,
5400
-			'[email protected]@remoteserver.com',
5401
-			'[email protected]',
5402
-			'shareOwner',
5403
-			$node,
5404
-			Constants::PERMISSION_READ,
5405
-			time(),
5406
-			null,
5407
-			2,
5408
-			$nodePath,
5409
-			$nodeId
5410
-		);
5411
-
5412
-		$this->previewManager->method('isAvailable')->with($node)->willReturn(false);
5413
-
5414
-		$this->rootFolder->method('getUserFolder')
5415
-			->with($this->currentUser)
5416
-			->willReturnSelf();
5417
-
5418
-		$this->rootFolder->method('getFirstNodeById')
5419
-			->with($share->getNodeId())
5420
-			->willReturn($node);
5421
-
5422
-		$this->rootFolder->method('getRelativePath')
5423
-			->with($node->getPath())
5424
-			->willReturnArgument(0);
5425
-
5426
-		$serverName = 'remoteserver.com';
5427
-		$this->trustedServers->method('isTrustedServer')
5428
-			->with($serverName)
5429
-			->willReturn(true);
5430
-
5431
-		$result = $this->invokePrivate($this->ocs, 'formatShare', [$share]);
5432
-
5433
-		$this->assertTrue($result['is_trusted_server']);
5434
-	}
591
+    public function createShare(
592
+        int $id,
593
+        int $shareType,
594
+        ?string $sharedWith,
595
+        string $sharedBy,
596
+        string $shareOwner,
597
+        File|Folder|null $node,
598
+        int $permissions,
599
+        int $shareTime,
600
+        ?\DateTime $expiration,
601
+        int $parent,
602
+        string $target,
603
+        int $mail_send,
604
+        string $note = '',
605
+        ?string $token = null,
606
+        ?string $password = null,
607
+        string $label = '',
608
+        ?IShareAttributes $attributes = null,
609
+    ): MockObject {
610
+        $share = $this->createMock(IShare::class);
611
+        $share->method('getId')->willReturn($id);
612
+        $share->method('getShareType')->willReturn($shareType);
613
+        $share->method('getSharedWith')->willReturn($sharedWith);
614
+        $share->method('getSharedBy')->willReturn($sharedBy);
615
+        $share->method('getShareOwner')->willReturn($shareOwner);
616
+        $share->method('getNode')->willReturn($node);
617
+        $share->method('getPermissions')->willReturn($permissions);
618
+        $share->method('getNote')->willReturn($note);
619
+        $share->method('getLabel')->willReturn($label);
620
+        $share->method('getAttributes')->willReturn($attributes);
621
+        $time = new \DateTime();
622
+        $time->setTimestamp($shareTime);
623
+        $share->method('getShareTime')->willReturn($time);
624
+        $share->method('getExpirationDate')->willReturn($expiration);
625
+        $share->method('getTarget')->willReturn($target);
626
+        $share->method('getMailSend')->willReturn($mail_send);
627
+        $share->method('getToken')->willReturn($token);
628
+        $share->method('getPassword')->willReturn($password);
629
+
630
+        if ($shareType === IShare::TYPE_USER
631
+            || $shareType === IShare::TYPE_GROUP
632
+            || $shareType === IShare::TYPE_LINK) {
633
+            $share->method('getFullId')->willReturn('ocinternal:' . $id);
634
+        }
635
+
636
+        return $share;
637
+    }
638
+
639
+    public static function dataGetShare(): array {
640
+        $data = [];
641
+
642
+        $file = [
643
+            'class' => File::class,
644
+            'id' => 1,
645
+            'path' => 'file',
646
+            'mimeType' => 'myMimeType',
647
+        ];
648
+
649
+        $folder = [
650
+            'class' => Folder::class,
651
+            'id' => 2,
652
+            'path' => 'folder',
653
+            'mimeType' => 'myFolderMimeType',
654
+        ];
655
+
656
+        // File shared with user
657
+        $share = [
658
+            100,
659
+            IShare::TYPE_USER,
660
+            'userId',
661
+            'initiatorId',
662
+            'ownerId',
663
+            $file,
664
+            4,
665
+            5,
666
+            null,
667
+            6,
668
+            'target',
669
+            0,
670
+            'personal note',
671
+            null,
672
+            null,
673
+            '',
674
+            [],
675
+        ];
676
+        $expected = [
677
+            'id' => 100,
678
+            'share_type' => IShare::TYPE_USER,
679
+            'share_with' => 'userId',
680
+            'share_with_displayname' => 'userDisplay',
681
+            'share_with_displayname_unique' => '[email protected]',
682
+            'uid_owner' => 'initiatorId',
683
+            'displayname_owner' => 'initiatorDisplay',
684
+            'item_type' => 'file',
685
+            'item_source' => 1,
686
+            'file_source' => 1,
687
+            'file_target' => 'target',
688
+            'file_parent' => 3,
689
+            'token' => null,
690
+            'expiration' => null,
691
+            'permissions' => 4,
692
+            'stime' => 5,
693
+            'parent' => null,
694
+            'storage_id' => 'STORAGE',
695
+            'path' => 'file',
696
+            'storage' => 101,
697
+            'mail_send' => 0,
698
+            'uid_file_owner' => 'ownerId',
699
+            'note' => 'personal note',
700
+            'label' => '',
701
+            'displayname_file_owner' => 'ownerDisplay',
702
+            'mimetype' => 'myMimeType',
703
+            'has_preview' => false,
704
+            'hide_download' => 0,
705
+            'can_edit' => false,
706
+            'can_delete' => false,
707
+            'item_size' => 123465,
708
+            'item_mtime' => 1234567890,
709
+            'item_permissions' => 4,
710
+            'is-mount-root' => false,
711
+            'mount-type' => '',
712
+        ];
713
+        $data['File shared with user'] = [$share, $expected, true];
714
+
715
+        // Folder shared with group
716
+        $share = [
717
+            101,
718
+            IShare::TYPE_GROUP,
719
+            'groupId',
720
+            'initiatorId',
721
+            'ownerId',
722
+            $folder,
723
+            4,
724
+            5,
725
+            null,
726
+            6,
727
+            'target',
728
+            0,
729
+            'personal note',
730
+            null,
731
+            null,
732
+            '',
733
+            [],
734
+        ];
735
+        $expected = [
736
+            'id' => 101,
737
+            'share_type' => IShare::TYPE_GROUP,
738
+            'share_with' => 'groupId',
739
+            'share_with_displayname' => 'groupId',
740
+            'uid_owner' => 'initiatorId',
741
+            'displayname_owner' => 'initiatorDisplay',
742
+            'item_type' => 'folder',
743
+            'item_source' => 2,
744
+            'file_source' => 2,
745
+            'file_target' => 'target',
746
+            'file_parent' => 3,
747
+            'token' => null,
748
+            'expiration' => null,
749
+            'permissions' => 4,
750
+            'stime' => 5,
751
+            'parent' => null,
752
+            'storage_id' => 'STORAGE',
753
+            'path' => 'folder',
754
+            'storage' => 101,
755
+            'mail_send' => 0,
756
+            'uid_file_owner' => 'ownerId',
757
+            'note' => 'personal note',
758
+            'label' => '',
759
+            'displayname_file_owner' => 'ownerDisplay',
760
+            'mimetype' => 'myFolderMimeType',
761
+            'has_preview' => false,
762
+            'hide_download' => 0,
763
+            'can_edit' => false,
764
+            'can_delete' => false,
765
+            'item_size' => 123465,
766
+            'item_mtime' => 1234567890,
767
+            'item_permissions' => 4,
768
+            'is-mount-root' => false,
769
+            'mount-type' => '',
770
+        ];
771
+        $data['Folder shared with group'] = [$share, $expected, true];
772
+
773
+        // File shared by link with Expire
774
+        $expire = \DateTime::createFromFormat('Y-m-d h:i:s', '2000-01-02 01:02:03');
775
+        $share = [
776
+            101,
777
+            IShare::TYPE_LINK,
778
+            null,
779
+            'initiatorId',
780
+            'ownerId',
781
+            $folder,
782
+            4,
783
+            5,
784
+            $expire,
785
+            6,
786
+            'target',
787
+            0,
788
+            'personal note',
789
+            'token',
790
+            'password',
791
+            'first link share'
792
+        ];
793
+        $expected = [
794
+            'id' => 101,
795
+            'share_type' => IShare::TYPE_LINK,
796
+            'password' => 'password',
797
+            'share_with' => 'password',
798
+            'share_with_displayname' => '(Shared link)',
799
+            'send_password_by_talk' => false,
800
+            'uid_owner' => 'initiatorId',
801
+            'displayname_owner' => 'initiatorDisplay',
802
+            'item_type' => 'folder',
803
+            'item_source' => 2,
804
+            'file_source' => 2,
805
+            'file_target' => 'target',
806
+            'file_parent' => 3,
807
+            'token' => 'token',
808
+            'expiration' => '2000-01-02 00:00:00',
809
+            'permissions' => 4,
810
+            'attributes' => null,
811
+            'stime' => 5,
812
+            'parent' => null,
813
+            'storage_id' => 'STORAGE',
814
+            'path' => 'folder',
815
+            'storage' => 101,
816
+            'mail_send' => 0,
817
+            'url' => 'url',
818
+            'uid_file_owner' => 'ownerId',
819
+            'note' => 'personal note',
820
+            'label' => 'first link share',
821
+            'displayname_file_owner' => 'ownerDisplay',
822
+            'mimetype' => 'myFolderMimeType',
823
+            'has_preview' => false,
824
+            'hide_download' => 0,
825
+            'can_edit' => false,
826
+            'can_delete' => false,
827
+            'item_size' => 123465,
828
+            'item_mtime' => 1234567890,
829
+            'item_permissions' => 4,
830
+            'is-mount-root' => false,
831
+            'mount-type' => '',
832
+        ];
833
+        $data['File shared by link with Expire'] = [$share, $expected, false];
834
+
835
+        return $data;
836
+    }
837
+
838
+    #[DataProvider('dataGetShare')]
839
+    public function testGetShare(array $shareParams, array $result, bool $attributes): void {
840
+
841
+        $cache = $this->createMock(ICache::class);
842
+        $cache->method('getNumericStorageId')->willReturn(101);
843
+
844
+        $storage = $this->createMock(IStorage::class);
845
+        $storage->method('getId')->willReturn('STORAGE');
846
+        $storage->method('getCache')->willReturn($cache);
847
+
848
+        $parentFolder = $this->createMock(Folder::class);
849
+        $parentFolder->method('getId')->willReturn(3);
850
+
851
+        $mountPoint = $this->createMock(IMountPoint::class);
852
+        $mountPoint->method('getMountType')->willReturn('');
853
+
854
+        $nodeParams = $shareParams[5];
855
+        $node = $this->createMock($nodeParams['class']);
856
+        $node->method('getId')->willReturn($nodeParams['id']);
857
+        $node->method('getPath')->willReturn($nodeParams['path']);
858
+        $node->method('getStorage')->willReturn($storage);
859
+        $node->method('getParent')->willReturn($parentFolder);
860
+        $node->method('getSize')->willReturn(123465);
861
+        $node->method('getMTime')->willReturn(1234567890);
862
+        $node->method('getMimeType')->willReturn($nodeParams['mimeType']);
863
+        $node->method('getMountPoint')->willReturn($mountPoint);
864
+
865
+        $shareParams[5] = $node;
866
+
867
+        if ($attributes) {
868
+            [$shareAttributes, $shareAttributesReturnJson] = $this->mockShareAttributes();
869
+            $result['attributes'] = $shareAttributesReturnJson;
870
+            $shareParams[16] = $shareAttributes;
871
+        }
872
+
873
+        $share = $this->createShare(...$shareParams);
874
+        /** @var ShareAPIController&MockObject $ocs */
875
+        $ocs = $this->getMockBuilder(ShareAPIController::class)
876
+            ->setConstructorArgs([
877
+                $this->appName,
878
+                $this->request,
879
+                $this->shareManager,
880
+                $this->groupManager,
881
+                $this->userManager,
882
+                $this->rootFolder,
883
+                $this->urlGenerator,
884
+                $this->l,
885
+                $this->config,
886
+                $this->appConfig,
887
+                $this->appManager,
888
+                $this->serverContainer,
889
+                $this->userStatusManager,
890
+                $this->previewManager,
891
+                $this->dateTimeZone,
892
+                $this->logger,
893
+                $this->factory,
894
+                $this->mailer,
895
+                $this->tagManager,
896
+                $this->getEmailValidatorWithStrictEmailCheck(),
897
+                $this->trustedServers,
898
+                $this->currentUser,
899
+            ])
900
+            ->onlyMethods(['canAccessShare'])
901
+            ->getMock();
902
+
903
+        $ocs->expects($this->any())
904
+            ->method('canAccessShare')
905
+            ->willReturn(true);
906
+
907
+        $this->shareManager
908
+            ->expects($this->any())
909
+            ->method('getShareById')
910
+            ->with($share->getFullId(), 'currentUser')
911
+            ->willReturn($share);
912
+
913
+        $userFolder = $this->getMockBuilder(Folder::class)->getMock();
914
+        $userFolder
915
+            ->method('getRelativePath')
916
+            ->willReturnArgument(0);
917
+
918
+        $userFolder->method('getById')
919
+            ->with($share->getNodeId())
920
+            ->willReturn([$share->getNode()]);
921
+        $userFolder->method('getFirstNodeById')
922
+            ->with($share->getNodeId())
923
+            ->willReturn($share->getNode());
924
+
925
+        $this->rootFolder->method('getUserFolder')
926
+            ->with($this->currentUser)
927
+            ->willReturn($userFolder);
928
+
929
+        $this->urlGenerator
930
+            ->method('linkToRouteAbsolute')
931
+            ->willReturn('url');
932
+
933
+        $initiator = $this->getMockBuilder(IUser::class)->getMock();
934
+        $initiator->method('getUID')->willReturn('initiatorId');
935
+        $initiator->method('getDisplayName')->willReturn('initiatorDisplay');
936
+
937
+        $owner = $this->getMockBuilder(IUser::class)->getMock();
938
+        $owner->method('getUID')->willReturn('ownerId');
939
+        $owner->method('getDisplayName')->willReturn('ownerDisplay');
940
+
941
+        $user = $this->getMockBuilder(IUser::class)->getMock();
942
+        $user->method('getUID')->willReturn('userId');
943
+        $user->method('getDisplayName')->willReturn('userDisplay');
944
+        $user->method('getSystemEMailAddress')->willReturn('[email protected]');
945
+
946
+        $group = $this->getMockBuilder(IGroup::class)->getMock();
947
+        $group->method('getGID')->willReturn('groupId');
948
+
949
+        $this->userManager->method('get')->willReturnMap([
950
+            ['userId', $user],
951
+            ['initiatorId', $initiator],
952
+            ['ownerId', $owner],
953
+        ]);
954
+        $this->groupManager->method('get')->willReturnMap([
955
+            ['group', $group],
956
+        ]);
957
+        $this->dateTimeZone->method('getTimezone')->willReturn(new \DateTimeZone('UTC'));
958
+
959
+        $data = $ocs->getShare((string)$share->getId())->getData()[0];
960
+        $this->assertEquals($result, $data);
961
+    }
962
+
963
+
964
+    public function testGetShareInvalidNode(): void {
965
+        $this->expectException(OCSNotFoundException::class);
966
+        $this->expectExceptionMessage('Wrong share ID, share does not exist');
967
+
968
+        $share = Server::get(IManager::class)->newShare();
969
+        $share->setSharedBy('initiator')
970
+            ->setSharedWith('recipient')
971
+            ->setShareOwner('owner');
972
+
973
+        $this->shareManager
974
+            ->expects($this->once())
975
+            ->method('getShareById')
976
+            ->with('ocinternal:42', 'currentUser')
977
+            ->willReturn($share);
978
+
979
+        $userFolder = $this->getMockBuilder(Folder::class)->getMock();
980
+        $this->rootFolder->method('getUserFolder')
981
+            ->with($this->currentUser)
982
+            ->willReturn($userFolder);
983
+
984
+        $this->ocs->getShare('42');
985
+    }
986
+
987
+    public static function dataGetShares(): array {
988
+        $file1 = [
989
+            'class' => File::class,
990
+            'methods' => [
991
+                'getName' => 'file1',
992
+            ]
993
+        ];
994
+        $file2 = [
995
+            'class' => File::class,
996
+            'methods' => [
997
+                'getName' => 'file2',
998
+            ]
999
+        ];
1000
+
1001
+        $folder = [
1002
+            'class' => Folder::class,
1003
+            'methods' => [
1004
+                'getDirectoryListing' => [$file1, $file2]
1005
+            ]
1006
+        ];
1007
+
1008
+        $file1UserShareOwner = [
1009
+            'type' => IShare::TYPE_USER,
1010
+            'sharedWith' => 'recipient',
1011
+            'sharedBy' => 'initiator',
1012
+            'owner' => 'currentUser',
1013
+            'node' => $file1,
1014
+            'id' => 4,
1015
+        ];
1016
+
1017
+        $file1UserShareOwnerExpected = [
1018
+            'id' => 4,
1019
+            'share_type' => IShare::TYPE_USER,
1020
+        ];
1021
+
1022
+        $file1UserShareInitiator = [
1023
+            'type' => IShare::TYPE_USER,
1024
+            'sharedWith' => 'recipient',
1025
+            'sharedBy' => 'currentUser',
1026
+            'owner' => 'owner',
1027
+            'node' => $file1,
1028
+            'id' => 8,
1029
+        ];
1030
+
1031
+        $file1UserShareInitiatorExpected = [
1032
+            'id' => 8,
1033
+            'share_type' => IShare::TYPE_USER,
1034
+        ];
1035
+
1036
+        $file1UserShareRecipient = [
1037
+            'type' => IShare::TYPE_USER,
1038
+            'sharedWith' => 'currentUser',
1039
+            'sharedBy' => 'initiator',
1040
+            'owner' => 'owner',
1041
+            'node' => $file1,
1042
+            'id' => 15,
1043
+        ];
1044
+
1045
+        $file1UserShareRecipientExpected = [
1046
+            'id' => 15,
1047
+            'share_type' => IShare::TYPE_USER,
1048
+        ];
1049
+
1050
+        $file1UserShareOther = [
1051
+            'type' => IShare::TYPE_USER,
1052
+            'sharedWith' => 'recipient',
1053
+            'sharedBy' => 'initiator',
1054
+            'owner' => 'owner',
1055
+            'node' => $file1,
1056
+            'id' => 16,
1057
+        ];
1058
+
1059
+        $file1UserShareOtherExpected = [
1060
+            'id' => 16,
1061
+            'share_type' => IShare::TYPE_USER,
1062
+        ];
1063
+
1064
+        $file1GroupShareOwner = [
1065
+            'type' => IShare::TYPE_GROUP,
1066
+            'sharedWith' => 'recipient',
1067
+            'sharedBy' => 'initiator',
1068
+            'owner' => 'currentUser',
1069
+            'node' => $file1,
1070
+            'id' => 23,
1071
+        ];
1072
+
1073
+        $file1GroupShareOwnerExpected = [
1074
+            'id' => 23,
1075
+            'share_type' => IShare::TYPE_GROUP,
1076
+        ];
1077
+
1078
+        $file1GroupShareRecipient = [
1079
+            'type' => IShare::TYPE_GROUP,
1080
+            'sharedWith' => 'currentUserGroup',
1081
+            'sharedBy' => 'initiator',
1082
+            'owner' => 'owner',
1083
+            'node' => $file1,
1084
+            'id' => 42,
1085
+        ];
1086
+
1087
+        $file1GroupShareRecipientExpected = [
1088
+            'id' => 42,
1089
+            'share_type' => IShare::TYPE_GROUP,
1090
+        ];
1091
+
1092
+        $file1GroupShareOther = [
1093
+            'type' => IShare::TYPE_GROUP,
1094
+            'sharedWith' => 'recipient',
1095
+            'sharedBy' => 'initiator',
1096
+            'owner' => 'owner',
1097
+            'node' => $file1,
1098
+            'id' => 108,
1099
+        ];
1100
+
1101
+        $file1LinkShareOwner = [
1102
+            'type' => IShare::TYPE_LINK,
1103
+            'sharedWith' => 'recipient',
1104
+            'sharedBy' => 'initiator',
1105
+            'owner' => 'currentUser',
1106
+            'node' => $file1,
1107
+            'id' => 415,
1108
+        ];
1109
+
1110
+        $file1LinkShareOwnerExpected = [
1111
+            'id' => 415,
1112
+            'share_type' => IShare::TYPE_LINK,
1113
+        ];
1114
+
1115
+        $file1EmailShareOwner = [
1116
+            'type' => IShare::TYPE_EMAIL,
1117
+            'sharedWith' => 'recipient',
1118
+            'sharedBy' => 'initiator',
1119
+            'owner' => 'currentUser',
1120
+            'node' => $file1,
1121
+            'id' => 416,
1122
+        ];
1123
+
1124
+        $file1EmailShareOwnerExpected = [
1125
+            'id' => 416,
1126
+            'share_type' => IShare::TYPE_EMAIL,
1127
+        ];
1128
+
1129
+        $file1CircleShareOwner = [
1130
+            'type' => IShare::TYPE_CIRCLE,
1131
+            'sharedWith' => 'recipient',
1132
+            'sharedBy' => 'initiator',
1133
+            'owner' => 'currentUser',
1134
+            'node' => $file1,
1135
+            'id' => 423,
1136
+        ];
1137
+
1138
+        $file1CircleShareOwnerExpected = [
1139
+            'id' => 423,
1140
+            'share_type' => IShare::TYPE_CIRCLE,
1141
+        ];
1142
+
1143
+        $file1RoomShareOwner = [
1144
+            'type' => IShare::TYPE_ROOM,
1145
+            'sharedWith' => 'recipient',
1146
+            'sharedBy' => 'initiator',
1147
+            'owner' => 'currentUser',
1148
+            'node' => $file1,
1149
+            'id' => 442,
1150
+        ];
1151
+
1152
+        $file1RoomShareOwnerExpected = [
1153
+            'id' => 442,
1154
+            'share_type' => IShare::TYPE_ROOM,
1155
+        ];
1156
+
1157
+        $file1RemoteShareOwner = [
1158
+            'type' => IShare::TYPE_REMOTE,
1159
+            'sharedWith' => 'recipient',
1160
+            'sharedBy' => 'initiator',
1161
+            'owner' => 'currentUser',
1162
+            'expirationDate' => new \DateTime('2000-01-01T01:02:03'),
1163
+            'node' => $file1,
1164
+            'id' => 815,
1165
+        ];
1166
+
1167
+        $file1RemoteShareOwnerExpected = [
1168
+            'id' => 815,
1169
+            'share_type' => IShare::TYPE_REMOTE,
1170
+        ];
1171
+
1172
+        $file1RemoteGroupShareOwner = [
1173
+            'type' => IShare::TYPE_REMOTE_GROUP,
1174
+            'sharedWith' => 'recipient',
1175
+            'sharedBy' => 'initiator',
1176
+            'owner' => 'currentUser',
1177
+            'expirationDate' => new \DateTime('2000-01-01T01:02:03'),
1178
+            'node' => $file1,
1179
+            'id' => 816,
1180
+        ];
1181
+
1182
+        $file1RemoteGroupShareOwnerExpected = [
1183
+            'id' => 816,
1184
+            'share_type' => IShare::TYPE_REMOTE_GROUP,
1185
+        ];
1186
+
1187
+        $file2UserShareOwner = [
1188
+            'type' => IShare::TYPE_USER,
1189
+            'sharedWith' => 'recipient',
1190
+            'sharedBy' => 'initiator',
1191
+            'owner' => 'currentUser',
1192
+            'node' => $file2,
1193
+            'id' => 823,
1194
+        ];
1195
+
1196
+        $file2UserShareOwnerExpected = [
1197
+            'id' => 823,
1198
+            'share_type' => IShare::TYPE_USER,
1199
+        ];
1200
+
1201
+        $data = [
1202
+            [
1203
+                [
1204
+                    'node' => $file1,
1205
+                ],
1206
+                [
1207
+                    'file1' => [
1208
+                        IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareOwner, $file1UserShareOwner],
1209
+                    ],
1210
+                ],
1211
+                [
1212
+                ],
1213
+                [
1214
+                    $file1UserShareOwnerExpected
1215
+                ]
1216
+            ],
1217
+            [
1218
+                [
1219
+                    'node' => $file1,
1220
+                ],
1221
+                [
1222
+                    'file1' => [
1223
+                        IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareRecipient],
1224
+                    ],
1225
+                ],
1226
+                [
1227
+                ],
1228
+                [
1229
+                    $file1UserShareOwnerExpected,
1230
+                ]
1231
+            ],
1232
+            [
1233
+                [
1234
+                    'node' => $file1,
1235
+                ],
1236
+                [
1237
+                    'file1' => [
1238
+                        IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareRecipient, $file1UserShareInitiator, $file1UserShareOther],
1239
+                    ],
1240
+                ],
1241
+                [
1242
+                ],
1243
+                [
1244
+                    $file1UserShareOwnerExpected,
1245
+                    $file1UserShareInitiatorExpected,
1246
+                    $file1UserShareOtherExpected,
1247
+                ]
1248
+            ],
1249
+            [
1250
+                [
1251
+                    'node' => $file1,
1252
+                ],
1253
+                [
1254
+                    'file1' => [
1255
+                        IShare::TYPE_USER => [$file1UserShareRecipient, $file1UserShareInitiator, $file1UserShareOther],
1256
+                    ],
1257
+                ],
1258
+                [
1259
+                ],
1260
+                [
1261
+                    $file1UserShareInitiatorExpected,
1262
+                ]
1263
+            ],
1264
+            [
1265
+                [
1266
+                    'node' => $file1,
1267
+                ],
1268
+                [
1269
+                    'file1' => [
1270
+                        IShare::TYPE_USER => [$file1UserShareOwner],
1271
+                        IShare::TYPE_GROUP => [$file1GroupShareRecipient],
1272
+                    ],
1273
+                ],
1274
+                [
1275
+                ],
1276
+                [
1277
+                    $file1UserShareOwnerExpected,
1278
+                    $file1GroupShareRecipientExpected,
1279
+                ]
1280
+            ],
1281
+            [
1282
+                [
1283
+                    'node' => $file1,
1284
+                ],
1285
+                [
1286
+                    'file1' => [
1287
+                        IShare::TYPE_USER => [$file1UserShareOwner],
1288
+                        IShare::TYPE_GROUP => [$file1GroupShareOwner],
1289
+                        IShare::TYPE_LINK => [$file1LinkShareOwner],
1290
+                        IShare::TYPE_EMAIL => [$file1EmailShareOwner],
1291
+                        IShare::TYPE_CIRCLE => [$file1CircleShareOwner],
1292
+                        IShare::TYPE_ROOM => [$file1RoomShareOwner],
1293
+                        IShare::TYPE_REMOTE => [$file1RemoteShareOwner],
1294
+                        IShare::TYPE_REMOTE_GROUP => [$file1RemoteGroupShareOwner],
1295
+                    ],
1296
+                ],
1297
+                [
1298
+                ],
1299
+                [
1300
+                    $file1UserShareOwnerExpected,
1301
+                    $file1GroupShareOwnerExpected,
1302
+                    $file1LinkShareOwnerExpected,
1303
+                    $file1EmailShareOwnerExpected,
1304
+                    $file1CircleShareOwnerExpected,
1305
+                    $file1RoomShareOwnerExpected,
1306
+                ]
1307
+            ],
1308
+            [
1309
+                [
1310
+                    'node' => $file1,
1311
+                ],
1312
+                [
1313
+                    'file1' => [
1314
+                        IShare::TYPE_USER => [$file1UserShareOwner],
1315
+                        IShare::TYPE_GROUP => [$file1GroupShareOwner],
1316
+                        IShare::TYPE_LINK => [$file1LinkShareOwner],
1317
+                        IShare::TYPE_EMAIL => [$file1EmailShareOwner],
1318
+                        IShare::TYPE_CIRCLE => [$file1CircleShareOwner],
1319
+                        IShare::TYPE_ROOM => [$file1RoomShareOwner],
1320
+                        IShare::TYPE_REMOTE => [$file1RemoteShareOwner],
1321
+                        IShare::TYPE_REMOTE_GROUP => [$file1RemoteGroupShareOwner],
1322
+                    ],
1323
+                ],
1324
+                [
1325
+                    IShare::TYPE_REMOTE => true,
1326
+                    IShare::TYPE_REMOTE_GROUP => true,
1327
+                ],
1328
+                [
1329
+                    $file1UserShareOwnerExpected,
1330
+                    $file1GroupShareOwnerExpected,
1331
+                    $file1LinkShareOwnerExpected,
1332
+                    $file1EmailShareOwnerExpected,
1333
+                    $file1CircleShareOwnerExpected,
1334
+                    $file1RoomShareOwnerExpected,
1335
+                    $file1RemoteShareOwnerExpected,
1336
+                    $file1RemoteGroupShareOwnerExpected,
1337
+                ]
1338
+            ],
1339
+            [
1340
+                [
1341
+                    'node' => $folder,
1342
+                    'subfiles' => 'true',
1343
+                ],
1344
+                [
1345
+                    'file1' => [
1346
+                        IShare::TYPE_USER => [$file1UserShareOwner],
1347
+                    ],
1348
+                    'file2' => [
1349
+                        IShare::TYPE_USER => [$file2UserShareOwner],
1350
+                    ],
1351
+                ],
1352
+                [
1353
+                ],
1354
+                [
1355
+                    $file1UserShareOwnerExpected,
1356
+                    $file2UserShareOwnerExpected,
1357
+                ]
1358
+            ],
1359
+            [
1360
+                [
1361
+                    'node' => $folder,
1362
+                    'subfiles' => 'true',
1363
+                ],
1364
+                [
1365
+                    'file1' => [
1366
+                        IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareOwner, $file1UserShareOwner],
1367
+                    ],
1368
+                ],
1369
+                [
1370
+                ],
1371
+                [
1372
+                    $file1UserShareOwnerExpected,
1373
+                ]
1374
+            ],
1375
+            [
1376
+                [
1377
+                    'node' => $folder,
1378
+                    'subfiles' => 'true',
1379
+                ],
1380
+                [
1381
+                    'file1' => [
1382
+                        IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareRecipient],
1383
+                    ],
1384
+                ],
1385
+                [
1386
+                ],
1387
+                [
1388
+                    $file1UserShareOwnerExpected
1389
+                ]
1390
+            ],
1391
+            [
1392
+                [
1393
+                    'node' => $folder,
1394
+                    'subfiles' => 'true',
1395
+                ],
1396
+                [
1397
+                    'file1' => [
1398
+                        IShare::TYPE_USER => [$file1UserShareRecipient, $file1UserShareInitiator, $file1UserShareOther],
1399
+                    ],
1400
+                    'file2' => [
1401
+                        IShare::TYPE_USER => [$file2UserShareOwner],
1402
+                    ],
1403
+                ],
1404
+                [
1405
+                ],
1406
+                [
1407
+                    $file1UserShareInitiatorExpected,
1408
+                    $file1UserShareOtherExpected,
1409
+                    $file2UserShareOwnerExpected,
1410
+                ]
1411
+            ],
1412
+            // This might not happen in a real environment, as the combination
1413
+            // of shares does not seem to be possible on a folder without
1414
+            // resharing rights; if the folder has resharing rights then the
1415
+            // share with others would be included too in the results.
1416
+            [
1417
+                [
1418
+                    'node' => $folder,
1419
+                    'subfiles' => 'true',
1420
+                ],
1421
+                [
1422
+                    'file1' => [
1423
+                        IShare::TYPE_USER => [$file1UserShareRecipient, $file1UserShareInitiator, $file1UserShareOther],
1424
+                    ],
1425
+                ],
1426
+                [
1427
+                ],
1428
+                [
1429
+                    $file1UserShareInitiatorExpected,
1430
+                ]
1431
+            ],
1432
+            [
1433
+                [
1434
+                    'node' => $folder,
1435
+                    'subfiles' => 'true',
1436
+                ],
1437
+                [
1438
+                    'file1' => [
1439
+                        IShare::TYPE_USER => [$file1UserShareOwner],
1440
+                        IShare::TYPE_GROUP => [$file1GroupShareRecipient],
1441
+                    ],
1442
+                ],
1443
+                [
1444
+                ],
1445
+                [
1446
+                    $file1UserShareOwnerExpected,
1447
+                    $file1GroupShareRecipientExpected,
1448
+                ]
1449
+            ],
1450
+            [
1451
+                [
1452
+                    'node' => $folder,
1453
+                    'subfiles' => 'true',
1454
+                ],
1455
+                [
1456
+                    'file1' => [
1457
+                        IShare::TYPE_USER => [$file1UserShareOwner],
1458
+                        IShare::TYPE_GROUP => [$file1GroupShareOwner],
1459
+                        IShare::TYPE_LINK => [$file1LinkShareOwner],
1460
+                        IShare::TYPE_EMAIL => [$file1EmailShareOwner],
1461
+                        IShare::TYPE_CIRCLE => [$file1CircleShareOwner],
1462
+                        IShare::TYPE_ROOM => [$file1RoomShareOwner],
1463
+                        IShare::TYPE_REMOTE => [$file1RemoteShareOwner],
1464
+                        IShare::TYPE_REMOTE_GROUP => [$file1RemoteGroupShareOwner],
1465
+                    ],
1466
+                ],
1467
+                [
1468
+                ],
1469
+                [
1470
+                    $file1UserShareOwnerExpected,
1471
+                    $file1GroupShareOwnerExpected,
1472
+                    $file1LinkShareOwnerExpected,
1473
+                    $file1EmailShareOwnerExpected,
1474
+                    $file1CircleShareOwnerExpected,
1475
+                    $file1RoomShareOwnerExpected,
1476
+                ]
1477
+            ],
1478
+            [
1479
+                [
1480
+                    'node' => $folder,
1481
+                    'subfiles' => 'true',
1482
+                ],
1483
+                [
1484
+                    'file1' => [
1485
+                        IShare::TYPE_USER => [$file1UserShareOwner],
1486
+                        IShare::TYPE_GROUP => [$file1GroupShareOwner],
1487
+                        IShare::TYPE_LINK => [$file1LinkShareOwner],
1488
+                        IShare::TYPE_EMAIL => [$file1EmailShareOwner],
1489
+                        IShare::TYPE_CIRCLE => [$file1CircleShareOwner],
1490
+                        IShare::TYPE_ROOM => [$file1RoomShareOwner],
1491
+                        IShare::TYPE_REMOTE => [$file1RemoteShareOwner],
1492
+                        IShare::TYPE_REMOTE_GROUP => [$file1RemoteGroupShareOwner],
1493
+                    ],
1494
+                ],
1495
+                [
1496
+                    IShare::TYPE_REMOTE => true,
1497
+                    IShare::TYPE_REMOTE_GROUP => true,
1498
+                ],
1499
+                [
1500
+                    $file1UserShareOwnerExpected,
1501
+                    $file1GroupShareOwnerExpected,
1502
+                    $file1LinkShareOwnerExpected,
1503
+                    $file1EmailShareOwnerExpected,
1504
+                    $file1CircleShareOwnerExpected,
1505
+                    $file1RoomShareOwnerExpected,
1506
+                    $file1RemoteShareOwnerExpected,
1507
+                    $file1RemoteGroupShareOwnerExpected,
1508
+                ]
1509
+            ],
1510
+        ];
1511
+
1512
+        return $data;
1513
+    }
1514
+
1515
+    private function mockSimpleNode(string $class, array $methods): MockObject {
1516
+        $node = $this->createMock($class);
1517
+        foreach ($methods as $method => $return) {
1518
+            if ($method === 'getDirectoryListing') {
1519
+                $return = array_map(
1520
+                    fn ($nodeParams) => $this->mockSimpleNode(...$nodeParams),
1521
+                    $return
1522
+                );
1523
+            }
1524
+            $node->method($method)->willReturn($return);
1525
+        }
1526
+        return $node;
1527
+    }
1528
+
1529
+    #[DataProvider('dataGetShares')]
1530
+    public function testGetShares(array $getSharesParameters, array $shares, array $extraShareTypes, array $expected): void {
1531
+        $shares = array_map(
1532
+            fn ($sharesByType) => array_map(
1533
+                fn ($shareList) => array_map(
1534
+                    function (array $shareParams): IShare {
1535
+                        $share = Server::get(IManager::class)->newShare();
1536
+                        $share->setShareType($shareParams['type'])
1537
+                            ->setSharedBy($shareParams['sharedBy'])
1538
+                            ->setShareOwner($shareParams['owner'])
1539
+                            ->setPermissions(Constants::PERMISSION_READ)
1540
+                            ->setId($shareParams['id']);
1541
+                        if (isset($shareParams['sharedWith'])) {
1542
+                            $share->setSharedWith($shareParams['sharedWith']);
1543
+                        }
1544
+                        if (isset($shareParams['sharedWithDisplayName'])) {
1545
+                            $share->setSharedWithDisplayName($shareParams['sharedWithDisplayName']);
1546
+                        }
1547
+                        if (isset($shareParams['sharedWithAvatar'])) {
1548
+                            $share->setSharedWithAvatar($shareParams['sharedWithAvatar']);
1549
+                        }
1550
+                        if (isset($shareParams['attributes'])) {
1551
+                            $shareAttributes = $this->createMock(IShareAttributes::class);
1552
+                            $shareAttributes->method('toArray')->willReturn($shareParams['attributes']);
1553
+                            $shareAttributes->method('getAttribute')->with('permissions', 'download')->willReturn(true);
1554
+                            $share->setAttributes($shareAttributes);
1555
+
1556
+                            $expects['attributes'] = \json_encode($shareParams['attributes']);
1557
+                        }
1558
+                        if (isset($shareParams['node'])) {
1559
+                            $node = $this->mockSimpleNode(...$shareParams['node']);
1560
+                            $share->setNode($node);
1561
+                        }
1562
+                        if (isset($shareParams['note'])) {
1563
+                            $share->setNote($shareParams['note']);
1564
+                        }
1565
+                        if (isset($shareParams['expirationDate'])) {
1566
+                            $share->setExpirationDate($shareParams['expirationDate']);
1567
+                        }
1568
+                        if (isset($shareParams['token'])) {
1569
+                            $share->setToken($shareParams['token']);
1570
+                        }
1571
+                        if (isset($shareParams['label'])) {
1572
+                            $share->setLabel($shareParams['label']);
1573
+                        }
1574
+                        if (isset($shareParams['password'])) {
1575
+                            $share->setPassword($shareParams['password']);
1576
+                        }
1577
+                        if (isset($shareParams['sendPasswordByTalk'])) {
1578
+                            $share->setSendPasswordByTalk($shareParams['sendPasswordByTalk']);
1579
+                        }
1580
+                        return $share;
1581
+                    },
1582
+                    $shareList
1583
+                ),
1584
+                $sharesByType
1585
+            ),
1586
+            $shares
1587
+        );
1588
+
1589
+        /** @var ShareAPIController&MockObject $ocs */
1590
+        $ocs = $this->getMockBuilder(ShareAPIController::class)
1591
+            ->setConstructorArgs([
1592
+                $this->appName,
1593
+                $this->request,
1594
+                $this->shareManager,
1595
+                $this->groupManager,
1596
+                $this->userManager,
1597
+                $this->rootFolder,
1598
+                $this->urlGenerator,
1599
+                $this->l,
1600
+                $this->config,
1601
+                $this->appConfig,
1602
+                $this->appManager,
1603
+                $this->serverContainer,
1604
+                $this->userStatusManager,
1605
+                $this->previewManager,
1606
+                $this->dateTimeZone,
1607
+                $this->logger,
1608
+                $this->factory,
1609
+                $this->mailer,
1610
+                $this->tagManager,
1611
+                $this->getEmailValidatorWithStrictEmailCheck(),
1612
+                $this->trustedServers,
1613
+                $this->currentUser,
1614
+            ])
1615
+            ->onlyMethods(['formatShare'])
1616
+            ->getMock();
1617
+
1618
+        $ocs->method('formatShare')
1619
+            ->willReturnCallback(
1620
+                function ($share) {
1621
+                    return [
1622
+                        'id' => $share->getId(),
1623
+                        'share_type' => $share->getShareType()
1624
+                    ];
1625
+                }
1626
+            );
1627
+
1628
+        $userFolder = $this->getMockBuilder(Folder::class)->getMock();
1629
+        $userFolder->method('get')
1630
+            ->with('path')
1631
+            ->willReturn($this->mockSimpleNode(...$getSharesParameters['node']));
1632
+
1633
+        $this->rootFolder->method('getUserFolder')
1634
+            ->with($this->currentUser)
1635
+            ->willReturn($userFolder);
1636
+
1637
+        $this->shareManager
1638
+            ->method('getSharesBy')
1639
+            ->willReturnCallback(
1640
+                function ($user, $shareType, $node) use ($shares) {
1641
+                    if (!isset($shares[$node->getName()]) || !isset($shares[$node->getName()][$shareType])) {
1642
+                        return [];
1643
+                    }
1644
+                    return $shares[$node->getName()][$shareType];
1645
+                }
1646
+            );
1647
+
1648
+        $this->shareManager
1649
+            ->method('outgoingServer2ServerSharesAllowed')
1650
+            ->willReturn($extraShareTypes[ISHARE::TYPE_REMOTE] ?? false);
1651
+
1652
+        $this->shareManager
1653
+            ->method('outgoingServer2ServerGroupSharesAllowed')
1654
+            ->willReturn($extraShareTypes[ISHARE::TYPE_REMOTE_GROUP] ?? false);
1655
+
1656
+        $this->groupManager
1657
+            ->method('isInGroup')
1658
+            ->willReturnCallback(
1659
+                function ($user, $group) {
1660
+                    return $group === 'currentUserGroup';
1661
+                }
1662
+            );
1663
+
1664
+        $result = $ocs->getShares(
1665
+            $getSharesParameters['sharedWithMe'] ?? 'false',
1666
+            $getSharesParameters['reshares'] ?? 'false',
1667
+            $getSharesParameters['subfiles'] ?? 'false',
1668
+            'path'
1669
+        );
1670
+
1671
+        $this->assertEquals($expected, $result->getData());
1672
+    }
1673
+
1674
+    public function testCanAccessShareAsOwner(): void {
1675
+        $share = $this->createMock(IShare::class);
1676
+        $share->method('getShareOwner')->willReturn($this->currentUser);
1677
+        $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1678
+    }
1679
+
1680
+    public function testCanAccessShareAsSharer(): void {
1681
+        $share = $this->createMock(IShare::class);
1682
+        $share->method('getSharedBy')->willReturn($this->currentUser);
1683
+        $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1684
+    }
1685
+
1686
+    public function testCanAccessShareAsSharee(): void {
1687
+        $share = $this->createMock(IShare::class);
1688
+        $share->method('getShareType')->willReturn(IShare::TYPE_USER);
1689
+        $share->method('getSharedWith')->willReturn($this->currentUser);
1690
+        $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1691
+    }
1692
+
1693
+    public function testCannotAccessLinkShare(): void {
1694
+        $share = $this->createMock(IShare::class);
1695
+        $share->method('getShareType')->willReturn(IShare::TYPE_LINK);
1696
+        $share->method('getNodeId')->willReturn(42);
1697
+
1698
+        $userFolder = $this->createMock(Folder::class);
1699
+        $this->rootFolder->method('getUserFolder')
1700
+            ->with($this->currentUser)
1701
+            ->willReturn($userFolder);
1702
+
1703
+        $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1704
+    }
1705
+
1706
+    #[DataProvider('dataCanAccessShareWithPermissions')]
1707
+    public function testCanAccessShareWithPermissions(int $permissions, bool $expected): void {
1708
+        $share = $this->createMock(IShare::class);
1709
+        $share->method('getShareType')->willReturn(IShare::TYPE_USER);
1710
+        $share->method('getSharedWith')->willReturn($this->createMock(IUser::class));
1711
+        $share->method('getNodeId')->willReturn(42);
1712
+
1713
+        $file = $this->createMock(File::class);
1714
+
1715
+        $userFolder = $this->getMockBuilder(Folder::class)->getMock();
1716
+        $userFolder->method('getFirstNodeById')
1717
+            ->with($share->getNodeId())
1718
+            ->willReturn($file);
1719
+        $userFolder->method('getById')
1720
+            ->with($share->getNodeId())
1721
+            ->willReturn([$file]);
1722
+        $this->rootFolder->method('getUserFolder')
1723
+            ->with($this->currentUser)
1724
+            ->willReturn($userFolder);
1725
+
1726
+        $file->method('getPermissions')
1727
+            ->willReturn($permissions);
1728
+
1729
+        if ($expected) {
1730
+            $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1731
+        } else {
1732
+            $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1733
+        }
1734
+    }
1735
+
1736
+    public static function dataCanAccessShareWithPermissions(): array {
1737
+        return [
1738
+            [Constants::PERMISSION_SHARE, true],
1739
+            [Constants::PERMISSION_READ, false],
1740
+            [Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, true],
1741
+        ];
1742
+    }
1743
+
1744
+    #[DataProvider('dataCanAccessShareAsGroupMember')]
1745
+    public function testCanAccessShareAsGroupMember(string $group, bool $expected): void {
1746
+        $share = $this->createMock(IShare::class);
1747
+        $share->method('getShareType')->willReturn(IShare::TYPE_GROUP);
1748
+        $share->method('getSharedWith')->willReturn($group);
1749
+        $share->method('getNodeId')->willReturn(42);
1750
+
1751
+        $file = $this->createMock(File::class);
1752
+
1753
+        $userFolder = $this->createMock(Folder::class);
1754
+        $userFolder->method('getFirstNodeById')
1755
+            ->with($share->getNodeId())
1756
+            ->willReturn($file);
1757
+        $userFolder->method('getById')
1758
+            ->with($share->getNodeId())
1759
+            ->willReturn([$file]);
1760
+        $this->rootFolder->method('getUserFolder')
1761
+            ->with($this->currentUser)
1762
+            ->willReturn($userFolder);
1763
+
1764
+        $user = $this->createMock(IUser::class);
1765
+        $this->userManager->method('get')
1766
+            ->with($this->currentUser)
1767
+            ->willReturn($user);
1768
+
1769
+        $group = $this->createMock(IGroup::class);
1770
+        $group->method('inGroup')->with($user)->willReturn(true);
1771
+        $group2 = $this->createMock(IGroup::class);
1772
+        $group2->method('inGroup')->with($user)->willReturn(false);
1773
+
1774
+        $this->groupManager->method('get')->willReturnMap([
1775
+            ['group', $group],
1776
+            ['group2', $group2],
1777
+            ['group-null', null],
1778
+        ]);
1779
+
1780
+        if ($expected) {
1781
+            $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1782
+        } else {
1783
+            $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1784
+        }
1785
+    }
1786
+
1787
+    public static function dataCanAccessShareAsGroupMember(): array {
1788
+        return [
1789
+            ['group', true],
1790
+            ['group2', false],
1791
+            ['group-null', false],
1792
+        ];
1793
+    }
1794
+
1795
+    public static function dataCanAccessRoomShare(): array {
1796
+        return [
1797
+            [false, false, false],
1798
+            [false, false, true],
1799
+            [true, true, true],
1800
+            [false, true, false],
1801
+        ];
1802
+    }
1803
+
1804
+    #[DataProvider('dataCanAccessRoomShare')]
1805
+    public function testCanAccessRoomShare(
1806
+        bool $expected,
1807
+        bool $helperAvailable,
1808
+        bool $canAccessShareByHelper,
1809
+    ): void {
1810
+        $share = $this->createMock(IShare::class);
1811
+        $share->method('getShareType')->willReturn(IShare::TYPE_ROOM);
1812
+        $share->method('getSharedWith')->willReturn('recipientRoom');
1813
+
1814
+        $userFolder = $this->getMockBuilder(Folder::class)->getMock();
1815
+        $this->rootFolder->method('getUserFolder')
1816
+            ->with($this->currentUser)
1817
+            ->willReturn($userFolder);
1818
+
1819
+        $userFolder->method('getById')
1820
+            ->with($share->getNodeId())
1821
+            ->willReturn([$share->getNode()]);
1822
+
1823
+        if (!$helperAvailable) {
1824
+            $this->appManager->method('isEnabledForUser')
1825
+                ->with('spreed')
1826
+                ->willReturn(false);
1827
+        } else {
1828
+            $this->appManager->method('isEnabledForUser')
1829
+                ->with('spreed')
1830
+                ->willReturn(true);
1831
+
1832
+            // This is not possible anymore with PHPUnit 10+
1833
+            // as `setMethods` was removed and now real reflection is used, thus the class needs to exist.
1834
+            // $helper = $this->getMockBuilder('\OCA\Talk\Share\Helper\ShareAPIController')
1835
+            $helper = $this->getMockBuilder(\stdClass::class)
1836
+                ->addMethods(['canAccessShare'])
1837
+                ->getMock();
1838
+            $helper->method('canAccessShare')
1839
+                ->with($share, $this->currentUser)
1840
+                ->willReturn($canAccessShareByHelper);
1841
+
1842
+            $this->serverContainer->method('get')
1843
+                ->with('\OCA\Talk\Share\Helper\ShareAPIController')
1844
+                ->willReturn($helper);
1845
+        }
1846
+
1847
+        $this->assertEquals($expected, $this->invokePrivate($this->ocs, 'canAccessShare', [$share]));
1848
+    }
1849
+
1850
+
1851
+    public function testCreateShareNoPath(): void {
1852
+        $this->expectException(OCSNotFoundException::class);
1853
+        $this->expectExceptionMessage('Please specify a file or folder path');
1854
+
1855
+        $this->ocs->createShare();
1856
+    }
1857
+
1858
+
1859
+    public function testCreateShareInvalidPath(): void {
1860
+        $this->expectException(OCSNotFoundException::class);
1861
+        $this->expectExceptionMessage('Wrong path, file/folder does not exist');
1862
+
1863
+        $userFolder = $this->getMockBuilder(Folder::class)->getMock();
1864
+        $this->rootFolder->expects($this->once())
1865
+            ->method('getUserFolder')
1866
+            ->with('currentUser')
1867
+            ->willReturn($userFolder);
1868
+
1869
+        $userFolder->expects($this->once())
1870
+            ->method('get')
1871
+            ->with('invalid-path')
1872
+            ->willThrowException(new NotFoundException());
1873
+
1874
+        $this->ocs->createShare('invalid-path');
1875
+    }
1876
+
1877
+    public function testCreateShareInvalidShareType(): void {
1878
+        $this->expectException(OCSBadRequestException::class);
1879
+        $this->expectExceptionMessage('Unknown share type');
1880
+
1881
+        $share = $this->newShare();
1882
+        $this->shareManager->method('newShare')->willReturn($share);
1883
+
1884
+        [$userFolder, $file] = $this->getNonSharedUserFile();
1885
+        $this->rootFolder->expects($this->atLeastOnce())
1886
+            ->method('getUserFolder')
1887
+            ->with('currentUser')
1888
+            ->willReturn($userFolder);
1889
+
1890
+        $userFolder->expects($this->atLeastOnce())
1891
+            ->method('get')
1892
+            ->with('valid-path')
1893
+            ->willReturn($file);
1894
+        $userFolder->method('getById')
1895
+            ->willReturn([]);
1896
+
1897
+        $file->expects($this->once())
1898
+            ->method('lock')
1899
+            ->with(ILockingProvider::LOCK_SHARED);
1900
+
1901
+        $this->ocs->createShare('valid-path', 31);
1902
+    }
1903
+
1904
+    public function testCreateShareUserNoShareWith(): void {
1905
+        $this->expectException(OCSNotFoundException::class);
1906
+        $this->expectExceptionMessage('Please specify a valid account to share with');
1907
+
1908
+        $share = $this->newShare();
1909
+        $this->shareManager->method('newShare')->willReturn($share);
1910
+
1911
+        [$userFolder, $path] = $this->getNonSharedUserFile();
1912
+        $this->rootFolder->method('getUserFolder')
1913
+            ->with('currentUser')
1914
+            ->willReturn($userFolder);
1915
+
1916
+        $userFolder->expects($this->once())
1917
+            ->method('get')
1918
+            ->with('valid-path')
1919
+            ->willReturn($path);
1920
+        $userFolder->method('getById')
1921
+            ->willReturn([]);
1922
+
1923
+        $path->expects($this->once())
1924
+            ->method('lock')
1925
+            ->with(ILockingProvider::LOCK_SHARED);
1926
+
1927
+        $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_USER);
1928
+    }
1929
+
1930
+
1931
+    public function testCreateShareUserNoValidShareWith(): void {
1932
+        $this->expectException(OCSNotFoundException::class);
1933
+        $this->expectExceptionMessage('Please specify a valid account to share with');
1934
+
1935
+        $share = $this->newShare();
1936
+        $this->shareManager->method('newShare')->willReturn($share);
1937
+
1938
+        [$userFolder, $path] = $this->getNonSharedUserFile();
1939
+        $this->rootFolder->method('getUserFolder')
1940
+            ->with('currentUser')
1941
+            ->willReturn($userFolder);
1942
+
1943
+        $userFolder->expects($this->once())
1944
+            ->method('get')
1945
+            ->with('valid-path')
1946
+            ->willReturn($path);
1947
+        $userFolder->method('getById')
1948
+            ->willReturn([]);
1949
+        $path->expects($this->once())
1950
+            ->method('lock')
1951
+            ->with(ILockingProvider::LOCK_SHARED);
1952
+        $this->userManager->method('userExists')
1953
+            ->with('invalidUser')
1954
+            ->willReturn(false);
1955
+
1956
+        $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_USER, 'invalidUser');
1957
+    }
1958
+
1959
+    public function testCreateShareUser(): void {
1960
+        $share = $this->newShare();
1961
+        $this->shareManager->method('newShare')->willReturn($share);
1962
+
1963
+        /** @var ShareAPIController $ocs */
1964
+        $ocs = $this->getMockBuilder(ShareAPIController::class)
1965
+            ->setConstructorArgs([
1966
+                $this->appName,
1967
+                $this->request,
1968
+                $this->shareManager,
1969
+                $this->groupManager,
1970
+                $this->userManager,
1971
+                $this->rootFolder,
1972
+                $this->urlGenerator,
1973
+                $this->l,
1974
+                $this->config,
1975
+                $this->appConfig,
1976
+                $this->appManager,
1977
+                $this->serverContainer,
1978
+                $this->userStatusManager,
1979
+                $this->previewManager,
1980
+                $this->dateTimeZone,
1981
+                $this->logger,
1982
+                $this->factory,
1983
+                $this->mailer,
1984
+                $this->tagManager,
1985
+                $this->getEmailValidatorWithStrictEmailCheck(),
1986
+                $this->trustedServers,
1987
+                $this->currentUser,
1988
+            ])->onlyMethods(['formatShare'])
1989
+            ->getMock();
1990
+
1991
+        [$userFolder, $path] = $this->getNonSharedUserFile();
1992
+        $this->rootFolder->expects($this->exactly(2))
1993
+            ->method('getUserFolder')
1994
+            ->with('currentUser')
1995
+            ->willReturn($userFolder);
1996
+
1997
+        $userFolder->expects($this->once())
1998
+            ->method('get')
1999
+            ->with('valid-path')
2000
+            ->willReturn($path);
2001
+        $userFolder->method('getById')
2002
+            ->willReturn([]);
2003
+
2004
+        $this->userManager->method('userExists')->with('validUser')->willReturn(true);
2005
+
2006
+        $path->expects($this->once())
2007
+            ->method('lock')
2008
+            ->with(ILockingProvider::LOCK_SHARED);
2009
+
2010
+        $this->shareManager->method('createShare')
2011
+            ->with($this->callback(function (IShare $share) use ($path) {
2012
+                return $share->getNode() === $path
2013
+                    && $share->getPermissions() === (
2014
+                        Constants::PERMISSION_ALL
2015
+                        & ~Constants::PERMISSION_DELETE
2016
+                        & ~Constants::PERMISSION_CREATE
2017
+                    )
2018
+                    && $share->getShareType() === IShare::TYPE_USER
2019
+                    && $share->getSharedWith() === 'validUser'
2020
+                    && $share->getSharedBy() === 'currentUser';
2021
+            }))
2022
+            ->willReturnArgument(0);
2023
+
2024
+        $expected = new DataResponse([]);
2025
+        $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_USER, 'validUser');
2026
+
2027
+        $this->assertInstanceOf(get_class($expected), $result);
2028
+        $this->assertEquals($expected->getData(), $result->getData());
2029
+    }
2030
+
2031
+
2032
+    public function testCreateShareGroupNoValidShareWith(): void {
2033
+        $this->expectException(OCSNotFoundException::class);
2034
+        $this->expectExceptionMessage('Please specify a valid group');
2035
+
2036
+        $share = $this->newShare();
2037
+        $this->shareManager->method('newShare')->willReturn($share);
2038
+        $this->shareManager->method('createShare')->willReturnArgument(0);
2039
+        $this->shareManager->method('allowGroupSharing')->willReturn(true);
2040
+
2041
+        [$userFolder, $path] = $this->getNonSharedUserFile();
2042
+        $this->rootFolder->method('getUserFolder')
2043
+            ->with('currentUser')
2044
+            ->willReturn($userFolder);
2045
+
2046
+        $userFolder->expects($this->once())
2047
+            ->method('get')
2048
+            ->with('valid-path')
2049
+            ->willReturn($path);
2050
+        $userFolder->method('getById')
2051
+            ->willReturn([]);
2052
+
2053
+        $path->expects($this->once())
2054
+            ->method('lock')
2055
+            ->with(ILockingProvider::LOCK_SHARED);
2056
+
2057
+        $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_GROUP, 'invalidGroup');
2058
+    }
2059
+
2060
+    public function testCreateShareGroup(): void {
2061
+        $share = $this->newShare();
2062
+        $this->shareManager->method('newShare')->willReturn($share);
2063
+
2064
+        /** @var ShareAPIController&MockObject $ocs */
2065
+        $ocs = $this->getMockBuilder(ShareAPIController::class)
2066
+            ->setConstructorArgs([
2067
+                $this->appName,
2068
+                $this->request,
2069
+                $this->shareManager,
2070
+                $this->groupManager,
2071
+                $this->userManager,
2072
+                $this->rootFolder,
2073
+                $this->urlGenerator,
2074
+                $this->l,
2075
+                $this->config,
2076
+                $this->appConfig,
2077
+                $this->appManager,
2078
+                $this->serverContainer,
2079
+                $this->userStatusManager,
2080
+                $this->previewManager,
2081
+                $this->dateTimeZone,
2082
+                $this->logger,
2083
+                $this->factory,
2084
+                $this->mailer,
2085
+                $this->tagManager,
2086
+                $this->getEmailValidatorWithStrictEmailCheck(),
2087
+                $this->trustedServers,
2088
+                $this->currentUser,
2089
+            ])->onlyMethods(['formatShare'])
2090
+            ->getMock();
2091
+
2092
+        $this->request
2093
+            ->method('getParam')
2094
+            ->willReturnMap([
2095
+                ['path', null, 'valid-path'],
2096
+                ['permissions', null, Constants::PERMISSION_ALL],
2097
+                ['shareType', '-1', IShare::TYPE_GROUP],
2098
+                ['shareWith', null, 'validGroup'],
2099
+            ]);
2100
+
2101
+        [$userFolder, $path] = $this->getNonSharedUserFolder();
2102
+        $this->rootFolder->expects($this->exactly(2))
2103
+            ->method('getUserFolder')
2104
+            ->with('currentUser')
2105
+            ->willReturn($userFolder);
2106
+
2107
+        $userFolder->expects($this->once())
2108
+            ->method('get')
2109
+            ->with('valid-path')
2110
+            ->willReturn($path);
2111
+        $userFolder->method('getById')
2112
+            ->willReturn([]);
2113
+
2114
+        $this->groupManager->method('groupExists')->with('validGroup')->willReturn(true);
2115
+
2116
+        $this->shareManager->expects($this->once())
2117
+            ->method('allowGroupSharing')
2118
+            ->willReturn(true);
2119
+
2120
+        $path->expects($this->once())
2121
+            ->method('lock')
2122
+            ->with(ILockingProvider::LOCK_SHARED);
2123
+
2124
+        $this->shareManager->method('createShare')
2125
+            ->with($this->callback(function (IShare $share) use ($path) {
2126
+                return $share->getNode() === $path
2127
+                && $share->getPermissions() === Constants::PERMISSION_ALL
2128
+                && $share->getShareType() === IShare::TYPE_GROUP
2129
+                && $share->getSharedWith() === 'validGroup'
2130
+                && $share->getSharedBy() === 'currentUser';
2131
+            }))
2132
+            ->willReturnArgument(0);
2133
+
2134
+        $expected = new DataResponse([]);
2135
+        $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_GROUP, 'validGroup');
2136
+
2137
+        $this->assertInstanceOf(get_class($expected), $result);
2138
+        $this->assertEquals($expected->getData(), $result->getData());
2139
+    }
2140
+
2141
+
2142
+    public function testCreateShareGroupNotAllowed(): void {
2143
+        $this->expectException(OCSNotFoundException::class);
2144
+        $this->expectExceptionMessage('Group sharing is disabled by the administrator');
2145
+
2146
+        $share = $this->newShare();
2147
+        $this->shareManager->method('newShare')->willReturn($share);
2148
+
2149
+        [$userFolder, $path] = $this->getNonSharedUserFolder();
2150
+        $this->rootFolder->method('getUserFolder')
2151
+            ->with('currentUser')
2152
+            ->willReturn($userFolder);
2153
+
2154
+        $userFolder->expects($this->once())
2155
+            ->method('get')
2156
+            ->with('valid-path')
2157
+            ->willReturn($path);
2158
+        $userFolder->method('getById')
2159
+            ->willReturn([]);
2160
+
2161
+        $this->groupManager->method('groupExists')->with('validGroup')->willReturn(true);
2162
+
2163
+        $this->shareManager->expects($this->once())
2164
+            ->method('allowGroupSharing')
2165
+            ->willReturn(false);
2166
+
2167
+        $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_GROUP, 'invalidGroup');
2168
+    }
2169
+
2170
+
2171
+    public function testCreateShareLinkNoLinksAllowed(): void {
2172
+        $this->expectException(OCSNotFoundException::class);
2173
+        $this->expectExceptionMessage('Public link sharing is disabled by the administrator');
2174
+
2175
+        $this->request
2176
+            ->method('getParam')
2177
+            ->willReturnMap([
2178
+                ['path', null, 'valid-path'],
2179
+                ['shareType', '-1', IShare::TYPE_LINK],
2180
+            ]);
2181
+
2182
+        $path = $this->getMockBuilder(Folder::class)->getMock();
2183
+        $path->method('getId')->willReturn(42);
2184
+        $storage = $this->createMock(IStorage::class);
2185
+        $storage->method('instanceOfStorage')
2186
+            ->willReturnMap([
2187
+                ['OCA\Files_Sharing\External\Storage', false],
2188
+                ['OCA\Files_Sharing\SharedStorage', false],
2189
+            ]);
2190
+        $path->method('getStorage')->willReturn($storage);
2191
+        $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2192
+        $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2193
+        $this->rootFolder->method('getById')
2194
+            ->willReturn([]);
2195
+
2196
+        $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2197
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2198
+        $this->shareManager->method('shareApiAllowLinks')->willReturn(false);
2199
+
2200
+        $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK);
2201
+    }
2202
+
2203
+
2204
+    public function testCreateShareLinkNoPublicUpload(): void {
2205
+        $this->expectException(OCSForbiddenException::class);
2206
+        $this->expectExceptionMessage('Public upload disabled by the administrator');
2207
+
2208
+        $path = $this->getMockBuilder(Folder::class)->getMock();
2209
+        $path->method('getId')->willReturn(42);
2210
+        $storage = $this->createMock(IStorage::class);
2211
+        $storage->method('instanceOfStorage')
2212
+            ->willReturnMap([
2213
+                ['OCA\Files_Sharing\External\Storage', false],
2214
+                ['OCA\Files_Sharing\SharedStorage', false],
2215
+            ]);
2216
+        $path->method('getStorage')->willReturn($storage);
2217
+        $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2218
+        $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2219
+        $this->rootFolder->method('getById')
2220
+            ->willReturn([]);
2221
+
2222
+        $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2223
+        $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2224
+
2225
+        $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true');
2226
+    }
2227
+
2228
+
2229
+    public function testCreateShareLinkPublicUploadFile(): void {
2230
+        $this->expectException(OCSBadRequestException::class);
2231
+        $this->expectExceptionMessage('Public upload is only possible for publicly shared folders');
2232
+
2233
+        $storage = $this->createMock(IStorage::class);
2234
+        $storage->method('instanceOfStorage')
2235
+            ->willReturnMap([
2236
+                ['OCA\Files_Sharing\External\Storage', false],
2237
+                ['OCA\Files_Sharing\SharedStorage', false],
2238
+            ]);
2239
+
2240
+        $file = $this->createMock(File::class);
2241
+        $file->method('getId')->willReturn(42);
2242
+        $file->method('getStorage')->willReturn($storage);
2243
+
2244
+        $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2245
+        $this->rootFolder->method('get')->with('valid-path')->willReturn($file);
2246
+        $this->rootFolder->method('getById')
2247
+            ->willReturn([]);
2248
+
2249
+        $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2250
+        $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2251
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2252
+
2253
+        $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true');
2254
+    }
2255
+
2256
+    public function testCreateShareLinkPublicUploadFolder(): void {
2257
+        $ocs = $this->mockFormatShare();
2258
+
2259
+        $path = $this->getMockBuilder(Folder::class)->getMock();
2260
+        $path->method('getId')->willReturn(1);
2261
+        $storage = $this->createMock(IStorage::class);
2262
+        $storage->method('instanceOfStorage')
2263
+            ->willReturnMap([
2264
+                ['OCA\Files_Sharing\External\Storage', false],
2265
+                ['OCA\Files_Sharing\SharedStorage', false],
2266
+            ]);
2267
+        $path->method('getStorage')->willReturn($storage);
2268
+        $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2269
+        $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2270
+        $this->rootFolder->method('getById')
2271
+            ->willReturn([]);
2272
+
2273
+        $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2274
+        $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2275
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2276
+
2277
+        $this->shareManager->expects($this->once())->method('createShare')->with(
2278
+            $this->callback(function (IShare $share) use ($path) {
2279
+                return $share->getNode() === $path
2280
+                    && $share->getShareType() === IShare::TYPE_LINK
2281
+                    && $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
2282
+                    && $share->getSharedBy() === 'currentUser'
2283
+                    && $share->getPassword() === null
2284
+                    && $share->getExpirationDate() === null;
2285
+            })
2286
+        )->willReturnArgument(0);
2287
+
2288
+        $expected = new DataResponse([]);
2289
+        $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true', '', null, '');
2290
+
2291
+        $this->assertInstanceOf(get_class($expected), $result);
2292
+        $this->assertEquals($expected->getData(), $result->getData());
2293
+    }
2294
+
2295
+    public function testCreateShareLinkPassword(): void {
2296
+        $ocs = $this->mockFormatShare();
2297
+
2298
+        $path = $this->getMockBuilder(Folder::class)->getMock();
2299
+        $path->method('getId')->willReturn(42);
2300
+        $storage = $this->createMock(IStorage::class);
2301
+        $storage->method('instanceOfStorage')
2302
+            ->willReturnMap([
2303
+                ['OCA\Files_Sharing\External\Storage', false],
2304
+                ['OCA\Files_Sharing\SharedStorage', false],
2305
+            ]);
2306
+        $path->method('getStorage')->willReturn($storage);
2307
+        $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2308
+        $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2309
+        $this->rootFolder->method('getById')
2310
+            ->willReturn([]);
2311
+
2312
+        $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2313
+        $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2314
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2315
+
2316
+        $this->shareManager->expects($this->once())->method('createShare')->with(
2317
+            $this->callback(function (IShare $share) use ($path) {
2318
+                return $share->getNode() === $path
2319
+                && $share->getShareType() === IShare::TYPE_LINK
2320
+                && $share->getPermissions() === Constants::PERMISSION_READ // publicUpload was set to false
2321
+                && $share->getSharedBy() === 'currentUser'
2322
+                && $share->getPassword() === 'password'
2323
+                && $share->getExpirationDate() === null;
2324
+            })
2325
+        )->willReturnArgument(0);
2326
+
2327
+        $expected = new DataResponse([]);
2328
+        $result = $ocs->createShare('valid-path', Constants::PERMISSION_READ, IShare::TYPE_LINK, null, 'false', 'password', null, '');
2329
+
2330
+        $this->assertInstanceOf(get_class($expected), $result);
2331
+        $this->assertEquals($expected->getData(), $result->getData());
2332
+    }
2333
+
2334
+    public function testCreateShareLinkSendPasswordByTalk(): void {
2335
+        $ocs = $this->mockFormatShare();
2336
+
2337
+        $path = $this->getMockBuilder(Folder::class)->getMock();
2338
+        $path->method('getId')->willReturn(42);
2339
+        $storage = $this->createMock(IStorage::class);
2340
+        $storage->method('instanceOfStorage')
2341
+            ->willReturnMap([
2342
+                ['OCA\Files_Sharing\External\Storage', false],
2343
+                ['OCA\Files_Sharing\SharedStorage', false],
2344
+            ]);
2345
+        $path->method('getStorage')->willReturn($storage);
2346
+        $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2347
+        $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2348
+        $this->rootFolder->method('getById')
2349
+            ->willReturn([]);
2350
+
2351
+        $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2352
+        $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2353
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2354
+
2355
+        $this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(true);
2356
+
2357
+        $this->shareManager->expects($this->once())->method('createShare')->with(
2358
+            $this->callback(function (IShare $share) use ($path) {
2359
+                return $share->getNode() === $path
2360
+                && $share->getShareType() === IShare::TYPE_LINK
2361
+                && $share->getPermissions() === (Constants::PERMISSION_ALL & ~(Constants::PERMISSION_SHARE))
2362
+                && $share->getSharedBy() === 'currentUser'
2363
+                && $share->getPassword() === 'password'
2364
+                && $share->getSendPasswordByTalk() === true
2365
+                && $share->getExpirationDate() === null;
2366
+            })
2367
+        )->willReturnArgument(0);
2368
+
2369
+        $expected = new DataResponse([]);
2370
+        $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true', 'password', 'true', '');
2371
+
2372
+        $this->assertInstanceOf(get_class($expected), $result);
2373
+        $this->assertEquals($expected->getData(), $result->getData());
2374
+    }
2375
+
2376
+
2377
+    public function testCreateShareLinkSendPasswordByTalkWithTalkDisabled(): void {
2378
+        $this->expectException(OCSForbiddenException::class);
2379
+        $this->expectExceptionMessage('Sharing valid-path sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled');
2380
+
2381
+        $ocs = $this->mockFormatShare();
2382
+
2383
+        $path = $this->getMockBuilder(Folder::class)->getMock();
2384
+        $path->method('getId')->willReturn(42);
2385
+        $storage = $this->createMock(IStorage::class);
2386
+        $storage->method('instanceOfStorage')
2387
+            ->willReturnMap([
2388
+                ['OCA\Files_Sharing\External\Storage', false],
2389
+                ['OCA\Files_Sharing\SharedStorage', false],
2390
+            ]);
2391
+        $path->method('getStorage')->willReturn($storage);
2392
+        $path->method('getPath')->willReturn('valid-path');
2393
+        $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2394
+        $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2395
+        $this->rootFolder->method('getById')
2396
+            ->willReturn([]);
2397
+
2398
+        $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2399
+        $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2400
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2401
+
2402
+        $this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(false);
2403
+
2404
+        $this->shareManager->expects($this->never())->method('createShare');
2405
+
2406
+        $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', 'password', 'true', '');
2407
+    }
2408
+
2409
+    public function testCreateShareValidExpireDate(): void {
2410
+        $ocs = $this->mockFormatShare();
2411
+
2412
+        $this->request
2413
+            ->method('getParam')
2414
+            ->willReturnMap([
2415
+                ['path', null, 'valid-path'],
2416
+                ['shareType', '-1', IShare::TYPE_LINK],
2417
+                ['publicUpload', null, 'false'],
2418
+                ['expireDate', '', '2000-01-01'],
2419
+                ['password', '', ''],
2420
+            ]);
2421
+
2422
+        $path = $this->getMockBuilder(Folder::class)->getMock();
2423
+        $path->method('getId')->willReturn(42);
2424
+        $storage = $this->createMock(IStorage::class);
2425
+        $storage->method('instanceOfStorage')
2426
+            ->willReturnMap([
2427
+                ['OCA\Files_Sharing\External\Storage', false],
2428
+                ['OCA\Files_Sharing\SharedStorage', false],
2429
+            ]);
2430
+        $path->method('getStorage')->willReturn($storage);
2431
+        $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2432
+        $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2433
+        $this->rootFolder->method('getById')
2434
+            ->willReturn([]);
2435
+
2436
+        $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2437
+        $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2438
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2439
+
2440
+        $this->shareManager->expects($this->once())->method('createShare')->with(
2441
+            $this->callback(function (IShare $share) use ($path) {
2442
+                $date = new \DateTime('2000-01-01');
2443
+                $date->setTime(0, 0, 0);
2444
+
2445
+                return $share->getNode() === $path
2446
+                && $share->getShareType() === IShare::TYPE_LINK
2447
+                && $share->getPermissions() === Constants::PERMISSION_READ | Constants::PERMISSION_SHARE
2448
+                && $share->getSharedBy() === 'currentUser'
2449
+                && $share->getPassword() === null
2450
+                && $share->getExpirationDate() == $date;
2451
+            })
2452
+        )->willReturnArgument(0);
2453
+
2454
+        $expected = new DataResponse([]);
2455
+        $result = $ocs->createShare('valid-path', null, IShare::TYPE_LINK, null, 'false', '', null, '2000-01-01');
2456
+
2457
+        $this->assertInstanceOf(get_class($expected), $result);
2458
+        $this->assertEquals($expected->getData(), $result->getData());
2459
+    }
2460
+
2461
+
2462
+    public function testCreateShareInvalidExpireDate(): void {
2463
+        $this->expectException(OCSNotFoundException::class);
2464
+        $this->expectExceptionMessage('Invalid date. Format must be YYYY-MM-DD');
2465
+
2466
+        $ocs = $this->mockFormatShare();
2467
+
2468
+        $path = $this->getMockBuilder(Folder::class)->getMock();
2469
+        $path->method('getId')->willReturn(42);
2470
+        $storage = $this->createMock(IStorage::class);
2471
+        $storage->method('instanceOfStorage')
2472
+            ->willReturnMap([
2473
+                ['OCA\Files_Sharing\External\Storage', false],
2474
+                ['OCA\Files_Sharing\SharedStorage', false],
2475
+            ]);
2476
+        $path->method('getStorage')->willReturn($storage);
2477
+        $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf();
2478
+        $this->rootFolder->method('get')->with('valid-path')->willReturn($path);
2479
+        $this->rootFolder->method('getById')
2480
+            ->willReturn([]);
2481
+
2482
+        $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare());
2483
+        $this->shareManager->method('shareApiAllowLinks')->willReturn(true);
2484
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
2485
+
2486
+        $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, 'a1b2d3');
2487
+    }
2488
+
2489
+    public function testCreateShareRemote(): void {
2490
+        $share = $this->newShare();
2491
+        $this->shareManager->method('newShare')->willReturn($share);
2492
+
2493
+        /** @var ShareAPIController $ocs */
2494
+        $ocs = $this->getMockBuilder(ShareAPIController::class)
2495
+            ->setConstructorArgs([
2496
+                $this->appName,
2497
+                $this->request,
2498
+                $this->shareManager,
2499
+                $this->groupManager,
2500
+                $this->userManager,
2501
+                $this->rootFolder,
2502
+                $this->urlGenerator,
2503
+                $this->l,
2504
+                $this->config,
2505
+                $this->appConfig,
2506
+                $this->appManager,
2507
+                $this->serverContainer,
2508
+                $this->userStatusManager,
2509
+                $this->previewManager,
2510
+                $this->dateTimeZone,
2511
+                $this->logger,
2512
+                $this->factory,
2513
+                $this->mailer,
2514
+                $this->tagManager,
2515
+                $this->getEmailValidatorWithStrictEmailCheck(),
2516
+                $this->trustedServers,
2517
+                $this->currentUser,
2518
+            ])->onlyMethods(['formatShare'])
2519
+            ->getMock();
2520
+
2521
+        [$userFolder, $path] = $this->getNonSharedUserFile();
2522
+        $this->rootFolder->expects($this->exactly(2))
2523
+            ->method('getUserFolder')
2524
+            ->with('currentUser')
2525
+            ->willReturn($userFolder);
2526
+
2527
+        $userFolder->expects($this->once())
2528
+            ->method('get')
2529
+            ->with('valid-path')
2530
+            ->willReturn($path);
2531
+        $userFolder->method('getById')
2532
+            ->willReturn([]);
2533
+
2534
+        $this->userManager->method('userExists')->with('validUser')->willReturn(true);
2535
+
2536
+        $path->expects($this->once())
2537
+            ->method('lock')
2538
+            ->with(ILockingProvider::LOCK_SHARED);
2539
+
2540
+        $this->shareManager->method('createShare')
2541
+            ->with($this->callback(function (IShare $share) use ($path) {
2542
+                return $share->getNode() === $path
2543
+                    && $share->getPermissions() === (
2544
+                        Constants::PERMISSION_ALL
2545
+                        & ~Constants::PERMISSION_DELETE
2546
+                        & ~Constants::PERMISSION_CREATE
2547
+                    )
2548
+                    && $share->getShareType() === IShare::TYPE_REMOTE
2549
+                    && $share->getSharedWith() === '[email protected]'
2550
+                    && $share->getSharedBy() === 'currentUser';
2551
+            }))
2552
+            ->willReturnArgument(0);
2553
+
2554
+        $this->shareManager->method('outgoingServer2ServerSharesAllowed')->willReturn(true);
2555
+
2556
+        $expected = new DataResponse([]);
2557
+        $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_REMOTE, '[email protected]');
2558
+
2559
+        $this->assertInstanceOf(get_class($expected), $result);
2560
+        $this->assertEquals($expected->getData(), $result->getData());
2561
+    }
2562
+
2563
+    public function testCreateShareRemoteGroup(): void {
2564
+        $share = $this->newShare();
2565
+        $this->shareManager->method('newShare')->willReturn($share);
2566
+
2567
+        /** @var ShareAPIController $ocs */
2568
+        $ocs = $this->getMockBuilder(ShareAPIController::class)
2569
+            ->setConstructorArgs([
2570
+                $this->appName,
2571
+                $this->request,
2572
+                $this->shareManager,
2573
+                $this->groupManager,
2574
+                $this->userManager,
2575
+                $this->rootFolder,
2576
+                $this->urlGenerator,
2577
+                $this->l,
2578
+                $this->config,
2579
+                $this->appConfig,
2580
+                $this->appManager,
2581
+                $this->serverContainer,
2582
+                $this->userStatusManager,
2583
+                $this->previewManager,
2584
+                $this->dateTimeZone,
2585
+                $this->logger,
2586
+                $this->factory,
2587
+                $this->mailer,
2588
+                $this->tagManager,
2589
+                $this->getEmailValidatorWithStrictEmailCheck(),
2590
+                $this->trustedServers,
2591
+                $this->currentUser,
2592
+            ])->onlyMethods(['formatShare'])
2593
+            ->getMock();
2594
+
2595
+        [$userFolder, $path] = $this->getNonSharedUserFile();
2596
+        $this->rootFolder->expects($this->exactly(2))
2597
+            ->method('getUserFolder')
2598
+            ->with('currentUser')
2599
+            ->willReturn($userFolder);
2600
+
2601
+        $userFolder->expects($this->once())
2602
+            ->method('get')
2603
+            ->with('valid-path')
2604
+            ->willReturn($path);
2605
+        $userFolder->method('getById')
2606
+            ->willReturn([]);
2607
+
2608
+        $this->userManager->method('userExists')->with('validUser')->willReturn(true);
2609
+
2610
+        $path->expects($this->once())
2611
+            ->method('lock')
2612
+            ->with(ILockingProvider::LOCK_SHARED);
2613
+
2614
+        $this->shareManager->method('createShare')
2615
+            ->with($this->callback(function (IShare $share) use ($path) {
2616
+                return $share->getNode() === $path
2617
+                    && $share->getPermissions() === (
2618
+                        Constants::PERMISSION_ALL
2619
+                        & ~Constants::PERMISSION_DELETE
2620
+                        & ~Constants::PERMISSION_CREATE
2621
+                    )
2622
+                    && $share->getShareType() === IShare::TYPE_REMOTE_GROUP
2623
+                    && $share->getSharedWith() === '[email protected]'
2624
+                    && $share->getSharedBy() === 'currentUser';
2625
+            }))
2626
+            ->willReturnArgument(0);
2627
+
2628
+        $this->shareManager->method('outgoingServer2ServerGroupSharesAllowed')->willReturn(true);
2629
+
2630
+        $expected = new DataResponse([]);
2631
+        $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_REMOTE_GROUP, '[email protected]');
2632
+
2633
+        $this->assertInstanceOf(get_class($expected), $result);
2634
+        $this->assertEquals($expected->getData(), $result->getData());
2635
+    }
2636
+
2637
+    public function testCreateShareRoom(): void {
2638
+        $ocs = $this->mockFormatShare();
2639
+
2640
+        $share = $this->newShare();
2641
+        $this->shareManager->method('newShare')->willReturn($share);
2642
+
2643
+        [$userFolder, $path] = $this->getNonSharedUserFile();
2644
+        $this->rootFolder->expects($this->exactly(2))
2645
+            ->method('getUserFolder')
2646
+            ->with('currentUser')
2647
+            ->willReturn($userFolder);
2648
+
2649
+        $userFolder->expects($this->once())
2650
+            ->method('get')
2651
+            ->with('valid-path')
2652
+            ->willReturn($path);
2653
+        $userFolder->method('getById')
2654
+            ->willReturn([]);
2655
+
2656
+        $path->expects($this->once())
2657
+            ->method('lock')
2658
+            ->with(ILockingProvider::LOCK_SHARED);
2659
+
2660
+        $this->appManager->method('isEnabledForUser')
2661
+            ->with('spreed')
2662
+            ->willReturn(true);
2663
+
2664
+        // This is not possible anymore with PHPUnit 10+
2665
+        // as `setMethods` was removed and now real reflection is used, thus the class needs to exist.
2666
+        // $helper = $this->getMockBuilder('\OCA\Talk\Share\Helper\ShareAPIController')
2667
+        $helper = $this->getMockBuilder(\stdClass::class)
2668
+            ->addMethods(['createShare'])
2669
+            ->getMock();
2670
+        $helper->method('createShare')
2671
+            ->with(
2672
+                $share,
2673
+                'recipientRoom',
2674
+                Constants::PERMISSION_ALL
2675
+                & ~Constants::PERMISSION_DELETE
2676
+                & ~Constants::PERMISSION_CREATE,
2677
+                ''
2678
+            )->willReturnCallback(
2679
+                function ($share): void {
2680
+                    $share->setSharedWith('recipientRoom');
2681
+                    $share->setPermissions(Constants::PERMISSION_ALL);
2682
+                }
2683
+            );
2684
+
2685
+        $this->serverContainer->method('get')
2686
+            ->with('\OCA\Talk\Share\Helper\ShareAPIController')
2687
+            ->willReturn($helper);
2688
+
2689
+        $this->shareManager->method('createShare')
2690
+            ->with($this->callback(function (IShare $share) use ($path) {
2691
+                return $share->getNode() === $path
2692
+                    && $share->getPermissions() === Constants::PERMISSION_ALL
2693
+                    && $share->getShareType() === IShare::TYPE_ROOM
2694
+                    && $share->getSharedWith() === 'recipientRoom'
2695
+                    && $share->getSharedBy() === 'currentUser';
2696
+            }))
2697
+            ->willReturnArgument(0);
2698
+
2699
+        $expected = new DataResponse([]);
2700
+        $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_ROOM, 'recipientRoom');
2701
+
2702
+        $this->assertInstanceOf(get_class($expected), $result);
2703
+        $this->assertEquals($expected->getData(), $result->getData());
2704
+    }
2705
+
2706
+
2707
+    public function testCreateShareRoomHelperNotAvailable(): void {
2708
+        $this->expectException(OCSForbiddenException::class);
2709
+        $this->expectExceptionMessage('Sharing valid-path failed because the back end does not support room shares');
2710
+
2711
+        $ocs = $this->mockFormatShare();
2712
+
2713
+        $share = $this->newShare();
2714
+        $this->shareManager->method('newShare')->willReturn($share);
2715
+
2716
+        [$userFolder, $path] = $this->getNonSharedUserFolder();
2717
+        $this->rootFolder->method('getUserFolder')
2718
+            ->with('currentUser')
2719
+            ->willReturn($userFolder);
2720
+
2721
+        $path->method('getPath')->willReturn('valid-path');
2722
+        $userFolder->expects($this->once())
2723
+            ->method('get')
2724
+            ->with('valid-path')
2725
+            ->willReturn($path);
2726
+        $userFolder->method('getById')
2727
+            ->willReturn([]);
2728
+
2729
+        $path->expects($this->once())
2730
+            ->method('lock')
2731
+            ->with(ILockingProvider::LOCK_SHARED);
2732
+
2733
+        $this->appManager->method('isEnabledForUser')
2734
+            ->with('spreed')
2735
+            ->willReturn(false);
2736
+
2737
+        $this->shareManager->expects($this->never())->method('createShare');
2738
+
2739
+        $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_ROOM, 'recipientRoom');
2740
+    }
2741
+
2742
+
2743
+    public function testCreateShareRoomHelperThrowException(): void {
2744
+        $this->expectException(OCSNotFoundException::class);
2745
+        $this->expectExceptionMessage('Exception thrown by the helper');
2746
+
2747
+        $ocs = $this->mockFormatShare();
2748
+
2749
+        $share = $this->newShare();
2750
+        $share->setSharedBy('currentUser');
2751
+        $this->shareManager->method('newShare')->willReturn($share);
2752
+
2753
+        [$userFolder, $path] = $this->getNonSharedUserFile();
2754
+        $this->rootFolder->method('getUserFolder')
2755
+            ->with('currentUser')
2756
+            ->willReturn($userFolder);
2757
+
2758
+        $userFolder->expects($this->once())
2759
+            ->method('get')
2760
+            ->with('valid-path')
2761
+            ->willReturn($path);
2762
+        $userFolder->method('getById')
2763
+            ->willReturn([]);
2764
+
2765
+        $path->expects($this->once())
2766
+            ->method('lock')
2767
+            ->with(ILockingProvider::LOCK_SHARED);
2768
+
2769
+        $this->appManager->method('isEnabledForUser')
2770
+            ->with('spreed')
2771
+            ->willReturn(true);
2772
+
2773
+        // This is not possible anymore with PHPUnit 10+
2774
+        // as `setMethods` was removed and now real reflection is used, thus the class needs to exist.
2775
+        // $helper = $this->getMockBuilder('\OCA\Talk\Share\Helper\ShareAPIController')
2776
+        $helper = $this->getMockBuilder(\stdClass::class)
2777
+            ->addMethods(['createShare'])
2778
+            ->getMock();
2779
+        $helper->method('createShare')
2780
+            ->with(
2781
+                $share,
2782
+                'recipientRoom',
2783
+                Constants::PERMISSION_ALL & ~(Constants::PERMISSION_CREATE | Constants::PERMISSION_DELETE),
2784
+                ''
2785
+            )->willReturnCallback(
2786
+                function ($share): void {
2787
+                    throw new OCSNotFoundException('Exception thrown by the helper');
2788
+                }
2789
+            );
2790
+
2791
+        $this->serverContainer->method('get')
2792
+            ->with('\OCA\Talk\Share\Helper\ShareAPIController')
2793
+            ->willReturn($helper);
2794
+
2795
+        $this->shareManager->expects($this->never())->method('createShare');
2796
+
2797
+        $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_ROOM, 'recipientRoom');
2798
+    }
2799
+
2800
+    /**
2801
+     * Test for https://github.com/owncloud/core/issues/22587
2802
+     * TODO: Remove once proper solution is in place
2803
+     */
2804
+    public function testCreateReshareOfFederatedMountNoDeletePermissions(): void {
2805
+        $share = Server::get(IManager::class)->newShare();
2806
+        $this->shareManager->method('newShare')->willReturn($share);
2807
+
2808
+        /** @var ShareAPIController&MockObject $ocs */
2809
+        $ocs = $this->getMockBuilder(ShareAPIController::class)
2810
+            ->setConstructorArgs([
2811
+                $this->appName,
2812
+                $this->request,
2813
+                $this->shareManager,
2814
+                $this->groupManager,
2815
+                $this->userManager,
2816
+                $this->rootFolder,
2817
+                $this->urlGenerator,
2818
+                $this->l,
2819
+                $this->config,
2820
+                $this->appConfig,
2821
+                $this->appManager,
2822
+                $this->serverContainer,
2823
+                $this->userStatusManager,
2824
+                $this->previewManager,
2825
+                $this->dateTimeZone,
2826
+                $this->logger,
2827
+                $this->factory,
2828
+                $this->mailer,
2829
+                $this->tagManager,
2830
+                $this->getEmailValidatorWithStrictEmailCheck(),
2831
+                $this->trustedServers,
2832
+                $this->currentUser,
2833
+            ])->onlyMethods(['formatShare'])
2834
+            ->getMock();
2835
+
2836
+        $userFolder = $this->getMockBuilder(Folder::class)->getMock();
2837
+        $this->rootFolder->expects($this->exactly(2))
2838
+            ->method('getUserFolder')
2839
+            ->with('currentUser')
2840
+            ->willReturn($userFolder);
2841
+
2842
+        $path = $this->getMockBuilder(Folder::class)->getMock();
2843
+        $path->method('getId')->willReturn(42);
2844
+
2845
+        $storage = $this->createMock(IStorage::class);
2846
+        $storage->method('instanceOfStorage')
2847
+            ->willReturnMap([
2848
+                ['OCA\Files_Sharing\External\Storage', true],
2849
+                ['OCA\Files_Sharing\SharedStorage', false],
2850
+            ]);
2851
+        $userFolder->method('getStorage')->willReturn($storage);
2852
+        $path->method('getStorage')->willReturn($storage);
2853
+
2854
+        $path->method('getPermissions')->willReturn(Constants::PERMISSION_READ);
2855
+        $userFolder->expects($this->once())
2856
+            ->method('get')
2857
+            ->with('valid-path')
2858
+            ->willReturn($path);
2859
+        $userFolder->method('getById')
2860
+            ->willReturn([]);
2861
+
2862
+        $this->userManager->method('userExists')->with('validUser')->willReturn(true);
2863
+
2864
+        $this->shareManager
2865
+            ->expects($this->once())
2866
+            ->method('createShare')
2867
+            ->with($this->callback(function (IShare $share) {
2868
+                return $share->getPermissions() === Constants::PERMISSION_READ;
2869
+            }))
2870
+            ->willReturnArgument(0);
2871
+
2872
+        $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_USER, 'validUser');
2873
+    }
2874
+
2875
+
2876
+    public function testUpdateShareCantAccess(): void {
2877
+        $this->expectException(OCSNotFoundException::class);
2878
+        $this->expectExceptionMessage('Wrong share ID, share does not exist');
2879
+
2880
+        [$userFolder, $node] = $this->getNonSharedUserFolder();
2881
+        $share = $this->newShare();
2882
+        $share->setNode($node);
2883
+
2884
+        $node->expects($this->once())
2885
+            ->method('lock')
2886
+            ->with(ILockingProvider::LOCK_SHARED);
2887
+
2888
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
2889
+
2890
+        $this->rootFolder->method('getUserFolder')
2891
+            ->with($this->currentUser)
2892
+            ->willReturn($userFolder);
2893
+
2894
+        $userFolder->method('getById')
2895
+            ->with($share->getNodeId())
2896
+            ->willReturn([$share->getNode()]);
2897
+
2898
+        $this->ocs->updateShare(42);
2899
+    }
2900
+
2901
+
2902
+    public function testUpdateNoParametersLink(): void {
2903
+        $this->expectException(OCSBadRequestException::class);
2904
+        $this->expectExceptionMessage('Wrong or no update parameter given');
2905
+
2906
+        $node = $this->getMockBuilder(Folder::class)->getMock();
2907
+        $share = $this->newShare();
2908
+        $share->setPermissions(Constants::PERMISSION_ALL)
2909
+            ->setSharedBy($this->currentUser)
2910
+            ->setShareType(IShare::TYPE_LINK)
2911
+            ->setNode($node);
2912
+
2913
+        $node->expects($this->once())
2914
+            ->method('lock')
2915
+            ->with(ILockingProvider::LOCK_SHARED);
2916
+
2917
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
2918
+
2919
+        $this->ocs->updateShare(42);
2920
+    }
2921
+
2922
+
2923
+    public function testUpdateNoParametersOther(): void {
2924
+        $this->expectException(OCSBadRequestException::class);
2925
+        $this->expectExceptionMessage('Wrong or no update parameter given');
2926
+
2927
+        $node = $this->getMockBuilder(Folder::class)->getMock();
2928
+        $share = $this->newShare();
2929
+        $share->setPermissions(Constants::PERMISSION_ALL)
2930
+            ->setSharedBy($this->currentUser)
2931
+            ->setShareType(IShare::TYPE_GROUP)
2932
+            ->setNode($node);
2933
+
2934
+        $node->expects($this->once())
2935
+            ->method('lock')
2936
+            ->with(ILockingProvider::LOCK_SHARED);
2937
+
2938
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
2939
+
2940
+        $this->ocs->updateShare(42);
2941
+    }
2942
+
2943
+    public function testUpdateLinkShareClear(): void {
2944
+        $ocs = $this->mockFormatShare();
2945
+
2946
+        [$userFolder, $node] = $this->getNonSharedUserFolder();
2947
+        $node->method('getId')
2948
+            ->willReturn(42);
2949
+        $share = $this->newShare();
2950
+        $share->setPermissions(Constants::PERMISSION_ALL)
2951
+            ->setSharedBy($this->currentUser)
2952
+            ->setShareType(IShare::TYPE_LINK)
2953
+            ->setPassword('password')
2954
+            ->setExpirationDate(new \DateTime())
2955
+            ->setNote('note')
2956
+            ->setLabel('label')
2957
+            ->setHideDownload(true)
2958
+            ->setPermissions(Constants::PERMISSION_ALL)
2959
+            ->setNode($node);
2960
+
2961
+        $node->expects($this->once())
2962
+            ->method('lock')
2963
+            ->with(ILockingProvider::LOCK_SHARED);
2964
+
2965
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
2966
+
2967
+        $this->shareManager->expects($this->once())->method('updateShare')->with(
2968
+            $this->callback(function (IShare $share) {
2969
+                return $share->getPermissions() === Constants::PERMISSION_READ
2970
+                && $share->getPassword() === null
2971
+                && $share->getExpirationDate() === null
2972
+                // Once set a note or a label are never back to null, only to an
2973
+                // empty string.
2974
+                && $share->getNote() === ''
2975
+                && $share->getLabel() === ''
2976
+                && $share->getHideDownload() === false;
2977
+            })
2978
+        )->willReturnArgument(0);
2979
+
2980
+        $this->shareManager->method('getSharedWith')
2981
+            ->willReturn([]);
2982
+
2983
+        $this->rootFolder->method('getUserFolder')
2984
+            ->with($this->currentUser)
2985
+            ->willReturn($userFolder);
2986
+
2987
+        $userFolder->method('getById')
2988
+            ->with(42)
2989
+            ->willReturn([$node]);
2990
+        $userFolder->method('getFirstNodeById')
2991
+            ->with(42)
2992
+            ->willReturn($node);
2993
+
2994
+        $mountPoint = $this->createMock(IMountPoint::class);
2995
+        $node->method('getMountPoint')
2996
+            ->willReturn($mountPoint);
2997
+        $mountPoint->method('getStorageRootId')
2998
+            ->willReturn(42);
2999
+
3000
+        $expected = new DataResponse([]);
3001
+        $result = $ocs->updateShare(42, null, '', null, 'false', '', '', '', 'false');
3002
+
3003
+        $this->assertInstanceOf(get_class($expected), $result);
3004
+        $this->assertEquals($expected->getData(), $result->getData());
3005
+    }
3006
+
3007
+    public function testUpdateLinkShareSet(): void {
3008
+        $ocs = $this->mockFormatShare();
3009
+
3010
+        [$userFolder, $folder] = $this->getNonSharedUserFolder();
3011
+        $folder->method('getId')
3012
+            ->willReturn(42);
3013
+
3014
+        $share = Server::get(IManager::class)->newShare();
3015
+        $share->setPermissions(Constants::PERMISSION_ALL)
3016
+            ->setSharedBy($this->currentUser)
3017
+            ->setShareType(IShare::TYPE_LINK)
3018
+            ->setNode($folder);
3019
+
3020
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3021
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3022
+
3023
+        $this->shareManager->expects($this->once())->method('updateShare')->with(
3024
+            $this->callback(function (IShare $share) {
3025
+                $date = new \DateTime('2000-01-01');
3026
+                $date->setTime(0, 0, 0);
3027
+
3028
+                return $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
3029
+                && $share->getPassword() === 'password'
3030
+                && $share->getExpirationDate() == $date
3031
+                && $share->getNote() === 'note'
3032
+                && $share->getLabel() === 'label'
3033
+                && $share->getHideDownload() === true;
3034
+            })
3035
+        )->willReturnArgument(0);
3036
+
3037
+        $this->shareManager->method('getSharedWith')
3038
+            ->willReturn([]);
3039
+
3040
+        $this->rootFolder->method('getUserFolder')
3041
+            ->with($this->currentUser)
3042
+            ->willReturn($userFolder);
3043
+
3044
+        $userFolder->method('getById')
3045
+            ->with(42)
3046
+            ->willReturn([$folder]);
3047
+
3048
+        $mountPoint = $this->createMock(IMountPoint::class);
3049
+        $folder->method('getMountPoint')
3050
+            ->willReturn($mountPoint);
3051
+        $mountPoint->method('getStorageRootId')
3052
+            ->willReturn(42);
3053
+
3054
+        $expected = new DataResponse([]);
3055
+        $result = $ocs->updateShare(42, null, 'password', null, 'true', '2000-01-01', 'note', 'label', 'true');
3056
+
3057
+        $this->assertInstanceOf(get_class($expected), $result);
3058
+        $this->assertEquals($expected->getData(), $result->getData());
3059
+    }
3060
+
3061
+    #[DataProvider('publicUploadParamsProvider')]
3062
+    public function testUpdateLinkShareEnablePublicUpload($permissions, $publicUpload, $expireDate, $password): void {
3063
+        $ocs = $this->mockFormatShare();
3064
+
3065
+        [$userFolder, $folder] = $this->getNonSharedUserFolder();
3066
+        $folder->method('getId')
3067
+            ->willReturn(42);
3068
+
3069
+        $share = Server::get(IManager::class)->newShare();
3070
+        $share->setPermissions(Constants::PERMISSION_ALL)
3071
+            ->setSharedBy($this->currentUser)
3072
+            ->setShareType(IShare::TYPE_LINK)
3073
+            ->setPassword('password')
3074
+            ->setNode($folder);
3075
+
3076
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3077
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3078
+        $this->shareManager->method('getSharedWith')->willReturn([]);
3079
+
3080
+        $this->shareManager->expects($this->once())->method('updateShare')->with(
3081
+            $this->callback(function (IShare $share) {
3082
+                return $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
3083
+                && $share->getPassword() === 'password'
3084
+                && $share->getExpirationDate() === null;
3085
+            })
3086
+        )->willReturnArgument(0);
3087
+
3088
+        $this->rootFolder->method('getUserFolder')
3089
+            ->with($this->currentUser)
3090
+            ->willReturn($userFolder);
3091
+
3092
+        $userFolder->method('getById')
3093
+            ->with(42)
3094
+            ->willReturn([$folder]);
3095
+
3096
+        $mountPoint = $this->createMock(IMountPoint::class);
3097
+        $folder->method('getMountPoint')
3098
+            ->willReturn($mountPoint);
3099
+        $mountPoint->method('getStorageRootId')
3100
+            ->willReturn(42);
3101
+
3102
+        $expected = new DataResponse([]);
3103
+        $result = $ocs->updateShare(42, $permissions, $password, null, $publicUpload, $expireDate);
3104
+
3105
+        $this->assertInstanceOf(get_class($expected), $result);
3106
+        $this->assertEquals($expected->getData(), $result->getData());
3107
+    }
3108
+
3109
+
3110
+    public static function publicLinkValidPermissionsProvider() {
3111
+        return [
3112
+            [Constants::PERMISSION_CREATE],
3113
+            [Constants::PERMISSION_READ],
3114
+            [Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE],
3115
+            [Constants::PERMISSION_READ | Constants::PERMISSION_DELETE],
3116
+            [Constants::PERMISSION_READ | Constants::PERMISSION_CREATE],
3117
+        ];
3118
+    }
3119
+
3120
+    #[DataProvider('publicLinkValidPermissionsProvider')]
3121
+    public function testUpdateLinkShareSetCRUDPermissions($permissions): void {
3122
+        $ocs = $this->mockFormatShare();
3123
+
3124
+        [$userFolder, $folder] = $this->getNonSharedUserFolder();
3125
+        $folder->method('getId')
3126
+            ->willReturn(42);
3127
+
3128
+        $share = Server::get(IManager::class)->newShare();
3129
+        $share->setPermissions(Constants::PERMISSION_ALL)
3130
+            ->setSharedBy($this->currentUser)
3131
+            ->setShareType(IShare::TYPE_LINK)
3132
+            ->setPassword('password')
3133
+            ->setNode($folder);
3134
+
3135
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3136
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3137
+        $this->shareManager->method('getSharedWith')->willReturn([]);
3138
+
3139
+        $this->shareManager
3140
+            ->expects($this->any())
3141
+            ->method('updateShare')
3142
+            ->willReturnArgument(0);
3143
+
3144
+        $this->rootFolder->method('getUserFolder')
3145
+            ->with($this->currentUser)
3146
+            ->willReturn($userFolder);
3147
+
3148
+        $userFolder->method('getById')
3149
+            ->with(42)
3150
+            ->willReturn([$folder]);
3151
+
3152
+        $mountPoint = $this->createMock(IMountPoint::class);
3153
+        $folder->method('getMountPoint')
3154
+            ->willReturn($mountPoint);
3155
+        $mountPoint->method('getStorageRootId')
3156
+            ->willReturn(42);
3157
+
3158
+        $expected = new DataResponse([]);
3159
+        $result = $ocs->updateShare(42, $permissions, 'password', null, null, null);
3160
+
3161
+        $this->assertInstanceOf(get_class($expected), $result);
3162
+        $this->assertEquals($expected->getData(), $result->getData());
3163
+    }
3164
+
3165
+    public static function publicLinkInvalidPermissionsProvider1() {
3166
+        return [
3167
+            [Constants::PERMISSION_DELETE],
3168
+            [Constants::PERMISSION_UPDATE],
3169
+            [Constants::PERMISSION_SHARE],
3170
+        ];
3171
+    }
3172
+
3173
+    #[DataProvider('publicLinkInvalidPermissionsProvider1')]
3174
+    public function testUpdateLinkShareSetInvalidCRUDPermissions1($permissions): void {
3175
+        $this->expectException(OCSBadRequestException::class);
3176
+        $this->expectExceptionMessage('Share must at least have READ or CREATE permissions');
3177
+
3178
+        $this->testUpdateLinkShareSetCRUDPermissions($permissions, null);
3179
+    }
3180
+
3181
+    public static function publicLinkInvalidPermissionsProvider2() {
3182
+        return [
3183
+            [Constants::PERMISSION_CREATE | Constants::PERMISSION_DELETE],
3184
+            [Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE],
3185
+        ];
3186
+    }
3187
+
3188
+    #[DataProvider('publicLinkInvalidPermissionsProvider2')]
3189
+    public function testUpdateLinkShareSetInvalidCRUDPermissions2($permissions): void {
3190
+        $this->expectException(OCSBadRequestException::class);
3191
+        $this->expectExceptionMessage('Share must have READ permission if UPDATE or DELETE permission is set');
3192
+
3193
+        $this->testUpdateLinkShareSetCRUDPermissions($permissions);
3194
+    }
3195
+
3196
+    public function testUpdateLinkShareInvalidDate(): void {
3197
+        $this->expectException(OCSBadRequestException::class);
3198
+        $this->expectExceptionMessage('Invalid date. Format must be YYYY-MM-DD');
3199
+
3200
+        $ocs = $this->mockFormatShare();
3201
+        [$userFolder, $folder] = $this->getNonSharedUserFolder();
3202
+        $userFolder->method('getById')
3203
+            ->with(42)
3204
+            ->willReturn([$folder]);
3205
+        $this->rootFolder->method('getUserFolder')
3206
+            ->with($this->currentUser)
3207
+            ->willReturn($userFolder);
3208
+
3209
+        $folder->method('getId')
3210
+            ->willReturn(42);
3211
+
3212
+        $share = Server::get(IManager::class)->newShare();
3213
+        $share->setPermissions(Constants::PERMISSION_ALL)
3214
+            ->setSharedBy($this->currentUser)
3215
+            ->setShareType(IShare::TYPE_LINK)
3216
+            ->setNode($folder);
3217
+
3218
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3219
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3220
+
3221
+        $ocs->updateShare(42, null, 'password', null, 'true', '2000-01-a');
3222
+    }
3223
+
3224
+    public static function publicUploadParamsProvider() {
3225
+        return [
3226
+            [null, 'true', null, 'password'],
3227
+            // legacy had no delete
3228
+            [
3229
+                Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE,
3230
+                'true', null, 'password'
3231
+            ],
3232
+            // correct
3233
+            [
3234
+                Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE,
3235
+                null, null, 'password'
3236
+            ],
3237
+        ];
3238
+    }
3239
+
3240
+    #[DataProvider('publicUploadParamsProvider')]
3241
+    public function testUpdateLinkSharePublicUploadNotAllowed($permissions, $publicUpload, $expireDate, $password): void {
3242
+        $this->expectException(OCSForbiddenException::class);
3243
+        $this->expectExceptionMessage('Public upload disabled by the administrator');
3244
+
3245
+        $ocs = $this->mockFormatShare();
3246
+        [$userFolder, $folder] = $this->getNonSharedUserFolder();
3247
+        $userFolder->method('getById')
3248
+            ->with(42)
3249
+            ->willReturn([$folder]);
3250
+        $this->rootFolder->method('getUserFolder')
3251
+            ->with($this->currentUser)
3252
+            ->willReturn($userFolder);
3253
+
3254
+        $folder->method('getId')->willReturn(42);
3255
+
3256
+        $share = Server::get(IManager::class)->newShare();
3257
+        $share->setPermissions(Constants::PERMISSION_ALL)
3258
+            ->setSharedBy($this->currentUser)
3259
+            ->setShareType(IShare::TYPE_LINK)
3260
+            ->setNode($folder);
3261
+
3262
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3263
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(false);
3264
+
3265
+        $ocs->updateShare(42, $permissions, $password, null, $publicUpload, $expireDate);
3266
+    }
3267
+
3268
+
3269
+    public function testUpdateLinkSharePublicUploadOnFile(): void {
3270
+        $this->expectException(OCSBadRequestException::class);
3271
+        $this->expectExceptionMessage('Public upload is only possible for publicly shared folders');
3272
+
3273
+        $ocs = $this->mockFormatShare();
3274
+
3275
+        $file = $this->getMockBuilder(File::class)->getMock();
3276
+        $file->method('getId')
3277
+            ->willReturn(42);
3278
+        [$userFolder, $folder] = $this->getNonSharedUserFolder();
3279
+        $userFolder->method('getById')
3280
+            ->with(42)
3281
+            ->willReturn([$folder]);
3282
+        $this->rootFolder->method('getUserFolder')
3283
+            ->with($this->currentUser)
3284
+            ->willReturn($userFolder);
3285
+
3286
+        $share = Server::get(IManager::class)->newShare();
3287
+        $share->setPermissions(Constants::PERMISSION_ALL)
3288
+            ->setSharedBy($this->currentUser)
3289
+            ->setShareType(IShare::TYPE_LINK)
3290
+            ->setNode($file);
3291
+
3292
+        $this->shareManager
3293
+            ->method('getShareById')
3294
+            ->with('ocinternal:42')
3295
+            ->willReturn($share);
3296
+        $this->shareManager
3297
+            ->method('shareApiLinkAllowPublicUpload')
3298
+            ->willReturn(true);
3299
+        $this->shareManager
3300
+            ->method('updateShare')
3301
+            ->with($share)
3302
+            ->willThrowException(new \InvalidArgumentException('File shares cannot have create or delete permissions'));
3303
+
3304
+        $ocs->updateShare(42, null, 'password', null, 'true', '');
3305
+    }
3306
+
3307
+    public function testUpdateLinkSharePasswordDoesNotChangeOther(): void {
3308
+        $ocs = $this->mockFormatShare();
3309
+
3310
+        $date = new \DateTime('2000-01-01');
3311
+        $date->setTime(0, 0, 0);
3312
+
3313
+        [$userFolder, $node] = $this->getNonSharedUserFolder();
3314
+        $node->method('getId')->willReturn(42);
3315
+        $userFolder->method('getById')
3316
+            ->with(42)
3317
+            ->willReturn([$node]);
3318
+        $this->rootFolder->method('getUserFolder')
3319
+            ->with($this->currentUser)
3320
+            ->willReturn($userFolder);
3321
+        $share = $this->newShare();
3322
+        $share->setPermissions(Constants::PERMISSION_ALL)
3323
+            ->setSharedBy($this->currentUser)
3324
+            ->setShareType(IShare::TYPE_LINK)
3325
+            ->setPassword('password')
3326
+            ->setSendPasswordByTalk(true)
3327
+            ->setExpirationDate($date)
3328
+            ->setNote('note')
3329
+            ->setLabel('label')
3330
+            ->setHideDownload(true)
3331
+            ->setPermissions(Constants::PERMISSION_ALL)
3332
+            ->setNode($node);
3333
+
3334
+        $node->expects($this->once())
3335
+            ->method('lock')
3336
+            ->with(ILockingProvider::LOCK_SHARED);
3337
+
3338
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3339
+
3340
+        $this->shareManager->expects($this->once())->method('updateShare')->with(
3341
+            $this->callback(function (IShare $share) use ($date) {
3342
+                return $share->getPermissions() === Constants::PERMISSION_ALL
3343
+                && $share->getPassword() === 'newpassword'
3344
+                && $share->getSendPasswordByTalk() === true
3345
+                && $share->getExpirationDate() === $date
3346
+                && $share->getNote() === 'note'
3347
+                && $share->getLabel() === 'label'
3348
+                && $share->getHideDownload() === true;
3349
+            })
3350
+        )->willReturnArgument(0);
3351
+
3352
+        $expected = new DataResponse([]);
3353
+        $result = $ocs->updateShare(42, null, 'newpassword', null, null, null, null, null, null);
3354
+
3355
+        $this->assertInstanceOf(get_class($expected), $result);
3356
+        $this->assertEquals($expected->getData(), $result->getData());
3357
+    }
3358
+
3359
+    public function testUpdateLinkShareSendPasswordByTalkDoesNotChangeOther(): void {
3360
+        $ocs = $this->mockFormatShare();
3361
+
3362
+        $date = new \DateTime('2000-01-01');
3363
+        $date->setTime(0, 0, 0);
3364
+
3365
+        [$userFolder, $node] = $this->getNonSharedUserFolder();
3366
+        $userFolder->method('getById')
3367
+            ->with(42)
3368
+            ->willReturn([$node]);
3369
+        $this->rootFolder->method('getUserFolder')
3370
+            ->with($this->currentUser)
3371
+            ->willReturn($userFolder);
3372
+        $node->method('getId')->willReturn(42);
3373
+        $share = $this->newShare();
3374
+        $share->setPermissions(Constants::PERMISSION_ALL)
3375
+            ->setSharedBy($this->currentUser)
3376
+            ->setShareType(IShare::TYPE_LINK)
3377
+            ->setPassword('password')
3378
+            ->setSendPasswordByTalk(false)
3379
+            ->setExpirationDate($date)
3380
+            ->setNote('note')
3381
+            ->setLabel('label')
3382
+            ->setHideDownload(true)
3383
+            ->setPermissions(Constants::PERMISSION_ALL)
3384
+            ->setNode($node);
3385
+
3386
+        $node->expects($this->once())
3387
+            ->method('lock')
3388
+            ->with(ILockingProvider::LOCK_SHARED);
3389
+
3390
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3391
+
3392
+        $this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(true);
3393
+
3394
+        $this->shareManager->expects($this->once())->method('updateShare')->with(
3395
+            $this->callback(function (IShare $share) use ($date) {
3396
+                return $share->getPermissions() === Constants::PERMISSION_ALL
3397
+                && $share->getPassword() === 'password'
3398
+                && $share->getSendPasswordByTalk() === true
3399
+                && $share->getExpirationDate() === $date
3400
+                && $share->getNote() === 'note'
3401
+                && $share->getLabel() === 'label'
3402
+                && $share->getHideDownload() === true;
3403
+            })
3404
+        )->willReturnArgument(0);
3405
+
3406
+        $expected = new DataResponse([]);
3407
+        $result = $ocs->updateShare(42, null, null, 'true', null, null, null, null, null);
3408
+
3409
+        $this->assertInstanceOf(get_class($expected), $result);
3410
+        $this->assertEquals($expected->getData(), $result->getData());
3411
+    }
3412
+
3413
+
3414
+    public function testUpdateLinkShareSendPasswordByTalkWithTalkDisabledDoesNotChangeOther(): void {
3415
+        $this->expectException(OCSForbiddenException::class);
3416
+        $this->expectExceptionMessage('"Sending the password by Nextcloud Talk" for sharing a file or folder failed because Nextcloud Talk is not enabled.');
3417
+
3418
+        $ocs = $this->mockFormatShare();
3419
+
3420
+        $date = new \DateTime('2000-01-01');
3421
+        $date->setTime(0, 0, 0);
3422
+
3423
+        [$userFolder, $node] = $this->getNonSharedUserFolder();
3424
+        $userFolder->method('getById')
3425
+            ->with(42)
3426
+            ->willReturn([$node]);
3427
+        $this->rootFolder->method('getUserFolder')
3428
+            ->with($this->currentUser)
3429
+            ->willReturn($userFolder);
3430
+        $node->method('getId')->willReturn(42);
3431
+        $share = $this->newShare();
3432
+        $share->setPermissions(Constants::PERMISSION_ALL)
3433
+            ->setSharedBy($this->currentUser)
3434
+            ->setShareType(IShare::TYPE_LINK)
3435
+            ->setPassword('password')
3436
+            ->setSendPasswordByTalk(false)
3437
+            ->setExpirationDate($date)
3438
+            ->setNote('note')
3439
+            ->setLabel('label')
3440
+            ->setHideDownload(true)
3441
+            ->setPermissions(Constants::PERMISSION_ALL)
3442
+            ->setNode($node);
3443
+
3444
+        $node->expects($this->once())
3445
+            ->method('lock')
3446
+            ->with(ILockingProvider::LOCK_SHARED);
3447
+
3448
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3449
+
3450
+        $this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(false);
3451
+
3452
+        $this->shareManager->expects($this->never())->method('updateShare');
3453
+
3454
+        $ocs->updateShare(42, null, null, 'true', null, null, null, null, null);
3455
+    }
3456
+
3457
+    public function testUpdateLinkShareDoNotSendPasswordByTalkDoesNotChangeOther(): void {
3458
+        $ocs = $this->mockFormatShare();
3459
+
3460
+        $date = new \DateTime('2000-01-01');
3461
+        $date->setTime(0, 0, 0);
3462
+
3463
+        [$userFolder, $node] = $this->getNonSharedUserFolder();
3464
+        $userFolder->method('getById')
3465
+            ->with(42)
3466
+            ->willReturn([$node]);
3467
+        $this->rootFolder->method('getUserFolder')
3468
+            ->with($this->currentUser)
3469
+            ->willReturn($userFolder);
3470
+        $node->method('getId')->willReturn(42);
3471
+        $share = $this->newShare();
3472
+        $share->setPermissions(Constants::PERMISSION_ALL)
3473
+            ->setSharedBy($this->currentUser)
3474
+            ->setShareType(IShare::TYPE_LINK)
3475
+            ->setPassword('password')
3476
+            ->setSendPasswordByTalk(true)
3477
+            ->setExpirationDate($date)
3478
+            ->setNote('note')
3479
+            ->setLabel('label')
3480
+            ->setHideDownload(true)
3481
+            ->setPermissions(Constants::PERMISSION_ALL)
3482
+            ->setNode($node);
3483
+
3484
+        $node->expects($this->once())
3485
+            ->method('lock')
3486
+            ->with(ILockingProvider::LOCK_SHARED);
3487
+
3488
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3489
+
3490
+        $this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(true);
3491
+
3492
+        $this->shareManager->expects($this->once())->method('updateShare')->with(
3493
+            $this->callback(function (IShare $share) use ($date) {
3494
+                return $share->getPermissions() === Constants::PERMISSION_ALL
3495
+                && $share->getPassword() === 'password'
3496
+                && $share->getSendPasswordByTalk() === false
3497
+                && $share->getExpirationDate() === $date
3498
+                && $share->getNote() === 'note'
3499
+                && $share->getLabel() === 'label'
3500
+                && $share->getHideDownload() === true;
3501
+            })
3502
+        )->willReturnArgument(0);
3503
+
3504
+        $expected = new DataResponse([]);
3505
+        $result = $ocs->updateShare(42, null, null, 'false', null, null, null, null, null);
3506
+
3507
+        $this->assertInstanceOf(get_class($expected), $result);
3508
+        $this->assertEquals($expected->getData(), $result->getData());
3509
+    }
3510
+
3511
+    public function testUpdateLinkShareDoNotSendPasswordByTalkWithTalkDisabledDoesNotChangeOther(): void {
3512
+        $ocs = $this->mockFormatShare();
3513
+
3514
+        $date = new \DateTime('2000-01-01');
3515
+        $date->setTime(0, 0, 0);
3516
+
3517
+        [$userFolder, $node] = $this->getNonSharedUserFolder();
3518
+        $node->method('getId')
3519
+            ->willReturn(42);
3520
+
3521
+        $share = $this->newShare();
3522
+        $share->setPermissions(Constants::PERMISSION_ALL)
3523
+            ->setSharedBy($this->currentUser)
3524
+            ->setShareType(IShare::TYPE_LINK)
3525
+            ->setPassword('password')
3526
+            ->setSendPasswordByTalk(true)
3527
+            ->setExpirationDate($date)
3528
+            ->setNote('note')
3529
+            ->setLabel('label')
3530
+            ->setHideDownload(true)
3531
+            ->setPermissions(Constants::PERMISSION_ALL)
3532
+            ->setNode($node);
3533
+
3534
+        $node->expects($this->once())
3535
+            ->method('lock')
3536
+            ->with(ILockingProvider::LOCK_SHARED);
3537
+
3538
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3539
+
3540
+        $this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(false);
3541
+
3542
+        $this->shareManager->expects($this->once())->method('updateShare')->with(
3543
+            $this->callback(function (IShare $share) use ($date) {
3544
+                return $share->getPermissions() === Constants::PERMISSION_ALL
3545
+                && $share->getPassword() === 'password'
3546
+                && $share->getSendPasswordByTalk() === false
3547
+                && $share->getExpirationDate() === $date
3548
+                && $share->getNote() === 'note'
3549
+                && $share->getLabel() === 'label'
3550
+                && $share->getHideDownload() === true;
3551
+            })
3552
+        )->willReturnArgument(0);
3553
+
3554
+        $this->rootFolder->method('getUserFolder')
3555
+            ->with($this->currentUser)
3556
+            ->willReturn($userFolder);
3557
+
3558
+        $userFolder->method('getById')
3559
+            ->with(42)
3560
+            ->willReturn([$node]);
3561
+
3562
+        $mountPoint = $this->createMock(IMountPoint::class);
3563
+        $node->method('getMountPoint')
3564
+            ->willReturn($mountPoint);
3565
+        $mountPoint->method('getStorageRootId')
3566
+            ->willReturn(42);
3567
+
3568
+        $mountPoint = $this->createMock(IMountPoint::class);
3569
+        $node->method('getMountPoint')
3570
+            ->willReturn($mountPoint);
3571
+        $mountPoint->method('getStorageRootId')
3572
+            ->willReturn(42);
3573
+
3574
+        $expected = new DataResponse([]);
3575
+        $result = $ocs->updateShare(42, null, null, 'false', null, null, null, null, null);
3576
+
3577
+        $this->assertInstanceOf(get_class($expected), $result);
3578
+        $this->assertEquals($expected->getData(), $result->getData());
3579
+    }
3580
+
3581
+    public function testUpdateLinkShareExpireDateDoesNotChangeOther(): void {
3582
+        $ocs = $this->mockFormatShare();
3583
+
3584
+        [$userFolder, $node] = $this->getNonSharedUserFolder();
3585
+        $node->method('getId')
3586
+            ->willReturn(42);
3587
+
3588
+        $share = $this->newShare();
3589
+        $share->setPermissions(Constants::PERMISSION_ALL)
3590
+            ->setSharedBy($this->currentUser)
3591
+            ->setShareType(IShare::TYPE_LINK)
3592
+            ->setPassword('password')
3593
+            ->setSendPasswordByTalk(true)
3594
+            ->setExpirationDate(new \DateTime())
3595
+            ->setNote('note')
3596
+            ->setLabel('label')
3597
+            ->setHideDownload(true)
3598
+            ->setPermissions(Constants::PERMISSION_ALL)
3599
+            ->setNode($node);
3600
+
3601
+        $node->expects($this->once())
3602
+            ->method('lock')
3603
+            ->with(ILockingProvider::LOCK_SHARED);
3604
+
3605
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3606
+
3607
+        $this->shareManager->expects($this->once())->method('updateShare')->with(
3608
+            $this->callback(function (IShare $share) {
3609
+                $date = new \DateTime('2010-12-23');
3610
+                $date->setTime(0, 0, 0);
3611
+
3612
+                return $share->getPermissions() === Constants::PERMISSION_ALL
3613
+                && $share->getPassword() === 'password'
3614
+                && $share->getSendPasswordByTalk() === true
3615
+                && $share->getExpirationDate() == $date
3616
+                && $share->getNote() === 'note'
3617
+                && $share->getLabel() === 'label'
3618
+                && $share->getHideDownload() === true;
3619
+            })
3620
+        )->willReturnArgument(0);
3621
+
3622
+        $this->rootFolder->method('getUserFolder')
3623
+            ->with($this->currentUser)
3624
+            ->willReturn($userFolder);
3625
+
3626
+        $userFolder->method('getById')
3627
+            ->with(42)
3628
+            ->willReturn([$node]);
3629
+
3630
+        $mountPoint = $this->createMock(IMountPoint::class);
3631
+        $node->method('getMountPoint')
3632
+            ->willReturn($mountPoint);
3633
+        $mountPoint->method('getStorageRootId')
3634
+            ->willReturn(42);
3635
+
3636
+        $expected = new DataResponse([]);
3637
+        $result = $ocs->updateShare(42, null, null, null, null, '2010-12-23', null, null, null);
3638
+
3639
+        $this->assertInstanceOf(get_class($expected), $result);
3640
+        $this->assertEquals($expected->getData(), $result->getData());
3641
+    }
3642
+
3643
+    public function testUpdateLinkSharePublicUploadDoesNotChangeOther(): void {
3644
+        $ocs = $this->mockFormatShare();
3645
+
3646
+        $date = new \DateTime('2000-01-01');
3647
+
3648
+        [$userFolder, $folder] = $this->getNonSharedUserFolder();
3649
+        $folder->method('getId')
3650
+            ->willReturn(42);
3651
+
3652
+        $share = Server::get(IManager::class)->newShare();
3653
+        $share->setPermissions(Constants::PERMISSION_ALL)
3654
+            ->setSharedBy($this->currentUser)
3655
+            ->setShareType(IShare::TYPE_LINK)
3656
+            ->setPassword('password')
3657
+            ->setSendPasswordByTalk(true)
3658
+            ->setExpirationDate($date)
3659
+            ->setNote('note')
3660
+            ->setLabel('label')
3661
+            ->setHideDownload(true)
3662
+            ->setPermissions(Constants::PERMISSION_ALL)
3663
+            ->setNode($folder);
3664
+
3665
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3666
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3667
+
3668
+        $this->shareManager->expects($this->once())->method('updateShare')->with(
3669
+            $this->callback(function (IShare $share) use ($date) {
3670
+                return $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
3671
+                && $share->getPassword() === 'password'
3672
+                && $share->getSendPasswordByTalk() === true
3673
+                && $share->getExpirationDate() === $date
3674
+                && $share->getNote() === 'note'
3675
+                && $share->getLabel() === 'label'
3676
+                && $share->getHideDownload() === true;
3677
+            })
3678
+        )->willReturnArgument(0);
3679
+
3680
+        $this->shareManager->method('getSharedWith')
3681
+            ->willReturn([]);
3682
+
3683
+        $this->rootFolder->method('getUserFolder')
3684
+            ->with($this->currentUser)
3685
+            ->willReturn($userFolder);
3686
+
3687
+        $userFolder->method('getById')
3688
+            ->with(42)
3689
+            ->willReturn([$folder]);
3690
+
3691
+        $mountPoint = $this->createMock(IMountPoint::class);
3692
+        $folder->method('getMountPoint')
3693
+            ->willReturn($mountPoint);
3694
+        $mountPoint->method('getStorageRootId')
3695
+            ->willReturn(42);
3696
+
3697
+        $expected = new DataResponse([]);
3698
+        $result = $ocs->updateShare(42, null, null, null, 'true', null, null, null, null);
3699
+
3700
+        $this->assertInstanceOf(get_class($expected), $result);
3701
+        $this->assertEquals($expected->getData(), $result->getData());
3702
+    }
3703
+
3704
+    public function testUpdateLinkSharePermissions(): void {
3705
+        $ocs = $this->mockFormatShare();
3706
+
3707
+        $date = new \DateTime('2000-01-01');
3708
+
3709
+        [$userFolder, $folder] = $this->getNonSharedUserFolder();
3710
+        $folder->method('getId')
3711
+            ->willReturn(42);
3712
+
3713
+        $share = Server::get(IManager::class)->newShare();
3714
+        $share->setPermissions(Constants::PERMISSION_ALL)
3715
+            ->setSharedBy($this->currentUser)
3716
+            ->setShareType(IShare::TYPE_LINK)
3717
+            ->setPassword('password')
3718
+            ->setSendPasswordByTalk(true)
3719
+            ->setExpirationDate($date)
3720
+            ->setNote('note')
3721
+            ->setLabel('label')
3722
+            ->setHideDownload(true)
3723
+            ->setPermissions(Constants::PERMISSION_ALL)
3724
+            ->setNode($folder);
3725
+
3726
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3727
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3728
+
3729
+        $this->shareManager->expects($this->once())->method('updateShare')->with(
3730
+            $this->callback(function (IShare $share) use ($date): bool {
3731
+                return $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
3732
+                && $share->getPassword() === 'password'
3733
+                && $share->getSendPasswordByTalk() === true
3734
+                && $share->getExpirationDate() === $date
3735
+                && $share->getNote() === 'note'
3736
+                && $share->getLabel() === 'label'
3737
+                && $share->getHideDownload() === true;
3738
+            })
3739
+        )->willReturnArgument(0);
3740
+
3741
+        $this->shareManager->method('getSharedWith')->willReturn([]);
3742
+
3743
+        $this->rootFolder->method('getUserFolder')
3744
+            ->with($this->currentUser)
3745
+            ->willReturn($userFolder);
3746
+
3747
+        $userFolder->method('getById')
3748
+            ->with(42)
3749
+            ->willReturn([$folder]);
3750
+
3751
+        $mountPoint = $this->createMock(IMountPoint::class);
3752
+        $folder->method('getMountPoint')
3753
+            ->willReturn($mountPoint);
3754
+        $mountPoint->method('getStorageRootId')
3755
+            ->willReturn(42);
3756
+
3757
+        $expected = new DataResponse([]);
3758
+        $result = $ocs->updateShare(42, 7, null, null, 'true', null, null, null, null);
3759
+
3760
+        $this->assertInstanceOf(get_class($expected), $result);
3761
+        $this->assertEquals($expected->getData(), $result->getData());
3762
+    }
3763
+
3764
+    public function testUpdateLinkSharePermissionsShare(): void {
3765
+        $ocs = $this->mockFormatShare();
3766
+
3767
+        $date = new \DateTime('2000-01-01');
3768
+
3769
+        [$userFolder, $folder] = $this->getNonSharedUserFolder();
3770
+        $folder->method('getId')
3771
+            ->willReturn(42);
3772
+
3773
+        $share = Server::get(IManager::class)->newShare();
3774
+        $share->setPermissions(Constants::PERMISSION_ALL)
3775
+            ->setSharedBy($this->currentUser)
3776
+            ->setShareType(IShare::TYPE_LINK)
3777
+            ->setPassword('password')
3778
+            ->setSendPasswordByTalk(true)
3779
+            ->setExpirationDate($date)
3780
+            ->setNote('note')
3781
+            ->setLabel('label')
3782
+            ->setHideDownload(true)
3783
+            ->setPermissions(Constants::PERMISSION_READ)
3784
+            ->setNode($folder);
3785
+
3786
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3787
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3788
+
3789
+        $this->shareManager->expects($this->once())
3790
+            ->method('updateShare')
3791
+            ->with(
3792
+                $this->callback(function (IShare $share) use ($date) {
3793
+                    return $share->getPermissions() === Constants::PERMISSION_ALL
3794
+                        && $share->getPassword() === 'password'
3795
+                        && $share->getSendPasswordByTalk() === true
3796
+                        && $share->getExpirationDate() === $date
3797
+                        && $share->getNote() === 'note'
3798
+                        && $share->getLabel() === 'label'
3799
+                        && $share->getHideDownload() === true;
3800
+                })
3801
+            )->willReturnArgument(0);
3802
+
3803
+        $this->rootFolder->method('getUserFolder')
3804
+            ->with($this->currentUser)
3805
+            ->willReturn($userFolder);
3806
+
3807
+        $userFolder->method('getById')
3808
+            ->with(42)
3809
+            ->willReturn([$folder]);
3810
+
3811
+        $mountPoint = $this->createMock(IMountPoint::class);
3812
+        $folder->method('getMountPoint')
3813
+            ->willReturn($mountPoint);
3814
+        $mountPoint->method('getStorageRootId')
3815
+            ->willReturn(42);
3816
+
3817
+        $this->shareManager->method('getSharedWith')->willReturn([]);
3818
+
3819
+        $expected = new DataResponse([]);
3820
+        $result = $ocs->updateShare(42, Constants::PERMISSION_ALL, null, null, null, null, null, null, null);
3821
+
3822
+        $this->assertInstanceOf(get_class($expected), $result);
3823
+        $this->assertEquals($expected->getData(), $result->getData());
3824
+    }
3825
+
3826
+    public function testUpdateOtherPermissions(): void {
3827
+        $ocs = $this->mockFormatShare();
3828
+
3829
+        [$userFolder, $file] = $this->getNonSharedUserFolder();
3830
+        $file->method('getId')
3831
+            ->willReturn(42);
3832
+
3833
+        $share = Server::get(IManager::class)->newShare();
3834
+        $share->setPermissions(Constants::PERMISSION_ALL)
3835
+            ->setSharedBy($this->currentUser)
3836
+            ->setShareType(IShare::TYPE_USER)
3837
+            ->setNode($file);
3838
+
3839
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3840
+        $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true);
3841
+
3842
+        $this->shareManager->expects($this->once())->method('updateShare')->with(
3843
+            $this->callback(function (IShare $share) {
3844
+                return $share->getPermissions() === Constants::PERMISSION_ALL;
3845
+            })
3846
+        )->willReturnArgument(0);
3847
+
3848
+        $this->shareManager->method('getSharedWith')->willReturn([]);
3849
+
3850
+        [$userFolder, $folder] = $this->getNonSharedUserFolder();
3851
+        $this->rootFolder->method('getUserFolder')
3852
+            ->with($this->currentUser)
3853
+            ->willReturn($userFolder);
3854
+
3855
+        $userFolder->method('getById')
3856
+            ->with(42)
3857
+            ->willReturn([$file]);
3858
+
3859
+        $mountPoint = $this->createMock(IMountPoint::class);
3860
+        $file->method('getMountPoint')
3861
+            ->willReturn($mountPoint);
3862
+        $mountPoint->method('getStorageRootId')
3863
+            ->willReturn(42);
3864
+
3865
+        $expected = new DataResponse([]);
3866
+        $result = $ocs->updateShare(42, 31, null, null, null, null);
3867
+
3868
+        $this->assertInstanceOf(get_class($expected), $result);
3869
+        $this->assertEquals($expected->getData(), $result->getData());
3870
+    }
3871
+
3872
+    public function testUpdateShareCannotIncreasePermissions(): void {
3873
+        $ocs = $this->mockFormatShare();
3874
+
3875
+        [$userFolder, $folder] = $this->getNonSharedUserFolder();
3876
+        $folder->method('getId')
3877
+            ->willReturn(42);
3878
+
3879
+        $share = Server::get(IManager::class)->newShare();
3880
+        $share
3881
+            ->setId(42)
3882
+            ->setSharedBy($this->currentUser)
3883
+            ->setShareOwner('anotheruser')
3884
+            ->setShareType(IShare::TYPE_GROUP)
3885
+            ->setSharedWith('group1')
3886
+            ->setPermissions(Constants::PERMISSION_READ)
3887
+            ->setNode($folder);
3888
+
3889
+        // note: updateShare will modify the received instance but getSharedWith will reread from the database,
3890
+        // so their values will be different
3891
+        $incomingShare = Server::get(IManager::class)->newShare();
3892
+        $incomingShare
3893
+            ->setId(42)
3894
+            ->setSharedBy($this->currentUser)
3895
+            ->setShareOwner('anotheruser')
3896
+            ->setShareType(IShare::TYPE_GROUP)
3897
+            ->setSharedWith('group1')
3898
+            ->setPermissions(Constants::PERMISSION_READ)
3899
+            ->setNode($folder);
3900
+
3901
+        $this->request
3902
+            ->method('getParam')
3903
+            ->willReturnMap([
3904
+                ['permissions', null, '31'],
3905
+            ]);
3906
+
3907
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3908
+
3909
+        $this->shareManager->expects($this->any())
3910
+            ->method('getSharedWith')
3911
+            ->willReturnMap([
3912
+                ['currentUser', IShare::TYPE_USER, $share->getNode(), -1, 0, []],
3913
+                ['currentUser', IShare::TYPE_GROUP, $share->getNode(), -1, 0, [$incomingShare]],
3914
+                ['currentUser', IShare::TYPE_ROOM, $share->getNode(), -1, 0, []]
3915
+            ]);
3916
+
3917
+        $this->rootFolder->method('getUserFolder')
3918
+            ->with($this->currentUser)
3919
+            ->willReturn($userFolder);
3920
+
3921
+        $userFolder->method('getById')
3922
+            ->with(42)
3923
+            ->willReturn([$folder]);
3924
+        $userFolder->method('getFirstNodeById')
3925
+            ->with(42)
3926
+            ->willReturn($folder);
3927
+
3928
+        $mountPoint = $this->createMock(IMountPoint::class);
3929
+        $folder->method('getMountPoint')
3930
+            ->willReturn($mountPoint);
3931
+        $mountPoint->method('getStorageRootId')
3932
+            ->willReturn(42);
3933
+
3934
+        $this->shareManager->expects($this->once())
3935
+            ->method('updateShare')
3936
+            ->with($share)
3937
+            ->willThrowException(new GenericShareException('Cannot increase permissions of path/file', 'Cannot increase permissions of path/file', 404));
3938
+
3939
+        try {
3940
+            $ocs->updateShare(42, 31);
3941
+            $this->fail();
3942
+        } catch (OCSException $e) {
3943
+            $this->assertEquals('Cannot increase permissions of path/file', $e->getMessage());
3944
+        }
3945
+    }
3946
+
3947
+    public function testUpdateShareCanIncreasePermissionsIfOwner(): void {
3948
+        $ocs = $this->mockFormatShare();
3949
+
3950
+        [$userFolder, $folder] = $this->getNonSharedUserFolder();
3951
+        $folder->method('getId')
3952
+            ->willReturn(42);
3953
+
3954
+        $share = Server::get(IManager::class)->newShare();
3955
+        $share
3956
+            ->setId(42)
3957
+            ->setSharedBy($this->currentUser)
3958
+            ->setShareOwner($this->currentUser)
3959
+            ->setShareType(IShare::TYPE_GROUP)
3960
+            ->setSharedWith('group1')
3961
+            ->setPermissions(Constants::PERMISSION_READ)
3962
+            ->setNode($folder);
3963
+
3964
+        // note: updateShare will modify the received instance but getSharedWith will reread from the database,
3965
+        // so their values will be different
3966
+        $incomingShare = Server::get(IManager::class)->newShare();
3967
+        $incomingShare
3968
+            ->setId(42)
3969
+            ->setSharedBy($this->currentUser)
3970
+            ->setShareOwner($this->currentUser)
3971
+            ->setShareType(IShare::TYPE_GROUP)
3972
+            ->setSharedWith('group1')
3973
+            ->setPermissions(Constants::PERMISSION_READ)
3974
+            ->setNode($folder);
3975
+
3976
+        $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share);
3977
+
3978
+        $this->shareManager->expects($this->any())
3979
+            ->method('getSharedWith')
3980
+            ->willReturnMap([
3981
+                ['currentUser', IShare::TYPE_USER, $share->getNode(), -1, 0, []],
3982
+                ['currentUser', IShare::TYPE_GROUP, $share->getNode(), -1, 0, [$incomingShare]]
3983
+            ]);
3984
+
3985
+        $this->shareManager->expects($this->once())
3986
+            ->method('updateShare')
3987
+            ->with($share)
3988
+            ->willReturn($share);
3989
+
3990
+        $this->rootFolder->method('getUserFolder')
3991
+            ->with($this->currentUser)
3992
+            ->willReturn($userFolder);
3993
+
3994
+        $userFolder->method('getById')
3995
+            ->with(42)
3996
+            ->willReturn([$folder]);
3997
+
3998
+        $mountPoint = $this->createMock(IMountPoint::class);
3999
+        $folder->method('getMountPoint')
4000
+            ->willReturn($mountPoint);
4001
+        $mountPoint->method('getStorageRootId')
4002
+            ->willReturn(42);
4003
+
4004
+        $result = $ocs->updateShare(42, 31);
4005
+        $this->assertInstanceOf(DataResponse::class, $result);
4006
+    }
4007
+
4008
+    public function testUpdateShareOwnerless(): void {
4009
+        $ocs = $this->mockFormatShare();
4010
+
4011
+        $mount = $this->createMock(IShareOwnerlessMount::class);
4012
+
4013
+        $file = $this->createMock(File::class);
4014
+        $file
4015
+            ->expects($this->exactly(2))
4016
+            ->method('getPermissions')
4017
+            ->willReturn(Constants::PERMISSION_SHARE);
4018
+        $file
4019
+            ->expects($this->once())
4020
+            ->method('getMountPoint')
4021
+            ->willReturn($mount);
4022
+
4023
+        $userFolder = $this->createMock(Folder::class);
4024
+        $userFolder->method('getById')
4025
+            ->with(2)
4026
+            ->willReturn([$file]);
4027
+        $userFolder->method('getFirstNodeById')
4028
+            ->with(2)
4029
+            ->willReturn($file);
4030
+
4031
+        $this->rootFolder
4032
+            ->method('getUserFolder')
4033
+            ->with($this->currentUser)
4034
+            ->willReturn($userFolder);
4035
+
4036
+        $share = $this->createMock(IShare::class);
4037
+        $share
4038
+            ->expects($this->once())
4039
+            ->method('getNode')
4040
+            ->willReturn($file);
4041
+        $share
4042
+            ->expects($this->exactly(2))
4043
+            ->method('getNodeId')
4044
+            ->willReturn(2);
4045
+        $share
4046
+            ->expects($this->exactly(2))
4047
+            ->method('getPermissions')
4048
+            ->willReturn(Constants::PERMISSION_SHARE);
4049
+
4050
+        $this->shareManager
4051
+            ->expects($this->once())
4052
+            ->method('getShareById')
4053
+            ->with('ocinternal:1', $this->currentUser)
4054
+            ->willReturn($share);
4055
+
4056
+        $this->shareManager
4057
+            ->expects($this->once())
4058
+            ->method('updateShare')
4059
+            ->with($share)
4060
+            ->willReturn($share);
4061
+
4062
+        $result = $ocs->updateShare(1, Constants::PERMISSION_ALL);
4063
+        $this->assertInstanceOf(DataResponse::class, $result);
4064
+    }
4065
+
4066
+    public static function dataFormatShare(): array {
4067
+        $owner = ['getDisplayName' => 'ownerDN'];
4068
+        $initiator = ['getDisplayName' => 'initiatorDN'];
4069
+        $recipient = [
4070
+            'getDisplayName' => 'recipientDN',
4071
+            'getSystemEMailAddress' => 'recipient'
4072
+        ];
4073
+
4074
+        $folder = [
4075
+            'class' => Folder::class,
4076
+            'mimeType' => 'myFolderMimeType',
4077
+            'path' => 'folder',
4078
+            'id' => 2,
4079
+        ];
4080
+        $file = [
4081
+            'class' => File::class,
4082
+            'mimeType' => 'myMimeType',
4083
+            'path' => 'file',
4084
+            'id' => 3,
4085
+        ];
4086
+        $fileWithPreview = [
4087
+            'class' => File::class,
4088
+            'mimeType' => 'mimeWithPreview',
4089
+            'path' => 'fileWithPreview',
4090
+            'id' => 4,
4091
+        ];
4092
+
4093
+        $result = [];
4094
+
4095
+        $share = [
4096
+            'type' => IShare::TYPE_USER,
4097
+            'owner' => 'owner',
4098
+            'sharedWith' => 'recipient',
4099
+            'attributes' => [
4100
+                'scope' => 'permissions',
4101
+                'key' => 'download',
4102
+                'value' => true
4103
+            ],
4104
+            'node' => $file,
4105
+            'note' => 'personal note',
4106
+        ];
4107
+
4108
+        // User backend down
4109
+        $result[] = [
4110
+            [
4111
+                'id' => '42',
4112
+                'share_type' => IShare::TYPE_USER,
4113
+                'uid_owner' => 'initiator',
4114
+                'displayname_owner' => 'initiator',
4115
+                'permissions' => 1,
4116
+                'stime' => 946684862,
4117
+                'parent' => null,
4118
+                'expiration' => null,
4119
+                'token' => null,
4120
+                'uid_file_owner' => 'owner',
4121
+                'displayname_file_owner' => 'owner',
4122
+                'path' => 'file',
4123
+                'item_type' => 'file',
4124
+                'storage_id' => 'storageId',
4125
+                'storage' => 100,
4126
+                'item_source' => 3,
4127
+                'file_source' => 3,
4128
+                'file_parent' => 1,
4129
+                'file_target' => 'myTarget',
4130
+                'share_with' => 'recipient',
4131
+                'share_with_displayname' => 'recipient',
4132
+                'share_with_displayname_unique' => 'recipient',
4133
+                'note' => 'personal note',
4134
+                'label' => '',
4135
+                'mail_send' => 0,
4136
+                'mimetype' => 'myMimeType',
4137
+                'has_preview' => false,
4138
+                'hide_download' => 0,
4139
+                'can_edit' => false,
4140
+                'can_delete' => false,
4141
+                'item_size' => 123456,
4142
+                'item_mtime' => 1234567890,
4143
+                'is-mount-root' => false,
4144
+                'mount-type' => '',
4145
+                'attributes' => '[{"scope":"permissions","key":"download","value":true}]',
4146
+                'item_permissions' => 1,
4147
+            ],
4148
+            $share,
4149
+            [], false
4150
+        ];
4151
+        // User backend up
4152
+        $result[] = [
4153
+            [
4154
+                'id' => '42',
4155
+                'share_type' => IShare::TYPE_USER,
4156
+                'uid_owner' => 'initiator',
4157
+                'displayname_owner' => 'initiatorDN',
4158
+                'permissions' => 1,
4159
+                'stime' => 946684862,
4160
+                'parent' => null,
4161
+                'expiration' => null,
4162
+                'token' => null,
4163
+                'uid_file_owner' => 'owner',
4164
+                'displayname_file_owner' => 'ownerDN',
4165
+                'note' => 'personal note',
4166
+                'label' => '',
4167
+                'path' => 'file',
4168
+                'item_type' => 'file',
4169
+                'storage_id' => 'storageId',
4170
+                'storage' => 100,
4171
+                'item_source' => 3,
4172
+                'file_source' => 3,
4173
+                'file_parent' => 1,
4174
+                'file_target' => 'myTarget',
4175
+                'share_with' => 'recipient',
4176
+                'share_with_displayname' => 'recipientDN',
4177
+                'share_with_displayname_unique' => 'recipient',
4178
+                'mail_send' => 0,
4179
+                'mimetype' => 'myMimeType',
4180
+                'has_preview' => false,
4181
+                'hide_download' => 0,
4182
+                'can_edit' => false,
4183
+                'can_delete' => false,
4184
+                'item_size' => 123456,
4185
+                'item_mtime' => 1234567890,
4186
+                'is-mount-root' => false,
4187
+                'mount-type' => '',
4188
+                'attributes' => '[{"scope":"permissions","key":"download","value":true}]',
4189
+                'item_permissions' => 1,
4190
+            ], $share, [
4191
+                ['owner', $owner],
4192
+                ['initiator', $initiator],
4193
+                ['recipient', $recipient],
4194
+            ], false
4195
+        ];
4196
+
4197
+        // Same but no attributes
4198
+        $share = [
4199
+            'type' => IShare::TYPE_USER,
4200
+            'owner' => 'owner',
4201
+            'sharedWith' => 'recipient',
4202
+            'node' => $file,
4203
+            'note' => 'personal note',
4204
+        ];
4205
+
4206
+        // User backend down
4207
+        $result[] = [
4208
+            [
4209
+                'id' => '42',
4210
+                'share_type' => IShare::TYPE_USER,
4211
+                'uid_owner' => 'initiator',
4212
+                'displayname_owner' => 'initiator',
4213
+                'permissions' => 1,
4214
+                'attributes' => null,
4215
+                'stime' => 946684862,
4216
+                'parent' => null,
4217
+                'expiration' => null,
4218
+                'token' => null,
4219
+                'uid_file_owner' => 'owner',
4220
+                'displayname_file_owner' => 'owner',
4221
+                'note' => 'personal note',
4222
+                'label' => '',
4223
+                'path' => 'file',
4224
+                'item_type' => 'file',
4225
+                'storage_id' => 'storageId',
4226
+                'storage' => 100,
4227
+                'item_source' => 3,
4228
+                'file_source' => 3,
4229
+                'file_parent' => 1,
4230
+                'file_target' => 'myTarget',
4231
+                'share_with' => 'recipient',
4232
+                'share_with_displayname' => 'recipient',
4233
+                'share_with_displayname_unique' => 'recipient',
4234
+                'mail_send' => 0,
4235
+                'mimetype' => 'myMimeType',
4236
+                'has_preview' => false,
4237
+                'hide_download' => 0,
4238
+                'can_edit' => false,
4239
+                'can_delete' => false,
4240
+                'item_size' => 123456,
4241
+                'item_mtime' => 1234567890,
4242
+                'is-mount-root' => false,
4243
+                'mount-type' => '',
4244
+                'attributes' => null,
4245
+                'item_permissions' => 1,
4246
+            ], $share, [], false
4247
+        ];
4248
+
4249
+        $share['owner'] = 'currentUser';
4250
+
4251
+        // User backend down
4252
+        $result[] = [
4253
+            [
4254
+                'id' => '42',
4255
+                'share_type' => IShare::TYPE_USER,
4256
+                'uid_owner' => 'initiator',
4257
+                'displayname_owner' => 'initiator',
4258
+                'permissions' => 1,
4259
+                'attributes' => null,
4260
+                'stime' => 946684862,
4261
+                'parent' => null,
4262
+                'expiration' => null,
4263
+                'token' => null,
4264
+                'uid_file_owner' => 'currentUser',
4265
+                'displayname_file_owner' => 'currentUser',
4266
+                'note' => 'personal note',
4267
+                'label' => '',
4268
+                'path' => 'file',
4269
+                'item_type' => 'file',
4270
+                'storage_id' => 'storageId',
4271
+                'storage' => 100,
4272
+                'item_source' => 3,
4273
+                'file_source' => 3,
4274
+                'file_parent' => 1,
4275
+                'file_target' => 'myTarget',
4276
+                'share_with' => 'recipient',
4277
+                'share_with_displayname' => 'recipient',
4278
+                'share_with_displayname_unique' => 'recipient',
4279
+                'mail_send' => 0,
4280
+                'mimetype' => 'myMimeType',
4281
+                'has_preview' => false,
4282
+                'hide_download' => 0,
4283
+                'can_edit' => true,
4284
+                'can_delete' => true,
4285
+                'item_size' => 123456,
4286
+                'item_mtime' => 1234567890,
4287
+                'is-mount-root' => false,
4288
+                'mount-type' => '',
4289
+                'attributes' => null,
4290
+                'item_permissions' => 11,
4291
+            ], $share, [], false
4292
+        ];
4293
+
4294
+        // with existing group
4295
+        $share = [
4296
+            'type' => IShare::TYPE_GROUP,
4297
+            'owner' => 'owner',
4298
+            'sharedWith' => 'recipientGroup',
4299
+            'node' => $file,
4300
+            'note' => 'personal note',
4301
+        ];
4302
+
4303
+        $result[] = [
4304
+            [
4305
+                'id' => '42',
4306
+                'share_type' => IShare::TYPE_GROUP,
4307
+                'uid_owner' => 'initiator',
4308
+                'displayname_owner' => 'initiator',
4309
+                'permissions' => 1,
4310
+                'attributes' => null,
4311
+                'stime' => 946684862,
4312
+                'parent' => null,
4313
+                'expiration' => null,
4314
+                'token' => null,
4315
+                'uid_file_owner' => 'owner',
4316
+                'displayname_file_owner' => 'owner',
4317
+                'note' => 'personal note',
4318
+                'label' => '',
4319
+                'path' => 'file',
4320
+                'item_type' => 'file',
4321
+                'storage_id' => 'storageId',
4322
+                'storage' => 100,
4323
+                'item_source' => 3,
4324
+                'file_source' => 3,
4325
+                'file_parent' => 1,
4326
+                'file_target' => 'myTarget',
4327
+                'share_with' => 'recipientGroup',
4328
+                'share_with_displayname' => 'recipientGroupDisplayName',
4329
+                'mail_send' => 0,
4330
+                'mimetype' => 'myMimeType',
4331
+                'has_preview' => false,
4332
+                'hide_download' => 0,
4333
+                'can_edit' => false,
4334
+                'can_delete' => false,
4335
+                'item_size' => 123456,
4336
+                'item_mtime' => 1234567890,
4337
+                'is-mount-root' => false,
4338
+                'mount-type' => '',
4339
+                'attributes' => null,
4340
+                'item_permissions' => 1,
4341
+            ], $share, [], false
4342
+        ];
4343
+
4344
+        // with unknown group / no group backend
4345
+        $share['sharedWith'] = 'recipientGroup2';
4346
+
4347
+        $result[] = [
4348
+            [
4349
+                'id' => '42',
4350
+                'share_type' => IShare::TYPE_GROUP,
4351
+                'uid_owner' => 'initiator',
4352
+                'displayname_owner' => 'initiator',
4353
+                'permissions' => 1,
4354
+                'stime' => 946684862,
4355
+                'parent' => null,
4356
+                'expiration' => null,
4357
+                'token' => null,
4358
+                'uid_file_owner' => 'owner',
4359
+                'displayname_file_owner' => 'owner',
4360
+                'note' => 'personal note',
4361
+                'label' => '',
4362
+                'path' => 'file',
4363
+                'item_type' => 'file',
4364
+                'storage_id' => 'storageId',
4365
+                'storage' => 100,
4366
+                'item_source' => 3,
4367
+                'file_source' => 3,
4368
+                'file_parent' => 1,
4369
+                'file_target' => 'myTarget',
4370
+                'share_with' => 'recipientGroup2',
4371
+                'share_with_displayname' => 'recipientGroup2',
4372
+                'mail_send' => 0,
4373
+                'mimetype' => 'myMimeType',
4374
+                'has_preview' => false,
4375
+                'hide_download' => 0,
4376
+                'can_edit' => false,
4377
+                'can_delete' => false,
4378
+                'item_size' => 123456,
4379
+                'item_mtime' => 1234567890,
4380
+                'is-mount-root' => false,
4381
+                'mount-type' => '',
4382
+                'attributes' => null,
4383
+                'item_permissions' => 1,
4384
+            ], $share, [], false
4385
+        ];
4386
+
4387
+        $share = [
4388
+            'type' => IShare::TYPE_LINK,
4389
+            'owner' => 'owner',
4390
+            'node' => $file,
4391
+            'note' => 'personal note',
4392
+            'password' => 'mypassword',
4393
+            'expirationDate' => new \DateTime('2001-01-02T00:00:00'),
4394
+            'token' => 'myToken',
4395
+            'label' => 'new link share',
4396
+        ];
4397
+
4398
+        $result[] = [
4399
+            [
4400
+                'id' => '42',
4401
+                'share_type' => IShare::TYPE_LINK,
4402
+                'uid_owner' => 'initiator',
4403
+                'displayname_owner' => 'initiator',
4404
+                'permissions' => 1,
4405
+                'attributes' => null,
4406
+                'stime' => 946684862,
4407
+                'parent' => null,
4408
+                'expiration' => '2001-01-02 00:00:00',
4409
+                'token' => 'myToken',
4410
+                'uid_file_owner' => 'owner',
4411
+                'displayname_file_owner' => 'owner',
4412
+                'note' => 'personal note',
4413
+                'label' => 'new link share',
4414
+                'path' => 'file',
4415
+                'item_type' => 'file',
4416
+                'storage_id' => 'storageId',
4417
+                'storage' => 100,
4418
+                'item_source' => 3,
4419
+                'file_source' => 3,
4420
+                'file_parent' => 1,
4421
+                'file_target' => 'myTarget',
4422
+                'password' => 'mypassword',
4423
+                'share_with' => 'mypassword',
4424
+                'share_with_displayname' => '(Shared link)',
4425
+                'send_password_by_talk' => false,
4426
+                'mail_send' => 0,
4427
+                'url' => 'myLink',
4428
+                'mimetype' => 'myMimeType',
4429
+                'has_preview' => false,
4430
+                'hide_download' => 0,
4431
+                'can_edit' => false,
4432
+                'can_delete' => false,
4433
+                'item_size' => 123456,
4434
+                'item_mtime' => 1234567890,
4435
+                'is-mount-root' => false,
4436
+                'mount-type' => '',
4437
+                'attributes' => null,
4438
+                'item_permissions' => 1,
4439
+            ], $share, [], false
4440
+        ];
4441
+
4442
+        $share['sendPasswordByTalk'] = true;
4443
+
4444
+        $result[] = [
4445
+            [
4446
+                'id' => '42',
4447
+                'share_type' => IShare::TYPE_LINK,
4448
+                'uid_owner' => 'initiator',
4449
+                'displayname_owner' => 'initiator',
4450
+                'permissions' => 1,
4451
+                'stime' => 946684862,
4452
+                'parent' => null,
4453
+                'expiration' => '2001-01-02 00:00:00',
4454
+                'token' => 'myToken',
4455
+                'uid_file_owner' => 'owner',
4456
+                'displayname_file_owner' => 'owner',
4457
+                'note' => 'personal note',
4458
+                'label' => 'new link share',
4459
+                'path' => 'file',
4460
+                'item_type' => 'file',
4461
+                'storage_id' => 'storageId',
4462
+                'storage' => 100,
4463
+                'item_source' => 3,
4464
+                'file_source' => 3,
4465
+                'file_parent' => 1,
4466
+                'file_target' => 'myTarget',
4467
+                'password' => 'mypassword',
4468
+                'share_with' => 'mypassword',
4469
+                'share_with_displayname' => '(Shared link)',
4470
+                'send_password_by_talk' => true,
4471
+                'mail_send' => 0,
4472
+                'url' => 'myLink',
4473
+                'mimetype' => 'myMimeType',
4474
+                'has_preview' => false,
4475
+                'hide_download' => 0,
4476
+                'can_edit' => false,
4477
+                'can_delete' => false,
4478
+                'item_size' => 123456,
4479
+                'item_mtime' => 1234567890,
4480
+                'is-mount-root' => false,
4481
+                'mount-type' => '',
4482
+                'attributes' => null,
4483
+                'item_permissions' => 1,
4484
+            ], $share, [], false
4485
+        ];
4486
+
4487
+        $share = [
4488
+            'type' => IShare::TYPE_REMOTE,
4489
+            'owner' => 'owner',
4490
+            'sharedWith' => '[email protected]',
4491
+            'node' => $folder,
4492
+            'note' => 'personal note',
4493
+            'expirationDate' => new \DateTime('2001-02-03T04:05:06'),
4494
+        ];
4495
+
4496
+        $result[] = [
4497
+            [
4498
+                'id' => '42',
4499
+                'share_type' => IShare::TYPE_REMOTE,
4500
+                'uid_owner' => 'initiator',
4501
+                'displayname_owner' => 'initiator',
4502
+                'permissions' => 1,
4503
+                'stime' => 946684862,
4504
+                'parent' => null,
4505
+                'expiration' => '2001-02-03 00:00:00',
4506
+                'token' => null,
4507
+                'uid_file_owner' => 'owner',
4508
+                'displayname_file_owner' => 'owner',
4509
+                'note' => 'personal note',
4510
+                'label' => '',
4511
+                'path' => 'folder',
4512
+                'item_type' => 'folder',
4513
+                'storage_id' => 'storageId',
4514
+                'storage' => 100,
4515
+                'item_source' => 2,
4516
+                'file_source' => 2,
4517
+                'file_parent' => 1,
4518
+                'file_target' => 'myTarget',
4519
+                'share_with' => '[email protected]',
4520
+                'share_with_displayname' => 'foobar',
4521
+                'mail_send' => 0,
4522
+                'mimetype' => 'myFolderMimeType',
4523
+                'has_preview' => false,
4524
+                'hide_download' => 0,
4525
+                'can_edit' => false,
4526
+                'can_delete' => false,
4527
+                'item_size' => 123456,
4528
+                'item_mtime' => 1234567890,
4529
+                'is-mount-root' => false,
4530
+                'mount-type' => '',
4531
+                'attributes' => null,
4532
+                'item_permissions' => 1,
4533
+                'is_trusted_server' => false,
4534
+            ], $share, [], false
4535
+        ];
4536
+
4537
+        $share = [
4538
+            'type' => IShare::TYPE_REMOTE_GROUP,
4539
+            'owner' => 'owner',
4540
+            'sharedWith' => '[email protected]',
4541
+            'node' => $folder,
4542
+            'note' => 'personal note',
4543
+            'expirationDate' => new \DateTime('2001-02-03T04:05:06'),
4544
+        ];
4545
+
4546
+        $result[] = [
4547
+            [
4548
+                'id' => '42',
4549
+                'share_type' => IShare::TYPE_REMOTE_GROUP,
4550
+                'uid_owner' => 'initiator',
4551
+                'displayname_owner' => 'initiator',
4552
+                'permissions' => 1,
4553
+                'stime' => 946684862,
4554
+                'parent' => null,
4555
+                'expiration' => '2001-02-03 00:00:00',
4556
+                'token' => null,
4557
+                'uid_file_owner' => 'owner',
4558
+                'displayname_file_owner' => 'owner',
4559
+                'note' => 'personal note',
4560
+                'label' => '',
4561
+                'path' => 'folder',
4562
+                'item_type' => 'folder',
4563
+                'storage_id' => 'storageId',
4564
+                'storage' => 100,
4565
+                'item_source' => 2,
4566
+                'file_source' => 2,
4567
+                'file_parent' => 1,
4568
+                'file_target' => 'myTarget',
4569
+                'share_with' => '[email protected]',
4570
+                'share_with_displayname' => 'foobar',
4571
+                'mail_send' => 0,
4572
+                'mimetype' => 'myFolderMimeType',
4573
+                'has_preview' => false,
4574
+                'hide_download' => 0,
4575
+                'can_edit' => false,
4576
+                'can_delete' => false,
4577
+                'item_size' => 123456,
4578
+                'item_mtime' => 1234567890,
4579
+                'is-mount-root' => false,
4580
+                'mount-type' => '',
4581
+                'attributes' => null,
4582
+                'item_permissions' => 1,
4583
+                'is_trusted_server' => false,
4584
+            ], $share, [], false
4585
+        ];
4586
+
4587
+        // Circle with id, display name and avatar set by the Circles app
4588
+        $share = [
4589
+            'type' => IShare::TYPE_CIRCLE,
4590
+            'owner' => 'owner',
4591
+            'sharedWith' => 'Circle (Public circle, circleOwner) [4815162342]',
4592
+            'sharedWithDisplayName' => 'The display name',
4593
+            'sharedWithAvatar' => 'path/to/the/avatar',
4594
+            'node' => $folder,
4595
+        ];
4596
+
4597
+        $result[] = [
4598
+            [
4599
+                'id' => '42',
4600
+                'share_type' => IShare::TYPE_CIRCLE,
4601
+                'uid_owner' => 'initiator',
4602
+                'displayname_owner' => 'initiator',
4603
+                'permissions' => 1,
4604
+                'attributes' => null,
4605
+                'stime' => 946684862,
4606
+                'parent' => null,
4607
+                'expiration' => null,
4608
+                'token' => null,
4609
+                'uid_file_owner' => 'owner',
4610
+                'displayname_file_owner' => 'owner',
4611
+                'note' => '',
4612
+                'label' => '',
4613
+                'path' => 'folder',
4614
+                'item_type' => 'folder',
4615
+                'storage_id' => 'storageId',
4616
+                'storage' => 100,
4617
+                'item_source' => 2,
4618
+                'file_source' => 2,
4619
+                'file_parent' => 1,
4620
+                'file_target' => 'myTarget',
4621
+                'share_with' => '4815162342',
4622
+                'share_with_displayname' => 'The display name',
4623
+                'share_with_avatar' => 'path/to/the/avatar',
4624
+                'mail_send' => 0,
4625
+                'mimetype' => 'myFolderMimeType',
4626
+                'has_preview' => false,
4627
+                'hide_download' => 0,
4628
+                'can_edit' => false,
4629
+                'can_delete' => false,
4630
+                'item_size' => 123456,
4631
+                'item_mtime' => 1234567890,
4632
+                'is-mount-root' => false,
4633
+                'mount-type' => '',
4634
+                'attributes' => null,
4635
+                'item_permissions' => 1,
4636
+            ], $share, [], false
4637
+        ];
4638
+
4639
+        // Circle with id set by the Circles app
4640
+        $share = [
4641
+            'type' => IShare::TYPE_CIRCLE,
4642
+            'owner' => 'owner',
4643
+            'sharedWith' => 'Circle (Public circle, circleOwner) [4815162342]',
4644
+            'node' => $folder,
4645
+        ];
4646
+
4647
+        $result[] = [
4648
+            [
4649
+                'id' => '42',
4650
+                'share_type' => IShare::TYPE_CIRCLE,
4651
+                'uid_owner' => 'initiator',
4652
+                'displayname_owner' => 'initiator',
4653
+                'permissions' => 1,
4654
+                'stime' => 946684862,
4655
+                'parent' => null,
4656
+                'expiration' => null,
4657
+                'token' => null,
4658
+                'uid_file_owner' => 'owner',
4659
+                'displayname_file_owner' => 'owner',
4660
+                'note' => '',
4661
+                'label' => '',
4662
+                'path' => 'folder',
4663
+                'item_type' => 'folder',
4664
+                'storage_id' => 'storageId',
4665
+                'storage' => 100,
4666
+                'item_source' => 2,
4667
+                'file_source' => 2,
4668
+                'file_parent' => 1,
4669
+                'file_target' => 'myTarget',
4670
+                'share_with' => '4815162342',
4671
+                'share_with_displayname' => 'Circle (Public circle, circleOwner)',
4672
+                'share_with_avatar' => '',
4673
+                'mail_send' => 0,
4674
+                'mimetype' => 'myFolderMimeType',
4675
+                'has_preview' => false,
4676
+                'hide_download' => 0,
4677
+                'can_edit' => false,
4678
+                'can_delete' => false,
4679
+                'item_size' => 123456,
4680
+                'item_mtime' => 1234567890,
4681
+                'is-mount-root' => false,
4682
+                'mount-type' => '',
4683
+                'attributes' => null,
4684
+                'item_permissions' => 1,
4685
+            ], $share, [], false
4686
+        ];
4687
+
4688
+        // Circle with id not set by the Circles app
4689
+        $share = [
4690
+            'type' => IShare::TYPE_CIRCLE,
4691
+            'owner' => 'owner',
4692
+            'sharedWith' => 'Circle (Public circle, circleOwner)',
4693
+            'node' => $folder,
4694
+        ];
4695
+
4696
+        $result[] = [
4697
+            [
4698
+                'id' => '42',
4699
+                'share_type' => IShare::TYPE_CIRCLE,
4700
+                'uid_owner' => 'initiator',
4701
+                'displayname_owner' => 'initiator',
4702
+                'permissions' => 1,
4703
+                'stime' => 946684862,
4704
+                'parent' => null,
4705
+                'expiration' => null,
4706
+                'token' => null,
4707
+                'uid_file_owner' => 'owner',
4708
+                'displayname_file_owner' => 'owner',
4709
+                'note' => '',
4710
+                'label' => '',
4711
+                'path' => 'folder',
4712
+                'item_type' => 'folder',
4713
+                'storage_id' => 'storageId',
4714
+                'storage' => 100,
4715
+                'item_source' => 2,
4716
+                'file_source' => 2,
4717
+                'file_parent' => 1,
4718
+                'file_target' => 'myTarget',
4719
+                'share_with' => 'Circle',
4720
+                'share_with_displayname' => 'Circle (Public circle, circleOwner)',
4721
+                'share_with_avatar' => '',
4722
+                'mail_send' => 0,
4723
+                'mimetype' => 'myFolderMimeType',
4724
+                'has_preview' => false,
4725
+                'hide_download' => 0,
4726
+                'can_edit' => false,
4727
+                'can_delete' => false,
4728
+                'item_size' => 123456,
4729
+                'item_mtime' => 1234567890,
4730
+                'is-mount-root' => false,
4731
+                'mount-type' => '',
4732
+                'attributes' => null,
4733
+                'item_permissions' => 1,
4734
+            ], $share, [], false
4735
+        ];
4736
+
4737
+        // No node
4738
+        $share = [
4739
+            'type' => IShare::TYPE_USER,
4740
+            'owner' => 'owner',
4741
+            'sharedWith' => 'recipient',
4742
+            'note' => 'personal note',
4743
+        ];
4744
+
4745
+        $result[] = [
4746
+            [], $share, [], true
4747
+        ];
4748
+
4749
+        $share = [
4750
+            'type' => IShare::TYPE_EMAIL,
4751
+            'owner' => 'owner',
4752
+            'sharedWith' => '[email protected]',
4753
+            'node' => $folder,
4754
+            'password' => 'password',
4755
+        ];
4756
+
4757
+        $result[] = [
4758
+            [
4759
+                'id' => '42',
4760
+                'share_type' => IShare::TYPE_EMAIL,
4761
+                'uid_owner' => 'initiator',
4762
+                'displayname_owner' => 'initiator',
4763
+                'permissions' => 1,
4764
+                'stime' => 946684862,
4765
+                'parent' => null,
4766
+                'expiration' => null,
4767
+                'token' => null,
4768
+                'uid_file_owner' => 'owner',
4769
+                'displayname_file_owner' => 'owner',
4770
+                'note' => '',
4771
+                'label' => '',
4772
+                'path' => 'folder',
4773
+                'item_type' => 'folder',
4774
+                'storage_id' => 'storageId',
4775
+                'storage' => 100,
4776
+                'item_source' => 2,
4777
+                'file_source' => 2,
4778
+                'file_parent' => 1,
4779
+                'file_target' => 'myTarget',
4780
+                'share_with' => '[email protected]',
4781
+                'share_with_displayname' => 'mail display name',
4782
+                'mail_send' => 0,
4783
+                'mimetype' => 'myFolderMimeType',
4784
+                'has_preview' => false,
4785
+                'password' => 'password',
4786
+                'send_password_by_talk' => false,
4787
+                'hide_download' => 0,
4788
+                'can_edit' => false,
4789
+                'can_delete' => false,
4790
+                'password_expiration_time' => null,
4791
+                'item_size' => 123456,
4792
+                'item_mtime' => 1234567890,
4793
+                'is-mount-root' => false,
4794
+                'mount-type' => '',
4795
+                'attributes' => null,
4796
+                'item_permissions' => 1,
4797
+            ], $share, [], false
4798
+        ];
4799
+
4800
+        $share['sendPasswordByTalk'] = true;
4801
+
4802
+        $result[] = [
4803
+            [
4804
+                'id' => '42',
4805
+                'share_type' => IShare::TYPE_EMAIL,
4806
+                'uid_owner' => 'initiator',
4807
+                'displayname_owner' => 'initiator',
4808
+                'permissions' => 1,
4809
+                'stime' => 946684862,
4810
+                'parent' => null,
4811
+                'expiration' => null,
4812
+                'token' => null,
4813
+                'uid_file_owner' => 'owner',
4814
+                'displayname_file_owner' => 'owner',
4815
+                'note' => '',
4816
+                'label' => '',
4817
+                'path' => 'folder',
4818
+                'item_type' => 'folder',
4819
+                'storage_id' => 'storageId',
4820
+                'storage' => 100,
4821
+                'item_source' => 2,
4822
+                'file_source' => 2,
4823
+                'file_parent' => 1,
4824
+                'file_target' => 'myTarget',
4825
+                'share_with' => '[email protected]',
4826
+                'share_with_displayname' => 'mail display name',
4827
+                'mail_send' => 0,
4828
+                'mimetype' => 'myFolderMimeType',
4829
+                'has_preview' => false,
4830
+                'password' => 'password',
4831
+                'send_password_by_talk' => true,
4832
+                'hide_download' => 0,
4833
+                'can_edit' => false,
4834
+                'can_delete' => false,
4835
+                'password_expiration_time' => null,
4836
+                'item_size' => 123456,
4837
+                'item_mtime' => 1234567890,
4838
+                'is-mount-root' => false,
4839
+                'mount-type' => '',
4840
+                'attributes' => null,
4841
+                'item_permissions' => 1,
4842
+            ], $share, [], false
4843
+        ];
4844
+
4845
+        // Preview is available
4846
+        $share = [
4847
+            'type' => IShare::TYPE_USER,
4848
+            'owner' => 'currentUser',
4849
+            'sharedWith' => 'recipient',
4850
+            'node' => $fileWithPreview,
4851
+            'note' => 'personal note',
4852
+        ];
4853
+
4854
+        $result[] = [
4855
+            [
4856
+                'id' => '42',
4857
+                'share_type' => IShare::TYPE_USER,
4858
+                'uid_owner' => 'initiator',
4859
+                'displayname_owner' => 'initiator',
4860
+                'permissions' => 1,
4861
+                'stime' => 946684862,
4862
+                'parent' => null,
4863
+                'expiration' => null,
4864
+                'token' => null,
4865
+                'uid_file_owner' => 'currentUser',
4866
+                'displayname_file_owner' => 'currentUser',
4867
+                'note' => 'personal note',
4868
+                'label' => '',
4869
+                'path' => 'fileWithPreview',
4870
+                'item_type' => 'file',
4871
+                'storage_id' => 'storageId',
4872
+                'storage' => 100,
4873
+                'item_source' => 4,
4874
+                'file_source' => 4,
4875
+                'file_parent' => 1,
4876
+                'file_target' => 'myTarget',
4877
+                'share_with' => 'recipient',
4878
+                'share_with_displayname' => 'recipient',
4879
+                'share_with_displayname_unique' => 'recipient',
4880
+                'mail_send' => 0,
4881
+                'mimetype' => 'mimeWithPreview',
4882
+                'has_preview' => true,
4883
+                'hide_download' => 0,
4884
+                'can_edit' => true,
4885
+                'can_delete' => true,
4886
+                'item_size' => 123456,
4887
+                'item_mtime' => 1234567890,
4888
+                'is-mount-root' => false,
4889
+                'mount-type' => '',
4890
+                'attributes' => null,
4891
+                'item_permissions' => 11,
4892
+            ], $share, [], false
4893
+        ];
4894
+
4895
+        return $result;
4896
+    }
4897
+
4898
+    #[DataProvider('dataFormatShare')]
4899
+    public function testFormatShare(
4900
+        array $expects,
4901
+        array $shareParams,
4902
+        array $users,
4903
+        bool $exception,
4904
+    ): void {
4905
+        $users = array_map(
4906
+            function ($user) {
4907
+                $mock = $this->createMock(IUser::class);
4908
+                foreach ($user[1] as $method => $return) {
4909
+                    $mock->method($method)->willReturn($return);
4910
+                }
4911
+                return [$user[0],$mock];
4912
+            },
4913
+            $users
4914
+        );
4915
+
4916
+        $share = Server::get(IManager::class)->newShare();
4917
+        $share->setShareType($shareParams['type'])
4918
+            ->setSharedBy('initiator')
4919
+            ->setShareOwner($shareParams['owner'])
4920
+            ->setPermissions(Constants::PERMISSION_READ)
4921
+            ->setShareTime(new \DateTime('2000-01-01T00:01:02'))
4922
+            ->setTarget('myTarget')
4923
+            ->setId(42);
4924
+        if (isset($shareParams['sharedWith'])) {
4925
+            $share->setSharedWith($shareParams['sharedWith']);
4926
+        }
4927
+        if (isset($shareParams['sharedWithDisplayName'])) {
4928
+            $share->setSharedWithDisplayName($shareParams['sharedWithDisplayName']);
4929
+        }
4930
+        if (isset($shareParams['sharedWithAvatar'])) {
4931
+            $share->setSharedWithAvatar($shareParams['sharedWithAvatar']);
4932
+        }
4933
+        if (isset($shareParams['attributes'])) {
4934
+            $shareAttributes = $this->createMock(IShareAttributes::class);
4935
+            $shareAttributes->method('toArray')->willReturn($shareParams['attributes']);
4936
+            $shareAttributes->method('getAttribute')->with('permissions', 'download')->willReturn(true);
4937
+            $share->setAttributes($shareAttributes);
4938
+
4939
+            $expects['attributes'] = \json_encode($shareParams['attributes']);
4940
+        }
4941
+        if (isset($shareParams['node'])) {
4942
+            $node = $this->createMock($shareParams['node']['class']);
4943
+
4944
+            $node->method('getMimeType')->willReturn($shareParams['node']['mimeType']);
4945
+
4946
+            $mountPoint = $this->createMock(IMountPoint::class);
4947
+            $mountPoint->method('getMountType')->willReturn('');
4948
+            $node->method('getMountPoint')->willReturn($mountPoint);
4949
+
4950
+            $node->method('getPath')->willReturn($shareParams['node']['path']);
4951
+            $node->method('getId')->willReturn($shareParams['node']['id']);
4952
+
4953
+            $parent = $this->createMock(Folder::class);
4954
+            $parent->method('getId')->willReturn(1);
4955
+            $node->method('getParent')->willReturn($parent);
4956
+
4957
+            $node->method('getSize')->willReturn(123456);
4958
+            $node->method('getMTime')->willReturn(1234567890);
4959
+
4960
+            $cache = $this->createMock(ICache::class);
4961
+            $cache->method('getNumericStorageId')->willReturn(100);
4962
+            $storage = $this->createMock(IStorage::class);
4963
+            $storage->method('getId')->willReturn('storageId');
4964
+            $storage->method('getCache')->willReturn($cache);
4965
+
4966
+            $node->method('getStorage')->willReturn($storage);
4967
+
4968
+            $share->setNode($node);
4969
+        }
4970
+        if (isset($shareParams['note'])) {
4971
+            $share->setNote($shareParams['note']);
4972
+        }
4973
+        if (isset($shareParams['expirationDate'])) {
4974
+            $share->setExpirationDate($shareParams['expirationDate']);
4975
+        }
4976
+        if (isset($shareParams['token'])) {
4977
+            $share->setToken($shareParams['token']);
4978
+        }
4979
+        if (isset($shareParams['label'])) {
4980
+            $share->setLabel($shareParams['label']);
4981
+        }
4982
+        if (isset($shareParams['password'])) {
4983
+            $share->setPassword($shareParams['password']);
4984
+        }
4985
+        if (isset($shareParams['sendPasswordByTalk'])) {
4986
+            $share->setSendPasswordByTalk($shareParams['sendPasswordByTalk']);
4987
+        }
4988
+
4989
+        $this->userManager->method('get')->willReturnMap($users);
4990
+
4991
+        $recipientGroup = $this->createMock(IGroup::class);
4992
+        $recipientGroup->method('getDisplayName')->willReturn('recipientGroupDisplayName');
4993
+        $this->groupManager->method('get')->willReturnMap([
4994
+            ['recipientGroup', $recipientGroup],
4995
+        ]);
4996
+
4997
+        $this->urlGenerator->method('linkToRouteAbsolute')
4998
+            ->with('files_sharing.sharecontroller.showShare', ['token' => 'myToken'])
4999
+            ->willReturn('myLink');
5000
+
5001
+        $this->rootFolder->method('getUserFolder')
5002
+            ->with($this->currentUser)
5003
+            ->willReturnSelf();
5004
+        $this->dateTimeZone->method('getTimezone')->willReturn(new \DateTimeZone('UTC'));
5005
+
5006
+        if (!$exception) {
5007
+            $this->rootFolder->method('getFirstNodeById')
5008
+                ->with($share->getNodeId())
5009
+                ->willReturn($share->getNode());
5010
+
5011
+            $this->rootFolder->method('getRelativePath')
5012
+                ->with($share->getNode()->getPath())
5013
+                ->willReturnArgument(0);
5014
+        }
5015
+
5016
+        $cm = $this->createMock(\OCP\Contacts\IManager::class);
5017
+        $this->overwriteService(\OCP\Contacts\IManager::class, $cm);
5018
+
5019
+        $cm->method('search')
5020
+            ->willReturnMap([
5021
+                ['[email protected]', ['CLOUD'], [
5022
+                    'limit' => 1,
5023
+                    'enumeration' => false,
5024
+                    'strict_search' => true,
5025
+                ],
5026
+                    [
5027
+                        [
5028
+                            'CLOUD' => [
5029
+                                '[email protected]',
5030
+                            ],
5031
+                            'FN' => 'foobar',
5032
+                        ],
5033
+                    ],
5034
+                ],
5035
+                ['[email protected]', ['EMAIL'], [
5036
+                    'limit' => 1,
5037
+                    'enumeration' => false,
5038
+                    'strict_search' => true,
5039
+                ],
5040
+                    [
5041
+                        [
5042
+                            'EMAIL' => [
5043
+                                '[email protected]',
5044
+                            ],
5045
+                            'FN' => 'mail display name',
5046
+                        ],
5047
+                    ],
5048
+                ],
5049
+            ]);
5050
+
5051
+        try {
5052
+            $result = $this->invokePrivate($this->ocs, 'formatShare', [$share]);
5053
+            $this->assertFalse($exception);
5054
+            $this->assertEquals($expects, $result);
5055
+        } catch (NotFoundException $e) {
5056
+            $this->assertTrue($exception);
5057
+        }
5058
+    }
5059
+
5060
+    public static function dataFormatRoomShare(): array {
5061
+        $result = [];
5062
+
5063
+        $result[] = [
5064
+            [
5065
+                'id' => '42',
5066
+                'share_type' => IShare::TYPE_ROOM,
5067
+                'uid_owner' => 'initiator',
5068
+                'displayname_owner' => 'initiator',
5069
+                'permissions' => 1,
5070
+                'stime' => 946684862,
5071
+                'parent' => null,
5072
+                'expiration' => null,
5073
+                'token' => null,
5074
+                'uid_file_owner' => 'owner',
5075
+                'displayname_file_owner' => 'owner',
5076
+                'note' => 'personal note',
5077
+                'path' => 'file',
5078
+                'item_type' => 'file',
5079
+                'storage_id' => 'storageId',
5080
+                'storage' => 100,
5081
+                'item_source' => 3,
5082
+                'file_source' => 3,
5083
+                'file_parent' => 1,
5084
+                'file_target' => 'myTarget',
5085
+                'share_with' => 'recipientRoom',
5086
+                'share_with_displayname' => '',
5087
+                'mail_send' => 0,
5088
+                'mimetype' => 'myMimeType',
5089
+                'has_preview' => false,
5090
+                'hide_download' => 0,
5091
+                'label' => '',
5092
+                'can_edit' => false,
5093
+                'can_delete' => false,
5094
+                'item_size' => 123456,
5095
+                'item_mtime' => 1234567890,
5096
+                'is-mount-root' => false,
5097
+                'mount-type' => '',
5098
+                'attributes' => null,
5099
+                'item_permissions' => 1,
5100
+            ], false, []
5101
+        ];
5102
+
5103
+        $result[] = [
5104
+            [
5105
+                'id' => '42',
5106
+                'share_type' => IShare::TYPE_ROOM,
5107
+                'uid_owner' => 'initiator',
5108
+                'displayname_owner' => 'initiator',
5109
+                'permissions' => 1,
5110
+                'stime' => 946684862,
5111
+                'parent' => null,
5112
+                'expiration' => null,
5113
+                'token' => null,
5114
+                'uid_file_owner' => 'owner',
5115
+                'displayname_file_owner' => 'owner',
5116
+                'note' => 'personal note',
5117
+                'path' => 'file',
5118
+                'item_type' => 'file',
5119
+                'storage_id' => 'storageId',
5120
+                'storage' => 100,
5121
+                'item_source' => 3,
5122
+                'file_source' => 3,
5123
+                'file_parent' => 1,
5124
+                'file_target' => 'myTarget',
5125
+                'share_with' => 'recipientRoom',
5126
+                'share_with_displayname' => 'recipientRoomName',
5127
+                'mail_send' => 0,
5128
+                'mimetype' => 'myMimeType',
5129
+                'has_preview' => false,
5130
+                'hide_download' => 0,
5131
+                'label' => '',
5132
+                'can_edit' => false,
5133
+                'can_delete' => false,
5134
+                'item_size' => 123456,
5135
+                'item_mtime' => 1234567890,
5136
+                'is-mount-root' => false,
5137
+                'mount-type' => '',
5138
+                'attributes' => null,
5139
+                'item_permissions' => 9,
5140
+            ], true, [
5141
+                'share_with_displayname' => 'recipientRoomName'
5142
+            ]
5143
+        ];
5144
+
5145
+        return $result;
5146
+    }
5147
+
5148
+    /**
5149
+     *
5150
+     * @param array $expects
5151
+     * @param IShare $share
5152
+     * @param bool $helperAvailable
5153
+     * @param array $formatShareByHelper
5154
+     */
5155
+    #[DataProvider('dataFormatRoomShare')]
5156
+    public function testFormatRoomShare(array $expects, bool $helperAvailable, array $formatShareByHelper): void {
5157
+        $file = $this->createMock(File::class);
5158
+
5159
+        $file->method('getMimeType')->willReturn('myMimeType');
5160
+        $file->method('getPath')->willReturn('file');
5161
+        $file->method('getId')->willReturn(3);
5162
+
5163
+        $parent = $this->createMock(Folder::class);
5164
+        $parent->method('getId')->willReturn(1);
5165
+        $file->method('getParent')->willReturn($parent);
5166
+
5167
+        $file->method('getSize')->willReturn(123456);
5168
+        $file->method('getMTime')->willReturn(1234567890);
5169
+
5170
+        $mountPoint = $this->createMock(IMountPoint::class);
5171
+        $mountPoint->method('getMountType')->willReturn('');
5172
+        $file->method('getMountPoint')->willReturn($mountPoint);
5173
+
5174
+        $cache = $this->createMock(ICache::class);
5175
+        $cache->method('getNumericStorageId')->willReturn(100);
5176
+        $storage = $this->createMock(IStorage::class);
5177
+        $storage->method('getId')->willReturn('storageId');
5178
+        $storage->method('getCache')->willReturn($cache);
5179
+
5180
+        $file->method('getStorage')->willReturn($storage);
5181
+
5182
+        $share = Server::get(IManager::class)->newShare();
5183
+        $share->setShareType(IShare::TYPE_ROOM)
5184
+            ->setSharedWith('recipientRoom')
5185
+            ->setSharedBy('initiator')
5186
+            ->setShareOwner('owner')
5187
+            ->setPermissions(Constants::PERMISSION_READ)
5188
+            ->setNode($file)
5189
+            ->setShareTime(new \DateTime('2000-01-01T00:01:02'))
5190
+            ->setTarget('myTarget')
5191
+            ->setNote('personal note')
5192
+            ->setId(42);
5193
+
5194
+        $this->rootFolder->method('getUserFolder')
5195
+            ->with($this->currentUser)
5196
+            ->willReturnSelf();
5197
+
5198
+        $this->rootFolder->method('getFirstNodeById')
5199
+            ->with($share->getNodeId())
5200
+            ->willReturn($share->getNode());
5201
+
5202
+        $this->rootFolder->method('getRelativePath')
5203
+            ->with($share->getNode()->getPath())
5204
+            ->willReturnArgument(0);
5205
+
5206
+        if (!$helperAvailable) {
5207
+            $this->appManager->method('isEnabledForUser')
5208
+                ->with('spreed')
5209
+                ->willReturn(false);
5210
+        } else {
5211
+            $this->appManager->method('isEnabledForUser')
5212
+                ->with('spreed')
5213
+                ->willReturn(true);
5214
+
5215
+            // This is not possible anymore with PHPUnit 10+
5216
+            // as `setMethods` was removed and now real reflection is used, thus the class needs to exist.
5217
+            // $helper = $this->getMockBuilder('\OCA\Talk\Share\Helper\ShareAPIController')
5218
+            $helper = $this->getMockBuilder(\stdClass::class)
5219
+                ->addMethods(['formatShare', 'canAccessShare'])
5220
+                ->getMock();
5221
+            $helper->method('formatShare')
5222
+                ->with($share)
5223
+                ->willReturn($formatShareByHelper);
5224
+            $helper->method('canAccessShare')
5225
+                ->with($share)
5226
+                ->willReturn(true);
5227
+
5228
+            $this->serverContainer->method('get')
5229
+                ->with('\OCA\Talk\Share\Helper\ShareAPIController')
5230
+                ->willReturn($helper);
5231
+        }
5232
+
5233
+        $result = $this->invokePrivate($this->ocs, 'formatShare', [$share]);
5234
+        $this->assertEquals($expects, $result);
5235
+    }
5236
+
5237
+    /**
5238
+     * @return list{Folder, Folder}
5239
+     */
5240
+    private function getNonSharedUserFolder(): array {
5241
+        $node = $this->getMockBuilder(Folder::class)->getMock();
5242
+        $userFolder = $this->getMockBuilder(Folder::class)->getMock();
5243
+        $storage = $this->createMock(IStorage::class);
5244
+        $storage->method('instanceOfStorage')
5245
+            ->willReturnMap([
5246
+                ['OCA\Files_Sharing\External\Storage', false],
5247
+                ['OCA\Files_Sharing\SharedStorage', false],
5248
+            ]);
5249
+        $userFolder->method('getStorage')->willReturn($storage);
5250
+        $node->method('getStorage')->willReturn($storage);
5251
+        $node->method('getId')->willReturn(42);
5252
+        $user = $this->createMock(IUser::class);
5253
+        $user->method('getUID')->willReturn($this->currentUser);
5254
+        $node->method('getOwner')->willReturn($user);
5255
+        return [$userFolder, $node];
5256
+    }
5257
+
5258
+    /**
5259
+     * @return list{Folder, File}
5260
+     */
5261
+    private function getNonSharedUserFile(): array {
5262
+        $node = $this->getMockBuilder(File::class)->getMock();
5263
+        $userFolder = $this->getMockBuilder(Folder::class)->getMock();
5264
+        $storage = $this->createMock(IStorage::class);
5265
+        $storage->method('instanceOfStorage')
5266
+            ->willReturnMap([
5267
+                ['OCA\Files_Sharing\External\Storage', false],
5268
+                ['OCA\Files_Sharing\SharedStorage', false],
5269
+            ]);
5270
+        $userFolder->method('getStorage')->willReturn($storage);
5271
+        $node->method('getStorage')->willReturn($storage);
5272
+        $node->method('getId')->willReturn(42);
5273
+        return [$userFolder, $node];
5274
+    }
5275
+
5276
+    public function testPopulateTags(): void {
5277
+        $tagger = $this->createMock(ITags::class);
5278
+        $this->tagManager->method('load')
5279
+            ->with('files')
5280
+            ->willReturn($tagger);
5281
+        $data = [
5282
+            ['file_source' => 10],
5283
+            ['file_source' => 22, 'foo' => 'bar'],
5284
+            ['file_source' => 42, 'x' => 'y'],
5285
+        ];
5286
+        $tags = [
5287
+            10 => ['tag3'],
5288
+            42 => ['tag1', 'tag2'],
5289
+        ];
5290
+        $tagger->method('getTagsForObjects')
5291
+            ->with([10, 22, 42])
5292
+            ->willReturn($tags);
5293
+
5294
+        $result = self::invokePrivate($this->ocs, 'populateTags', [$data]);
5295
+        $this->assertSame([
5296
+            ['file_source' => 10, 'tags' => ['tag3']],
5297
+            ['file_source' => 22, 'foo' => 'bar', 'tags' => []],
5298
+            ['file_source' => 42, 'x' => 'y', 'tags' => ['tag1', 'tag2']],
5299
+        ], $result);
5300
+    }
5301
+
5302
+    public static function trustedServerProvider(): array {
5303
+        return [
5304
+            'Trusted server' => [true, true],
5305
+            'Untrusted server' => [false, false],
5306
+        ];
5307
+    }
5308
+
5309
+    #[DataProvider('trustedServerProvider')]
5310
+    public function testFormatShareWithFederatedShare(bool $isKnownServer, bool $isTrusted): void {
5311
+        $nodeId = 12;
5312
+        $nodePath = '/test.txt';
5313
+
5314
+        $node = $this->createMock(File::class);
5315
+        $node->method('getId')->willReturn($nodeId);
5316
+        $node->method('getPath')->willReturn($nodePath);
5317
+        $node->method('getInternalPath')->willReturn(ltrim($nodePath, '/'));
5318
+        $mountPoint = $this->createMock(IMountPoint::class);
5319
+        $mountPoint->method('getMountType')->willReturn('local');
5320
+        $node->method('getMountPoint')->willReturn($mountPoint);
5321
+        $node->method('getMimetype')->willReturn('text/plain');
5322
+        $storage = $this->createMock(IStorage::class);
5323
+        $storageCache = $this->createMock(ICache::class);
5324
+        $storageCache->method('getNumericStorageId')->willReturn(1);
5325
+        $storage->method('getCache')->willReturn($storageCache);
5326
+        $storage->method('getId')->willReturn('home::shareOwner');
5327
+        $node->method('getStorage')->willReturn($storage);
5328
+        $parent = $this->createMock(Folder::class);
5329
+        $parent->method('getId')->willReturn(2);
5330
+        $node->method('getParent')->willReturn($parent);
5331
+        $node->method('getSize')->willReturn(1234);
5332
+        $node->method('getMTime')->willReturn(1234567890);
5333
+
5334
+        $share = $this->createShare(
5335
+            1,
5336
+            IShare::TYPE_REMOTE,
5337
+            '[email protected]', // shared with
5338
+            '[email protected]',      // shared by
5339
+            'shareOwner',                 // share owner
5340
+            $node,
5341
+            Constants::PERMISSION_READ,
5342
+            time(),
5343
+            null,
5344
+            2,
5345
+            $nodePath,
5346
+            $nodeId
5347
+        );
5348
+
5349
+        $this->previewManager->method('isAvailable')->with($node)->willReturn(false);
5350
+
5351
+        $this->rootFolder->method('getUserFolder')
5352
+            ->with($this->currentUser)
5353
+            ->willReturnSelf();
5354
+
5355
+        $this->rootFolder->method('getFirstNodeById')
5356
+            ->with($share->getNodeId())
5357
+            ->willReturn($node);
5358
+
5359
+        $this->rootFolder->method('getRelativePath')
5360
+            ->with($node->getPath())
5361
+            ->willReturnArgument(0);
5362
+
5363
+        $serverName = 'remoteserver.com';
5364
+        $this->trustedServers->method('isTrustedServer')
5365
+            ->with($serverName)
5366
+            ->willReturn($isKnownServer);
5367
+
5368
+        $result = $this->invokePrivate($this->ocs, 'formatShare', [$share]);
5369
+
5370
+        $this->assertSame($isTrusted, $result['is_trusted_server']);
5371
+    }
5372
+
5373
+    public function testFormatShareWithFederatedShareWithAtInUsername(): void {
5374
+        $nodeId = 12;
5375
+        $nodePath = '/test.txt';
5376
+
5377
+        $node = $this->createMock(File::class);
5378
+        $node->method('getId')->willReturn($nodeId);
5379
+        $node->method('getPath')->willReturn($nodePath);
5380
+        $node->method('getInternalPath')->willReturn(ltrim($nodePath, '/'));
5381
+        $mountPoint = $this->createMock(IMountPoint::class);
5382
+        $mountPoint->method('getMountType')->willReturn('local');
5383
+        $node->method('getMountPoint')->willReturn($mountPoint);
5384
+        $node->method('getMimetype')->willReturn('text/plain');
5385
+        $storage = $this->createMock(IStorage::class);
5386
+        $storageCache = $this->createMock(ICache::class);
5387
+        $storageCache->method('getNumericStorageId')->willReturn(1);
5388
+        $storage->method('getCache')->willReturn($storageCache);
5389
+        $storage->method('getId')->willReturn('home::shareOwner');
5390
+        $node->method('getStorage')->willReturn($storage);
5391
+        $parent = $this->createMock(Folder::class);
5392
+        $parent->method('getId')->willReturn(2);
5393
+        $node->method('getParent')->willReturn($parent);
5394
+        $node->method('getSize')->willReturn(1234);
5395
+        $node->method('getMTime')->willReturn(1234567890);
5396
+
5397
+        $share = $this->createShare(
5398
+            1,
5399
+            IShare::TYPE_REMOTE,
5400
+            '[email protected]@remoteserver.com',
5401
+            '[email protected]',
5402
+            'shareOwner',
5403
+            $node,
5404
+            Constants::PERMISSION_READ,
5405
+            time(),
5406
+            null,
5407
+            2,
5408
+            $nodePath,
5409
+            $nodeId
5410
+        );
5411
+
5412
+        $this->previewManager->method('isAvailable')->with($node)->willReturn(false);
5413
+
5414
+        $this->rootFolder->method('getUserFolder')
5415
+            ->with($this->currentUser)
5416
+            ->willReturnSelf();
5417
+
5418
+        $this->rootFolder->method('getFirstNodeById')
5419
+            ->with($share->getNodeId())
5420
+            ->willReturn($node);
5421
+
5422
+        $this->rootFolder->method('getRelativePath')
5423
+            ->with($node->getPath())
5424
+            ->willReturnArgument(0);
5425
+
5426
+        $serverName = 'remoteserver.com';
5427
+        $this->trustedServers->method('isTrustedServer')
5428
+            ->with($serverName)
5429
+            ->willReturn(true);
5430
+
5431
+        $result = $this->invokePrivate($this->ocs, 'formatShare', [$share]);
5432
+
5433
+        $this->assertTrue($result['is_trusted_server']);
5434
+    }
5435 5435
 }
Please login to merge, or discard this patch.
tests/lib/Collaboration/Collaborators/MailPluginTest.php 1 patch
Indentation   +669 added lines, -669 removed lines patch added patch discarded remove patch
@@ -27,673 +27,673 @@
 block discarded – undo
27 27
 use Test\Traits\EmailValidatorTrait;
28 28
 
29 29
 class MailPluginTest extends TestCase {
30
-	use EmailValidatorTrait;
31
-
32
-	/** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
33
-	protected $config;
34
-
35
-	/** @var IManager|\PHPUnit\Framework\MockObject\MockObject */
36
-	protected $contactsManager;
37
-
38
-	/** @var ICloudIdManager|\PHPUnit\Framework\MockObject\MockObject */
39
-	protected $cloudIdManager;
40
-
41
-	/** @var MailPlugin */
42
-	protected $plugin;
43
-
44
-	/** @var SearchResult */
45
-	protected $searchResult;
46
-
47
-	/** @var IGroupManager|\PHPUnit\Framework\MockObject\MockObject */
48
-	protected $groupManager;
49
-
50
-	/** @var KnownUserService|\PHPUnit\Framework\MockObject\MockObject */
51
-	protected $knownUserService;
52
-
53
-	/** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
54
-	protected $userSession;
55
-
56
-	protected function setUp(): void {
57
-		parent::setUp();
58
-
59
-		$this->config = $this->createMock(IConfig::class);
60
-		$this->contactsManager = $this->createMock(IManager::class);
61
-		$this->groupManager = $this->createMock(IGroupManager::class);
62
-		$this->knownUserService = $this->createMock(KnownUserService::class);
63
-		$this->userSession = $this->createMock(IUserSession::class);
64
-		$this->cloudIdManager = new CloudIdManager(
65
-			$this->createMock(ICacheFactory::class),
66
-			$this->createMock(IEventDispatcher::class),
67
-			$this->contactsManager,
68
-			$this->createMock(IURLGenerator::class),
69
-			$this->createMock(IUserManager::class),
70
-		);
71
-
72
-		$this->searchResult = new SearchResult();
73
-	}
74
-
75
-	public function instantiatePlugin() {
76
-		$this->plugin = new MailPlugin(
77
-			$this->contactsManager,
78
-			$this->cloudIdManager,
79
-			$this->config,
80
-			$this->groupManager,
81
-			$this->knownUserService,
82
-			$this->userSession,
83
-			$this->getEmailValidatorWithStrictEmailCheck(),
84
-		);
85
-	}
86
-
87
-	/**
88
-	 *
89
-	 * @param string $searchTerm
90
-	 * @param array $contacts
91
-	 * @param bool $shareeEnumeration
92
-	 * @param array $expected
93
-	 * @param bool $reachedEnd
94
-	 */
95
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataGetEmail')]
96
-	public function testSearch($searchTerm, $contacts, $shareeEnumeration, $expected, $exactIdMatch, $reachedEnd, $validEmail): void {
97
-		$this->config->expects($this->any())
98
-			->method('getAppValue')
99
-			->willReturnCallback(
100
-				function ($appName, $key, $default) use ($shareeEnumeration) {
101
-					if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
102
-						return $shareeEnumeration ? 'yes' : 'no';
103
-					}
104
-					return $default;
105
-				}
106
-			);
107
-
108
-		$this->instantiatePlugin();
109
-
110
-		$currentUser = $this->createMock(IUser::class);
111
-		$currentUser->method('getUID')
112
-			->willReturn('current');
113
-		$this->userSession->method('getUser')
114
-			->willReturn($currentUser);
115
-
116
-		$this->contactsManager->expects($this->any())
117
-			->method('search')
118
-			->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
119
-				if ($search === $searchTerm) {
120
-					return $contacts;
121
-				}
122
-				return [];
123
-			});
124
-
125
-		$moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult);
126
-		$result = $this->searchResult->asArray();
127
-
128
-		$this->assertSame($exactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails')));
129
-		$this->assertEquals($expected, $result);
130
-		$this->assertSame($reachedEnd, $moreResults);
131
-	}
132
-
133
-	public static function dataGetEmail(): array {
134
-		return [
135
-			// data set 0
136
-			['test', [], true, ['emails' => [], 'exact' => ['emails' => []]], false, false, false],
137
-			// data set 1
138
-			['test', [], false, ['emails' => [], 'exact' => ['emails' => []]], false, false, false],
139
-			// data set 2
140
-			[
141
-				'[email protected]',
142
-				[],
143
-				true,
144
-				['emails' => [], 'exact' => ['emails' => [['uuid' => '[email protected]', 'label' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
145
-				false,
146
-				false,
147
-				true,
148
-			],
149
-			// data set 3
150
-			[ // no valid email address
151
-				'test@remote',
152
-				[],
153
-				true,
154
-				['emails' => [], 'exact' => ['emails' => []]],
155
-				false,
156
-				false,
157
-				false,
158
-			],
159
-			// data set 4
160
-			[
161
-				'[email protected]',
162
-				[],
163
-				false,
164
-				['emails' => [], 'exact' => ['emails' => [['uuid' => '[email protected]', 'label' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
165
-				false,
166
-				false,
167
-				true,
168
-			],
169
-			// data set 5
170
-			[
171
-				'test',
172
-				[
173
-					[
174
-						'UID' => 'uid3',
175
-						'FN' => 'User3 @ Localhost',
176
-					],
177
-					[
178
-						'UID' => 'uid2',
179
-						'FN' => 'User2 @ Localhost',
180
-						'EMAIL' => [
181
-						],
182
-					],
183
-					[
184
-						'UID' => 'uid1',
185
-						'FN' => 'User @ Localhost',
186
-						'EMAIL' => [
187
-							'[email protected]',
188
-						],
189
-					],
190
-				],
191
-				true,
192
-				['emails' => [['uuid' => 'uid1', 'name' => 'User @ Localhost', 'type' => '', 'label' => 'User @ Localhost ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]], 'exact' => ['emails' => []]],
193
-				false,
194
-				false,
195
-				false,
196
-			],
197
-			// data set 6
198
-			[
199
-				'test',
200
-				[
201
-					[
202
-						'UID' => 'uid3',
203
-						'FN' => 'User3 @ Localhost',
204
-					],
205
-					[
206
-						'UID' => 'uid2',
207
-						'FN' => 'User2 @ Localhost',
208
-						'EMAIL' => [
209
-						],
210
-					],
211
-					[
212
-						'isLocalSystemBook' => true,
213
-						'UID' => 'uid1',
214
-						'FN' => 'User @ Localhost',
215
-						'EMAIL' => [
216
-							'username@localhost',
217
-						],
218
-					],
219
-				],
220
-				false,
221
-				['emails' => [], 'exact' => ['emails' => []]],
222
-				false,
223
-				false,
224
-				false,
225
-			],
226
-			// data set 7
227
-			[
228
-				'[email protected]',
229
-				[
230
-					[
231
-						'UID' => 'uid3',
232
-						'FN' => 'User3 @ example.com',
233
-					],
234
-					[
235
-						'UID' => 'uid2',
236
-						'FN' => 'User2 @ example.com',
237
-						'EMAIL' => [
238
-						],
239
-					],
240
-					[
241
-						'UID' => 'uid1',
242
-						'FN' => 'User @ example.com',
243
-						'EMAIL' => [
244
-							'[email protected]',
245
-						],
246
-					],
247
-				],
248
-				true,
249
-				['emails' => [['uuid' => 'uid1', 'name' => 'User @ example.com', 'type' => '', 'label' => 'User @ example.com ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
250
-				false,
251
-				false,
252
-				true,
253
-			],
254
-			// data set 8
255
-			[
256
-				'[email protected]',
257
-				[
258
-					[
259
-						'UID' => 'uid3',
260
-						'FN' => 'User3 @ Localhost',
261
-					],
262
-					[
263
-						'UID' => 'uid2',
264
-						'FN' => 'User2 @ Localhost',
265
-						'EMAIL' => [
266
-						],
267
-					],
268
-					[
269
-						'isLocalSystemBook' => true,
270
-						'UID' => 'uid1',
271
-						'FN' => 'User @ Localhost',
272
-						'EMAIL' => [
273
-							'username@localhost',
274
-						],
275
-					],
276
-				],
277
-				false,
278
-				['emails' => [], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
279
-				false,
280
-				false,
281
-				true,
282
-			],
283
-			// data set 9
284
-			[
285
-				'[email protected]',
286
-				[
287
-					[
288
-						'UID' => 'uid3',
289
-						'FN' => 'User3 @ example.com',
290
-					],
291
-					[
292
-						'UID' => 'uid2',
293
-						'FN' => 'User2 @ example.com',
294
-						'EMAIL' => [
295
-						],
296
-					],
297
-					[
298
-						'UID' => 'uid1',
299
-						'FN' => 'User @ example.com',
300
-						'EMAIL' => [
301
-							'[email protected]',
302
-						],
303
-					],
304
-				],
305
-				true,
306
-				['emails' => [], 'exact' => ['emails' => [['name' => 'User @ example.com', 'uuid' => 'uid1', 'type' => '', 'label' => 'User @ example.com ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
307
-				true,
308
-				false,
309
-				false,
310
-			],
311
-			// data set 10
312
-			[
313
-				'[email protected]',
314
-				[
315
-					[
316
-						'UID' => 'uid1',
317
-						'FN' => 'User3 @ example.com',
318
-					],
319
-					[
320
-						'UID' => 'uid2',
321
-						'FN' => 'User2 @ example.com',
322
-						'EMAIL' => [
323
-						],
324
-					],
325
-					[
326
-						'UID' => 'uid1',
327
-						'FN' => 'User @ example.com',
328
-						'EMAIL' => [
329
-							'[email protected]',
330
-						],
331
-					],
332
-				],
333
-				false,
334
-				['emails' => [], 'exact' => ['emails' => [['name' => 'User @ example.com', 'uuid' => 'uid1', 'type' => '', 'label' => 'User @ example.com ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
335
-				true,
336
-				false,
337
-				false,
338
-			],
339
-			// data set 11
340
-			// contact with space
341
-			[
342
-				'user name@localhost',
343
-				[
344
-					[
345
-						'UID' => 'uid3',
346
-						'FN' => 'User3 @ Localhost',
347
-					],
348
-					[
349
-						'UID' => 'uid2',
350
-						'FN' => 'User2 @ Localhost',
351
-						'EMAIL' => [
352
-						],
353
-					],
354
-					[
355
-						'UID' => 'uid1',
356
-						'FN' => 'User Name @ Localhost',
357
-						'EMAIL' => [
358
-							'user name@localhost',
359
-						],
360
-					],
361
-				],
362
-				false,
363
-				['emails' => [], 'exact' => ['emails' => []]],
364
-				false,
365
-				false,
366
-				false,
367
-			],
368
-			// data set 12
369
-			// remote with space, no contact
370
-			[
371
-				'user [email protected]',
372
-				[
373
-					[
374
-						'UID' => 'uid3',
375
-						'FN' => 'User3 @ Localhost',
376
-					],
377
-					[
378
-						'UID' => 'uid2',
379
-						'FN' => 'User2 @ Localhost',
380
-						'EMAIL' => [
381
-						],
382
-					],
383
-					[
384
-						'isLocalSystemBook' => true,
385
-						'UID' => 'uid1',
386
-						'FN' => 'User @ Localhost',
387
-						'EMAIL' => [
388
-							'username@localhost',
389
-						],
390
-					],
391
-				],
392
-				false,
393
-				['emails' => [], 'exact' => ['emails' => []]],
394
-				false,
395
-				false,
396
-				false,
397
-			],
398
-			// data set 13
399
-			// Local user found by email
400
-			[
401
-				'[email protected]',
402
-				[
403
-					[
404
-						'UID' => 'uid1',
405
-						'FN' => 'User',
406
-						'EMAIL' => ['[email protected]'],
407
-						'CLOUD' => ['test@localhost'],
408
-						'isLocalSystemBook' => true,
409
-					]
410
-				],
411
-				false,
412
-				['users' => [], 'exact' => ['users' => [['uuid' => 'uid1', 'name' => 'User', 'label' => 'User ([email protected])','value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'shareWithDisplayNameUnique' => '[email protected]']]]],
413
-				true,
414
-				false,
415
-				true,
416
-			],
417
-			// data set 14
418
-			// Current local user found by email => no result
419
-			[
420
-				'[email protected]',
421
-				[
422
-					[
423
-						'UID' => 'uid1',
424
-						'FN' => 'User',
425
-						'EMAIL' => ['[email protected]'],
426
-						'CLOUD' => ['current@localhost'],
427
-						'isLocalSystemBook' => true,
428
-					]
429
-				],
430
-				true,
431
-				['exact' => []],
432
-				false,
433
-				false,
434
-				true,
435
-			],
436
-			// data set 15
437
-			// Pagination and "more results" for user matches byyyyyyy emails
438
-			[
439
-				'test@example',
440
-				[
441
-					[
442
-						'UID' => 'uid1',
443
-						'FN' => 'User1',
444
-						'EMAIL' => ['[email protected]'],
445
-						'CLOUD' => ['test1@localhost'],
446
-						'isLocalSystemBook' => true,
447
-					],
448
-					[
449
-						'UID' => 'uid2',
450
-						'FN' => 'User2',
451
-						'EMAIL' => ['[email protected]'],
452
-						'CLOUD' => ['test2@localhost'],
453
-						'isLocalSystemBook' => true,
454
-					],
455
-					[
456
-						'UID' => 'uid3',
457
-						'FN' => 'User3',
458
-						'EMAIL' => ['[email protected]'],
459
-						'CLOUD' => ['test3@localhost'],
460
-						'isLocalSystemBook' => true,
461
-					],
462
-					[
463
-						'UID' => 'uid4',
464
-						'FN' => 'User4',
465
-						'EMAIL' => ['[email protected]'],
466
-						'CLOUD' => ['test4@localhost'],
467
-						'isLocalSystemBook' => true,
468
-					],
469
-				],
470
-				true,
471
-				['users' => [
472
-					['uuid' => 'uid1', 'name' => 'User1', 'label' => 'User1 ([email protected])', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test1'], 'shareWithDisplayNameUnique' => '[email protected]'],
473
-					['uuid' => 'uid2', 'name' => 'User2', 'label' => 'User2 ([email protected])', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test2'], 'shareWithDisplayNameUnique' => '[email protected]'],
474
-				], 'emails' => [], 'exact' => ['users' => [], 'emails' => []]],
475
-				false,
476
-				true,
477
-				false,
478
-			],
479
-			// data set 16
480
-			// Pagination and "more results" for normal emails
481
-			[
482
-				'test@example',
483
-				[
484
-					[
485
-						'UID' => 'uid1',
486
-						'FN' => 'User1',
487
-						'EMAIL' => ['[email protected]'],
488
-						'CLOUD' => ['test1@localhost'],
489
-					],
490
-					[
491
-						'UID' => 'uid2',
492
-						'FN' => 'User2',
493
-						'EMAIL' => ['[email protected]'],
494
-						'CLOUD' => ['test2@localhost'],
495
-					],
496
-					[
497
-						'UID' => 'uid3',
498
-						'FN' => 'User3',
499
-						'EMAIL' => ['[email protected]'],
500
-						'CLOUD' => ['test3@localhost'],
501
-					],
502
-					[
503
-						'UID' => 'uid4',
504
-						'FN' => 'User4',
505
-						'EMAIL' => ['[email protected]'],
506
-						'CLOUD' => ['test4@localhost'],
507
-					],
508
-				],
509
-				true,
510
-				['emails' => [
511
-					['uuid' => 'uid1', 'name' => 'User1', 'type' => '', 'label' => 'User1 ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']],
512
-					['uuid' => 'uid2', 'name' => 'User2', 'type' => '', 'label' => 'User2 ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']],
513
-				], 'exact' => ['emails' => []]],
514
-				false,
515
-				true,
516
-				false,
517
-			],
518
-			// data set 17
519
-			// multiple email addresses with type
520
-			[
521
-				'User Name',
522
-				[
523
-					[
524
-						'UID' => 'uid3',
525
-						'FN' => 'User3',
526
-					],
527
-					[
528
-						'UID' => 'uid2',
529
-						'FN' => 'User2',
530
-						'EMAIL' => [
531
-						],
532
-					],
533
-					[
534
-						'UID' => 'uid1',
535
-						'FN' => 'User Name',
536
-						'EMAIL' => [
537
-							['type' => 'HOME', 'value' => '[email protected]'],
538
-							['type' => 'WORK', 'value' => '[email protected]'],
539
-						],
540
-					],
541
-				],
542
-				false,
543
-				['emails' => [
544
-				], 'exact' => ['emails' => [
545
-					['name' => 'User Name', 'uuid' => 'uid1', 'type' => 'HOME', 'label' => 'User Name ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']],
546
-					['name' => 'User Name', 'uuid' => 'uid1', 'type' => 'WORK', 'label' => 'User Name ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]
547
-				]]],
548
-				false,
549
-				false,
550
-				false,
551
-			],
552
-			// data set 18
553
-			// idn email
554
-			[
555
-				'test@lölölölölölölöl.com',
556
-				[],
557
-				true,
558
-				['emails' => [], 'exact' => ['emails' => [['uuid' => 'test@lölölölölölölöl.com', 'label' => 'test@lölölölölölölöl.com', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => 'test@lölölölölölölöl.com']]]]],
559
-				false,
560
-				false,
561
-				true,
562
-			],
563
-		];
564
-	}
565
-
566
-	/**
567
-	 *
568
-	 * @param string $searchTerm
569
-	 * @param array $contacts
570
-	 * @param array $expected
571
-	 * @param bool $exactIdMatch
572
-	 * @param bool $reachedEnd
573
-	 * @param array groups
574
-	 */
575
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataGetEmailGroupsOnly')]
576
-	public function testSearchGroupsOnly($searchTerm, $contacts, $expected, $exactIdMatch, $reachedEnd, $userToGroupMapping, $validEmail): void {
577
-		$this->config->expects($this->any())
578
-			->method('getAppValue')
579
-			->willReturnCallback(
580
-				function ($appName, $key, $default) {
581
-					if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
582
-						return 'yes';
583
-					} elseif ($appName === 'core' && $key === 'shareapi_only_share_with_group_members') {
584
-						return 'yes';
585
-					}
586
-					return $default;
587
-				}
588
-			);
589
-
590
-		$this->instantiatePlugin();
591
-
592
-		/** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
593
-		$currentUser = $this->createMock('\OCP\IUser');
594
-
595
-		$currentUser->expects($this->any())
596
-			->method('getUID')
597
-			->willReturn('currentUser');
598
-
599
-		$this->contactsManager->expects($this->any())
600
-			->method('search')
601
-			->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
602
-				if ($search === $searchTerm) {
603
-					return $contacts;
604
-				}
605
-				return [];
606
-			});
607
-
608
-		$this->userSession->expects($this->any())
609
-			->method('getUser')
610
-			->willReturn($currentUser);
611
-
612
-		$this->groupManager->expects($this->any())
613
-			->method('getUserGroupIds')
614
-			->willReturnCallback(function (IUser $user) use ($userToGroupMapping) {
615
-				return $userToGroupMapping[$user->getUID()];
616
-			});
617
-
618
-		$this->groupManager->expects($this->any())
619
-			->method('isInGroup')
620
-			->willReturnCallback(function ($userId, $group) use ($userToGroupMapping) {
621
-				return in_array($group, $userToGroupMapping[$userId]);
622
-			});
623
-
624
-		$moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult);
625
-		$result = $this->searchResult->asArray();
626
-
627
-		$this->assertSame($exactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails')));
628
-		$this->assertEquals($expected, $result);
629
-		$this->assertSame($reachedEnd, $moreResults);
630
-	}
631
-
632
-	public static function dataGetEmailGroupsOnly(): array {
633
-		return [
634
-			// The user `User` can share with the current user
635
-			[
636
-				'test',
637
-				[
638
-					[
639
-						'FN' => 'User',
640
-						'EMAIL' => ['[email protected]'],
641
-						'CLOUD' => ['test@localhost'],
642
-						'isLocalSystemBook' => true,
643
-						'UID' => 'User'
644
-					]
645
-				],
646
-				['users' => [['label' => 'User ([email protected])', 'uuid' => 'User', 'name' => 'User', 'value' => ['shareType' => 0, 'shareWith' => 'test'],'shareWithDisplayNameUnique' => '[email protected]',]], 'emails' => [], 'exact' => ['emails' => [], 'users' => []]],
647
-				false,
648
-				false,
649
-				[
650
-					'currentUser' => ['group1'],
651
-					'User' => ['group1']
652
-				],
653
-				false,
654
-			],
655
-			// The user `User` cannot share with the current user
656
-			[
657
-				'test',
658
-				[
659
-					[
660
-						'FN' => 'User',
661
-						'EMAIL' => ['[email protected]'],
662
-						'CLOUD' => ['test@localhost'],
663
-						'isLocalSystemBook' => true,
664
-						'UID' => 'User'
665
-					]
666
-				],
667
-				['emails' => [], 'exact' => ['emails' => []]],
668
-				false,
669
-				false,
670
-				[
671
-					'currentUser' => ['group1'],
672
-					'User' => ['group2']
673
-				],
674
-				false,
675
-			],
676
-			// The user `User` cannot share with the current user, but there is an exact match on the e-mail address -> share by e-mail
677
-			[
678
-				'[email protected]',
679
-				[
680
-					[
681
-						'FN' => 'User',
682
-						'EMAIL' => ['[email protected]'],
683
-						'CLOUD' => ['test@localhost'],
684
-						'isLocalSystemBook' => true,
685
-						'UID' => 'User'
686
-					]
687
-				],
688
-				['emails' => [], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => 4,'shareWith' => '[email protected]']]]]],
689
-				false,
690
-				false,
691
-				[
692
-					'currentUser' => ['group1'],
693
-					'User' => ['group2']
694
-				],
695
-				true,
696
-			]
697
-		];
698
-	}
30
+    use EmailValidatorTrait;
31
+
32
+    /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
33
+    protected $config;
34
+
35
+    /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */
36
+    protected $contactsManager;
37
+
38
+    /** @var ICloudIdManager|\PHPUnit\Framework\MockObject\MockObject */
39
+    protected $cloudIdManager;
40
+
41
+    /** @var MailPlugin */
42
+    protected $plugin;
43
+
44
+    /** @var SearchResult */
45
+    protected $searchResult;
46
+
47
+    /** @var IGroupManager|\PHPUnit\Framework\MockObject\MockObject */
48
+    protected $groupManager;
49
+
50
+    /** @var KnownUserService|\PHPUnit\Framework\MockObject\MockObject */
51
+    protected $knownUserService;
52
+
53
+    /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
54
+    protected $userSession;
55
+
56
+    protected function setUp(): void {
57
+        parent::setUp();
58
+
59
+        $this->config = $this->createMock(IConfig::class);
60
+        $this->contactsManager = $this->createMock(IManager::class);
61
+        $this->groupManager = $this->createMock(IGroupManager::class);
62
+        $this->knownUserService = $this->createMock(KnownUserService::class);
63
+        $this->userSession = $this->createMock(IUserSession::class);
64
+        $this->cloudIdManager = new CloudIdManager(
65
+            $this->createMock(ICacheFactory::class),
66
+            $this->createMock(IEventDispatcher::class),
67
+            $this->contactsManager,
68
+            $this->createMock(IURLGenerator::class),
69
+            $this->createMock(IUserManager::class),
70
+        );
71
+
72
+        $this->searchResult = new SearchResult();
73
+    }
74
+
75
+    public function instantiatePlugin() {
76
+        $this->plugin = new MailPlugin(
77
+            $this->contactsManager,
78
+            $this->cloudIdManager,
79
+            $this->config,
80
+            $this->groupManager,
81
+            $this->knownUserService,
82
+            $this->userSession,
83
+            $this->getEmailValidatorWithStrictEmailCheck(),
84
+        );
85
+    }
86
+
87
+    /**
88
+     *
89
+     * @param string $searchTerm
90
+     * @param array $contacts
91
+     * @param bool $shareeEnumeration
92
+     * @param array $expected
93
+     * @param bool $reachedEnd
94
+     */
95
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataGetEmail')]
96
+    public function testSearch($searchTerm, $contacts, $shareeEnumeration, $expected, $exactIdMatch, $reachedEnd, $validEmail): void {
97
+        $this->config->expects($this->any())
98
+            ->method('getAppValue')
99
+            ->willReturnCallback(
100
+                function ($appName, $key, $default) use ($shareeEnumeration) {
101
+                    if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
102
+                        return $shareeEnumeration ? 'yes' : 'no';
103
+                    }
104
+                    return $default;
105
+                }
106
+            );
107
+
108
+        $this->instantiatePlugin();
109
+
110
+        $currentUser = $this->createMock(IUser::class);
111
+        $currentUser->method('getUID')
112
+            ->willReturn('current');
113
+        $this->userSession->method('getUser')
114
+            ->willReturn($currentUser);
115
+
116
+        $this->contactsManager->expects($this->any())
117
+            ->method('search')
118
+            ->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
119
+                if ($search === $searchTerm) {
120
+                    return $contacts;
121
+                }
122
+                return [];
123
+            });
124
+
125
+        $moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult);
126
+        $result = $this->searchResult->asArray();
127
+
128
+        $this->assertSame($exactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails')));
129
+        $this->assertEquals($expected, $result);
130
+        $this->assertSame($reachedEnd, $moreResults);
131
+    }
132
+
133
+    public static function dataGetEmail(): array {
134
+        return [
135
+            // data set 0
136
+            ['test', [], true, ['emails' => [], 'exact' => ['emails' => []]], false, false, false],
137
+            // data set 1
138
+            ['test', [], false, ['emails' => [], 'exact' => ['emails' => []]], false, false, false],
139
+            // data set 2
140
+            [
141
+                '[email protected]',
142
+                [],
143
+                true,
144
+                ['emails' => [], 'exact' => ['emails' => [['uuid' => '[email protected]', 'label' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
145
+                false,
146
+                false,
147
+                true,
148
+            ],
149
+            // data set 3
150
+            [ // no valid email address
151
+                'test@remote',
152
+                [],
153
+                true,
154
+                ['emails' => [], 'exact' => ['emails' => []]],
155
+                false,
156
+                false,
157
+                false,
158
+            ],
159
+            // data set 4
160
+            [
161
+                '[email protected]',
162
+                [],
163
+                false,
164
+                ['emails' => [], 'exact' => ['emails' => [['uuid' => '[email protected]', 'label' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
165
+                false,
166
+                false,
167
+                true,
168
+            ],
169
+            // data set 5
170
+            [
171
+                'test',
172
+                [
173
+                    [
174
+                        'UID' => 'uid3',
175
+                        'FN' => 'User3 @ Localhost',
176
+                    ],
177
+                    [
178
+                        'UID' => 'uid2',
179
+                        'FN' => 'User2 @ Localhost',
180
+                        'EMAIL' => [
181
+                        ],
182
+                    ],
183
+                    [
184
+                        'UID' => 'uid1',
185
+                        'FN' => 'User @ Localhost',
186
+                        'EMAIL' => [
187
+                            '[email protected]',
188
+                        ],
189
+                    ],
190
+                ],
191
+                true,
192
+                ['emails' => [['uuid' => 'uid1', 'name' => 'User @ Localhost', 'type' => '', 'label' => 'User @ Localhost ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]], 'exact' => ['emails' => []]],
193
+                false,
194
+                false,
195
+                false,
196
+            ],
197
+            // data set 6
198
+            [
199
+                'test',
200
+                [
201
+                    [
202
+                        'UID' => 'uid3',
203
+                        'FN' => 'User3 @ Localhost',
204
+                    ],
205
+                    [
206
+                        'UID' => 'uid2',
207
+                        'FN' => 'User2 @ Localhost',
208
+                        'EMAIL' => [
209
+                        ],
210
+                    ],
211
+                    [
212
+                        'isLocalSystemBook' => true,
213
+                        'UID' => 'uid1',
214
+                        'FN' => 'User @ Localhost',
215
+                        'EMAIL' => [
216
+                            'username@localhost',
217
+                        ],
218
+                    ],
219
+                ],
220
+                false,
221
+                ['emails' => [], 'exact' => ['emails' => []]],
222
+                false,
223
+                false,
224
+                false,
225
+            ],
226
+            // data set 7
227
+            [
228
+                '[email protected]',
229
+                [
230
+                    [
231
+                        'UID' => 'uid3',
232
+                        'FN' => 'User3 @ example.com',
233
+                    ],
234
+                    [
235
+                        'UID' => 'uid2',
236
+                        'FN' => 'User2 @ example.com',
237
+                        'EMAIL' => [
238
+                        ],
239
+                    ],
240
+                    [
241
+                        'UID' => 'uid1',
242
+                        'FN' => 'User @ example.com',
243
+                        'EMAIL' => [
244
+                            '[email protected]',
245
+                        ],
246
+                    ],
247
+                ],
248
+                true,
249
+                ['emails' => [['uuid' => 'uid1', 'name' => 'User @ example.com', 'type' => '', 'label' => 'User @ example.com ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
250
+                false,
251
+                false,
252
+                true,
253
+            ],
254
+            // data set 8
255
+            [
256
+                '[email protected]',
257
+                [
258
+                    [
259
+                        'UID' => 'uid3',
260
+                        'FN' => 'User3 @ Localhost',
261
+                    ],
262
+                    [
263
+                        'UID' => 'uid2',
264
+                        'FN' => 'User2 @ Localhost',
265
+                        'EMAIL' => [
266
+                        ],
267
+                    ],
268
+                    [
269
+                        'isLocalSystemBook' => true,
270
+                        'UID' => 'uid1',
271
+                        'FN' => 'User @ Localhost',
272
+                        'EMAIL' => [
273
+                            'username@localhost',
274
+                        ],
275
+                    ],
276
+                ],
277
+                false,
278
+                ['emails' => [], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
279
+                false,
280
+                false,
281
+                true,
282
+            ],
283
+            // data set 9
284
+            [
285
+                '[email protected]',
286
+                [
287
+                    [
288
+                        'UID' => 'uid3',
289
+                        'FN' => 'User3 @ example.com',
290
+                    ],
291
+                    [
292
+                        'UID' => 'uid2',
293
+                        'FN' => 'User2 @ example.com',
294
+                        'EMAIL' => [
295
+                        ],
296
+                    ],
297
+                    [
298
+                        'UID' => 'uid1',
299
+                        'FN' => 'User @ example.com',
300
+                        'EMAIL' => [
301
+                            '[email protected]',
302
+                        ],
303
+                    ],
304
+                ],
305
+                true,
306
+                ['emails' => [], 'exact' => ['emails' => [['name' => 'User @ example.com', 'uuid' => 'uid1', 'type' => '', 'label' => 'User @ example.com ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
307
+                true,
308
+                false,
309
+                false,
310
+            ],
311
+            // data set 10
312
+            [
313
+                '[email protected]',
314
+                [
315
+                    [
316
+                        'UID' => 'uid1',
317
+                        'FN' => 'User3 @ example.com',
318
+                    ],
319
+                    [
320
+                        'UID' => 'uid2',
321
+                        'FN' => 'User2 @ example.com',
322
+                        'EMAIL' => [
323
+                        ],
324
+                    ],
325
+                    [
326
+                        'UID' => 'uid1',
327
+                        'FN' => 'User @ example.com',
328
+                        'EMAIL' => [
329
+                            '[email protected]',
330
+                        ],
331
+                    ],
332
+                ],
333
+                false,
334
+                ['emails' => [], 'exact' => ['emails' => [['name' => 'User @ example.com', 'uuid' => 'uid1', 'type' => '', 'label' => 'User @ example.com ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
335
+                true,
336
+                false,
337
+                false,
338
+            ],
339
+            // data set 11
340
+            // contact with space
341
+            [
342
+                'user name@localhost',
343
+                [
344
+                    [
345
+                        'UID' => 'uid3',
346
+                        'FN' => 'User3 @ Localhost',
347
+                    ],
348
+                    [
349
+                        'UID' => 'uid2',
350
+                        'FN' => 'User2 @ Localhost',
351
+                        'EMAIL' => [
352
+                        ],
353
+                    ],
354
+                    [
355
+                        'UID' => 'uid1',
356
+                        'FN' => 'User Name @ Localhost',
357
+                        'EMAIL' => [
358
+                            'user name@localhost',
359
+                        ],
360
+                    ],
361
+                ],
362
+                false,
363
+                ['emails' => [], 'exact' => ['emails' => []]],
364
+                false,
365
+                false,
366
+                false,
367
+            ],
368
+            // data set 12
369
+            // remote with space, no contact
370
+            [
371
+                'user [email protected]',
372
+                [
373
+                    [
374
+                        'UID' => 'uid3',
375
+                        'FN' => 'User3 @ Localhost',
376
+                    ],
377
+                    [
378
+                        'UID' => 'uid2',
379
+                        'FN' => 'User2 @ Localhost',
380
+                        'EMAIL' => [
381
+                        ],
382
+                    ],
383
+                    [
384
+                        'isLocalSystemBook' => true,
385
+                        'UID' => 'uid1',
386
+                        'FN' => 'User @ Localhost',
387
+                        'EMAIL' => [
388
+                            'username@localhost',
389
+                        ],
390
+                    ],
391
+                ],
392
+                false,
393
+                ['emails' => [], 'exact' => ['emails' => []]],
394
+                false,
395
+                false,
396
+                false,
397
+            ],
398
+            // data set 13
399
+            // Local user found by email
400
+            [
401
+                '[email protected]',
402
+                [
403
+                    [
404
+                        'UID' => 'uid1',
405
+                        'FN' => 'User',
406
+                        'EMAIL' => ['[email protected]'],
407
+                        'CLOUD' => ['test@localhost'],
408
+                        'isLocalSystemBook' => true,
409
+                    ]
410
+                ],
411
+                false,
412
+                ['users' => [], 'exact' => ['users' => [['uuid' => 'uid1', 'name' => 'User', 'label' => 'User ([email protected])','value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'shareWithDisplayNameUnique' => '[email protected]']]]],
413
+                true,
414
+                false,
415
+                true,
416
+            ],
417
+            // data set 14
418
+            // Current local user found by email => no result
419
+            [
420
+                '[email protected]',
421
+                [
422
+                    [
423
+                        'UID' => 'uid1',
424
+                        'FN' => 'User',
425
+                        'EMAIL' => ['[email protected]'],
426
+                        'CLOUD' => ['current@localhost'],
427
+                        'isLocalSystemBook' => true,
428
+                    ]
429
+                ],
430
+                true,
431
+                ['exact' => []],
432
+                false,
433
+                false,
434
+                true,
435
+            ],
436
+            // data set 15
437
+            // Pagination and "more results" for user matches byyyyyyy emails
438
+            [
439
+                'test@example',
440
+                [
441
+                    [
442
+                        'UID' => 'uid1',
443
+                        'FN' => 'User1',
444
+                        'EMAIL' => ['[email protected]'],
445
+                        'CLOUD' => ['test1@localhost'],
446
+                        'isLocalSystemBook' => true,
447
+                    ],
448
+                    [
449
+                        'UID' => 'uid2',
450
+                        'FN' => 'User2',
451
+                        'EMAIL' => ['[email protected]'],
452
+                        'CLOUD' => ['test2@localhost'],
453
+                        'isLocalSystemBook' => true,
454
+                    ],
455
+                    [
456
+                        'UID' => 'uid3',
457
+                        'FN' => 'User3',
458
+                        'EMAIL' => ['[email protected]'],
459
+                        'CLOUD' => ['test3@localhost'],
460
+                        'isLocalSystemBook' => true,
461
+                    ],
462
+                    [
463
+                        'UID' => 'uid4',
464
+                        'FN' => 'User4',
465
+                        'EMAIL' => ['[email protected]'],
466
+                        'CLOUD' => ['test4@localhost'],
467
+                        'isLocalSystemBook' => true,
468
+                    ],
469
+                ],
470
+                true,
471
+                ['users' => [
472
+                    ['uuid' => 'uid1', 'name' => 'User1', 'label' => 'User1 ([email protected])', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test1'], 'shareWithDisplayNameUnique' => '[email protected]'],
473
+                    ['uuid' => 'uid2', 'name' => 'User2', 'label' => 'User2 ([email protected])', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test2'], 'shareWithDisplayNameUnique' => '[email protected]'],
474
+                ], 'emails' => [], 'exact' => ['users' => [], 'emails' => []]],
475
+                false,
476
+                true,
477
+                false,
478
+            ],
479
+            // data set 16
480
+            // Pagination and "more results" for normal emails
481
+            [
482
+                'test@example',
483
+                [
484
+                    [
485
+                        'UID' => 'uid1',
486
+                        'FN' => 'User1',
487
+                        'EMAIL' => ['[email protected]'],
488
+                        'CLOUD' => ['test1@localhost'],
489
+                    ],
490
+                    [
491
+                        'UID' => 'uid2',
492
+                        'FN' => 'User2',
493
+                        'EMAIL' => ['[email protected]'],
494
+                        'CLOUD' => ['test2@localhost'],
495
+                    ],
496
+                    [
497
+                        'UID' => 'uid3',
498
+                        'FN' => 'User3',
499
+                        'EMAIL' => ['[email protected]'],
500
+                        'CLOUD' => ['test3@localhost'],
501
+                    ],
502
+                    [
503
+                        'UID' => 'uid4',
504
+                        'FN' => 'User4',
505
+                        'EMAIL' => ['[email protected]'],
506
+                        'CLOUD' => ['test4@localhost'],
507
+                    ],
508
+                ],
509
+                true,
510
+                ['emails' => [
511
+                    ['uuid' => 'uid1', 'name' => 'User1', 'type' => '', 'label' => 'User1 ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']],
512
+                    ['uuid' => 'uid2', 'name' => 'User2', 'type' => '', 'label' => 'User2 ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']],
513
+                ], 'exact' => ['emails' => []]],
514
+                false,
515
+                true,
516
+                false,
517
+            ],
518
+            // data set 17
519
+            // multiple email addresses with type
520
+            [
521
+                'User Name',
522
+                [
523
+                    [
524
+                        'UID' => 'uid3',
525
+                        'FN' => 'User3',
526
+                    ],
527
+                    [
528
+                        'UID' => 'uid2',
529
+                        'FN' => 'User2',
530
+                        'EMAIL' => [
531
+                        ],
532
+                    ],
533
+                    [
534
+                        'UID' => 'uid1',
535
+                        'FN' => 'User Name',
536
+                        'EMAIL' => [
537
+                            ['type' => 'HOME', 'value' => '[email protected]'],
538
+                            ['type' => 'WORK', 'value' => '[email protected]'],
539
+                        ],
540
+                    ],
541
+                ],
542
+                false,
543
+                ['emails' => [
544
+                ], 'exact' => ['emails' => [
545
+                    ['name' => 'User Name', 'uuid' => 'uid1', 'type' => 'HOME', 'label' => 'User Name ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']],
546
+                    ['name' => 'User Name', 'uuid' => 'uid1', 'type' => 'WORK', 'label' => 'User Name ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]
547
+                ]]],
548
+                false,
549
+                false,
550
+                false,
551
+            ],
552
+            // data set 18
553
+            // idn email
554
+            [
555
+                'test@lölölölölölölöl.com',
556
+                [],
557
+                true,
558
+                ['emails' => [], 'exact' => ['emails' => [['uuid' => 'test@lölölölölölölöl.com', 'label' => 'test@lölölölölölölöl.com', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => 'test@lölölölölölölöl.com']]]]],
559
+                false,
560
+                false,
561
+                true,
562
+            ],
563
+        ];
564
+    }
565
+
566
+    /**
567
+     *
568
+     * @param string $searchTerm
569
+     * @param array $contacts
570
+     * @param array $expected
571
+     * @param bool $exactIdMatch
572
+     * @param bool $reachedEnd
573
+     * @param array groups
574
+     */
575
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataGetEmailGroupsOnly')]
576
+    public function testSearchGroupsOnly($searchTerm, $contacts, $expected, $exactIdMatch, $reachedEnd, $userToGroupMapping, $validEmail): void {
577
+        $this->config->expects($this->any())
578
+            ->method('getAppValue')
579
+            ->willReturnCallback(
580
+                function ($appName, $key, $default) {
581
+                    if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
582
+                        return 'yes';
583
+                    } elseif ($appName === 'core' && $key === 'shareapi_only_share_with_group_members') {
584
+                        return 'yes';
585
+                    }
586
+                    return $default;
587
+                }
588
+            );
589
+
590
+        $this->instantiatePlugin();
591
+
592
+        /** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
593
+        $currentUser = $this->createMock('\OCP\IUser');
594
+
595
+        $currentUser->expects($this->any())
596
+            ->method('getUID')
597
+            ->willReturn('currentUser');
598
+
599
+        $this->contactsManager->expects($this->any())
600
+            ->method('search')
601
+            ->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
602
+                if ($search === $searchTerm) {
603
+                    return $contacts;
604
+                }
605
+                return [];
606
+            });
607
+
608
+        $this->userSession->expects($this->any())
609
+            ->method('getUser')
610
+            ->willReturn($currentUser);
611
+
612
+        $this->groupManager->expects($this->any())
613
+            ->method('getUserGroupIds')
614
+            ->willReturnCallback(function (IUser $user) use ($userToGroupMapping) {
615
+                return $userToGroupMapping[$user->getUID()];
616
+            });
617
+
618
+        $this->groupManager->expects($this->any())
619
+            ->method('isInGroup')
620
+            ->willReturnCallback(function ($userId, $group) use ($userToGroupMapping) {
621
+                return in_array($group, $userToGroupMapping[$userId]);
622
+            });
623
+
624
+        $moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult);
625
+        $result = $this->searchResult->asArray();
626
+
627
+        $this->assertSame($exactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails')));
628
+        $this->assertEquals($expected, $result);
629
+        $this->assertSame($reachedEnd, $moreResults);
630
+    }
631
+
632
+    public static function dataGetEmailGroupsOnly(): array {
633
+        return [
634
+            // The user `User` can share with the current user
635
+            [
636
+                'test',
637
+                [
638
+                    [
639
+                        'FN' => 'User',
640
+                        'EMAIL' => ['[email protected]'],
641
+                        'CLOUD' => ['test@localhost'],
642
+                        'isLocalSystemBook' => true,
643
+                        'UID' => 'User'
644
+                    ]
645
+                ],
646
+                ['users' => [['label' => 'User ([email protected])', 'uuid' => 'User', 'name' => 'User', 'value' => ['shareType' => 0, 'shareWith' => 'test'],'shareWithDisplayNameUnique' => '[email protected]',]], 'emails' => [], 'exact' => ['emails' => [], 'users' => []]],
647
+                false,
648
+                false,
649
+                [
650
+                    'currentUser' => ['group1'],
651
+                    'User' => ['group1']
652
+                ],
653
+                false,
654
+            ],
655
+            // The user `User` cannot share with the current user
656
+            [
657
+                'test',
658
+                [
659
+                    [
660
+                        'FN' => 'User',
661
+                        'EMAIL' => ['[email protected]'],
662
+                        'CLOUD' => ['test@localhost'],
663
+                        'isLocalSystemBook' => true,
664
+                        'UID' => 'User'
665
+                    ]
666
+                ],
667
+                ['emails' => [], 'exact' => ['emails' => []]],
668
+                false,
669
+                false,
670
+                [
671
+                    'currentUser' => ['group1'],
672
+                    'User' => ['group2']
673
+                ],
674
+                false,
675
+            ],
676
+            // The user `User` cannot share with the current user, but there is an exact match on the e-mail address -> share by e-mail
677
+            [
678
+                '[email protected]',
679
+                [
680
+                    [
681
+                        'FN' => 'User',
682
+                        'EMAIL' => ['[email protected]'],
683
+                        'CLOUD' => ['test@localhost'],
684
+                        'isLocalSystemBook' => true,
685
+                        'UID' => 'User'
686
+                    ]
687
+                ],
688
+                ['emails' => [], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => 4,'shareWith' => '[email protected]']]]]],
689
+                false,
690
+                false,
691
+                [
692
+                    'currentUser' => ['group1'],
693
+                    'User' => ['group2']
694
+                ],
695
+                true,
696
+            ]
697
+        ];
698
+    }
699 699
 }
Please login to merge, or discard this patch.
tests/lib/Share20/ShareByMailProviderTest.php 1 patch
Indentation   +259 added lines, -259 removed lines patch added patch discarded remove patch
@@ -38,263 +38,263 @@
 block discarded – undo
38 38
  * @group DB
39 39
  */
40 40
 class ShareByMailProviderTest extends TestCase {
41
-	use EmailValidatorTrait;
42
-
43
-	/** @var IDBConnection */
44
-	protected $dbConn;
45
-
46
-	/** @var IUserManager | \PHPUnit\Framework\MockObject\MockObject */
47
-	protected $userManager;
48
-
49
-	/** @var IRootFolder | \PHPUnit\Framework\MockObject\MockObject */
50
-	protected $rootFolder;
51
-
52
-	/** @var ShareByMailProvider */
53
-	protected $provider;
54
-
55
-	/** @var \PHPUnit\Framework\MockObject\MockObject|IMailer */
56
-	protected $mailer;
57
-
58
-	/** @var \PHPUnit\Framework\MockObject\MockObject|IL10N */
59
-	protected $l10n;
60
-
61
-	/** @var \PHPUnit\Framework\MockObject\MockObject|Defaults */
62
-	protected $defaults;
63
-
64
-	/** @var \PHPUnit\Framework\MockObject\MockObject|IURLGenerator */
65
-	protected $urlGenerator;
66
-
67
-	/** @var IConfig|MockObject */
68
-	protected $config;
69
-
70
-	/** @var LoggerInterface|MockObject */
71
-	private $logger;
72
-
73
-	/** @var IHasher|MockObject */
74
-	private $hasher;
75
-
76
-	/** @var \OCP\Activity\IManager|MockObject */
77
-	private $activityManager;
78
-
79
-	/** @var IEventDispatcher|MockObject */
80
-	private $eventDispatcher;
81
-
82
-	/** @var \OCP\Share\IManager|MockObject */
83
-	private $shareManager;
84
-
85
-	/** @var ISecureRandom|MockObject */
86
-	private $secureRandom;
87
-
88
-	/** @var SettingsManager|MockObject */
89
-	private $settingsManager;
90
-
91
-	protected function setUp(): void {
92
-		$this->dbConn = Server::get(IDBConnection::class);
93
-		$this->userManager = $this->createMock(IUserManager::class);
94
-		$this->rootFolder = $this->createMock(IRootFolder::class);
95
-		$this->mailer = $this->createMock(IMailer::class);
96
-		$this->l10n = $this->createMock(IL10N::class);
97
-		$this->defaults = $this->getMockBuilder(Defaults::class)->disableOriginalConstructor()->getMock();
98
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
99
-		$this->logger = $this->createMock(LoggerInterface::class);
100
-		$this->activityManager = $this->createMock(\OCP\Activity\IManager::class);
101
-		$this->settingsManager = $this->createMock(SettingsManager::class);
102
-		$this->hasher = $this->createMock(IHasher::class);
103
-		$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
104
-		$this->shareManager = $this->createMock(\OCP\Share\IManager::class);
105
-		$this->secureRandom = $this->createMock(ISecureRandom::class);
106
-		$this->config = $this->createMock(IConfig::class);
107
-
108
-		// Empty share table
109
-		$this->dbConn->getQueryBuilder()->delete('share')->executeStatement();
110
-
111
-		$this->provider = new ShareByMailProvider(
112
-			$this->config,
113
-			$this->dbConn,
114
-			$this->secureRandom,
115
-			$this->userManager,
116
-			$this->rootFolder,
117
-			$this->l10n,
118
-			$this->logger,
119
-			$this->mailer,
120
-			$this->urlGenerator,
121
-			$this->activityManager,
122
-			$this->settingsManager,
123
-			$this->defaults,
124
-			$this->hasher,
125
-			$this->eventDispatcher,
126
-			$this->shareManager,
127
-			$this->getEmailValidatorWithStrictEmailCheck(),
128
-		);
129
-	}
130
-
131
-	protected function tearDown(): void {
132
-		$this->dbConn->getQueryBuilder()->delete('share')->executeStatement();
133
-		$this->dbConn->getQueryBuilder()->delete('filecache')->runAcrossAllShards()->executeStatement();
134
-		$this->dbConn->getQueryBuilder()->delete('storages')->executeStatement();
135
-	}
136
-
137
-	/**
138
-	 * @param int $shareType
139
-	 * @param string $sharedWith
140
-	 * @param string $sharedBy
141
-	 * @param string $shareOwner
142
-	 * @param string $itemType
143
-	 * @param int $fileSource
144
-	 * @param string $fileTarget
145
-	 * @param int $permissions
146
-	 * @param $token
147
-	 * @param $expiration
148
-	 * @param $parent
149
-	 * @return int
150
-	 *
151
-	 * @throws \OCP\DB\Exception
152
-	 */
153
-	private function addShareToDB($shareType, $sharedWith, $sharedBy, $shareOwner,
154
-		$itemType, $fileSource, $fileTarget, $permissions, $token, $expiration,
155
-		$parent) {
156
-		$qb = $this->dbConn->getQueryBuilder();
157
-		$qb->insert('share');
158
-
159
-		if ($shareType) {
160
-			$qb->setValue('share_type', $qb->expr()->literal($shareType));
161
-		}
162
-		if ($sharedWith) {
163
-			$qb->setValue('share_with', $qb->expr()->literal($sharedWith));
164
-		}
165
-		if ($sharedBy) {
166
-			$qb->setValue('uid_initiator', $qb->expr()->literal($sharedBy));
167
-		}
168
-		if ($shareOwner) {
169
-			$qb->setValue('uid_owner', $qb->expr()->literal($shareOwner));
170
-		}
171
-		if ($itemType) {
172
-			$qb->setValue('item_type', $qb->expr()->literal($itemType));
173
-		}
174
-		if ($fileSource) {
175
-			$qb->setValue('file_source', $qb->expr()->literal($fileSource));
176
-		}
177
-		if ($fileTarget) {
178
-			$qb->setValue('file_target', $qb->expr()->literal($fileTarget));
179
-		}
180
-		if ($permissions) {
181
-			$qb->setValue('permissions', $qb->expr()->literal($permissions));
182
-		}
183
-		if ($token) {
184
-			$qb->setValue('token', $qb->expr()->literal($token));
185
-		}
186
-		if ($expiration) {
187
-			$qb->setValue('expiration', $qb->createNamedParameter($expiration, IQueryBuilder::PARAM_DATETIME_MUTABLE));
188
-		}
189
-		if ($parent) {
190
-			$qb->setValue('parent', $qb->expr()->literal($parent));
191
-		}
192
-
193
-		$this->assertEquals(1, $qb->executeStatement());
194
-		return $qb->getLastInsertId();
195
-	}
196
-
197
-	public function testGetSharesByWithResharesAndNoNode(): void {
198
-		$this->addShareToDB(
199
-			IShare::TYPE_EMAIL,
200
-			'[email protected]',
201
-			'user1',
202
-			'user1',
203
-			'folder',
204
-			42,
205
-			null,
206
-			17,
207
-			'foobar',
208
-			null,
209
-			null,
210
-		);
211
-		$this->addShareToDB(
212
-			IShare::TYPE_EMAIL,
213
-			'[email protected]',
214
-			'user2',
215
-			'user2',
216
-			'folder',
217
-			42,
218
-			null,
219
-			17,
220
-			'barfoo',
221
-			null,
222
-			null,
223
-		);
224
-
225
-		// Return own shares only if not asked for a specific node
226
-		/** @var IShare[] $actual */
227
-		$actual = $this->provider->getSharesBy(
228
-			'user1',
229
-			IShare::TYPE_EMAIL,
230
-			null,
231
-			true,
232
-			-1,
233
-			0,
234
-		);
235
-
236
-		$this->assertCount(1, $actual);
237
-
238
-		$this->assertEquals(IShare::TYPE_EMAIL, $actual[0]->getShareType());
239
-		$this->assertEquals('user1', $actual[0]->getSharedBy());
240
-		$this->assertEquals('user1', $actual[0]->getShareOwner());
241
-		$this->assertEquals('[email protected]', $actual[0]->getSharedWith());
242
-	}
243
-
244
-	public function testGetSharesByWithResharesAndNode(): void {
245
-		$this->addShareToDB(
246
-			IShare::TYPE_EMAIL,
247
-			'[email protected]',
248
-			'user1',
249
-			'user1',
250
-			'folder',
251
-			42,
252
-			null,
253
-			17,
254
-			'foobar',
255
-			null,
256
-			null,
257
-		);
258
-		$this->addShareToDB(
259
-			IShare::TYPE_EMAIL,
260
-			'[email protected]',
261
-			'user2',
262
-			'user2',
263
-			'folder',
264
-			42,
265
-			null,
266
-			17,
267
-			'barfoo',
268
-			null,
269
-			null,
270
-		);
271
-
272
-		$node = $this->createMock(Node::class);
273
-		$node->expects($this->once())
274
-			->method('getId')
275
-			->willReturn(42);
276
-
277
-		// Return all shares if asked for specific node
278
-		/** @var IShare[] $actual */
279
-		$actual = $this->provider->getSharesBy(
280
-			'user1',
281
-			IShare::TYPE_EMAIL,
282
-			$node,
283
-			true,
284
-			-1,
285
-			0,
286
-		);
287
-
288
-		$this->assertCount(2, $actual);
289
-
290
-		$this->assertEquals(IShare::TYPE_EMAIL, $actual[0]->getShareType());
291
-		$this->assertEquals('user1', $actual[0]->getSharedBy());
292
-		$this->assertEquals('user1', $actual[0]->getShareOwner());
293
-		$this->assertEquals('[email protected]', $actual[0]->getSharedWith());
294
-
295
-		$this->assertEquals(IShare::TYPE_EMAIL, $actual[1]->getShareType());
296
-		$this->assertEquals('user2', $actual[1]->getSharedBy());
297
-		$this->assertEquals('user2', $actual[1]->getShareOwner());
298
-		$this->assertEquals('[email protected]', $actual[1]->getSharedWith());
299
-	}
41
+    use EmailValidatorTrait;
42
+
43
+    /** @var IDBConnection */
44
+    protected $dbConn;
45
+
46
+    /** @var IUserManager | \PHPUnit\Framework\MockObject\MockObject */
47
+    protected $userManager;
48
+
49
+    /** @var IRootFolder | \PHPUnit\Framework\MockObject\MockObject */
50
+    protected $rootFolder;
51
+
52
+    /** @var ShareByMailProvider */
53
+    protected $provider;
54
+
55
+    /** @var \PHPUnit\Framework\MockObject\MockObject|IMailer */
56
+    protected $mailer;
57
+
58
+    /** @var \PHPUnit\Framework\MockObject\MockObject|IL10N */
59
+    protected $l10n;
60
+
61
+    /** @var \PHPUnit\Framework\MockObject\MockObject|Defaults */
62
+    protected $defaults;
63
+
64
+    /** @var \PHPUnit\Framework\MockObject\MockObject|IURLGenerator */
65
+    protected $urlGenerator;
66
+
67
+    /** @var IConfig|MockObject */
68
+    protected $config;
69
+
70
+    /** @var LoggerInterface|MockObject */
71
+    private $logger;
72
+
73
+    /** @var IHasher|MockObject */
74
+    private $hasher;
75
+
76
+    /** @var \OCP\Activity\IManager|MockObject */
77
+    private $activityManager;
78
+
79
+    /** @var IEventDispatcher|MockObject */
80
+    private $eventDispatcher;
81
+
82
+    /** @var \OCP\Share\IManager|MockObject */
83
+    private $shareManager;
84
+
85
+    /** @var ISecureRandom|MockObject */
86
+    private $secureRandom;
87
+
88
+    /** @var SettingsManager|MockObject */
89
+    private $settingsManager;
90
+
91
+    protected function setUp(): void {
92
+        $this->dbConn = Server::get(IDBConnection::class);
93
+        $this->userManager = $this->createMock(IUserManager::class);
94
+        $this->rootFolder = $this->createMock(IRootFolder::class);
95
+        $this->mailer = $this->createMock(IMailer::class);
96
+        $this->l10n = $this->createMock(IL10N::class);
97
+        $this->defaults = $this->getMockBuilder(Defaults::class)->disableOriginalConstructor()->getMock();
98
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
99
+        $this->logger = $this->createMock(LoggerInterface::class);
100
+        $this->activityManager = $this->createMock(\OCP\Activity\IManager::class);
101
+        $this->settingsManager = $this->createMock(SettingsManager::class);
102
+        $this->hasher = $this->createMock(IHasher::class);
103
+        $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
104
+        $this->shareManager = $this->createMock(\OCP\Share\IManager::class);
105
+        $this->secureRandom = $this->createMock(ISecureRandom::class);
106
+        $this->config = $this->createMock(IConfig::class);
107
+
108
+        // Empty share table
109
+        $this->dbConn->getQueryBuilder()->delete('share')->executeStatement();
110
+
111
+        $this->provider = new ShareByMailProvider(
112
+            $this->config,
113
+            $this->dbConn,
114
+            $this->secureRandom,
115
+            $this->userManager,
116
+            $this->rootFolder,
117
+            $this->l10n,
118
+            $this->logger,
119
+            $this->mailer,
120
+            $this->urlGenerator,
121
+            $this->activityManager,
122
+            $this->settingsManager,
123
+            $this->defaults,
124
+            $this->hasher,
125
+            $this->eventDispatcher,
126
+            $this->shareManager,
127
+            $this->getEmailValidatorWithStrictEmailCheck(),
128
+        );
129
+    }
130
+
131
+    protected function tearDown(): void {
132
+        $this->dbConn->getQueryBuilder()->delete('share')->executeStatement();
133
+        $this->dbConn->getQueryBuilder()->delete('filecache')->runAcrossAllShards()->executeStatement();
134
+        $this->dbConn->getQueryBuilder()->delete('storages')->executeStatement();
135
+    }
136
+
137
+    /**
138
+     * @param int $shareType
139
+     * @param string $sharedWith
140
+     * @param string $sharedBy
141
+     * @param string $shareOwner
142
+     * @param string $itemType
143
+     * @param int $fileSource
144
+     * @param string $fileTarget
145
+     * @param int $permissions
146
+     * @param $token
147
+     * @param $expiration
148
+     * @param $parent
149
+     * @return int
150
+     *
151
+     * @throws \OCP\DB\Exception
152
+     */
153
+    private function addShareToDB($shareType, $sharedWith, $sharedBy, $shareOwner,
154
+        $itemType, $fileSource, $fileTarget, $permissions, $token, $expiration,
155
+        $parent) {
156
+        $qb = $this->dbConn->getQueryBuilder();
157
+        $qb->insert('share');
158
+
159
+        if ($shareType) {
160
+            $qb->setValue('share_type', $qb->expr()->literal($shareType));
161
+        }
162
+        if ($sharedWith) {
163
+            $qb->setValue('share_with', $qb->expr()->literal($sharedWith));
164
+        }
165
+        if ($sharedBy) {
166
+            $qb->setValue('uid_initiator', $qb->expr()->literal($sharedBy));
167
+        }
168
+        if ($shareOwner) {
169
+            $qb->setValue('uid_owner', $qb->expr()->literal($shareOwner));
170
+        }
171
+        if ($itemType) {
172
+            $qb->setValue('item_type', $qb->expr()->literal($itemType));
173
+        }
174
+        if ($fileSource) {
175
+            $qb->setValue('file_source', $qb->expr()->literal($fileSource));
176
+        }
177
+        if ($fileTarget) {
178
+            $qb->setValue('file_target', $qb->expr()->literal($fileTarget));
179
+        }
180
+        if ($permissions) {
181
+            $qb->setValue('permissions', $qb->expr()->literal($permissions));
182
+        }
183
+        if ($token) {
184
+            $qb->setValue('token', $qb->expr()->literal($token));
185
+        }
186
+        if ($expiration) {
187
+            $qb->setValue('expiration', $qb->createNamedParameter($expiration, IQueryBuilder::PARAM_DATETIME_MUTABLE));
188
+        }
189
+        if ($parent) {
190
+            $qb->setValue('parent', $qb->expr()->literal($parent));
191
+        }
192
+
193
+        $this->assertEquals(1, $qb->executeStatement());
194
+        return $qb->getLastInsertId();
195
+    }
196
+
197
+    public function testGetSharesByWithResharesAndNoNode(): void {
198
+        $this->addShareToDB(
199
+            IShare::TYPE_EMAIL,
200
+            '[email protected]',
201
+            'user1',
202
+            'user1',
203
+            'folder',
204
+            42,
205
+            null,
206
+            17,
207
+            'foobar',
208
+            null,
209
+            null,
210
+        );
211
+        $this->addShareToDB(
212
+            IShare::TYPE_EMAIL,
213
+            '[email protected]',
214
+            'user2',
215
+            'user2',
216
+            'folder',
217
+            42,
218
+            null,
219
+            17,
220
+            'barfoo',
221
+            null,
222
+            null,
223
+        );
224
+
225
+        // Return own shares only if not asked for a specific node
226
+        /** @var IShare[] $actual */
227
+        $actual = $this->provider->getSharesBy(
228
+            'user1',
229
+            IShare::TYPE_EMAIL,
230
+            null,
231
+            true,
232
+            -1,
233
+            0,
234
+        );
235
+
236
+        $this->assertCount(1, $actual);
237
+
238
+        $this->assertEquals(IShare::TYPE_EMAIL, $actual[0]->getShareType());
239
+        $this->assertEquals('user1', $actual[0]->getSharedBy());
240
+        $this->assertEquals('user1', $actual[0]->getShareOwner());
241
+        $this->assertEquals('[email protected]', $actual[0]->getSharedWith());
242
+    }
243
+
244
+    public function testGetSharesByWithResharesAndNode(): void {
245
+        $this->addShareToDB(
246
+            IShare::TYPE_EMAIL,
247
+            '[email protected]',
248
+            'user1',
249
+            'user1',
250
+            'folder',
251
+            42,
252
+            null,
253
+            17,
254
+            'foobar',
255
+            null,
256
+            null,
257
+        );
258
+        $this->addShareToDB(
259
+            IShare::TYPE_EMAIL,
260
+            '[email protected]',
261
+            'user2',
262
+            'user2',
263
+            'folder',
264
+            42,
265
+            null,
266
+            17,
267
+            'barfoo',
268
+            null,
269
+            null,
270
+        );
271
+
272
+        $node = $this->createMock(Node::class);
273
+        $node->expects($this->once())
274
+            ->method('getId')
275
+            ->willReturn(42);
276
+
277
+        // Return all shares if asked for specific node
278
+        /** @var IShare[] $actual */
279
+        $actual = $this->provider->getSharesBy(
280
+            'user1',
281
+            IShare::TYPE_EMAIL,
282
+            $node,
283
+            true,
284
+            -1,
285
+            0,
286
+        );
287
+
288
+        $this->assertCount(2, $actual);
289
+
290
+        $this->assertEquals(IShare::TYPE_EMAIL, $actual[0]->getShareType());
291
+        $this->assertEquals('user1', $actual[0]->getSharedBy());
292
+        $this->assertEquals('user1', $actual[0]->getShareOwner());
293
+        $this->assertEquals('[email protected]', $actual[0]->getSharedWith());
294
+
295
+        $this->assertEquals(IShare::TYPE_EMAIL, $actual[1]->getShareType());
296
+        $this->assertEquals('user2', $actual[1]->getSharedBy());
297
+        $this->assertEquals('user2', $actual[1]->getShareOwner());
298
+        $this->assertEquals('[email protected]', $actual[1]->getSharedWith());
299
+    }
300 300
 }
Please login to merge, or discard this patch.
tests/Core/Command/User/AddTest.php 1 patch
Indentation   +123 added lines, -123 removed lines patch added patch discarded remove patch
@@ -25,127 +25,127 @@
 block discarded – undo
25 25
 use Test\Traits\EmailValidatorTrait;
26 26
 
27 27
 class AddTest extends TestCase {
28
-	use EmailValidatorTrait;
29
-
30
-	/** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */
31
-	private $userManager;
32
-
33
-	/** @var IGroupManager|\PHPUnit\Framework\MockObject\MockObject */
34
-	private $groupManager;
35
-
36
-	/** @var IMailer|\PHPUnit\Framework\MockObject\MockObject */
37
-	private $mailer;
38
-
39
-	/** @var IAppConfig|\PHPUnit\Framework\MockObject\MockObject */
40
-	private $appConfig;
41
-
42
-	/** @var NewUserMailHelper|\PHPUnit\Framework\MockObject\MockObject */
43
-	private $mailHelper;
44
-
45
-	/** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */
46
-	private $eventDispatcher;
47
-
48
-	/** @var ISecureRandom|\PHPUnit\Framework\MockObject\MockObject */
49
-	private $secureRandom;
50
-
51
-	/** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
52
-	private $user;
53
-
54
-	/** @var InputInterface|\PHPUnit\Framework\MockObject\MockObject */
55
-	private $consoleInput;
56
-
57
-	/** @var OutputInterface|\PHPUnit\Framework\MockObject\MockObject */
58
-	private $consoleOutput;
59
-
60
-	/** @var Add */
61
-	private $addCommand;
62
-
63
-	public function setUp(): void {
64
-		parent::setUp();
65
-
66
-		$this->userManager = static::createMock(IUserManager::class);
67
-		$this->groupManager = static::createStub(IGroupManager::class);
68
-		$this->appConfig = static::createMock(IAppConfig::class);
69
-		$this->mailHelper = static::createMock(NewUserMailHelper::class);
70
-		$this->eventDispatcher = static::createStub(IEventDispatcher::class);
71
-		$this->secureRandom = static::createStub(ISecureRandom::class);
72
-
73
-		$this->user = static::createMock(IUser::class);
74
-
75
-		$this->consoleInput = static::createMock(InputInterface::class);
76
-		$this->consoleOutput = static::createMock(OutputInterface::class);
77
-
78
-		$this->addCommand = new Add(
79
-			$this->userManager,
80
-			$this->groupManager,
81
-			$this->getEmailValidatorWithStrictEmailCheck(),
82
-			$this->appConfig,
83
-			$this->mailHelper,
84
-			$this->eventDispatcher,
85
-			$this->secureRandom
86
-		);
87
-	}
88
-
89
-	#[\PHPUnit\Framework\Attributes\DataProvider('addEmailDataProvider')]
90
-	public function testAddEmail(
91
-		?string $email,
92
-		bool $isEmailValid,
93
-		bool $shouldSendEmail,
94
-	): void {
95
-		$this->user->expects($isEmailValid ? static::once() : static::never())
96
-			->method('setSystemEMailAddress')
97
-			->with(static::equalTo($email));
98
-
99
-		$this->userManager->method('createUser')
100
-			->willReturn($this->user);
101
-
102
-		$this->appConfig->method('getValueString')
103
-			->willReturn($shouldSendEmail ? 'yes' : 'no');
104
-
105
-		$this->mailHelper->method('generateTemplate')
106
-			->willReturn(static::createMock(IEMailTemplate::class));
107
-
108
-		$this->mailHelper->expects($isEmailValid && $shouldSendEmail ? static::once() : static::never())
109
-			->method('sendMail');
110
-
111
-		$this->consoleInput->method('getOption')
112
-			->willReturnMap([
113
-				['generate-password', 'true'],
114
-				['email', $email],
115
-				['group', []],
116
-			]);
117
-
118
-		$this->invokePrivate($this->addCommand, 'execute', [
119
-			$this->consoleInput,
120
-			$this->consoleOutput
121
-		]);
122
-	}
123
-
124
-	/**
125
-	 * @return array
126
-	 */
127
-	public static function addEmailDataProvider(): array {
128
-		return [
129
-			'Valid E-Mail' => [
130
-				'[email protected]',
131
-				true,
132
-				true,
133
-			],
134
-			'Invalid E-Mail' => [
135
-				'info@@example.com',
136
-				false,
137
-				false,
138
-			],
139
-			'No E-Mail' => [
140
-				'',
141
-				false,
142
-				false,
143
-			],
144
-			'Valid E-Mail, but no mail should be sent' => [
145
-				'[email protected]',
146
-				true,
147
-				false,
148
-			],
149
-		];
150
-	}
28
+    use EmailValidatorTrait;
29
+
30
+    /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */
31
+    private $userManager;
32
+
33
+    /** @var IGroupManager|\PHPUnit\Framework\MockObject\MockObject */
34
+    private $groupManager;
35
+
36
+    /** @var IMailer|\PHPUnit\Framework\MockObject\MockObject */
37
+    private $mailer;
38
+
39
+    /** @var IAppConfig|\PHPUnit\Framework\MockObject\MockObject */
40
+    private $appConfig;
41
+
42
+    /** @var NewUserMailHelper|\PHPUnit\Framework\MockObject\MockObject */
43
+    private $mailHelper;
44
+
45
+    /** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */
46
+    private $eventDispatcher;
47
+
48
+    /** @var ISecureRandom|\PHPUnit\Framework\MockObject\MockObject */
49
+    private $secureRandom;
50
+
51
+    /** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
52
+    private $user;
53
+
54
+    /** @var InputInterface|\PHPUnit\Framework\MockObject\MockObject */
55
+    private $consoleInput;
56
+
57
+    /** @var OutputInterface|\PHPUnit\Framework\MockObject\MockObject */
58
+    private $consoleOutput;
59
+
60
+    /** @var Add */
61
+    private $addCommand;
62
+
63
+    public function setUp(): void {
64
+        parent::setUp();
65
+
66
+        $this->userManager = static::createMock(IUserManager::class);
67
+        $this->groupManager = static::createStub(IGroupManager::class);
68
+        $this->appConfig = static::createMock(IAppConfig::class);
69
+        $this->mailHelper = static::createMock(NewUserMailHelper::class);
70
+        $this->eventDispatcher = static::createStub(IEventDispatcher::class);
71
+        $this->secureRandom = static::createStub(ISecureRandom::class);
72
+
73
+        $this->user = static::createMock(IUser::class);
74
+
75
+        $this->consoleInput = static::createMock(InputInterface::class);
76
+        $this->consoleOutput = static::createMock(OutputInterface::class);
77
+
78
+        $this->addCommand = new Add(
79
+            $this->userManager,
80
+            $this->groupManager,
81
+            $this->getEmailValidatorWithStrictEmailCheck(),
82
+            $this->appConfig,
83
+            $this->mailHelper,
84
+            $this->eventDispatcher,
85
+            $this->secureRandom
86
+        );
87
+    }
88
+
89
+    #[\PHPUnit\Framework\Attributes\DataProvider('addEmailDataProvider')]
90
+    public function testAddEmail(
91
+        ?string $email,
92
+        bool $isEmailValid,
93
+        bool $shouldSendEmail,
94
+    ): void {
95
+        $this->user->expects($isEmailValid ? static::once() : static::never())
96
+            ->method('setSystemEMailAddress')
97
+            ->with(static::equalTo($email));
98
+
99
+        $this->userManager->method('createUser')
100
+            ->willReturn($this->user);
101
+
102
+        $this->appConfig->method('getValueString')
103
+            ->willReturn($shouldSendEmail ? 'yes' : 'no');
104
+
105
+        $this->mailHelper->method('generateTemplate')
106
+            ->willReturn(static::createMock(IEMailTemplate::class));
107
+
108
+        $this->mailHelper->expects($isEmailValid && $shouldSendEmail ? static::once() : static::never())
109
+            ->method('sendMail');
110
+
111
+        $this->consoleInput->method('getOption')
112
+            ->willReturnMap([
113
+                ['generate-password', 'true'],
114
+                ['email', $email],
115
+                ['group', []],
116
+            ]);
117
+
118
+        $this->invokePrivate($this->addCommand, 'execute', [
119
+            $this->consoleInput,
120
+            $this->consoleOutput
121
+        ]);
122
+    }
123
+
124
+    /**
125
+     * @return array
126
+     */
127
+    public static function addEmailDataProvider(): array {
128
+        return [
129
+            'Valid E-Mail' => [
130
+                '[email protected]',
131
+                true,
132
+                true,
133
+            ],
134
+            'Invalid E-Mail' => [
135
+                'info@@example.com',
136
+                false,
137
+                false,
138
+            ],
139
+            'No E-Mail' => [
140
+                '',
141
+                false,
142
+                false,
143
+            ],
144
+            'Valid E-Mail, but no mail should be sent' => [
145
+                '[email protected]',
146
+                true,
147
+                false,
148
+            ],
149
+        ];
150
+    }
151 151
 }
Please login to merge, or discard this patch.