Skip to content

Commit

Permalink
Merge pull request #10541 from nextcloud/feat/10404/note-to-self
Browse files Browse the repository at this point in the history
feat(note-to-self): Add API for note-to-self
  • Loading branch information
nickvergessen authored Sep 27, 2023
2 parents 0a71376 + e0e87cf commit 9ac434c
Show file tree
Hide file tree
Showing 17 changed files with 274 additions and 8 deletions.
2 changes: 2 additions & 0 deletions appinfo/routes/routesRoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
['name' => 'Room#getListedRooms', 'url' => '/api/{apiVersion}/listed-room', 'verb' => 'GET', 'requirements' => $requirements],
/** @see \OCA\Talk\Controller\RoomController::createRoom() */
['name' => 'Room#createRoom', 'url' => '/api/{apiVersion}/room', 'verb' => 'POST', 'requirements' => $requirements],
/** @see \OCA\Talk\Controller\RoomController::getNoteToSelfConversation() */
['name' => 'Room#getNoteToSelfConversation', 'url' => '/api/{apiVersion}/room/note-to-self', 'verb' => 'GET', 'requirements' => $requirements],
/** @see \OCA\Talk\Controller\RoomController::getSingleRoom() */
['name' => 'Room#getSingleRoom', 'url' => '/api/{apiVersion}/room/{token}', 'verb' => 'GET', 'requirements' => $requirementsWithToken],
/** @see \OCA\Talk\Controller\RoomController::getBreakoutRooms() */
Expand Down
1 change: 1 addition & 0 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,5 @@

