Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(calls): Add notifications for federated calls #12845

Merged
merged 5 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ public function register(IRegistrationContext $context): void {

// Notification listeners
$context->registerEventListener(AttendeesAddedEvent::class, NotificationListener::class);
$context->registerEventListener(ActiveSinceModifiedEvent::class, NotificationListener::class);
$context->registerEventListener(BeforeParticipantModifiedEvent::class, NotificationListener::class);
$context->registerEventListener(CallNotificationSendEvent::class, NotificationListener::class);
$context->registerEventListener(ParticipantModifiedEvent::class, NotificationListener::class);
Expand Down
24 changes: 21 additions & 3 deletions lib/Controller/CallController.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,13 @@ public function joinCall(?int $flags = null, ?int $forcePermissions = null, bool
if ($this->room->isFederatedConversation()) {
/** @var \OCA\Talk\Federation\Proxy\TalkV1\Controller\CallController $proxy */
$proxy = \OCP\Server::get(\OCA\Talk\Federation\Proxy\TalkV1\Controller\CallController::class);
return $proxy->joinFederatedCall($this->room, $this->participant, $flags, $silent, $recordingConsent);
$response = $proxy->joinFederatedCall($this->room, $this->participant, $flags, $silent, $recordingConsent);

if ($response->getStatus() === Http::STATUS_OK) {
$this->participantService->changeInCall($this->room, $this->participant, $flags, false, $silent);
}

return $response;
}

if ($forcePermissions !== null && $this->participant->hasModeratorPermissions()) {
Expand Down Expand Up @@ -325,7 +331,13 @@ public function updateCallFlags(int $flags): DataResponse {
if ($this->room->isFederatedConversation()) {
/** @var \OCA\Talk\Federation\Proxy\TalkV1\Controller\CallController $proxy */
$proxy = \OCP\Server::get(\OCA\Talk\Federation\Proxy\TalkV1\Controller\CallController::class);
return $proxy->updateFederatedCallFlags($this->room, $this->participant, $flags);
$response = $proxy->updateFederatedCallFlags($this->room, $this->participant, $flags);

if ($response->getStatus() === Http::STATUS_OK) {
$this->participantService->updateCallFlags($this->room, $this->participant, $flags);
}

return $response;
}

try {
Expand Down Expand Up @@ -391,7 +403,13 @@ public function leaveCall(bool $all = false): DataResponse {
if ($this->room->isFederatedConversation()) {
/** @var \OCA\Talk\Federation\Proxy\TalkV1\Controller\CallController $proxy */
$proxy = \OCP\Server::get(\OCA\Talk\Federation\Proxy\TalkV1\Controller\CallController::class);
return $proxy->leaveFederatedCall($this->room, $this->participant);
$response = $proxy->leaveFederatedCall($this->room, $this->participant);

if ($response->getStatus() === Http::STATUS_OK) {
$this->participantService->changeInCall($this->room, $this->participant, Participant::FLAG_DISCONNECTED);
}

return $response;
}

if ($all && $this->participant->hasModeratorPermissions()) {
Expand Down
22 changes: 22 additions & 0 deletions lib/Events/ActiveSinceModifiedEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,27 @@

namespace OCA\Talk\Events;

use OCA\Talk\Room;

class ActiveSinceModifiedEvent extends AActiveSinceModifiedEvent {
public function __construct(
Room $room,
?\DateTime $newValue,
?\DateTime $oldValue,
int $callFlag,
int $oldCallFlag,
protected bool $updatedActiveSince,
) {
parent::__construct(
$room,
$newValue,
$oldValue,
$callFlag,
$oldCallFlag,
);
}

public function hasUpdatedActiveSince(): bool {
return $this->updatedActiveSince;
}
}
14 changes: 14 additions & 0 deletions lib/Notification/Listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use OCA\Talk\AppInfo\Application;
use OCA\Talk\Controller\ChatController;
use OCA\Talk\Events\ActiveSinceModifiedEvent;
use OCA\Talk\Events\AParticipantModifiedEvent;
use OCA\Talk\Events\AttendeesAddedEvent;
use OCA\Talk\Events\BeforeParticipantModifiedEvent;
Expand Down Expand Up @@ -61,6 +62,7 @@ public function handle(Event $event): void {
UserJoinedRoomEvent::class => $this->handleUserJoinedRoomEvent($event),
BeforeParticipantModifiedEvent::class => $this->checkCallNotifications($event),
ParticipantModifiedEvent::class => $this->afterParticipantJoinedCall($event),
ActiveSinceModifiedEvent::class => $this->afterActiveSinceModified($event),
};
}

Expand Down Expand Up @@ -222,6 +224,18 @@ protected function afterParticipantJoinedCall(ParticipantModifiedEvent $event):
}
}

protected function afterActiveSinceModified(ActiveSinceModifiedEvent $event): void {
if (!$event->hasUpdatedActiveSince()) {
return;
}

if (!$event->getRoom()->isFederatedConversation()) {
return;
}

$this->sendCallNotifications($event->getRoom());
}

/**
* Call notification: "{user} wants to talk with you"
*
Expand Down
5 changes: 4 additions & 1 deletion lib/Notification/Notifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,10 @@ protected function parseCall(INotification $notification, Room $room, IL10N $l):
throw new AlreadyProcessedException();
}
} elseif (\in_array($room->getType(), [Room::TYPE_GROUP, Room::TYPE_PUBLIC], true)) {
if ($this->notificationManager->isPreparingPushNotification() || $this->participantService->hasActiveSessionsInCall($room)) {
if ($this->notificationManager->isPreparingPushNotification()
|| (!$room->isFederatedConversation() && $this->participantService->hasActiveSessionsInCall($room))
|| ($room->isFederatedConversation() && $room->getActiveSince())
) {
$notification = $this->addActionButton($notification, 'call_view', $l->t('Join call'), true, true);
$subject = $l->t('A group call has started in {call}');
} else {
Expand Down
8 changes: 4 additions & 4 deletions lib/Service/RoomService.php
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ public function resetActiveSince(Room $room): bool {

$result = (bool) $update->executeStatement();

$event = new ActiveSinceModifiedEvent($room, null, $oldActiveSince, Participant::FLAG_DISCONNECTED, $oldCallFlag);
$event = new ActiveSinceModifiedEvent($room, null, $oldActiveSince, Participant::FLAG_DISCONNECTED, $oldCallFlag, $result);
$this->dispatcher->dispatchTyped($event);

return $result;
Expand Down Expand Up @@ -901,14 +901,14 @@ public function setActiveSince(Room $room, \DateTime $since, int $callFlag): boo
->set('active_since', $update->createNamedParameter($since, IQueryBuilder::PARAM_DATE))
->where($update->expr()->eq('id', $update->createNamedParameter($room->getId(), IQueryBuilder::PARAM_INT)))
->andWhere($update->expr()->isNull('active_since'));
$update->executeStatement();
$result = (bool) $update->executeStatement();

$room->setActiveSince($since, $callFlag);

$event = new ActiveSinceModifiedEvent($room, $since, $oldActiveSince, $callFlag, $oldCallFlag);
$event = new ActiveSinceModifiedEvent($room, $since, $oldActiveSince, $callFlag, $oldCallFlag, $result);
$this->dispatcher->dispatchTyped($event);

return true;
return $result;
}

public function setLastMessage(Room $room, IComment $message): void {
Expand Down
112 changes: 112 additions & 0 deletions tests/integration/features/federation/call.feature
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,115 @@ Feature: federation/call
| actorType | actorId | inCall |
| federated_users | participant1@{$LOCAL_URL} | 0 |
| users | participant2 | 0 |

Scenario: normal call notification for federated user
Given user "participant1" creates room "room" (v4)
| roomType | 2 |
| roomName | room |
And user "participant1" adds federated_user "participant2@REMOTE" to room "room" with 200 (v4)
And using server "REMOTE"
And user "participant2" has the following invitations (v1)
| remoteServerUrl | remoteToken | state | inviterCloudId | inviterDisplayName |
| LOCAL | room | 0 | participant1@http://localhost:8080 | participant1-displayname |
And user "participant2" accepts invite to room "room" of server "LOCAL" with 200 (v1)
| id | name | type | remoteServer | remoteToken |
| LOCAL::room | room | 2 | LOCAL | room |
And user "participant2" joins room "LOCAL::room" with 200 (v4)
And using server "LOCAL"
And user "participant1" joins room "room" with 200 (v4)
When user "participant1" joins call "room" with 200 (v4)
Then using server "REMOTE"
And user "participant2" has the following notifications
| app | object_type | object_id | subject |
| spreed | call | LOCAL::room | A group call has started in room |

Scenario: normal call notification for federated user is cleared when joining
Given user "participant1" creates room "room" (v4)
| roomType | 2 |
| roomName | room |
And user "participant1" adds federated_user "participant2@REMOTE" to room "room" with 200 (v4)
And using server "REMOTE"
And user "participant2" has the following invitations (v1)
| remoteServerUrl | remoteToken | state | inviterCloudId | inviterDisplayName |
| LOCAL | room | 0 | participant1@http://localhost:8080 | participant1-displayname |
And user "participant2" accepts invite to room "room" of server "LOCAL" with 200 (v1)
| id | name | type | remoteServer | remoteToken |
| LOCAL::room | room | 2 | LOCAL | room |
And user "participant2" joins room "LOCAL::room" with 200 (v4)
And using server "LOCAL"
And user "participant1" joins room "room" with 200 (v4)
When user "participant1" joins call "room" with 200 (v4)
And using server "REMOTE"
And user "participant2" has the following notifications
| app | object_type | object_id | subject |
| spreed | call | LOCAL::room | A group call has started in room |
When user "participant2" joins call "LOCAL::room" with 200 (v4)
Then user "participant2" has the following notifications
| app | object_type | object_id | subject |

Scenario: missed call notification for federated user
Given user "participant1" creates room "room" (v4)
| roomType | 2 |
| roomName | room |
And user "participant1" adds federated_user "participant2@REMOTE" to room "room" with 200 (v4)
And using server "REMOTE"
And user "participant2" has the following invitations (v1)
| remoteServerUrl | remoteToken | state | inviterCloudId | inviterDisplayName |
| LOCAL | room | 0 | participant1@http://localhost:8080 | participant1-displayname |
And user "participant2" accepts invite to room "room" of server "LOCAL" with 200 (v1)
| id | name | type | remoteServer | remoteToken |
| LOCAL::room | room | 2 | LOCAL | room |
And user "participant2" joins room "LOCAL::room" with 200 (v4)
And using server "LOCAL"
And user "participant1" joins room "room" with 200 (v4)
And user "participant1" joins call "room" with 200 (v4)
When user "participant1" leaves call "room" with 200 (v4)
Then using server "REMOTE"
And user "participant2" has the following notifications
| app | object_type | object_id | subject |
| spreed | call | LOCAL::room | You missed a group call in room |

Scenario: silent call by federated user does not trigger call notification
Given user "participant1" creates room "room" (v4)
| roomType | 2 |
| roomName | room |
And user "participant1" adds federated_user "participant2@REMOTE" to room "room" with 200 (v4)
And using server "REMOTE"
And user "participant2" has the following invitations (v1)
| remoteServerUrl | remoteToken | state | inviterCloudId | inviterDisplayName |
| LOCAL | room | 0 | participant1@http://localhost:8080 | participant1-displayname |
And user "participant2" accepts invite to room "room" of server "LOCAL" with 200 (v1)
| id | name | type | remoteServer | remoteToken |
| LOCAL::room | room | 2 | LOCAL | room |
And using server "LOCAL"
And user "participant1" joins room "room" with 200 (v4)
And using server "REMOTE"
And user "participant2" joins room "LOCAL::room" with 200 (v4)
When user "participant2" joins call "LOCAL::room" with 200 (v4)
| silent | true |
Then using server "LOCAL"
And user "participant1" has the following notifications
| app | object_type | object_id | subject |

Scenario: missed silent call by federated user does not trigger call notification
Given user "participant1" creates room "room" (v4)
| roomType | 2 |
| roomName | room |
And user "participant1" adds federated_user "participant2@REMOTE" to room "room" with 200 (v4)
And using server "REMOTE"
And user "participant2" has the following invitations (v1)
| remoteServerUrl | remoteToken | state | inviterCloudId | inviterDisplayName |
| LOCAL | room | 0 | participant1@http://localhost:8080 | participant1-displayname |
And user "participant2" accepts invite to room "room" of server "LOCAL" with 200 (v1)
| id | name | type | remoteServer | remoteToken |
| LOCAL::room | room | 2 | LOCAL | room |
And using server "LOCAL"
And user "participant1" joins room "room" with 200 (v4)
And using server "REMOTE"
And user "participant2" joins room "LOCAL::room" with 200 (v4)
And user "participant2" joins call "LOCAL::room" with 200 (v4)
| silent | true |
When user "participant2" leaves call "LOCAL::room" with 200 (v4)
Then using server "LOCAL"
And user "participant1" has the following notifications
| app | object_type | object_id | subject |
Loading