diff --git a/lib/Controller/ChattyLLMController.php b/lib/Controller/ChattyLLMController.php index 5cc18745..53ef24a3 100644 --- a/lib/Controller/ChattyLLMController.php +++ b/lib/Controller/ChattyLLMController.php @@ -103,7 +103,7 @@ public function updateSessionTitle(int $sessionId, string $title): JSONResponse } try { - $this->sessionMapper->updateSessionTitle($sessionId, $title); + $this->sessionMapper->updateSessionTitle($this->userId, $sessionId, $title); return new JSONResponse(); } catch (\OCP\DB\Exception | \RuntimeException $e) { $this->logger->warning('Failed to update the chat session', ['exception' => $e]); @@ -124,7 +124,7 @@ public function deleteSession(int $sessionId): JSONResponse { } try { - $this->sessionMapper->deleteSession($sessionId); + $this->sessionMapper->deleteSession($this->userId, $sessionId); $this->messageMapper->deleteMessagesBySession($sessionId); return new JSONResponse(); } catch (\OCP\DB\Exception | \RuntimeException $e) { @@ -170,7 +170,7 @@ public function newMessage(int $sessionId, string $role, string $content, int $t } try { - $sessionExists = $this->sessionMapper->exists($sessionId); + $sessionExists = $this->sessionMapper->exists($this->userId, $sessionId); if (!$sessionExists) { return new JSONResponse(['error' => $this->l10n->t('Session not found')], Http::STATUS_NOT_FOUND); } @@ -189,7 +189,11 @@ public function newMessage(int $sessionId, string $role, string $content, int $t if ($firstHumanMessage) { // set the title of the session based on first human message - $this->sessionMapper->updateSessionTitle($sessionId, strlen($content) > 140 ? mb_substr($content, 0, 140) . '...' : $content); + $this->sessionMapper->updateSessionTitle( + $this->userId, + $sessionId, + strlen($content) > 140 ? mb_substr($content, 0, 140) . '...' : $content, + ); } return new JSONResponse($message); @@ -214,7 +218,7 @@ public function getMessages(int $sessionId, int $limit = 20, int $cursor = 0): J } try { - $sessionExists = $this->sessionMapper->exists($sessionId); + $sessionExists = $this->sessionMapper->exists($this->userId, $sessionId); if (!$sessionExists) { return new JSONResponse(['error' => $this->l10n->t('Session not found')], Http::STATUS_NOT_FOUND); } @@ -235,15 +239,21 @@ public function getMessages(int $sessionId, int $limit = 20, int $cursor = 0): J * Delete a chat message by ID * * @param integer $messageId + * @param integer $sessionId * @return JSONResponse */ #[NoAdminRequired] - public function deleteMessage(int $messageId): JSONResponse { + public function deleteMessage(int $messageId, int $sessionId): JSONResponse { if ($this->userId === null) { return new JSONResponse(['error' => $this->l10n->t('User not logged in')], Http::STATUS_UNAUTHORIZED); } try { + $sessionExists = $this->sessionMapper->exists($this->userId, $sessionId); + if (!$sessionExists) { + return new JSONResponse(['error' => $this->l10n->t('Session not found')], Http::STATUS_NOT_FOUND); + } + $this->messageMapper->deleteMessageById($messageId); return new JSONResponse(); } catch (\OCP\DB\Exception | \RuntimeException $e) { @@ -265,7 +275,7 @@ public function generateForSession(int $sessionId): JSONResponse { } try { - $sessionExists = $this->sessionMapper->exists($sessionId); + $sessionExists = $this->sessionMapper->exists($this->userId, $sessionId); if (!$sessionExists) { return new JSONResponse(['error' => $this->l10n->t('Session not found')], Http::STATUS_NOT_FOUND); } @@ -306,7 +316,7 @@ public function regenerateForSession(int $sessionId, int $messageId): JSONRespon } try { - $sessionExists = $this->sessionMapper->exists($sessionId); + $sessionExists = $this->sessionMapper->exists($this->userId, $sessionId); if (!$sessionExists) { return new JSONResponse(['error' => $this->l10n->t('Session not found')], Http::STATUS_NOT_FOUND); } @@ -372,7 +382,7 @@ public function generateTitle(int $sessionId): JSONResponse { } try { - $sessionExists = $this->sessionMapper->exists($sessionId); + $sessionExists = $this->sessionMapper->exists($this->userId, $sessionId); if (!$sessionExists) { return new JSONResponse(['error' => $this->l10n->t('Session not found')], Http::STATUS_NOT_FOUND); } @@ -394,7 +404,7 @@ public function generateTitle(int $sessionId): JSONResponse { $title = explode(PHP_EOL, $title)[0]; $title = trim($title); - $this->sessionMapper->updateSessionTitle($sessionId, $title); + $this->sessionMapper->updateSessionTitle($this->userId, $sessionId, $title); return new JSONResponse(['result' => $title]); } catch (\OCP\DB\Exception $e) { diff --git a/lib/Db/ChattyLLM/SessionMapper.php b/lib/Db/ChattyLLM/SessionMapper.php index c86b02df..60418d03 100644 --- a/lib/Db/ChattyLLM/SessionMapper.php +++ b/lib/Db/ChattyLLM/SessionMapper.php @@ -38,15 +38,17 @@ public function __construct(IDBConnection $db) { } /** + * @param string $userId * @param integer $sessionId * @return boolean * @throws \OCP\DB\Exception */ - public function exists(int $sessionId): bool { + public function exists(string $userId, int $sessionId): bool { $qb = $this->db->getQueryBuilder(); $qb->select('id') ->from($this->getTableName()) - ->where($qb->expr()->eq('id', $qb->createPositionalParameter($sessionId, IQueryBuilder::PARAM_INT))); + ->where($qb->expr()->eq('id', $qb->createPositionalParameter($sessionId, IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId, IQueryBuilder::PARAM_STR))); try { return $this->findEntity($qb) !== null; @@ -73,29 +75,33 @@ public function getUserSessions(string $userId): array { } /** + * @param string $userId * @param integer $sessionId * @param string $title * @throws \OCP\DB\Exception * @throws \RuntimeException */ - public function updateSessionTitle(int $sessionId, string $title) { + public function updateSessionTitle(string $userId, int $sessionId, string $title) { $qb = $this->db->getQueryBuilder(); $qb->update($this->getTableName()) ->set('title', $qb->createPositionalParameter($title, IQueryBuilder::PARAM_STR)) - ->where($qb->expr()->eq('id', $qb->createPositionalParameter($sessionId, IQueryBuilder::PARAM_INT))); + ->where($qb->expr()->eq('id', $qb->createPositionalParameter($sessionId, IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId, IQueryBuilder::PARAM_STR))); $qb->executeStatement(); } /** + * @param string $userId * @param integer $sessionId * @throws \OCP\DB\Exception * @throws \RuntimeException */ - public function deleteSession(int $sessionId) { + public function deleteSession(string $userId, int $sessionId) { $qb = $this->db->getQueryBuilder(); $qb->delete($this->getTableName()) - ->where($qb->expr()->eq('id', $qb->createPositionalParameter($sessionId, IQueryBuilder::PARAM_INT))); + ->where($qb->expr()->eq('id', $qb->createPositionalParameter($sessionId, IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId, IQueryBuilder::PARAM_STR))); $qb->executeStatement(); } diff --git a/src/components/ChattyLLM/ChattyLLMInputForm.vue b/src/components/ChattyLLM/ChattyLLMInputForm.vue index f2c2de5a..edb80bdf 100644 --- a/src/components/ChattyLLM/ChattyLLMInputForm.vue +++ b/src/components/ChattyLLM/ChattyLLMInputForm.vue @@ -384,7 +384,7 @@ export default { try { this.loading.messageDelete = true await axios.delete(getChatURL('/delete_message'), { - params: { messageId }, + params: { messageId, sessionId: this.active.id }, }) this.messages = this.messages.filter((message) => message.id !== messageId) } catch (error) { diff --git a/src/components/ChattyLLM/ConversationBox.vue b/src/components/ChattyLLM/ConversationBox.vue index a7966ba2..8a101a12 100644 --- a/src/components/ChattyLLM/ConversationBox.vue +++ b/src/components/ChattyLLM/ConversationBox.vue @@ -37,8 +37,6 @@ import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' import Message from './Message.vue' import NoSession from './NoSession.vue' -import { getCurrentUser } from '@nextcloud/auth' - export default { name: 'ConversationBox', @@ -74,8 +72,6 @@ export default { data: () => { return { - displayName: getCurrentUser()?.displayName ?? getCurrentUser()?.uid ?? t('assistant', 'You'), - userId: getCurrentUser()?.uid ?? t('assistant', 'yooniquely-you'), regenerateFromId: null, deleteMessageId: null, } diff --git a/src/components/ChattyLLM/EditableTextField.vue b/src/components/ChattyLLM/EditableTextField.vue index 0f254a7d..4fa2c894 100644 --- a/src/components/ChattyLLM/EditableTextField.vue +++ b/src/components/ChattyLLM/EditableTextField.vue @@ -170,7 +170,7 @@ export default { overflow: hidden; position: relative; min-height: var(--default-clickable-area); - align-items: flex-end; + align-items: center; &__edit { margin-left: var(--default-clickable-area); diff --git a/src/components/ChattyLLM/Message.vue b/src/components/ChattyLLM/Message.vue index 4f622496..bbaaf636 100644 --- a/src/components/ChattyLLM/Message.vue +++ b/src/components/ChattyLLM/Message.vue @@ -90,7 +90,7 @@ export default { data: () => { return { displayName: getCurrentUser()?.displayName ?? getCurrentUser()?.uid ?? t('assistant', 'You'), - userId: getCurrentUser()?.uid ?? t('assistant', 'yooniquely-you'), + userId: getCurrentUser()?.uid ?? t('assistant', 'You'), showMessageActions: false, } }, diff --git a/src/components/ChattyLLM/MessageActions.vue b/src/components/ChattyLLM/MessageActions.vue index 5f933cde..2bf8339d 100644 --- a/src/components/ChattyLLM/MessageActions.vue +++ b/src/components/ChattyLLM/MessageActions.vue @@ -13,6 +13,7 @@ type="tertiary" :aria-label="t('assistant', 'Regenerate message')" :title="t('assistant', 'Regenerate message')" + :disabled="regenerateLoading" @click="$emit('regenerate', $event)">