1<?php
2
3declare(strict_types=1);
4/**
5 * @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com>
6 *
7 * @license GNU AGPL version 3 or any later version
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU Affero General Public License for more details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24namespace OCA\Talk\Listener;
25
26use OCA\Circles\CirclesManager;
27use OCA\Circles\Model\Member;
28use OCA\Talk\Exceptions\ParticipantNotFoundException;
29use OCA\Talk\Manager;
30use OCA\Talk\Model\Attendee;
31use OCA\Talk\Participant;
32use OCA\Talk\Room;
33use OCA\Talk\Service\ParticipantService;
34use OCP\App\IAppManager;
35use OCP\EventDispatcher\IEventListener;
36use OCP\IGroupManager;
37use OCP\IUser;
38use Psr\Log\LoggerInterface;
39
40abstract class AMembershipListener implements IEventListener {
41
42	/** @var Manager */
43	protected $manager;
44	/** @var IAppManager */
45	protected $appManager;
46	/** @var IGroupManager */
47	protected $groupManager;
48	/** @var ParticipantService */
49	protected $participantService;
50
51	public function __construct(Manager $manager,
52								IAppManager $appManager,
53								IGroupManager $groupManager,
54								ParticipantService $participantService) {
55		$this->manager = $manager;
56		$this->appManager = $appManager;
57		$this->groupManager = $groupManager;
58		$this->participantService = $participantService;
59	}
60
61	protected function removeFromRoomsUnlessStillLinked(array $rooms, IUser $user): void {
62		$rooms = $this->filterRoomsWithOtherGroupMemberships($rooms, $user);
63		$rooms = $this->filterRoomsWithOtherCircleMemberships($rooms, $user);
64
65		foreach ($rooms as $room) {
66			try {
67				$participant = $room->getParticipant($user->getUID());
68				$participantType = $participant->getAttendee()->getParticipantType();
69				if ($participantType === Participant::USER) {
70					$this->participantService->removeUser($room, $user, Room::PARTICIPANT_REMOVED);
71				}
72			} catch (ParticipantNotFoundException $e) {
73			}
74		}
75	}
76
77	protected function filterRoomsWithOtherGroupMemberships(array $rooms, IUser $user): array {
78		$userGroupIds = $this->groupManager->getUserGroupIds($user);
79
80		$furtherMemberships = [];
81		foreach ($userGroupIds as $groupId) {
82			$groupRooms = $this->manager->getRoomsForActor(Attendee::ACTOR_GROUPS, $groupId);
83			foreach ($groupRooms as $room) {
84				$furtherMemberships[$room->getId()] = true;
85			}
86		}
87
88		return array_filter($rooms, static function (Room $room) use ($furtherMemberships) {
89			// Only delete from rooms where the user is not member via another group
90			return !isset($furtherMemberships[$room->getId()]);
91		});
92	}
93
94	protected function filterRoomsWithOtherCircleMemberships(array $rooms, IUser $user): array {
95		if (!$this->appManager->isEnabledForUser('circles', $user)) {
96			\OC::$server->get(LoggerInterface::class)->debug('Circles not enabled', ['app' => 'spreed']);
97			return $rooms;
98		}
99
100		try {
101			$circlesManager = \OC::$server->get(CirclesManager::class);
102			$federatedUser = $circlesManager->getFederatedUser($user->getUID(), Member::TYPE_USER);
103			$memberships = $federatedUser->getMemberships();
104		} catch (\Exception $e) {
105			return $rooms;
106		}
107
108		$furtherMemberships = [];
109		foreach ($memberships as $membership) {
110			$circleRooms = $this->manager->getRoomsForActor(Attendee::ACTOR_CIRCLES, $membership->getCircleId());
111
112			foreach ($circleRooms as $room) {
113				$furtherMemberships[$room->getId()] = true;
114			}
115		}
116
117		return array_filter($rooms, static function (Room $room) use ($furtherMemberships) {
118			// Only delete from rooms where the user is not member via another group
119			return !isset($furtherMemberships[$room->getId()]);
120		});
121	}
122}
123