Skip to content
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
3 changes: 3 additions & 0 deletions lib/Chat/ChatManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ public function addSystemMessage(
?IComment $replyTo = null,
bool $shouldSkipLastMessageUpdate = false,
bool $silent = false,
int $threadId = 0,
): IComment {
if ($chat->isFederatedConversation()) {
$e = new MessagingNotAllowedException();
Expand All @@ -167,6 +168,8 @@ public function addSystemMessage(
}
if ($replyTo !== null) {
$comment->setParentId($replyTo->getId());
} elseif ($threadId !== 0) {
$comment->setParentId((string)$threadId);
}

$messageDecoded = json_decode($message, true);
Expand Down
13 changes: 13 additions & 0 deletions lib/Chat/Parser/SystemMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -574,11 +574,24 @@ protected function parseMessage(Message $chatMessage, $allowInaccurate): void {
}
} elseif ($message === 'thread_created') {
$parsedMessage = $this->l->t('{actor} created thread {title}');
if ($currentUserIsActor) {
$parsedMessage = $this->l->t('You created thread {title}');
}
$parsedParameters['title'] = [
'type' => 'highlight',
'id' => 'thread/' . $parameters['thread'],
'name' => $parameters['title'] ?? (string)$parameters['thread'],
];
} elseif ($message === 'thread_renamed') {
$parsedMessage = $this->l->t('{actor} renamed thread {title}');
if ($currentUserIsActor) {
$parsedMessage = $this->l->t('You renamed thread {title}');
}
$parsedParameters['title'] = [
'type' => 'highlight',
'id' => 'thread/' . $parameters['thread'],
'name' => $parameters['title'],
];
} elseif ($message === 'matterbridge_config_edited') {
$parsedMessage = $this->l->t('{actor} updated the Matterbridge configuration');
if ($currentUserIsActor) {
Expand Down
4 changes: 2 additions & 2 deletions lib/Chat/SystemMessage/Listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -419,12 +419,12 @@ protected function fixMimeTypeOfVoiceMessage(ShareCreatedEvent|BeforeDuplicateSh
);

if ($threadTitle !== '' && $comment->getTopmostParentId() === '0') {
$this->threadService->createThread($room, (int)$comment->getId(), $threadTitle);
$thread = $this->threadService->createThread($room, (int)$comment->getId(), $threadTitle);

$this->sendSystemMessage(
$room,
'thread_created',
['thread' => (int)$comment->getId(), 'title' => $threadTitle],
['thread' => (int)$comment->getId(), 'title' => $thread->getName()],
shouldSkipLastMessageUpdate: true,
silent: true,
parent: $comment,
Expand Down
4 changes: 2 additions & 2 deletions lib/Controller/ChatController.php
Original file line number Diff line number Diff line change
Expand Up @@ -264,13 +264,13 @@ public function sendMessage(string $message, string $actorDisplayName = '', stri
try {
$comment = $this->chatManager->sendMessage($this->room, $this->participant, $actorType, $actorId, $message, $creationDateTime, $parent, $referenceId, $silent);
if ($replyTo === 0 && $threadTitle !== '') {
$this->threadService->createThread($this->room, (int)$comment->getId(), $threadTitle);
$thread = $this->threadService->createThread($this->room, (int)$comment->getId(), $threadTitle);

$this->chatManager->addSystemMessage(
$this->room,
$this->participant->getAttendee()->getActorType(),
$this->participant->getAttendee()->getActorId(),
json_encode(['message' => 'thread_created', 'parameters' => ['thread' => (int)$comment->getId(), 'title' => $threadTitle]]),
json_encode(['message' => 'thread_created', 'parameters' => ['thread' => (int)$comment->getId(), 'title' => $thread->getName()]]),
$this->timeFactory->getDateTime(),
false,
null,
Expand Down
78 changes: 78 additions & 0 deletions lib/Controller/ThreadController.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use OCP\AppFramework\Http\Attribute\RequestHeader;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Comments\NotFoundException;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IL10N;
use OCP\IRequest;
Expand Down Expand Up @@ -128,6 +129,83 @@ public function getThread(int $threadId): DataResponse {
return new DataResponse($threadInfo);
}

/**
* Rename a thread
*
* Required capability: `threads`
*
* @param int $threadId The thread ID to get the info for
* @psalm-param non-negative-int $threadId
* @param string $threadTitle New thread title, must not be empty
* @return DataResponse<Http::STATUS_OK, TalkThreadInfo, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error: 'title'}, array{}>|DataResponse<Http::STATUS_NOT_FOUND, array{error: 'thread'}, array{}>
*
* 200: Thread renamed successfully
* 400: When the provided title is empty
* 404: Thread not found
*/
#[FederationSupported]
#[PublicPage]
#[RequireModeratorOrNoLobby]
#[RequireParticipant]
#[RequestHeader(name: 'x-nextcloud-federation', description: 'Set to 1 when the request is performed by another Nextcloud Server to indicate a federation request', indirect: true)]
#[ApiRoute(verb: 'PUT', url: '/api/{apiVersion}/chat/{token}/threads/{threadId}', requirements: [
'apiVersion' => '(v1)',
'token' => '[a-z0-9]{4,30}',
'threadId' => '[0-9]+',
])]
public function renameThread(int $threadId, string $threadTitle): DataResponse {
$threadTitle = trim($threadTitle);
if ($this->room->isFederatedConversation()) {
/** @var \OCA\Talk\Federation\Proxy\TalkV1\Controller\ThreadController $proxy */
$proxy = \OCP\Server::get(\OCA\Talk\Federation\Proxy\TalkV1\Controller\ThreadController::class);
return $proxy->renameThread($this->room, $this->participant, $threadId, $threadTitle);
}

try {
$thread = $this->threadService->findByThreadId($threadId);
} catch (DoesNotExistException) {
return new DataResponse(['error' => 'thread'], Http::STATUS_NOT_FOUND);
}

if ($thread->getRoomId() !== $this->room->getId()) {
return new DataResponse(['error' => 'thread'], Http::STATUS_NOT_FOUND);
}

# FIXME Only allow for moderator and original author

try {
$this->threadService->renameThread($thread, $threadTitle);
} catch (\InvalidArgumentException $e) {
return new DataResponse(['error' => 'title'], Http::STATUS_BAD_REQUEST);
}

try {
$comment = $this->chatManager->getComment($this->room, (string)$threadId);
} catch (NotFoundException) {
// Root message expired, continuing without replying
$comment = null;
}

$this->chatManager->addSystemMessage(
$this->room,
$this->participant->getAttendee()->getActorType(),
$this->participant->getAttendee()->getActorId(),
json_encode(['message' => 'thread_renamed', 'parameters' => ['thread' => $threadId, 'title' => $thread->getName()]]),
$this->timeFactory->getDateTime(),
false,
null,
$comment,
true,
true,
$threadId,
);

$list = $this->prepareListOfThreads([$thread]);
/** @var TalkThreadInfo $threadInfo */
$threadInfo = array_shift($list);
return new DataResponse($threadInfo);
}

/**
* @param list<Thread> $threads
* @param ?list<ThreadAttendee> $attendees
Expand Down
49 changes: 49 additions & 0 deletions lib/Federation/Proxy/TalkV1/Controller/ThreadController.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,55 @@ public function getThread(Room $room, Participant $participant, int $threadId):
return new DataResponse($data, Http::STATUS_OK);
}

/**
* @see \OCA\Talk\Controller\ThreadController::setNotificationLevel()
*
* @psalm-param non-negative-int $threadId
* @return DataResponse<Http::STATUS_OK, TalkThreadInfo, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error: 'title'}, array{}>|DataResponse<Http::STATUS_NOT_FOUND, array{error: 'thread'}, array{}>
* @throws CannotReachRemoteException
*
* 200: Thread renamed successfully
* 400: When the provided title is empty
* 404: Thread not found
*/
public function renameThread(Room $room, Participant $participant, int $threadId, string $threadTitle): DataResponse {
$proxy = $this->proxy->put(
$participant->getAttendee()->getInvitedCloudId(),
$participant->getAttendee()->getAccessToken(),
$room->getRemoteServer() . '/ocs/v2.php/apps/spreed/api/v1/chat/' . $room->getRemoteToken() . '/threads/' . $threadId,
['threadTitle' => $threadTitle],
);

$statusCode = $proxy->getStatusCode();
if ($statusCode !== Http::STATUS_OK) {
if (!in_array($statusCode, [
Http::STATUS_BAD_REQUEST,
Http::STATUS_NOT_FOUND,
], true)) {
$statusCode = $this->proxy->logUnexpectedStatusCode(__METHOD__, $statusCode);
$data = ['error' => 'thread'];
} elseif ($statusCode === Http::STATUS_BAD_REQUEST) {
/** @var array{error: 'title'} $data */
$data = $this->proxy->getOCSData($proxy, [
Http::STATUS_BAD_REQUEST,
]);
} else {
/** @var array{error: 'thread'} $data */
$data = $this->proxy->getOCSData($proxy, [
Http::STATUS_NOT_FOUND,
]);
}
return new DataResponse($data, $statusCode);
}

/** @var TalkThreadInfo $data */
$data = $this->proxy->getOCSData($proxy);
$data = $this->userConverter->convertThreadInfo($room, $data);

return new DataResponse($data, Http::STATUS_OK);
}


/**
* @see \OCA\Talk\Controller\ThreadController::setNotificationLevel()
*
Expand Down
19 changes: 19 additions & 0 deletions lib/Service/ThreadService.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ public function __construct(
}

public function createThread(Room $room, int $threadId, string $title): Thread {
if (mb_strlen($title) > 203) {
$title = mb_substr($title, 0, 200) . '…';
}
$thread = new Thread();
$thread->setId($threadId);
$thread->setName($title);
Expand All @@ -49,6 +52,22 @@ public function findByThreadId(int $threadId): Thread {
return $this->threadMapper->findById($threadId);
}

/**
* @throws \InvalidArgumentException When the title is empty
*/
public function renameThread(Thread $thread, string $title): Thread {
if ($title === '') {
throw new \InvalidArgumentException('name');
}
if (mb_strlen($title) > 203) {
$title = mb_substr($title, 0, 200) . '…';
}
$thread->setName($title);
$this->threadMapper->update($thread);

return $thread;
}

/**
* @param int<1, 50> $limit
* @return list<Thread>
Expand Down
Loading
Loading