Start implementing matrix chat integration
Implement auto-login for element-web
This commit is contained in:
parent
33ca2c93db
commit
940c7bed6e
|
@ -12,5 +12,10 @@ return [
|
||||||
'verb' => 'OPTIONS',
|
'verb' => 'OPTIONS',
|
||||||
'requirements' => ['path' => '.+'],
|
'requirements' => ['path' => '.+'],
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'name' => 'ticket_api#fetch_chat',
|
||||||
|
'url' => '/api/v1/tickets/{id}/chat',
|
||||||
|
'verb' => 'GET',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
40
extra/element-config.json
Normal file
40
extra/element-config.json
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"default_server_config": {
|
||||||
|
"m.homeserver": {
|
||||||
|
"base_url": "http://localhost:8008",
|
||||||
|
"server_name": "synapse"
|
||||||
|
},
|
||||||
|
"m.identity_server": {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disable_custom_urls": false,
|
||||||
|
"disable_guests": true,
|
||||||
|
"disable_login_language_selector": false,
|
||||||
|
"disable_3pid_login": false,
|
||||||
|
"brand": "Element",
|
||||||
|
"integrations_ui_url": "",
|
||||||
|
"integrations_rest_url": "",
|
||||||
|
"integrations_widgets_urls": [],
|
||||||
|
"bug_report_endpoint_url": "https://element.io/bugreports/submit",
|
||||||
|
"uisi_autorageshake_app": "element-auto-uisi",
|
||||||
|
"defaultCountryCode": "DE",
|
||||||
|
"showLabsSettings": false,
|
||||||
|
"features": { },
|
||||||
|
"default_federate": true,
|
||||||
|
"default_theme": "light",
|
||||||
|
"roomDirectory": {
|
||||||
|
"servers": [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"piwik": {
|
||||||
|
},
|
||||||
|
"enable_presence_by_hs_url": {
|
||||||
|
},
|
||||||
|
"settingDefaults": {
|
||||||
|
"breadcrumbs": true
|
||||||
|
},
|
||||||
|
"jitsi": {
|
||||||
|
"preferredDomain": "meet.element.io"
|
||||||
|
},
|
||||||
|
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
|
||||||
|
}
|
|
@ -3,25 +3,48 @@
|
||||||
namespace OCA\UPschooling\Controller;
|
namespace OCA\UPschooling\Controller;
|
||||||
|
|
||||||
use OCA\UPschooling\AppInfo\Application;
|
use OCA\UPschooling\AppInfo\Application;
|
||||||
|
use OCA\UPschooling\Db\TicketMapper;
|
||||||
|
use OCA\UPschooling\Service\MatrixService;
|
||||||
use OCA\UPschooling\Service\TicketService;
|
use OCA\UPschooling\Service\TicketService;
|
||||||
use OCP\AppFramework\ApiController;
|
use OCP\AppFramework\ApiController;
|
||||||
use OCP\AppFramework\Http\DataResponse;
|
use OCP\AppFramework\Http\DataResponse;
|
||||||
use OCP\IRequest;
|
use OCP\IRequest;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Punic\Data;
|
||||||
|
|
||||||
class TicketApiController extends ApiController
|
class TicketApiController extends ApiController
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/** @var LoggerInterface */
|
||||||
|
private $logger;
|
||||||
|
|
||||||
/** @var TicketService */
|
/** @var TicketService */
|
||||||
private $service;
|
private $ticketService;
|
||||||
|
|
||||||
|
/** @var MatrixService */
|
||||||
|
private $matrixService;
|
||||||
|
|
||||||
|
/** @var TicketMapper */
|
||||||
|
private $ticketMapper;
|
||||||
|
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $userId;
|
private $userId;
|
||||||
|
|
||||||
use Errors;
|
use Errors;
|
||||||
|
|
||||||
public function __construct(IRequest $request, TicketService $service, $userId)
|
public function __construct(
|
||||||
{
|
IRequest $request,
|
||||||
|
LoggerInterface $logger,
|
||||||
|
TicketService $ticketService,
|
||||||
|
TicketMapper $ticketMapper,
|
||||||
|
MatrixService $matrixService,
|
||||||
|
string $userId
|
||||||
|
) {
|
||||||
parent::__construct(Application::APP_ID, $request);
|
parent::__construct(Application::APP_ID, $request);
|
||||||
$this->service = $service;
|
$this->logger = $logger;
|
||||||
|
$this->ticketService = $ticketService;
|
||||||
|
$this->ticketMapper = $ticketMapper;
|
||||||
|
$this->matrixService = $matrixService;
|
||||||
$this->userId = $userId;
|
$this->userId = $userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +53,7 @@ class TicketApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function index(): DataResponse
|
public function index(): DataResponse
|
||||||
{
|
{
|
||||||
return new DataResponse($this->service->findAll($this->userId));
|
return new DataResponse($this->ticketService->findAll($this->userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,7 +62,24 @@ class TicketApiController extends ApiController
|
||||||
public function show(int $id): DataResponse
|
public function show(int $id): DataResponse
|
||||||
{
|
{
|
||||||
return $this->handleNotFound(function () use ($id) {
|
return $this->handleNotFound(function () use ($id) {
|
||||||
return $this->service->find($id, $this->userId);
|
return $this->ticketService->find($id, $this->userId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @NoAdminRequired
|
||||||
|
*/
|
||||||
|
public function fetchChat(int $id): DataResponse
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
return array(
|
||||||
|
'matrixRoom' => $ticket->getMatrixRoom(), // FIXME: wrong room, create one for helper and user
|
||||||
|
'matrixAccessToken' => $matrixUser->getMatrixToken(),
|
||||||
|
'matrixServerUrl' => $this->matrixService->getServerUrl(),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +88,7 @@ class TicketApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function create(string $title, string $content): DataResponse
|
public function create(string $title, string $content): DataResponse
|
||||||
{
|
{
|
||||||
return new DataResponse($this->service->create($title, $content, $this->userId));
|
return new DataResponse($this->ticketService->create($title, $content, $this->userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,13 +96,13 @@ class TicketApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function update(int $id): DataResponse
|
public function update(int $id): DataResponse
|
||||||
{
|
{
|
||||||
return new DataResponse($this->service->assign($id, $this->userId));
|
return new DataResponse($this->ticketService->assign($id, $this->userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function destroy(int $id): DataResponse
|
public function destroy(int $id): DataResponse
|
||||||
{
|
{
|
||||||
return $this->handleNotFound(function () use ($id) {
|
return $this->handleNotFound(function () use ($id) {
|
||||||
return $this->service->delete($id, $this->userId);
|
return $this->ticketService->delete($id, $this->userId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,8 @@ class MatrixUser extends Entity implements JsonSerializable {
|
||||||
protected $matrixUser;
|
protected $matrixUser;
|
||||||
protected $matrixToken;
|
protected $matrixToken;
|
||||||
|
|
||||||
public function jsonSerialize(): array {
|
public function jsonSerialize(): array
|
||||||
|
{
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
'userId' => $this->userId,
|
'userId' => $this->userId,
|
||||||
|
|
|
@ -56,7 +56,7 @@ class MatrixService
|
||||||
);
|
);
|
||||||
$this->serverUrl = $this->config->getSystemValueString(
|
$this->serverUrl = $this->config->getSystemValueString(
|
||||||
"upschooling.matrix_server_url",
|
"upschooling.matrix_server_url",
|
||||||
"http://synapse:8008"
|
"http://localhost:8008"
|
||||||
);
|
);
|
||||||
$this->server = $this->config->getSystemValueString(
|
$this->server = $this->config->getSystemValueString(
|
||||||
"upschooling.matrix_server",
|
"upschooling.matrix_server",
|
||||||
|
@ -216,6 +216,14 @@ class MatrixService
|
||||||
return $roomId;
|
return $roomId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string the public matrix server url.
|
||||||
|
*/
|
||||||
|
public function getServerUrl(): string
|
||||||
|
{
|
||||||
|
return $this->serverUrl;
|
||||||
|
}
|
||||||
|
|
||||||
private function checkRateLimit()
|
private function checkRateLimit()
|
||||||
{
|
{
|
||||||
$fullSuperuserId = "@" . $this->superuser . ":" . $this->server;
|
$fullSuperuserId = "@" . $this->superuser . ":" . $this->server;
|
||||||
|
|
|
@ -104,7 +104,7 @@ class TicketService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* matrixTicketContent has all the syncronized data
|
* matrixTicketContent has all the synchronized data
|
||||||
* @param MatrixTicket $ticket the database object.
|
* @param MatrixTicket $ticket the database object.
|
||||||
* @return array a JSON serializable representation of the resolved ticket, for the frontend.
|
* @return array a JSON serializable representation of the resolved ticket, for the frontend.
|
||||||
*/
|
*/
|
||||||
|
@ -144,7 +144,7 @@ class TicketService {
|
||||||
* @throws MultipleObjectsReturnedException
|
* @throws MultipleObjectsReturnedException
|
||||||
* @throws \OCP\DB\Exception
|
* @throws \OCP\DB\Exception
|
||||||
*/
|
*/
|
||||||
private function getOrCreateUser(string $userId): MatrixUser
|
public function getOrCreateUser(string $userId): MatrixUser
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return $this->userMapper->find($userId);
|
return $this->userMapper->find($userId);
|
||||||
|
|
1
run.sh
1
run.sh
|
@ -139,6 +139,7 @@ $CONTAINER_RUNTIME run -d \
|
||||||
--name=elementweb \
|
--name=elementweb \
|
||||||
"--network=container:$($CONTAINER_RUNTIME inspect --format "{{.Id}}" nextcloud)" \
|
"--network=container:$($CONTAINER_RUNTIME inspect --format "{{.Id}}" nextcloud)" \
|
||||||
-v "$DIR/extra/element-web-nginx.conf:/etc/nginx/conf.d/default.conf" \
|
-v "$DIR/extra/element-web-nginx.conf:/etc/nginx/conf.d/default.conf" \
|
||||||
|
-v "$DIR/extra/element-config.json:/app/config.json" \
|
||||||
--hostname elementweb \
|
--hostname elementweb \
|
||||||
docker.io/vectorim/element-web
|
docker.io/vectorim/element-web
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ export default {
|
||||||
}).catch(console.error)
|
}).catch(console.error)
|
||||||
axios.get(
|
axios.get(
|
||||||
'api/v1/tickets/1',
|
'api/v1/tickets/1',
|
||||||
{ headers: { 'Content-Type': 'application/json', Accept: 'application/json' } },
|
{ headers: { Accept: 'application/json' } },
|
||||||
).catch(console.error)
|
).catch(console.error)
|
||||||
axios.put(
|
axios.put(
|
||||||
'api/v1/tickets/1',
|
'api/v1/tickets/1',
|
||||||
|
|
|
@ -18,12 +18,18 @@
|
||||||
{{ t('upschooling', 'Speichern') }}
|
{{ t('upschooling', 'Speichern') }}
|
||||||
</button>
|
</button>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="placeholder" />
|
<iframe id="element-web-frame"
|
||||||
|
src="about:blank"
|
||||||
|
title="Embedded Element Web"
|
||||||
|
width="100%"
|
||||||
|
height="400" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import KeyValueTable from './components/KeyValueTable'
|
import KeyValueTable from './components/KeyValueTable'
|
||||||
|
import axios from '@nextcloud/axios'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Ticket',
|
name: 'Ticket',
|
||||||
components: { KeyValueTable },
|
components: { KeyValueTable },
|
||||||
|
@ -40,6 +46,20 @@ export default {
|
||||||
description: this.ticket.description,
|
description: this.ticket.description,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
/** @type {HTMLIFrameElement} */
|
||||||
|
const elementWebFrame = document.getElementById('element-web-frame')
|
||||||
|
this.loadChat(elementWebFrame).catch((err) => {
|
||||||
|
console.error('Could not load Element Web in iframe', err)
|
||||||
|
elementWebFrame.src = 'about:blank'
|
||||||
|
elementWebFrame.onload = function() {
|
||||||
|
const textElement = elementWebFrame.contentDocument.createElement('strong')
|
||||||
|
textElement.innerText = 'Element Web konnte nicht geladen werden.'
|
||||||
|
elementWebFrame.contentDocument.body.appendChild(textElement)
|
||||||
|
elementWebFrame.onload = undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toLocaleDate(timestamp) {
|
toLocaleDate(timestamp) {
|
||||||
const date = new Date(timestamp)
|
const date = new Date(timestamp)
|
||||||
|
@ -53,6 +73,58 @@ export default {
|
||||||
back() {
|
back() {
|
||||||
this.$emit('show-ticket-list')
|
this.$emit('show-ticket-list')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async loadChat(elementWebFrame) {
|
||||||
|
const matrixInfoResponse = await axios.get(
|
||||||
|
`api/v1/tickets/${this.ticket.ticketId}/chat`,
|
||||||
|
{ headers: { Accept: 'application/json' } },
|
||||||
|
)
|
||||||
|
if (matrixInfoResponse.status !== 200) {
|
||||||
|
throw Error(`Received unexpected status code ${matrixInfoResponse.status} for fetching matrix chat data`)
|
||||||
|
}
|
||||||
|
if (!matrixInfoResponse.data) {
|
||||||
|
throw Error('Did not receive any matrix chat data')
|
||||||
|
}
|
||||||
|
if (typeof matrixInfoResponse.data !== 'object') {
|
||||||
|
throw Error('Unexpected return value for fetching matrix chat data')
|
||||||
|
}
|
||||||
|
|
||||||
|
const loginPromise = new Promise(function(resolve, reject) {
|
||||||
|
const tryLogin = (elementWebFrame, matrixInfo, round) => {
|
||||||
|
if (elementWebFrame.contentWindow.mxLoginWithAccessToken === undefined) {
|
||||||
|
console.warn('Couldn\'t login in round ' + round)
|
||||||
|
setTimeout(() => {
|
||||||
|
tryLogin(elementWebFrame, matrixInfo, round + 1)
|
||||||
|
}, 1000)
|
||||||
|
} else {
|
||||||
|
elementWebFrame.contentWindow.mxLoginWithAccessToken(
|
||||||
|
matrixInfo.matrixServerUrl,
|
||||||
|
matrixInfo.matrixAccessToken,
|
||||||
|
).then(resolve).catch(reject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elementWebFrame.onload = function() {
|
||||||
|
elementWebFrame.onload = undefined
|
||||||
|
tryLogin(elementWebFrame, matrixInfoResponse.data, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// load Element Web
|
||||||
|
elementWebFrame.src = '/upschooling/element-web/'
|
||||||
|
|
||||||
|
loginPromise.then(() => {
|
||||||
|
console.warn('LOGGED IN')
|
||||||
|
elementWebFrame.contentWindow.mxDispatcher.dispatch({
|
||||||
|
action: 'view_home_page',
|
||||||
|
justRegistered: false,
|
||||||
|
})
|
||||||
|
elementWebFrame.contentWindow.mxDispatcher.dispatch({
|
||||||
|
action: 'view_room',
|
||||||
|
room_id: matrixInfoResponse.data.matrixRoom,
|
||||||
|
})
|
||||||
|
}).catch(console.error)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in a new issue