## 18
* `session-state` - Sessions can mark themselves as inactive, so the participant receives notifications again
* `note-to-self` - Support for "Note-to-self" conversation exists
* `config => chat => has-translation-providers` - When true, translation tuples can be loaded from the [OCS Translation API](https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-translation-api.html#get-available-translation-options).
33 changes: 33 additions & 0 deletions docs/conversation.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,39 @@

- Data: See array definition in `Get user´s conversations`

## Get "Note-to-self" conversation

The conversation is like a group conversation and the user is the owner, but with the following limitations:

* Can not add participants to the conversation
* Can not allow guests
* Can not make read-only
* Can not open the conversations to users or guests
* Can not change permissions
* Can not set lobby
* Can not enable SIP
* Can not configure breakout rooms
* Can not call

If the conversation does not exist at the moment, it will be generated and the user added automatically.

* Required capability: `note-to-self`
* Method: `GET`
* Endpoint: `/room/note-to-self`

* Response:
- Status code:
+ `200 OK`
+ `401 Unauthorized` When the user is not logged in

- Header:

| field | type | Description |
|-------------------------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
| `X-Nextcloud-Talk-Hash` | string | Sha1 value over some config. When you receive a different value on subsequent requests, the capabilities and the signaling settings should be refreshed. |

- Data: See array definition in `Get user´s conversations`

## Get open conversations

* Required capability: `listable-rooms`
Expand Down
3 changes: 3 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
use OCA\Talk\Deck\DeckPluginLoader;
use OCA\Talk\Events\AttendeesAddedEvent;
use OCA\Talk\Events\AttendeesRemovedEvent;
use OCA\Talk\Events\BeforeRoomsFetchEvent;
use OCA\Talk\Events\BotInstallEvent;
use OCA\Talk\Events\BotUninstallEvent;
use OCA\Talk\Events\RoomEvent;
Expand All @@ -62,6 +63,7 @@
use OCA\Talk\Listener\FeaturePolicyListener;
use OCA\Talk\Listener\GroupDeletedListener;
use OCA\Talk\Listener\GroupMembershipListener;
use OCA\Talk\Listener\NoteToSelfListener;
use OCA\Talk\Listener\RestrictStartingCalls as RestrictStartingCallsListener;
use OCA\Talk\Listener\UserDeletedListener;
use OCA\Talk\Maps\MapsPluginLoader;
Expand Down Expand Up @@ -127,6 +129,7 @@ public function register(IRegistrationContext $context): void {

$context->registerEventListener(AddContentSecurityPolicyEvent::class, CSPListener::class);
$context->registerEventListener(AddFeaturePolicyEvent::class, FeaturePolicyListener::class);
$context->registerEventListener(BeforeRoomsFetchEvent::class, NoteToSelfListener::class);
$context->registerEventListener(BotInstallEvent::class, BotListener::class);
$context->registerEventListener(BotUninstallEvent::class, BotListener::class);
$context->registerEventListener(GroupDeletedEvent::class, GroupDeletedListener::class);
Expand Down
1 change: 1 addition & 0 deletions lib/Capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ public function getCapabilities(): array {
'bots-v1',
'markdown-messages',
'session-state',
'note-to-self',
],
'config' => [
'attachments' => [
Expand Down
5 changes: 4 additions & 1 deletion lib/Controller/CallController.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,11 @@ public function joinCall(?int $flags = null, ?int $forcePermissions = null, bool
$this->roomService->setPermissions($this->room, 'call', Attendee::PERMISSIONS_MODIFY_SET, $forcePermissions, true);
}

$this->participantService->changeInCall($this->room, $this->participant, $flags, false, $silent);
$joined = $this->participantService->changeInCall($this->room, $this->participant, $flags, false, $silent);

if (!$joined) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
return new DataResponse();
}

Expand Down
18 changes: 18 additions & 0 deletions lib/Controller/RoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

use InvalidArgumentException;
use OCA\Talk\Config;
use OCA\Talk\Events\BeforeRoomsFetchEvent;
use OCA\Talk\Events\UserEvent;
use OCA\Talk\Exceptions\ForbiddenException;
use OCA\Talk\Exceptions\InvalidPasswordException;
Expand All @@ -51,6 +52,7 @@
use OCA\Talk\Room;
use OCA\Talk\Service\BreakoutRoomService;
use OCA\Talk\Service\ChecksumVerificationService;
use OCA\Talk\Service\NoteToSelfService;
use OCA\Talk\Service\ParticipantService;
use OCA\Talk\Service\RoomFormatter;
use OCA\Talk\Service\RoomService;
Expand Down Expand Up @@ -95,6 +97,7 @@ public function __construct(
protected Manager $manager,
protected RoomService $roomService,
protected BreakoutRoomService $breakoutRoomService,
protected NoteToSelfService $noteToSelfService,
protected ParticipantService $participantService,
protected SessionService $sessionService,
protected GuestManager $guestManager,
Expand Down Expand Up @@ -155,6 +158,8 @@ public function getRooms(int $noStatusUpdate = 0, bool $includeStatus = false, i

$event = new UserEvent($this->userId);
$this->dispatcher->dispatch(self::EVENT_BEFORE_ROOMS_GET, $event);
$event = new BeforeRoomsFetchEvent($this->userId);
$this->dispatcher->dispatchTyped($event);

if ($noStatusUpdate === 0) {
$isMobileApp = $this->request->isUserAgent([
Expand Down Expand Up @@ -325,6 +330,18 @@ public function getSingleRoom(string $token): DataResponse {
}
}

/**
* Get the "Note to self" conversation for the user
*
* It will be automatically created when it is currently missing
*/
#[NoAdminRequired]
public function getNoteToSelfConversation(): DataResponse {
$room = $this->noteToSelfService->ensureNoteToSelfExistsForUser($this->userId);
$participant = $this->participantService->getParticipant($room, $this->userId, false);
return new DataResponse($this->formatRoom($room, $participant), Http::STATUS_OK, $this->getTalkHashHeader());
}

/**
* Check if the current request is coming from an allowed backend.
*
Expand Down Expand Up @@ -822,6 +839,7 @@ protected function formatParticipantList(array $participants, bool $includeStatu
public function addParticipantToRoom(string $newParticipant, string $source = 'users'): DataResponse {
if ($this->room->getType() === Room::TYPE_ONE_TO_ONE
|| $this->room->getType() === Room::TYPE_ONE_TO_ONE_FORMER
|| $this->room->getType() === Room::TYPE_NOTE_TO_SELF
|| $this->room->getObjectType() === 'share:password') {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
Expand Down
29 changes: 29 additions & 0 deletions lib/Events/BeforeRoomsFetchEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
*
* @author Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\Talk\Events;

class BeforeRoomsFetchEvent extends UserEvent {
}
45 changes: 45 additions & 0 deletions lib/Listener/NoteToSelfListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\Talk\Listener;

use OCA\Talk\Events\BeforeRoomsFetchEvent;
use OCA\Talk\Service\NoteToSelfService;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;

/**
* @template-implements IEventListener<Event>
*/
class NoteToSelfListener implements IEventListener {
public function __construct(
protected NoteToSelfService $service,
) {
}

public function handle(Event $event): void {
if ($event instanceof BeforeRoomsFetchEvent) {
$this->service->initialCreateNoteToSelfForUser($event->getUserId());
}
}
}
1 change: 1 addition & 0 deletions lib/Room.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class Room {
public const TYPE_PUBLIC = 3;
public const TYPE_CHANGELOG = 4;
public const TYPE_ONE_TO_ONE_FORMER = 5;
public const TYPE_NOTE_TO_SELF = 6;

public const RECORDING_NONE = 0;
public const RECORDING_VIDEO = 1;
Expand Down
111 changes: 111 additions & 0 deletions lib/Service/NoteToSelfService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\Talk\Service;

use OCA\Talk\Exceptions\RoomNotFoundException;
use OCA\Talk\Manager;
use OCA\Talk\Model\Attendee;
use OCA\Talk\Room;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IUser;
use OCP\IUserManager;

class NoteToSelfService {
public function __construct(
protected IConfig $config,
protected IUserManager $userManager,
protected Manager $manager,
protected RoomService $roomService,
protected AvatarService $avatarService,
protected ParticipantService $participantService,
protected IL10N $l,
) {
}

public function ensureNoteToSelfExistsForUser(string $userId): Room {
$noteToSelfId = $this->getNoteToSelfConversationId($userId);

if ($noteToSelfId !== 0) {
try {
return $this->manager->getRoomById($noteToSelfId);
} catch (RoomNotFoundException) {
// Fall through and recreate it …
}
}

$currentUser = $this->userManager->get($userId);
if (!$currentUser instanceof IUser) {
throw new \InvalidArgumentException('User not found');
}

return $this->createNoteToSelfConversation($currentUser);
}

public function initialCreateNoteToSelfForUser(string $userId): void {
$noteToSelfId = $this->getNoteToSelfConversationId($userId);
if ($noteToSelfId !== 0) {
return;
}

$currentUser = $this->userManager->get($userId);
if (!$currentUser instanceof IUser) {
throw new \InvalidArgumentException('User not found');
}

$this->createNoteToSelfConversation($currentUser);
}

protected function createNoteToSelfConversation(IUser $user): Room {
$room = $this->roomService->createConversation(
Room::TYPE_NOTE_TO_SELF,
$this->l->t('Note to self'),
$user,
'note_to_self',
$user->getUID()
);
$this->config->setUserValue($user->getUID(), 'spreed', 'note_to_self', (string) $room->getId());

$this->roomService->setDescription(
$room,
$this->l->t('A place for your private notes, thoughts and ideas'),
);

$this->avatarService->setAvatarFromEmoji($room, '📝', '0082c9');

$participant = $this->participantService->getParticipantByActor(
$room,
Attendee::ACTOR_USERS,
$user->getUID()
);

$this->participantService->updateFavoriteStatus($participant, true);

return $room;
}

protected function getNoteToSelfConversationId(string $userId): int {
return (int) $this->config->getUserValue($userId, 'spreed', 'note_to_self', '0');
}
}
10 changes: 8 additions & 2 deletions lib/Service/ParticipantService.php
Original file line number Diff line number Diff line change
Expand Up @@ -1031,10 +1031,14 @@ public function endCallForEveryone(Room $room, Participant $moderator): void {
$this->dispatcher->dispatch(Room::EVENT_AFTER_END_CALL_FOR_EVERYONE, $event);
}

public function changeInCall(Room $room, Participant $participant, int $flags, bool $endCallForEveryone = false, bool $silent = false): void {
public function changeInCall(Room $room, Participant $participant, int $flags, bool $endCallForEveryone = false, bool $silent = false): bool {
if ($room->getType() === Room::TYPE_CHANGELOG || $room->getType() === Room::TYPE_NOTE_TO_SELF) {
return false;
}

$session = $participant->getSession();
if (!$session instanceof Session) {
return;
return false;
}

$permissions = $participant->getPermissions();
Expand Down Expand Up @@ -1077,6 +1081,8 @@ public function changeInCall(Room $room, Participant $participant, int $flags, b
} else {
$this->dispatcher->dispatch(Room::EVENT_AFTER_SESSION_LEAVE_CALL, $event);
}

return true;
}

public function sendCallNotificationForAttendee(Room $room, Participant $currentParticipant, int $targetAttendeeId): bool {
Expand Down
Loading

0 comments on commit 9ac434c

Please sign in to comment.