diff --git a/lib/Controller/Errors.php b/lib/Controller/Errors.php index 7fcb2d6..2a62076 100644 --- a/lib/Controller/Errors.php +++ b/lib/Controller/Errors.php @@ -3,6 +3,7 @@ namespace OCA\UPschooling\Controller; use Closure; +use OCA\UPschooling\Exceptions\RoomNotFoundException; use OCA\UPschooling\Exceptions\TicketNotFoundException; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; @@ -11,9 +12,9 @@ trait Errors { protected function handleNotFound(Closure $callback): DataResponse { try { return new DataResponse($callback()); - } catch (TicketNotFoundException $e) { - $message = ['message' => $e->getMessage()]; - return new DataResponse($message, Http::STATUS_NOT_FOUND); + } catch (TicketNotFoundException|RoomNotFoundException $e) { + $result = $e->getResult(); + return new DataResponse($result->getMeta(), $result->getStatusCode()); } } } diff --git a/lib/Controller/TicketApiController.php b/lib/Controller/TicketApiController.php index 1cf7bc5..127c5da 100644 --- a/lib/Controller/TicketApiController.php +++ b/lib/Controller/TicketApiController.php @@ -4,13 +4,14 @@ namespace OCA\UPschooling\Controller; use OCA\UPschooling\AppInfo\Application; use OCA\UPschooling\Db\TicketMapper; +use OCA\UPschooling\Exceptions\RoomNotFoundException; +use OCA\UPschooling\Service\ChatService; use OCA\UPschooling\Service\MatrixService; use OCA\UPschooling\Service\TicketService; use OCP\AppFramework\ApiController; use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; use Psr\Log\LoggerInterface; -use Punic\Data; class TicketApiController extends ApiController { @@ -24,6 +25,9 @@ class TicketApiController extends ApiController /** @var MatrixService */ private $matrixService; + /** @var ChatService */ + private $chatService; + /** @var TicketMapper */ private $ticketMapper; @@ -38,6 +42,7 @@ class TicketApiController extends ApiController TicketService $ticketService, TicketMapper $ticketMapper, MatrixService $matrixService, + ChatService $chatService, string $userId ) { parent::__construct(Application::APP_ID, $request); @@ -45,6 +50,7 @@ class TicketApiController extends ApiController $this->ticketService = $ticketService; $this->ticketMapper = $ticketMapper; $this->matrixService = $matrixService; + $this->chatService = $chatService; $this->userId = $userId; } @@ -74,9 +80,12 @@ class TicketApiController extends ApiController return $this->handleNotFound(function () use ($id) { $matrixUser = $this->ticketService->getOrCreateUser($this->userId); $ticket = $this->ticketMapper->findForUser($id, $matrixUser); - $this->logger->debug("fetchChat found matrix data for room " . $ticket->getMatrixRoom()); + $this->logger->debug("fetchChat found matrix data for ticket " . print_r($ticket->jsonSerialize(), true)); + // returns 404 RoomNotFoundException if no room could/should be created + $chatRoom = $this->chatService->getOrCreateChatRoom($ticket); + $this->logger->debug("fetchChat got chat room " . print_r($chatRoom->jsonSerialize(), true)); return array( - 'matrixRoom' => $ticket->getMatrixRoom(), // FIXME: wrong room, create one for helper and user + 'matrixChatRoom' => $chatRoom->getMatrixRoomId(), 'matrixAccessToken' => $matrixUser->getMatrixToken(), 'matrixServerUrl' => $this->matrixService->getServerUrl(), ); diff --git a/lib/Db/ChatMapper.php b/lib/Db/ChatMapper.php new file mode 100644 index 0000000..99425e6 --- /dev/null +++ b/lib/Db/ChatMapper.php @@ -0,0 +1,63 @@ +db->getQueryBuilder(); + $qb->select('*') + ->from('upschooling_chats') + ->where($qb->expr()->eq('ticket_id', $qb->createNamedParameter($ticketId, IQueryBuilder::PARAM_INT))); + return $this->findEntities($qb); + } + + /** + * @param int $ticketId + * @return Entity|MatrixChat + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws DoesNotExistException + */ + public function findCurrent(int $ticketId): MatrixChat + { + /* @var $qb IQueryBuilder */ + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from('upschooling_chats') + ->where( + $qb->expr()->eq('ticket_id', $qb->createNamedParameter($ticketId, IQueryBuilder::PARAM_INT)), + $qb->expr()->isNull('end_date') + ); + return $this->findEntity($qb); + } + + /** + * @param \DateTime $dateTime + * @return mixed The database representation of the datetime with timezone. + * @throws \Doctrine\DBAL\Exception + * @throws \Doctrine\DBAL\Types\ConversionException + */ + public function convertDateTimeTz(\DateTime $dateTime) + { + $dateTimeTzType = Type::getType("datetimetz"); + return $dateTimeTzType->convertToDatabaseValue($dateTime, $this->db->getDatabasePlatform()); + } +} diff --git a/lib/Db/MatrixChat.php b/lib/Db/MatrixChat.php new file mode 100644 index 0000000..af0248c --- /dev/null +++ b/lib/Db/MatrixChat.php @@ -0,0 +1,29 @@ + $this->id, + 'ticketId' => $this->ticketId, + 'matrixRoomId' => $this->matrixRoomId, + 'matrixHelperUser' => $this->matrixHelperUser, + 'dateStart' => $this->dateStart, + 'dateEnd' => $this->dateEnd, + 'version' => $this->version, + ]; + } +} diff --git a/lib/Migration/Version000000Date20210918151800.php b/lib/Migration/Version000000Date20210918151800.php index fe154af..12db8be 100644 --- a/lib/Migration/Version000000Date20210918151800.php +++ b/lib/Migration/Version000000Date20210918151800.php @@ -55,30 +55,61 @@ class Version000000Date20210918151800 extends SimpleMigrationStep { $table->addIndex(['matrix_control_room'], 'upschooling_mx_room_id_idx'); } - if (!$schema->hasTable('upschooling_users')) { - $table = $schema->createTable('upschooling_users'); - $table->addColumn('id', 'integer', [ - 'autoincrement' => true, - 'notnull' => true, - ]); - $table->addColumn('user_id', 'string', [ - 'notnull' => true, - 'length' => 64, - ]); - $table->addColumn('matrix_user', 'string', [ - 'notnull' => true, - 'length' => 200, - ]); - $table->addColumn('matrix_token', 'string', [ - 'notnull' => true, - 'length' => 200, - ]); + if (!$schema->hasTable('upschooling_users')) { + $table = $schema->createTable('upschooling_users'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + ]); + $table->addColumn('user_id', 'string', [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('matrix_user', 'string', [ + 'notnull' => true, + 'length' => 200, + ]); + $table->addColumn('matrix_token', 'string', [ + 'notnull' => true, + 'length' => 200, + ]); - $table->setPrimaryKey(['id']); - $table->addUniqueConstraint(['user_id'], 'upschooling_mx_user_nc_uniq'); - $table->addUniqueConstraint(['matrix_user'], 'upschooling_mx_user_mx_uniq'); - $table->addForeignKeyConstraint('users', ['user_id'], ['uid'], [], 'upschooling_mx_user_nc_fk'); - } + $table->setPrimaryKey(['id']); + $table->addUniqueConstraint(['user_id'], 'upschooling_mx_user_nc_uniq'); + $table->addUniqueConstraint(['matrix_user'], 'upschooling_mx_user_mx_uniq'); + $table->addForeignKeyConstraint('users', ['user_id'], ['uid'], [], 'upschooling_mx_user_nc_fk'); + } + + if (!$schema->hasTable('upschooling_chats')) { + $table = $schema->createTable('upschooling_chats'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + ]); + $table->addColumn('ticket_id', 'integer', [ + 'notnull' => true, + ]); + $table->addColumn('matrix_room_id', 'string', [ + 'notnull' => true, + 'length' => 200, + ]); + $table->addColumn('matrix_helper_user', 'string', [ + 'notnull' => true, + 'length' => 200, + ]); + $table->addColumn('date_start', 'datetimetz', [ + 'notnull' => true, + ]); + $table->addColumn('date_end', 'datetimetz', [ + 'notnull' => false, + ]); + $table->addColumn('version', 'integer', [ + 'notnull' => true, + ]); + + $table->setPrimaryKey(['id']); + $table->addForeignKeyConstraint('upschooling_tickets', ['ticket_id'], ['id'], [], 'upschooling_tckt_id_fk'); + } return $schema; } } diff --git a/lib/Service/ChatService.php b/lib/Service/ChatService.php new file mode 100644 index 0000000..b8ae747 --- /dev/null +++ b/lib/Service/ChatService.php @@ -0,0 +1,62 @@ +chatMapper = $chatMapper; + $this->matrixService = $matrixService; + $this->logger = $logger; + } + + /** + * @param $ticket MatrixTicket Support ticket + * @throws RoomNotFoundException + */ + public function getOrCreateChatRoom(MatrixTicket $ticket): MatrixChat + { + try { + return $this->chatMapper->findCurrent($ticket->getId()); + } catch (DoesNotExistException $e) { + if ($ticket->getMatrixHelperUser() == null) { + $this->logger->debug("No helper assigned to ticket " . $ticket->getId() . ". Not creating chat room"); + throw new RoomNotFoundException(); + } + $this->logger->debug("Chat room for ticket " . $ticket->getId() . " does not exist. Creating room.."); + $roomId = $this->matrixService->createRoom(); + $startDate = new \DateTime('now', new \DateTimeZone("utc")); + $matrixChat = new MatrixChat(); + $matrixChat->setTicketId($ticket->getId()); + $matrixChat->setMatrixRoomId($roomId); + $matrixChat->setMatrixHelperUser($ticket->getMatrixHelperUser()); + $matrixChat->setDateStart($this->chatMapper->convertDateTimeTz($startDate)); + $matrixChat->setVersion(1); + + $this->matrixService->inviteUser($roomId, $ticket->getMatrixHelperUser()); + $this->matrixService->inviteUser($roomId, $ticket->getMatrixAssistedUser()); + + return $this->chatMapper->insert($matrixChat); + } + } +} diff --git a/lib/Service/MatrixService.php b/lib/Service/MatrixService.php index 02dba1c..28a0552 100644 --- a/lib/Service/MatrixService.php +++ b/lib/Service/MatrixService.php @@ -255,4 +255,10 @@ class MatrixService $this->logger->debug("No ratelimiting for " . $this->superuser); } } + + public function inviteUser(string $roomId, string $matrixUserId) + { + $room = $this->client->joinRoom($roomId); + $room->inviteUser($matrixUserId); + } } diff --git a/lib/Service/TicketService.php b/lib/Service/TicketService.php index c7a0ff7..b96fada 100644 --- a/lib/Service/TicketService.php +++ b/lib/Service/TicketService.php @@ -15,6 +15,7 @@ use OCA\UPschooling\Exceptions\TicketNotFoundException; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\IUserManager; +use Psr\Log\LoggerInterface; class TicketService { @@ -30,16 +31,21 @@ class TicketService { /** @var UserMapper */ private $userMapper; + /** @var LoggerInterface */ + private $logger; + public function __construct( IUserManager $userManager, MatrixService $matrix, TicketMapper $ticketMapper, - UserMapper $userMapper + UserMapper $userMapper, + LoggerInterface $logger ) { $this->userManager = $userManager; $this->matrix = $matrix; $this->ticketMapper = $ticketMapper; $this->userMapper = $userMapper; + $this->logger = $logger; } public function findAll(string $userId): array { @@ -83,6 +89,7 @@ class TicketService { } public function assign($id, $userId): array{ + $this->logger->debug("Assigning $userId to ticket $id.."); $matrixUser = $this->getOrCreateUser($userId); $ticket = $this->ticketMapper->findTicket($id); $roomID = $ticket->getMatrixControlRoom(); diff --git a/src/Ticket.vue b/src/Ticket.vue index c779a85..572b7f2 100644 --- a/src/Ticket.vue +++ b/src/Ticket.vue @@ -27,6 +27,7 @@