diff --git a/appinfo/routes.php b/appinfo/routes.php index 411af41b6a..e58a8a36db 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -541,6 +541,7 @@ 'textBlockShares' => ['url' => '/api/textBlockshares'], 'quickActions' => ['url' => '/api/quick-actions'], 'actionStep' => ['url' => '/api/action-step'], + 'messageTemplate' => ['url' => 'api/message-template'] ], 'ocs' => [ [ diff --git a/lib/Controller/MessageTemplateController.php b/lib/Controller/MessageTemplateController.php new file mode 100644 index 0000000000..b429f82ae7 --- /dev/null +++ b/lib/Controller/MessageTemplateController.php @@ -0,0 +1,94 @@ +currentUserId = $userId; + } + + /** + * @NoAdminRequired + */ + #[TrapError] + public function index(): JSONResponse { + $this->checkUser(); + $messageTemplates = $this->messageTemplateService->findMessageTemplates($this->currentUserId); + return new JSONResponse($messageTemplates, Http::STATUS_OK); + } + + /** + * @NoAdminRequired + * @throws ClientException + */ + #[TrapError] + public function create(string $title, string $body): JSONResponse { + $this->checkUser(); + $messageTemplate = $this->messageTemplateService->createMessageTemplate($this->currentUserId, $title, $body); + return new JSONResponse($messageTemplate, Http::STATUS_CREATED); + } + + /** + * @NoAdminRequired + * @throws ClientException + */ + #[TrapError] + public function update(int $id, string $title, string $body): JSONResponse { + $this->checkUser(); + + try { + $messageTemplate = $this->messageTemplateService->updateMessageTemplate($this->currentUserId, $id, $title, $body); + } catch (DoesNotExistException $e) { + return new JSONResponse(['message' => 'Message template not found'], Http::STATUS_NOT_FOUND); + } + + return new JSONResponse($messageTemplate, Http::STATUS_OK); + } + + /** + * @NoAdminRequired + */ + #[TrapError] + public function destroy(int $id): JSONResponse { + $this->checkUser(); + + try { + $this->messageTemplateService->deleteMessageTemplate($this->currentUserId, $id); + return new JSONResponse([], Http::STATUS_OK); + } catch (DoesNotExistException $e) { + return new JSONResponse(['message' => 'Message template not found'], Http::STATUS_NOT_FOUND); + } + } + + private function checkUser(): void { + if ($this->currentUserId === null) { + throw new ClientException('No user specified'); + } + } +} diff --git a/lib/Db/MessageTemplate.php b/lib/Db/MessageTemplate.php new file mode 100644 index 0000000000..3f0fa14341 --- /dev/null +++ b/lib/Db/MessageTemplate.php @@ -0,0 +1,48 @@ +addType('userId', 'string'); + $this->addType('title', 'string'); + $this->addType('body', 'string'); + } + + #[\Override] + #[ReturnTypeWillChange] + public function jsonSerialize() { + return [ + 'id' => $this->getId(), + 'userId' => $this->getUserId(), + 'title' => $this->getTitle(), + 'body' => $this->getBody() + ]; + } +} diff --git a/lib/Db/MessageTemplateMapper.php b/lib/Db/MessageTemplateMapper.php new file mode 100644 index 0000000000..390e4c849a --- /dev/null +++ b/lib/Db/MessageTemplateMapper.php @@ -0,0 +1,82 @@ + + */ +class MessageTemplateMapper extends QBMapper { + + public function __construct(IDBConnection $db) { + parent::__construct($db, 'mail_message_templates'); + } + + /** + * @throws DoesNotExistException + */ + public function find(int $id): MessageTemplate { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from($this->getTableName()) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT))); + return $this->findEntity($qb); + } + + /** + * @throws Exception + */ + public function findAll(string $userId): array { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from($this->getTableName()) + ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId))); + + return $this->findEntities($qb); + } + + /** + * @throws Exception + */ + public function saveTemplate(string $userId, string $title, string $body): MessageTemplate { + $template = new MessageTemplate(); + $template->setUserId($userId); + $template->setTitle($title); + $template->setBody($body); + + return $this->insert($template); + } + + /** + * @throws DoesNotExistException + */ + public function updateTemplate(int $id, $title, string $body): MessageTemplate { + $messageTemplate = $this->find($id); + $messageTemplate->setTitle($title); + $messageTemplate->setBody($body); + + return $this->update($messageTemplate); + } + + /** + * @throws DoesNotExistException + */ + public function deleteTemplate(int $id): MessageTemplate { + $messageTemplate = $this->find($id); + return $this->delete($messageTemplate); + } + +} diff --git a/lib/Migration/Version5201Date20260707120000.php b/lib/Migration/Version5201Date20260707120000.php new file mode 100644 index 0000000000..cc389729f0 --- /dev/null +++ b/lib/Migration/Version5201Date20260707120000.php @@ -0,0 +1,57 @@ +hasTable('mail_message_templates')) { + $table = $schema->createTable('mail_message_templates'); + $table->addColumn('id', Types::INTEGER, [ + 'autoincrement' => true, + 'notnull' => true, + ]); + + $table->addColumn('user_id', Types::STRING, [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('title', Types::STRING, [ + 'notnull' => true, + 'length' => 255, + ]); + + $table->addColumn('body', Types::TEXT, [ + 'notnull' => false, + ]); + + $table->setPrimaryKey(['id']); + $table->addIndex(['user_id'], 'mail_tmpl_user_idx'); + } + + return $schema; + } + +} diff --git a/lib/Service/MessageTemplateService.php b/lib/Service/MessageTemplateService.php new file mode 100644 index 0000000000..e70728f424 --- /dev/null +++ b/lib/Service/MessageTemplateService.php @@ -0,0 +1,81 @@ +messageTemplateMapper->findAll($userId); + } + + /** + * @throws ClientException + */ + public function createMessageTemplate(string $userId, string $title, string $body): MessageTemplate { + $this->validateFields($title, $body); + try { + return $this->messageTemplateMapper->saveTemplate($userId, $title, $body); + } catch (Exception $e) { + throw new ClientException('Failed to save message template'); + } + } + + /** + * @throws DoesNotExistException + * @throws ClientException + */ + public function updateMessageTemplate(string $userId, int $id, string $title, string $body): MessageTemplate { + $messageTemplate = $this->messageTemplateMapper->find($id); + if ($userId !== $messageTemplate->getUserId()) { + throw new ClientException('Message template does not belong to this user'); + } + + try { + return $this->messageTemplateMapper->updateTemplate($id, $title, $body); + } catch (DoesNotExistException $e) { + throw new ClientException('Message template does not exist'); + } + } + + /** + * @throws DoesNotExistException + * @throws ClientException + */ + public function deleteMessageTemplate(string $userId, int $id): MessageTemplate { + $messageTemplate = $this->messageTemplateMapper->find($id); + if ($userId !== $messageTemplate->getUserId()) { + throw new ClientException('Message template does not belong to this user'); + } + + try { + return $this->messageTemplateMapper->deleteTemplate($id); + } catch (DoesNotExistException $e) { + throw new ClientException('Message template does not exist'); + } + } + + private function validateFields(string $title, string $body): void { + if (trim($title) === '') { + throw new ClientException('Template title can not be empty'); + } + + if (trim($body) === '') { + throw new ClientException('Template body can not be empty'); + } + } +}