Compare commits
21 Commits
appservice
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 3427f6aa7f | |||
| 78296db650 | |||
| 4a1279948f | |||
| 886579a0b3 | |||
| 7c8276b2c7 | |||
| 48d65cc8ba | |||
| 1bc49eacc2 | |||
| 10402f4de0 | |||
| a1be51859c | |||
| 484fd78516 | |||
| 4cc642735f | |||
| d32eaa9b9a | |||
| bff282d0eb | |||
| dab3b59ef0 | |||
| 9c7f30f477 | |||
| d223041cf0 | |||
| e7546c41e6 | |||
| 6742ffb959 | |||
| 2549d91720 | |||
| e245bd8f82 | |||
| 30195d7587 |
@@ -1,5 +1,12 @@
|
||||
# Okupa mi coche - Backend
|
||||
Gestión de viajes en el valle.
|
||||
Travel management in the valley.
|
||||
|
||||
THIS PROJECT IS IN EARLY DEVELOPMENT - WORK IN PROGRESS (including this README)
|
||||
|
||||
## Prerequisites
|
||||
Install and run keycloak and synapse.
|
||||
|
||||
`docker/README` explains how to get a working local development environment.
|
||||
|
||||
## How to run
|
||||
1. `git clone git@git.fosil.eu:eneko/okupamicoche.git`
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
id("org.springframework.boot") version "2.4.1"
|
||||
id("io.spring.dependency-management") version "1.0.10.RELEASE"
|
||||
id("org.springframework.boot") version "2.6.1"
|
||||
id("io.spring.dependency-management") version "1.0.11.RELEASE"
|
||||
war
|
||||
kotlin("jvm") version "1.4.21"
|
||||
kotlin("plugin.spring") version "1.4.21"
|
||||
kotlin("plugin.jpa") version "1.4.21"
|
||||
kotlin("jvm") version "1.6.10"
|
||||
kotlin("plugin.spring") version "1.6.10"
|
||||
kotlin("plugin.jpa") version "1.6.10"
|
||||
}
|
||||
|
||||
group = "eu.fosil"
|
||||
@@ -20,18 +20,20 @@ repositories {
|
||||
dependencies {
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
implementation("io.github.microutils:kotlin-logging-jvm:2.0.6")
|
||||
// https://mvnrepository.com/artifact/net.folivo/matrix-spring-boot-bot
|
||||
implementation ("net.folivo:matrix-spring-boot-bot:0.4.6")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
|
||||
implementation("io.github.microutils:kotlin-logging-jvm:2.1.21")
|
||||
implementation ("net.folivo:matrix-spring-boot-bot:0.5.2")
|
||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||
runtimeOnly("com.h2database:h2")
|
||||
runtimeOnly("io.r2dbc:r2dbc-h2")
|
||||
providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
testImplementation("io.projectreactor:reactor-test")
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile> {
|
||||
|
||||
@@ -1,22 +1,69 @@
|
||||
# Okupa mi coche - Backend
|
||||
Gestión de viajes en el valle.
|
||||
# Okupa mi coche - Docker containers for the backend
|
||||
Guide for seting up a local development environment for the backend.
|
||||
|
||||
## Setup
|
||||
### Keycloak
|
||||
`docker run --name keycloak -p 8080:8080 -p 8443:8443 --mount type=volume,src=https,dst=/etc/x509/https -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin --network=okupamicoche quay.io/keycloak/keycloak:12.0.4`
|
||||
|
||||
### Matrix
|
||||
https://github.com/matrix-org/synapse/tree/master/docker
|
||||
|
||||
Add synapse in /etc/hosts as localhost alias.
|
||||
|
||||
`docker run -it --rm --mount type=volume,src=synapse-data,dst=/data -e SYNAPSE_SERVER_NAME=synapse -e SYNAPSE_REPORT_STATS=no matrixdotorg/synapse:latest generate`
|
||||
|
||||
`docker run --name synapse --mount type=volume,src=synapse-data,dst=/data -p 8008:8008 --network=okupamicoche matrixdotorg/synapse:latest`
|
||||
1. Install Docker in local machine
|
||||
2. Add following line to /etc/hosts
|
||||
```
|
||||
127.0.0.1 okupamicoche-keycloak okupamicoche-synapse
|
||||
```
|
||||
3. Create docker network okupamicoche
|
||||
```
|
||||
docker network create okupamicoche
|
||||
```
|
||||
3. Run dockerized Keycloak
|
||||
```
|
||||
cd docker/keycloak
|
||||
docker run --name okupamicoche-keycloak -p 8443:8443 -v $(pwd)/https:/etc/x509/https \
|
||||
-e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin --network=okupamicoche \
|
||||
-e KEYCLOAK_IMPORT=/tmp/realm.json -v $(pwd)/okupamicoche-realm-export.json:/tmp/realm.json quay.io/keycloak/keycloak:16.1.0
|
||||
```
|
||||
4. Build Synapse container
|
||||
```
|
||||
cd docker/synape
|
||||
docker build -t okupamicoche-synapse .
|
||||
```
|
||||
5. Generate data folder for Synapse
|
||||
```
|
||||
docker run -it --rm \
|
||||
--mount type=volume,src=synapse-data,dst=/data \
|
||||
-e SYNAPSE_SERVER_NAME=okupamicoche-synapse \
|
||||
-e SYNAPSE_REPORT_STATS=no \
|
||||
okupamicoche-synapse generate
|
||||
```
|
||||
6. Run dockerized Synapse
|
||||
```
|
||||
docker run --name okupamicoche-synapse -p 8008:8008 --mount type=volume,src=synapse-data,dst=/data \
|
||||
-e SYNAPSE_CONFIG_PATH=/homeserver.yaml \
|
||||
-v $(pwd)/homeserver.yaml:/homeserver.yaml -v $(pwd)/okupamicoche-appservice.yaml:/okupamicoche-appservice.yaml \
|
||||
--network=okupamicoche okupamicoche-synapse
|
||||
```
|
||||
7. (Optional) Add keycloak certificate to local machine
|
||||
Some clients (Quaternion, Nheko) fail with self-signed certificates. You can install the root certificate
|
||||
(docker/synape/keycloak-root.crt) in you local machine. For example, in Linux:
|
||||
```
|
||||
sudo cp docker/synapse/keycloak-root.crt /usr/local/share/ca-certificates/
|
||||
sudo update-ca-certificates
|
||||
```
|
||||
|
||||
## Run
|
||||
`docker restart keycloak`
|
||||
`docker restart synapse`
|
||||
`docker start okupamicoche-keycloak`
|
||||
`docker start okupamicoche-synapse`
|
||||
|
||||
## Inspect containter
|
||||
`docker exec -t -i synapse /bin/bash`
|
||||
`docker exec -t -i okupamicoche-synapse /bin/bash`
|
||||
|
||||
## Manage Keycloak
|
||||
Go to https://localhost:8443/auth/admin and login with user=admin pass=admin
|
||||
|
||||
# Renew/create SSL certificates for development
|
||||
1. Install mkcert from https://github.com/FiloSottile/mkcert
|
||||
2. Create and install CA root certificate
|
||||
|
||||
`mkcert -install`
|
||||
3. Create certificate for Keycloak
|
||||
|
||||
`mkcert okupamicoche-keycloak localhost 127.0.0.1 ::1`
|
||||
4. Copy okupamicoche-keycloak+3.pem to docker/keycloak/https/tls.crt
|
||||
5. Copy okupamicoche-keycloak+3-key.pem to docker/keycloak/https/tls.key
|
||||
6. Copy /usr/local/share/ca-certificates/mkcert_development_CA_*.crt to docker/synapse/keycloak-root.crt
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
keycloak:
|
||||
image: quay.io/keycloak/keycloak:12.0.4
|
||||
container_name: keycloak
|
||||
environment:
|
||||
KEYCLOAK_USER: admin
|
||||
KEYCLOAK_PASSWORD: admin
|
||||
ports:
|
||||
- "8080:8080"
|
||||
networks:
|
||||
- okupamicoche
|
||||
synapse:
|
||||
image: matrixdotorg/synapse:latest
|
||||
container_name: synapse
|
||||
ports:
|
||||
- "8008:8008"
|
||||
volumes:
|
||||
- ./synapse-data:/data
|
||||
networks:
|
||||
- okupamicoche
|
||||
depends_on:
|
||||
- keycloak
|
||||
|
||||
volumes:
|
||||
synapse-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
okupamicoche:
|
||||
external: true
|
||||
@@ -1,21 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDazCCAlOgAwIBAgIURQQZKTG7wENaPp3bnAVLUMhkBJEwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTAzMTQxNzE0MTZaFw0yMjAz
|
||||
MTQxNzE0MTZaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQD4RoutMqZ9zzuowIZ02N5DneNdTUPp8KTP3ewCTp5B
|
||||
pQB2ht06pEgb7AY0xjlxfwt+lEXc4aeN/B741frLDe6buts8IsedfL0Ub2KHfoqo
|
||||
o3qAimn9+fgoHwZYsls3OJK+fKbPNefp+m65SkZHz4ufQhg2TSLsW0BWATnxnbd8
|
||||
OQIXrCxtV/UKE2iaXfrlmaVSCqFeL4z7Rr+PJ8LiwOFMDLleLMsPiIo8CtR7u/lg
|
||||
65zWI34rhdjwMq9tYXmZtq5sSpS83L/3InQDOvyhNt8vdNS8qL+v7tNhpHldBYqt
|
||||
WJaC/QPeRGXQfa89qYZssZ+k32/i7del2raF8RxkcyVtAgMBAAGjUzBRMB0GA1Ud
|
||||
DgQWBBREbPhToZrilLuC26iiFNj8t+K0hDAfBgNVHSMEGDAWgBREbPhToZrilLuC
|
||||
26iiFNj8t+K0hDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAF
|
||||
NtdTjLsVLhfS0q5tVKQFZ6Ek1CcuyUVeAvTxWDinZVfXzuNFdF1DeDlMwP3gKufz
|
||||
RIAI//k3ISFMwXN0TzgETC86ck4edxpB08E5RKpBZhOrm7PZtoQ5h4hPpOgSG1pp
|
||||
gPvzIzCEtC8Uaf0zpr+2AAm/2+DLgTDzdnO/cxN3UloydW9BslFM1PTeZ7TphT8X
|
||||
3PgDzDBa/IACdTwIhh6RH03l7BhzvKbp5uXnwRSWrf/q1R3mErrsjq9Awx6GECWu
|
||||
Y6YLsHjm05ELHs8r7STQC5Wq+vtfut/iDUNgnNFHmpiaedC1Md3qdnIIMeYrjBjo
|
||||
ru7ot2RLcptsr9w7qd7C
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,27 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA+EaLrTKmfc87qMCGdNjeQ53jXU1D6fCkz93sAk6eQaUAdobd
|
||||
OqRIG+wGNMY5cX8LfpRF3OGnjfwe+NX6yw3um7rbPCLHnXy9FG9ih36KqKN6gIpp
|
||||
/fn4KB8GWLJbNziSvnymzzXn6fpuuUpGR8+Ln0IYNk0i7FtAVgE58Z23fDkCF6ws
|
||||
bVf1ChNoml365ZmlUgqhXi+M+0a/jyfC4sDhTAy5XizLD4iKPArUe7v5YOuc1iN+
|
||||
K4XY8DKvbWF5mbaubEqUvNy/9yJ0Azr8oTbfL3TUvKi/r+7TYaR5XQWKrViWgv0D
|
||||
3kRl0H2vPamGbLGfpN9v4u3Xpdq2hfEcZHMlbQIDAQABAoIBACTQoSmflxyUvC37
|
||||
znRJLDwuj2ZobKel7Wp9Z9+3tLPbOcRZnzhw39h0GT9+HUp9IkE0z18/fs8JEbao
|
||||
VDYD7Nvey1+RcLQjqQ38rkmVNA5pn2KsI6drh6a7Yv+IAwqfMvNYHIwhXDBP2FdV
|
||||
cjJ3ziZhcKGssn8F0PZv3B2921Vp++brFuVtDxvFdhRSSLtcwKI7L5SaOKsA8j2f
|
||||
8Yspq1eigkgCTYTFn1+wdjn3FxyndCV7IFs2BvgdHDBTcB/o6DipXVvK+Px1B3Cp
|
||||
g+ioAHiqn4EkxFkz/ceiscjpUZuITPS+e6aF5Qar7xO5VmeThhNlmsoCFW1nwaea
|
||||
wjwH6CkCgYEA/DxBU1N0o0ZObOnt1eb/LvrSRmxiNH8RKIbb8QL9gQ9Hx1GbP+5N
|
||||
JN5rayBNEg8UAtr0tvbil+ofoxpwlpSGFsFBG5NRcH1LIIHD1Sf0gkGc78ojdCT8
|
||||
O4PcWnCWjLtLIgZCVBxTupa1vsWmUMBzqTxdxn92ECLcPFvo21SRIYsCgYEA+/sp
|
||||
J2Do1lpUjkRDwWAIauHJ01ZHcA5epu2vXXZOnGw+OvPX8a493kwwJDjjrfOgDLTC
|
||||
1FDDBMzbCQUHUa1w3ZfsSOyheHr/8xlVUJ3gz98q+aizaJLJ8lZraL8lvsC9uogf
|
||||
x7P9iTp+SpIHQ1jXp+9WdFgeEgXVkK2GY1bzw+cCgYBiVOcuodFNuaHnSccDZZtD
|
||||
6FpDRAuA5ax9vR1PNtg3EQrthD3ezXrbja4YxC3nhWNKvas7DMJHcOlGf4821M31
|
||||
Xv+PzX2pOd8o3A3JMlta0FNrE8WAiM6gMQadZ1j5oiZnLEN9YNGvYwOVTJ5KyswM
|
||||
RNFWCeiv37c1/Kqpnq05gwKBgGys2QXzxNfV44vsIzC+Y0L9mFb+ahcJC4eBEVYE
|
||||
1UifYoN4cVT5qhM61rR4mLGIVinEuBZrsoBafck5EvwGCpx3jl+xNr7IhaTp8yKu
|
||||
xKvCez1rpdzfGhvba72kWvoXFHzjgplVpm5N/PPaYSmJopD6J1ZMPsPVIlOgk0o6
|
||||
0S1XAoGBALm8/9Gyer2jtfL/WZDILEeOV/rG13ELspTIx0pcbHkvZKFXrddu27E0
|
||||
e89SqTCIXhn3nFLvk4pdWjJbE2QA4uS99vV5HXIpvvEBgwzid5hyqxE3b7xuQwl6
|
||||
bAJld+V2lh5e1tQuaX/bF7B87k4ODlZFatCzhrOXBKMdRm4SkzSk
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -1,27 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA+EaLrTKmfc87qMCGdNjeQ53jXU1D6fCkz93sAk6eQaUAdobd
|
||||
OqRIG+wGNMY5cX8LfpRF3OGnjfwe+NX6yw3um7rbPCLHnXy9FG9ih36KqKN6gIpp
|
||||
/fn4KB8GWLJbNziSvnymzzXn6fpuuUpGR8+Ln0IYNk0i7FtAVgE58Z23fDkCF6ws
|
||||
bVf1ChNoml365ZmlUgqhXi+M+0a/jyfC4sDhTAy5XizLD4iKPArUe7v5YOuc1iN+
|
||||
K4XY8DKvbWF5mbaubEqUvNy/9yJ0Azr8oTbfL3TUvKi/r+7TYaR5XQWKrViWgv0D
|
||||
3kRl0H2vPamGbLGfpN9v4u3Xpdq2hfEcZHMlbQIDAQABAoIBACTQoSmflxyUvC37
|
||||
znRJLDwuj2ZobKel7Wp9Z9+3tLPbOcRZnzhw39h0GT9+HUp9IkE0z18/fs8JEbao
|
||||
VDYD7Nvey1+RcLQjqQ38rkmVNA5pn2KsI6drh6a7Yv+IAwqfMvNYHIwhXDBP2FdV
|
||||
cjJ3ziZhcKGssn8F0PZv3B2921Vp++brFuVtDxvFdhRSSLtcwKI7L5SaOKsA8j2f
|
||||
8Yspq1eigkgCTYTFn1+wdjn3FxyndCV7IFs2BvgdHDBTcB/o6DipXVvK+Px1B3Cp
|
||||
g+ioAHiqn4EkxFkz/ceiscjpUZuITPS+e6aF5Qar7xO5VmeThhNlmsoCFW1nwaea
|
||||
wjwH6CkCgYEA/DxBU1N0o0ZObOnt1eb/LvrSRmxiNH8RKIbb8QL9gQ9Hx1GbP+5N
|
||||
JN5rayBNEg8UAtr0tvbil+ofoxpwlpSGFsFBG5NRcH1LIIHD1Sf0gkGc78ojdCT8
|
||||
O4PcWnCWjLtLIgZCVBxTupa1vsWmUMBzqTxdxn92ECLcPFvo21SRIYsCgYEA+/sp
|
||||
J2Do1lpUjkRDwWAIauHJ01ZHcA5epu2vXXZOnGw+OvPX8a493kwwJDjjrfOgDLTC
|
||||
1FDDBMzbCQUHUa1w3ZfsSOyheHr/8xlVUJ3gz98q+aizaJLJ8lZraL8lvsC9uogf
|
||||
x7P9iTp+SpIHQ1jXp+9WdFgeEgXVkK2GY1bzw+cCgYBiVOcuodFNuaHnSccDZZtD
|
||||
6FpDRAuA5ax9vR1PNtg3EQrthD3ezXrbja4YxC3nhWNKvas7DMJHcOlGf4821M31
|
||||
Xv+PzX2pOd8o3A3JMlta0FNrE8WAiM6gMQadZ1j5oiZnLEN9YNGvYwOVTJ5KyswM
|
||||
RNFWCeiv37c1/Kqpnq05gwKBgGys2QXzxNfV44vsIzC+Y0L9mFb+ahcJC4eBEVYE
|
||||
1UifYoN4cVT5qhM61rR4mLGIVinEuBZrsoBafck5EvwGCpx3jl+xNr7IhaTp8yKu
|
||||
xKvCez1rpdzfGhvba72kWvoXFHzjgplVpm5N/PPaYSmJopD6J1ZMPsPVIlOgk0o6
|
||||
0S1XAoGBALm8/9Gyer2jtfL/WZDILEeOV/rG13ELspTIx0pcbHkvZKFXrddu27E0
|
||||
e89SqTCIXhn3nFLvk4pdWjJbE2QA4uS99vV5HXIpvvEBgwzid5hyqxE3b7xuQwl6
|
||||
bAJld+V2lh5e1tQuaX/bF7B87k4ODlZFatCzhrOXBKMdRm4SkzSk
|
||||
-----END RSA PRIVATE KEY-----
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,22 +0,0 @@
|
||||
version: 1
|
||||
|
||||
formatters:
|
||||
precise:
|
||||
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
|
||||
|
||||
handlers:
|
||||
console:
|
||||
class: logging.StreamHandler
|
||||
formatter: precise
|
||||
|
||||
loggers:
|
||||
synapse.storage.SQL:
|
||||
# beware: increasing this to DEBUG will make synapse log sensitive
|
||||
# information such as access tokens.
|
||||
level: INFO
|
||||
|
||||
root:
|
||||
level: INFO
|
||||
handlers: [console]
|
||||
|
||||
disable_existing_loggers: false
|
||||
@@ -1 +0,0 @@
|
||||
ed25519 a_IyNs PQ0dHIEEsxnfN6pnfBoXEkwNciqCvWAJJf4B2y88tvc
|
||||
25
docker/keycloak/https/tls.crt
Normal file
25
docker/keycloak/https/tls.crt
Normal file
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEQzCCAqugAwIBAgIQP8YUKLJIkSt+rdx8XntwITANBgkqhkiG9w0BAQsFADBj
|
||||
MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExHDAaBgNVBAsME2VuZWtv
|
||||
QGVuZWtvIChFbmVrbykxIzAhBgNVBAMMGm1rY2VydCBlbmVrb0BlbmVrbyAoRW5l
|
||||
a28pMB4XDTIxMTIyNjE0MDE1OVoXDTI0MDMyNjE0MDE1OVowRzEnMCUGA1UEChMe
|
||||
bWtjZXJ0IGRldmVsb3BtZW50IGNlcnRpZmljYXRlMRwwGgYDVQQLDBNlbmVrb0Bl
|
||||
bmVrbyAoRW5la28pMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApRvc
|
||||
rk9QWGx2SyqNZhWN7r/+9lKZTG0mQDwnPkiTr02PDAcVaVaVoYTFuBRdDCFvjIIN
|
||||
07SfogkzNTKAL+YaGTDIauqcEins0/3jUdBhy80ujoyouW6+YBUNIExT03VFmyRL
|
||||
Etmt+08pP7rlSqq5m2WyLcMhrCcq5U7Q1w0rDnkxM9JGKfyQIPRqnyp+6C/m9gMM
|
||||
mCe7KzqlFXOsAAmDUfW1yAk2evOWbauwMbd5nwAq13yUdCtJKNfUeWv45+nP/B1w
|
||||
mBinQqYmFYI2srm1R5vtcFgeEh0DiIloZputQhmYVLEXqKOtZsOcQB8l7BSO9s8J
|
||||
9KcfSmroxJZgT+cTQwIDAQABo4GOMIGLMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUE
|
||||
DDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBSsH2h4QtygW++i5NrI4ZLgj1PG/DBD
|
||||
BgNVHREEPDA6ghVva3VwYW1pY29jaGUta2V5Y2xvYWuCCWxvY2FsaG9zdIcEfwAA
|
||||
AYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAYEAIVtjxGfI7q5B
|
||||
pp7OL5dm0WKjqEyewrj8xd2DBXLMYncO8CcrwazRumNR/JWa9TUog0+RzQBoDcVp
|
||||
oTipybeMFOu5MuiVVdwqk/0q+JSHJ6SbZO5Yrh6NukXfzPM+k/5JLc/4a9yv1JG9
|
||||
IgQ9zwAQuyewr+AsG3fy48U1D9EZABXks0L3rMX7u4lBqqQz4whAyDTv7+mzoInR
|
||||
M4y8f1Ztvlp9Ss389Pz+1/wmnjzOhJ3Z350rXLv6Ax/pnf9pmOELfx6IuYmIQi6j
|
||||
vpCwEVcoBBU/gQqSsJLTJj3TFnNDFCxSyIg0jY+6UOBEGVI5QZK1MdB4RvygDJcn
|
||||
Udaep4E+JKBS+O5kAo21QDWvNds2/CRPhK8RB3M32BFU1JB8VPN0t5zSAPBpcQoL
|
||||
07oGVWF2Xd/A51SCtFqOxtZOTRgBSmTmsPinzlOMS4shqgQB4cjDqZ1RNHI7MbJ8
|
||||
Tbq3LN8/8hTM0hy78rdxuzedirkWq6sf4daTnCZ3sMTYMVgXdHwz
|
||||
-----END CERTIFICATE-----
|
||||
28
docker/keycloak/https/tls.key
Normal file
28
docker/keycloak/https/tls.key
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQClG9yuT1BYbHZL
|
||||
Ko1mFY3uv/72UplMbSZAPCc+SJOvTY8MBxVpVpWhhMW4FF0MIW+Mgg3TtJ+iCTM1
|
||||
MoAv5hoZMMhq6pwSKezT/eNR0GHLzS6OjKi5br5gFQ0gTFPTdUWbJEsS2a37Tyk/
|
||||
uuVKqrmbZbItwyGsJyrlTtDXDSsOeTEz0kYp/JAg9GqfKn7oL+b2AwyYJ7srOqUV
|
||||
c6wACYNR9bXICTZ685Ztq7Axt3mfACrXfJR0K0ko19R5a/jn6c/8HXCYGKdCpiYV
|
||||
gjayubVHm+1wWB4SHQOIiWhmm61CGZhUsReoo61mw5xAHyXsFI72zwn0px9KaujE
|
||||
lmBP5xNDAgMBAAECggEBAJUxFvi/HHe6Ei4blkdfRLAu9yD3RCRmIIE8ma1TAXgP
|
||||
WinhILzdizm28r5CUE3MzLInNn1NIk3ViFsSdfhSMNUAWqkZs8tJ7QEl0km0RRpW
|
||||
HjKa8T8VzZqeiwzbS4ew2SO16MxwvCBwyHIY3GXa3PqJKzbkssGPZthrnpQkBvr8
|
||||
ng+oueLSKbPploUs/0YjMB0SMtiYgRWwdCeRonQg93AAId5hg9GDUclXEJK0LGER
|
||||
vWHjXjRB0KmSnHTdCxSIqml0689cie4RKlUzn9GdN1oH1Ck7Z6hyPLpmQZQlTgJr
|
||||
gJToT/AU+v7eyuSFSod6klAmjTxwKl/0uL1Tp+I12tECgYEAyQnVqV6M472QJxfk
|
||||
MtV7VikqsmfWlR5aPJRjiGfcYsxC4JZhWes8O20ADR43rGzSQdmqBmZNoy77vpMZ
|
||||
bdOOoxSsaBN5UPyv48zWDoO9eUG+snj1o4ycq6aj7JDAZP0CH/30/1/2rTHGN+Wd
|
||||
b4f2/44X/4rvZFw/nVRnRE45/fsCgYEA0j9oaCkZ4MyZA8QgWBpskgJtNE/iyRJd
|
||||
SRtHyKZGoCcdVDMbR19VVOMbRd2yccPNIFKG9ZTbqzWcM3iKDwWONlT1FtWbV2LQ
|
||||
FNKBVFzoXudTgDB0Ikp+Y3lJJi3Q3QTeL9QTDkQUsvckeO3rBNyta3cLzraXOy2r
|
||||
FzVSOmAxpVkCgYBtqXywL9BApnXMrV6gUA1AOaJ9wOCvZOgqJXOJw8XW6r8MTVt7
|
||||
NjMb42Bkx3ftCUtD+lyhswpkmktecFUtsHodATjuaLkDcWLsqx6Uuk4Pp8pDBnJP
|
||||
rXMEuxiuAWPBcrXHB7ut1gX0AbOzaAASB6O3USZMEdh18VAOHS1beCRwIwKBgAC/
|
||||
Wvar1ry23YBm7RqDFYm7WnoKIqtGVnCRGUM8XBnrqa4H9HvfeeUwXYN1E1JWON95
|
||||
i6NJ4TINob2JGyyMf4Hv8WMgZUn9PvIkAXO0VNsphWF6Sp9olmRyJPFuzkRK5SNU
|
||||
ZLDzSwOL32RSrDg7NJ6iMLeObKE4O1h8xwsQFn0ZAoGAPchxDGNsWs9P0SLjNmJI
|
||||
92hkB4g54EYgFmPlsUYucjgYbGSsDd4bjrUSLT5/xX3nn2MNvRsEVdJWrvH97Isn
|
||||
qbE+LKH+i1T/4EDjgFYMsdx1sh5Vec1Yxm1oDsvBoUQzUqOMxZoQyQlEm/MIvISS
|
||||
4NjyOn2zOmWANHbQ/G8Ru5c=
|
||||
-----END PRIVATE KEY-----
|
||||
2193
docker/keycloak/okupamicoche-realm-export.json
Normal file
2193
docker/keycloak/okupamicoche-realm-export.json
Normal file
File diff suppressed because it is too large
Load Diff
3
docker/synapse/Dockerfile
Normal file
3
docker/synapse/Dockerfile
Normal file
@@ -0,0 +1,3 @@
|
||||
FROM matrixdotorg/synapse:latest
|
||||
COPY keycloak-root.crt /usr/local/share/ca-certificates/
|
||||
RUN update-ca-certificates
|
||||
@@ -1,13 +0,0 @@
|
||||
version: '3.3'
|
||||
services:
|
||||
matrix-synapse:
|
||||
image: matrixdotorg/synapse:latest
|
||||
container_name: synapse
|
||||
volumes:
|
||||
- ./synapse_data:/data
|
||||
environment:
|
||||
- SYNAPSE_REPORT_STATS=false
|
||||
- UID=1000
|
||||
- GID=1000
|
||||
ports:
|
||||
- 8008:8008
|
||||
40
docker/synapse/homeserver.yaml
Normal file
40
docker/synapse/homeserver.yaml
Normal file
@@ -0,0 +1,40 @@
|
||||
server_name: "okupamicoche-synapse"
|
||||
pid_file: /data/homeserver.pid
|
||||
public_baseurl: http://okupamicoche-synapse:8008/
|
||||
listeners:
|
||||
- port: 8008
|
||||
tls: false
|
||||
type: http
|
||||
x_forwarded: true
|
||||
resources:
|
||||
- names: [ client, federation ]
|
||||
compress: false
|
||||
database:
|
||||
name: sqlite3
|
||||
args:
|
||||
database: /data/homeserver.db
|
||||
log_config: "/data/okupamicoche-synapse.log.config"
|
||||
media_store_path: "/data/media_store"
|
||||
registration_shared_secret: "Y_XNuno*Dh,T2IpHA;i,bWF^fg&x.*t=iEz*@:y5REBMhgCA63"
|
||||
report_stats: false
|
||||
macaroon_secret_key: "6VvBQj_TedGcDDB_z,-qXV1W3:.CXrRG6AWF&4p:~iGNguy&_h"
|
||||
form_secret: "FM,2TSq++sZ@Tl0atcQP"
|
||||
signing_key_path: "/data/okupamicoche-synapse.signing.key"
|
||||
trusted_key_servers:
|
||||
- server_name: "matrix.org"
|
||||
oidc_providers:
|
||||
- idp_id: keycloak
|
||||
idp_name: Keycloak
|
||||
issuer: "https://okupamicoche-keycloak:8443/auth/realms/okupamicoche"
|
||||
client_id: "synapse"
|
||||
# client_secret: "PUBLIC-CLIENT-WITH-NO-PASSWORD"
|
||||
scopes: [ "openid", "profile" ]
|
||||
user_mapping_provider:
|
||||
config:
|
||||
localpart_template: "{{ user.preferred_username }}"
|
||||
display_name_template: "{{ user.name }}"
|
||||
sso:
|
||||
client_whitelist:
|
||||
- http://localhost:4200/
|
||||
app_service_config_files:
|
||||
- /okupamicoche-appservice.yaml
|
||||
27
docker/synapse/keycloak-root.crt
Normal file
27
docker/synapse/keycloak-root.crt
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIElTCCAv2gAwIBAgIQBi3ZVqJiORvrJIo554aoHzANBgkqhkiG9w0BAQsFADBj
|
||||
MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExHDAaBgNVBAsME2VuZWtv
|
||||
QGVuZWtvIChFbmVrbykxIzAhBgNVBAMMGm1rY2VydCBlbmVrb0BlbmVrbyAoRW5l
|
||||
a28pMB4XDTIxMTIyNjEzNTgzM1oXDTMxMTIyNjEzNTgzM1owYzEeMBwGA1UEChMV
|
||||
bWtjZXJ0IGRldmVsb3BtZW50IENBMRwwGgYDVQQLDBNlbmVrb0BlbmVrbyAoRW5l
|
||||
a28pMSMwIQYDVQQDDBpta2NlcnQgZW5la29AZW5la28gKEVuZWtvKTCCAaIwDQYJ
|
||||
KoZIhvcNAQEBBQADggGPADCCAYoCggGBAKjoNBECRJZyqJe39ijNkHoVeqENGgwK
|
||||
jmmzqgkVq3BR4p+hOtNXDWKQrakkIpyw4NLLoAbctFaHSctWb9G/UWJLOLTzkp8E
|
||||
0rYkxayLVfqRhO5Hl5ZA2CAFafoMYgNmPQFUzobg3k8jTLdCMJ2sYSHdu4TYqWwY
|
||||
5+e+vWgB0wU0z8mdiLlE1ampikjvGtVgWIOM5vTKfsUhYxKMJwLMmyAt/GKeq6Hc
|
||||
8tYdh/ZeNfeITgIQY9zHVB7xsyxi/JiubaKKoTnglznWwmbogvHZ6sjyzfgWSXEu
|
||||
N7GHGcxVN1yH9RadmrY2KesQ6yv6PI5tKZf0kt8F3XgLsRG9UFpBw7VNrlGwgT05
|
||||
O8JogpnZ6tnOxL+8vuLgzJ9lD5dk/ZKxkUx6IYhblbuE4p3ZlrId0WlMgUwN1Ppx
|
||||
U0K2mExQat5Zy+LLUZ/vjReObvdNyWYYDRWzM6iFmLDpnqMDNbx0kH8Ok/Pi1zvk
|
||||
Ho5VcAhpiU11VSKs0RJDVCTNA02/AiDIMwIDAQABo0UwQzAOBgNVHQ8BAf8EBAMC
|
||||
AgQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUrB9oeELcoFvvouTayOGS
|
||||
4I9TxvwwDQYJKoZIhvcNAQELBQADggGBADXTUSQ3u5vxFXUdgpRhvPf4H6z4qWuK
|
||||
wH0rIzIf5QGMe/UUgElRnUcMnRcaGafjshDiQnPAlFT7FwkxqxdvEnGMhziF6xn1
|
||||
yvKZAbKfMJEPlgZ39vdeMiWL2NVqzdcbD/I6hJZML9/OUqZGEq5oed46f6rY/Rnp
|
||||
9/V66bXl0Z1iermnObcyUmgGwNzEI6GhVAALylaHdOBEI5PRsGE3lQ5dCrvXq7LV
|
||||
NVzuj3bpRhINPO6Ry9r1ZJnRqwVdw319MUqTwIxokx1Q07B/1dXf+g6KkmL1nILT
|
||||
zowiTF+Mr0Q13DXKn6u67WpAIXsmzTu0shNPxpWzXykqY7RhUZ9bFMeeTb8ib6g4
|
||||
xUVhUZuq6dqrltMhNKlNZCSdOzAlxZrjJrdTb/+EUXIls6N58moMlHnKlI9eWhIu
|
||||
nMifCG7fX2em7fI6lnuZQXN/X9T3LLHbjp00Garxm28y2RWOIezuam0ALFS7IV8X
|
||||
lJlVtLS5yuOrbHb2QdmwqKM3+kVLtCGo/Q==
|
||||
-----END CERTIFICATE-----
|
||||
5
docker/synapse/synapse_data/.gitignore
vendored
5
docker/synapse/synapse_data/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
homeserver.db
|
||||
media_store
|
||||
|
||||
!.gitignore
|
||||
!homeserver.yaml
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDazCCAlOgAwIBAgIURQQZKTG7wENaPp3bnAVLUMhkBJEwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTAzMTQxNzE0MTZaFw0yMjAz
|
||||
MTQxNzE0MTZaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQD4RoutMqZ9zzuowIZ02N5DneNdTUPp8KTP3ewCTp5B
|
||||
pQB2ht06pEgb7AY0xjlxfwt+lEXc4aeN/B741frLDe6buts8IsedfL0Ub2KHfoqo
|
||||
o3qAimn9+fgoHwZYsls3OJK+fKbPNefp+m65SkZHz4ufQhg2TSLsW0BWATnxnbd8
|
||||
OQIXrCxtV/UKE2iaXfrlmaVSCqFeL4z7Rr+PJ8LiwOFMDLleLMsPiIo8CtR7u/lg
|
||||
65zWI34rhdjwMq9tYXmZtq5sSpS83L/3InQDOvyhNt8vdNS8qL+v7tNhpHldBYqt
|
||||
WJaC/QPeRGXQfa89qYZssZ+k32/i7del2raF8RxkcyVtAgMBAAGjUzBRMB0GA1Ud
|
||||
DgQWBBREbPhToZrilLuC26iiFNj8t+K0hDAfBgNVHSMEGDAWgBREbPhToZrilLuC
|
||||
26iiFNj8t+K0hDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAF
|
||||
NtdTjLsVLhfS0q5tVKQFZ6Ek1CcuyUVeAvTxWDinZVfXzuNFdF1DeDlMwP3gKufz
|
||||
RIAI//k3ISFMwXN0TzgETC86ck4edxpB08E5RKpBZhOrm7PZtoQ5h4hPpOgSG1pp
|
||||
gPvzIzCEtC8Uaf0zpr+2AAm/2+DLgTDzdnO/cxN3UloydW9BslFM1PTeZ7TphT8X
|
||||
3PgDzDBa/IACdTwIhh6RH03l7BhzvKbp5uXnwRSWrf/q1R3mErrsjq9Awx6GECWu
|
||||
Y6YLsHjm05ELHs8r7STQC5Wq+vtfut/iDUNgnNFHmpiaedC1Md3qdnIIMeYrjBjo
|
||||
ru7ot2RLcptsr9w7qd7C
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,27 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA+EaLrTKmfc87qMCGdNjeQ53jXU1D6fCkz93sAk6eQaUAdobd
|
||||
OqRIG+wGNMY5cX8LfpRF3OGnjfwe+NX6yw3um7rbPCLHnXy9FG9ih36KqKN6gIpp
|
||||
/fn4KB8GWLJbNziSvnymzzXn6fpuuUpGR8+Ln0IYNk0i7FtAVgE58Z23fDkCF6ws
|
||||
bVf1ChNoml365ZmlUgqhXi+M+0a/jyfC4sDhTAy5XizLD4iKPArUe7v5YOuc1iN+
|
||||
K4XY8DKvbWF5mbaubEqUvNy/9yJ0Azr8oTbfL3TUvKi/r+7TYaR5XQWKrViWgv0D
|
||||
3kRl0H2vPamGbLGfpN9v4u3Xpdq2hfEcZHMlbQIDAQABAoIBACTQoSmflxyUvC37
|
||||
znRJLDwuj2ZobKel7Wp9Z9+3tLPbOcRZnzhw39h0GT9+HUp9IkE0z18/fs8JEbao
|
||||
VDYD7Nvey1+RcLQjqQ38rkmVNA5pn2KsI6drh6a7Yv+IAwqfMvNYHIwhXDBP2FdV
|
||||
cjJ3ziZhcKGssn8F0PZv3B2921Vp++brFuVtDxvFdhRSSLtcwKI7L5SaOKsA8j2f
|
||||
8Yspq1eigkgCTYTFn1+wdjn3FxyndCV7IFs2BvgdHDBTcB/o6DipXVvK+Px1B3Cp
|
||||
g+ioAHiqn4EkxFkz/ceiscjpUZuITPS+e6aF5Qar7xO5VmeThhNlmsoCFW1nwaea
|
||||
wjwH6CkCgYEA/DxBU1N0o0ZObOnt1eb/LvrSRmxiNH8RKIbb8QL9gQ9Hx1GbP+5N
|
||||
JN5rayBNEg8UAtr0tvbil+ofoxpwlpSGFsFBG5NRcH1LIIHD1Sf0gkGc78ojdCT8
|
||||
O4PcWnCWjLtLIgZCVBxTupa1vsWmUMBzqTxdxn92ECLcPFvo21SRIYsCgYEA+/sp
|
||||
J2Do1lpUjkRDwWAIauHJ01ZHcA5epu2vXXZOnGw+OvPX8a493kwwJDjjrfOgDLTC
|
||||
1FDDBMzbCQUHUa1w3ZfsSOyheHr/8xlVUJ3gz98q+aizaJLJ8lZraL8lvsC9uogf
|
||||
x7P9iTp+SpIHQ1jXp+9WdFgeEgXVkK2GY1bzw+cCgYBiVOcuodFNuaHnSccDZZtD
|
||||
6FpDRAuA5ax9vR1PNtg3EQrthD3ezXrbja4YxC3nhWNKvas7DMJHcOlGf4821M31
|
||||
Xv+PzX2pOd8o3A3JMlta0FNrE8WAiM6gMQadZ1j5oiZnLEN9YNGvYwOVTJ5KyswM
|
||||
RNFWCeiv37c1/Kqpnq05gwKBgGys2QXzxNfV44vsIzC+Y0L9mFb+ahcJC4eBEVYE
|
||||
1UifYoN4cVT5qhM61rR4mLGIVinEuBZrsoBafck5EvwGCpx3jl+xNr7IhaTp8yKu
|
||||
xKvCez1rpdzfGhvba72kWvoXFHzjgplVpm5N/PPaYSmJopD6J1ZMPsPVIlOgk0o6
|
||||
0S1XAoGBALm8/9Gyer2jtfL/WZDILEeOV/rG13ELspTIx0pcbHkvZKFXrddu27E0
|
||||
e89SqTCIXhn3nFLvk4pdWjJbE2QA4uS99vV5HXIpvvEBgwzid5hyqxE3b7xuQwl6
|
||||
bAJld+V2lh5e1tQuaX/bF7B87k4ODlZFatCzhrOXBKMdRm4SkzSk
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -1,22 +0,0 @@
|
||||
version: 1
|
||||
|
||||
formatters:
|
||||
precise:
|
||||
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
|
||||
|
||||
handlers:
|
||||
console:
|
||||
class: logging.StreamHandler
|
||||
formatter: precise
|
||||
|
||||
loggers:
|
||||
synapse.storage.SQL:
|
||||
# beware: increasing this to DEBUG will make synapse log sensitive
|
||||
# information such as access tokens.
|
||||
level: INFO
|
||||
|
||||
root:
|
||||
level: INFO
|
||||
handlers: [console]
|
||||
|
||||
disable_existing_loggers: false
|
||||
@@ -1 +0,0 @@
|
||||
ed25519 a_cGhG bkRaBjufoVnCJ8Vk3S0h7cF4/7zDmQwM6Q+vnDj3baw
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -3,27 +3,27 @@ package eu.fosil.okupamicoche.dto
|
||||
import eu.fosil.okupamicoche.entities.User
|
||||
|
||||
class CreateUserDto(
|
||||
private val id: String,
|
||||
private val username: String,
|
||||
private val matrixId: String,
|
||||
private val name: String,
|
||||
private val email: String?
|
||||
private val id: String,
|
||||
private val username: String,
|
||||
private val matrixId: String,
|
||||
private val name: String,
|
||||
private val email: String?
|
||||
) {
|
||||
constructor(user: User) : this(
|
||||
user.id,
|
||||
user.username,
|
||||
user.matrixId,
|
||||
user.name,
|
||||
user.email
|
||||
user.id,
|
||||
user.username,
|
||||
user.matrixId,
|
||||
user.name,
|
||||
user.email
|
||||
)
|
||||
|
||||
fun toUser(): User {
|
||||
return User(
|
||||
id = id,
|
||||
username = username,
|
||||
matrixId = matrixId,
|
||||
name = name,
|
||||
email = email
|
||||
id = id,
|
||||
username = username,
|
||||
matrixId = matrixId,
|
||||
name = name,
|
||||
email = email
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,51 +1,54 @@
|
||||
package eu.fosil.okupamicoche.dto
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat
|
||||
import eu.fosil.okupamicoche.entities.Travel
|
||||
import eu.fosil.okupamicoche.entities.TravelId
|
||||
import eu.fosil.okupamicoche.entities.UserIdNotFoundException
|
||||
import eu.fosil.okupamicoche.entities.UserNotSpecifiedException
|
||||
import eu.fosil.okupamicoche.repositories.UserRepository
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import java.time.LocalDateTime
|
||||
|
||||
class TravelDto(
|
||||
// Los campos deben ser públicos para que aparezcan en el JSON
|
||||
val id: TravelId? = null,
|
||||
var driverInfo: UserInfoDto? = null,
|
||||
val travelersInfo: List<UserInfoDto> = emptyList(),
|
||||
val departureDate: String = "",
|
||||
val origin: String = "",
|
||||
val destination: String = "",
|
||||
val places: Int = 0,
|
||||
var description: String? = null,
|
||||
val matrixRoomId: String = ""
|
||||
// Los campos deben ser públicos para que aparezcan en el JSON
|
||||
val id: TravelId? = null,
|
||||
var driverInfo: UserInfoDto? = null,
|
||||
val travelersInfo: List<UserInfoDto> = emptyList(),
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||
val departureDate: LocalDateTime = LocalDateTime.MIN,
|
||||
val origin: String = "",
|
||||
val destination: String = "",
|
||||
val places: Int = 0,
|
||||
var description: String? = null,
|
||||
val matrixRoomId: String = ""
|
||||
) {
|
||||
constructor(travel: Travel) : this(
|
||||
travel.id,
|
||||
UserInfoDto(travel.driver),
|
||||
travel.travelers.map { traveler -> UserInfoDto(traveler) },
|
||||
travel.departureDate,
|
||||
travel.origin,
|
||||
travel.destination,
|
||||
travel.places,
|
||||
travel.description,
|
||||
travel.matrixRoomId
|
||||
travel.id,
|
||||
UserInfoDto(travel.driver),
|
||||
travel.travelers.map { traveler -> UserInfoDto(traveler) },
|
||||
travel.departureDate,
|
||||
travel.origin,
|
||||
travel.destination,
|
||||
travel.places,
|
||||
travel.description,
|
||||
travel.matrixRoomId
|
||||
)
|
||||
|
||||
fun toTravel(userRepository: UserRepository): Travel {
|
||||
driverInfo?.let { driverInfo ->
|
||||
val driver = userRepository.findByIdOrNull(driverInfo.id) ?: throw UserIdNotFoundException()
|
||||
val travelers = travelersInfo.mapNotNull { t -> userRepository.findByIdOrNull(t.id) }
|
||||
.toMutableList()
|
||||
.toMutableList()
|
||||
return Travel(
|
||||
id,
|
||||
driver,
|
||||
travelers,
|
||||
departureDate,
|
||||
origin,
|
||||
destination,
|
||||
places,
|
||||
description,
|
||||
matrixRoomId
|
||||
id,
|
||||
driver,
|
||||
travelers,
|
||||
departureDate,
|
||||
origin,
|
||||
destination,
|
||||
places,
|
||||
description,
|
||||
matrixRoomId
|
||||
)
|
||||
}
|
||||
throw UserNotSpecifiedException()
|
||||
|
||||
@@ -5,34 +5,34 @@ import eu.fosil.okupamicoche.entities.UserId
|
||||
import eu.fosil.okupamicoche.repositories.UserRepository
|
||||
|
||||
class UserDto(
|
||||
// Los campos deben ser públicos para que aparezcan en el JSON
|
||||
val id: UserId,
|
||||
val username: String,
|
||||
val matrixId: String,
|
||||
val name: String,
|
||||
val email: String?,
|
||||
val travelsAsDriver: List<TravelDto> = emptyList(),
|
||||
val travelsAsTraveler: List<TravelDto> = emptyList()
|
||||
// Los campos deben ser públicos para que aparezcan en el JSON
|
||||
val id: UserId,
|
||||
val username: String,
|
||||
val matrixId: String,
|
||||
val name: String,
|
||||
val email: String?,
|
||||
val travelsAsDriver: List<TravelDto> = emptyList(),
|
||||
val travelsAsTraveler: List<TravelDto> = emptyList()
|
||||
) {
|
||||
constructor(user: User) : this(
|
||||
user.id,
|
||||
user.username,
|
||||
user.matrixId,
|
||||
user.name,
|
||||
user.email,
|
||||
user.travelsAsDriver.map { t -> TravelDto(t) },
|
||||
user.travelsAsTraveler.map { t -> TravelDto(t) }
|
||||
user.id,
|
||||
user.username,
|
||||
user.matrixId,
|
||||
user.name,
|
||||
user.email,
|
||||
user.travelsAsDriver.map { t -> TravelDto(t) },
|
||||
user.travelsAsTraveler.map { t -> TravelDto(t) }
|
||||
)
|
||||
|
||||
fun toUser(userRepository: UserRepository): User {
|
||||
return User(
|
||||
id,
|
||||
username,
|
||||
matrixId,
|
||||
name,
|
||||
email,
|
||||
travelsAsDriver.map { t -> t.toTravel(userRepository) },
|
||||
travelsAsTraveler.map { t -> t.toTravel(userRepository) }
|
||||
id,
|
||||
username,
|
||||
matrixId,
|
||||
name,
|
||||
email,
|
||||
travelsAsDriver.map { t -> t.toTravel(userRepository) },
|
||||
travelsAsTraveler.map { t -> t.toTravel(userRepository) }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -4,25 +4,25 @@ import eu.fosil.okupamicoche.entities.User
|
||||
import eu.fosil.okupamicoche.entities.UserId
|
||||
|
||||
class UserInfoDto(
|
||||
// Los campos deben ser públicos para que aparezcan en el JSON
|
||||
val id: UserId,
|
||||
val username: String,
|
||||
val matrixId: String,
|
||||
val name: String
|
||||
// Los campos deben ser públicos para que aparezcan en el JSON
|
||||
val id: UserId,
|
||||
val username: String,
|
||||
val matrixId: String,
|
||||
val name: String
|
||||
) {
|
||||
constructor(user: User) : this(
|
||||
user.id,
|
||||
user.username,
|
||||
user.matrixId,
|
||||
user.name
|
||||
user.id,
|
||||
user.username,
|
||||
user.matrixId,
|
||||
user.name
|
||||
)
|
||||
|
||||
fun toUser(): User {
|
||||
return User(
|
||||
id,
|
||||
username,
|
||||
matrixId,
|
||||
name
|
||||
id,
|
||||
username,
|
||||
matrixId,
|
||||
name
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonInclude
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
open class ApiResponse<T>(val success: Boolean, val data: T?, val error: ApiError?) {
|
||||
constructor(success: Boolean, data: T) : this(success, data, null)
|
||||
constructor(success: Boolean, data: T?) : this(success, data, null)
|
||||
constructor(success: Boolean, error: ApiError) : this(success, null, error)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
package eu.fosil.okupamicoche.entities
|
||||
|
||||
import org.hibernate.annotations.LazyCollection
|
||||
import org.hibernate.annotations.LazyCollectionOption
|
||||
import java.time.LocalDateTime
|
||||
import javax.persistence.*
|
||||
|
||||
typealias TravelId = Long
|
||||
|
||||
@Entity
|
||||
@Table
|
||||
class Travel(
|
||||
@Id @GeneratedValue var id: TravelId? = null,
|
||||
@ManyToOne
|
||||
var driver: User,
|
||||
@ManyToMany
|
||||
var travelers: MutableList<User>,
|
||||
var departureDate: String,
|
||||
var origin: String,
|
||||
var destination: String,
|
||||
var places: Int,
|
||||
var description: String? = null,
|
||||
var matrixRoomId: String
|
||||
@Id @GeneratedValue var id: TravelId? = null,
|
||||
@ManyToOne
|
||||
@LazyCollection(LazyCollectionOption.FALSE)
|
||||
var driver: User,
|
||||
@ManyToMany
|
||||
@LazyCollection(LazyCollectionOption.FALSE)
|
||||
var travelers: MutableList<User>,
|
||||
var departureDate: LocalDateTime,
|
||||
var origin: String,
|
||||
var destination: String,
|
||||
var places: Int,
|
||||
var description: String? = null,
|
||||
var matrixRoomId: String
|
||||
) {
|
||||
fun users(): Set<User> {
|
||||
val allUsers = mutableSetOf(driver)
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
package eu.fosil.okupamicoche.entities
|
||||
|
||||
import org.hibernate.annotations.LazyCollection
|
||||
import org.hibernate.annotations.LazyCollectionOption
|
||||
import javax.persistence.*
|
||||
|
||||
typealias UserId = String
|
||||
|
||||
@Entity
|
||||
@Table
|
||||
class User(
|
||||
@Id var id: UserId,
|
||||
var username: String,
|
||||
var matrixId: String,
|
||||
var name: String,
|
||||
var email: String? = null,
|
||||
@OneToMany(mappedBy = "driver")
|
||||
@OneToMany
|
||||
@LazyCollection(LazyCollectionOption.FALSE)
|
||||
var travelsAsDriver: List<Travel> = emptyList(),
|
||||
@ManyToMany(mappedBy = "travelers")
|
||||
@ManyToMany @LazyCollection(LazyCollectionOption.FALSE)
|
||||
var travelsAsTraveler: List<Travel> = emptyList()
|
||||
)
|
||||
@@ -1,31 +1,31 @@
|
||||
package eu.fosil.okupamicoche.entities
|
||||
|
||||
class UserKeycloak(
|
||||
val id: UserId,
|
||||
val username: String,
|
||||
val admin: Boolean,
|
||||
val name: String,
|
||||
val email: String
|
||||
val id: UserId,
|
||||
val username: String,
|
||||
val admin: Boolean,
|
||||
val name: String,
|
||||
val email: String
|
||||
) {
|
||||
constructor(claims: Map<String, Any>) : this(
|
||||
claims["sub"].toString(),
|
||||
claims["preferred_username"].toString(),
|
||||
try {
|
||||
claims["admin"] as Boolean
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
},
|
||||
claims["name"].toString(),
|
||||
claims["email"].toString()
|
||||
claims["sub"].toString(),
|
||||
claims["preferred_username"].toString(),
|
||||
try {
|
||||
claims["admin"] as Boolean
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
},
|
||||
claims["name"].toString(),
|
||||
claims["email"].toString()
|
||||
)
|
||||
|
||||
fun toUser(): User {
|
||||
return User(
|
||||
id,
|
||||
username,
|
||||
"@$username:synapse",
|
||||
name,
|
||||
email
|
||||
id,
|
||||
username,
|
||||
"@$username:okupamicoche-synapse",
|
||||
name,
|
||||
email
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -10,17 +10,60 @@ import org.springframework.data.repository.PagingAndSortingRepository
|
||||
import org.springframework.data.repository.query.Param
|
||||
|
||||
interface TravelRepository : PagingAndSortingRepository<Travel, TravelId> {
|
||||
@Query("SELECT count(t) FROM Travel t " +
|
||||
"LEFT JOIN t.travelers u " +
|
||||
"WHERE (lower(t.origin) LIKE lower(concat('%', :filter,'%')) OR " +
|
||||
"lower(t.destination) LIKE lower(concat('%', :filter,'%')))")
|
||||
fun countTravels(
|
||||
@Param("filter") filter: String
|
||||
): Long
|
||||
|
||||
@Query("SELECT t FROM Travel t " +
|
||||
"LEFT JOIN t.travelers u " +
|
||||
"WHERE t.driver.id = :userId OR u.id = :userId")
|
||||
fun findUserTravels(@Param("userId") userId: UserId): List<Travel>
|
||||
|
||||
@Query("SELECT count(t) FROM Travel t " +
|
||||
"LEFT JOIN t.travelers u " +
|
||||
"WHERE t.driver.id = :userId OR u.id = :userId")
|
||||
fun countUserTravels(@Param("userId") userId: UserId): Long
|
||||
|
||||
@Query("SELECT t FROM Travel t " +
|
||||
"LEFT JOIN t.travelers u " +
|
||||
"WHERE (t.driver.id = :userId OR u.id = :userId) " +
|
||||
"AND " +
|
||||
"(lower(t.origin) LIKE lower(concat('%', :filter,'%')) OR " +
|
||||
"lower(t.destination) LIKE lower(concat('%', :filter,'%')))")
|
||||
fun findUserTravels(
|
||||
@Param("userId") userId: UserId,
|
||||
@Param("filter") filter: String,
|
||||
pageable: Pageable
|
||||
): Page<Travel>
|
||||
|
||||
@Query("SELECT count(t) FROM Travel t " +
|
||||
"LEFT JOIN t.travelers u " +
|
||||
"WHERE (t.driver.id = :userId OR u.id = :userId) " +
|
||||
"AND " +
|
||||
"(lower(t.origin) LIKE lower(concat('%', :filter,'%')) OR " +
|
||||
"lower(t.destination) LIKE lower(concat('%', :filter,'%')))")
|
||||
fun countUserTravels(
|
||||
@Param("userId") userId: UserId,
|
||||
@Param("filter") filter: String
|
||||
): Long
|
||||
|
||||
@Query("SELECT t FROM Travel t WHERE t.driver.id = :userId")
|
||||
fun findUserTravelsAsDriver(@Param("userId") userId: UserId): List<Travel>
|
||||
|
||||
@Query("SELECT count(t) FROM Travel t WHERE t.driver.id = :userId")
|
||||
fun countUserTravelsAsDriver(@Param("userId") userId: UserId): Long
|
||||
|
||||
@Query("SELECT t FROM Travel t JOIN t.travelers u WHERE u.id = :userId")
|
||||
fun findUserTravelsAsTraveler(@Param("userId") userId: UserId): List<Travel>
|
||||
|
||||
@Query("SELECT count(t) FROM Travel t JOIN t.travelers u WHERE u.id = :userId")
|
||||
fun countUserTravelsAsTraveler(@Param("userId") userId: UserId): Long
|
||||
|
||||
fun findByOriginContainingOrDestinationContainingAllIgnoreCase(
|
||||
filter: String, filter2: String, pageable: Pageable
|
||||
filterOrigin: String, filterDestination: String, pageable: Pageable
|
||||
): Page<Travel>
|
||||
}
|
||||
@@ -11,5 +11,5 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories
|
||||
class OkupaMiCocheApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<OkupaMiCocheApplication>(*args)
|
||||
runApplication<OkupaMiCocheApplication>(*args)
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package eu.fosil.okupamicoche.spring
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
|
||||
|
||||
class ServletInitializer : SpringBootServletInitializer() {
|
||||
|
||||
override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {
|
||||
return application.sources(OkupaMiCocheApplication::class.java)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +1,42 @@
|
||||
package eu.fosil.okupamicoche.spring.conf
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain
|
||||
import org.springframework.web.reactive.config.CorsRegistry
|
||||
import org.springframework.web.reactive.config.EnableWebFlux
|
||||
import org.springframework.web.reactive.config.WebFluxConfigurer
|
||||
|
||||
|
||||
@Configuration
|
||||
class JWTSecurityConfig : WebSecurityConfigurerAdapter() {
|
||||
@Throws(Exception::class)
|
||||
override fun configure(http: HttpSecurity) {//@formatter:off
|
||||
http.cors()
|
||||
@EnableWebFluxSecurity
|
||||
class SecurityConfig {
|
||||
@Bean
|
||||
fun configure(http: ServerHttpSecurity): SecurityWebFilterChain {//@formatter:off
|
||||
return http.cors()
|
||||
.and()
|
||||
.csrf().disable()
|
||||
.authorizeRequests()
|
||||
.antMatchers("/api/public/**").permitAll()
|
||||
.antMatchers("/api/user/**").authenticated()
|
||||
.antMatchers("/api/travel/**").authenticated()
|
||||
.anyRequest().denyAll()
|
||||
.authorizeExchange()
|
||||
.pathMatchers(HttpMethod.OPTIONS).permitAll()
|
||||
.pathMatchers("/_matrix/**").permitAll()
|
||||
.pathMatchers("/api/public/**").permitAll()
|
||||
.pathMatchers("/api/user/**").authenticated()
|
||||
.pathMatchers("/api/travel/**").authenticated()
|
||||
.anyExchange().denyAll()
|
||||
.and()
|
||||
.oauth2ResourceServer()
|
||||
.jwt()
|
||||
.oauth2ResourceServer().jwt()
|
||||
.and().and().build()
|
||||
}//@formatter:on
|
||||
}
|
||||
|
||||
@Configuration
|
||||
class CorsConfigurer : WebMvcConfigurer {
|
||||
override fun addCorsMappings(registry: CorsRegistry) {
|
||||
registry.addMapping("/**").allowedOrigins("http://localhost:4200")
|
||||
@EnableWebFlux
|
||||
class CorsGlobalConfiguration : WebFluxConfigurer {
|
||||
override fun addCorsMappings(corsRegistry: CorsRegistry) {
|
||||
corsRegistry.addMapping("/**")
|
||||
.allowedOrigins("http://localhost:4200")
|
||||
.allowedMethods("*")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,117 +8,146 @@ import eu.fosil.okupamicoche.repositories.TravelRepository
|
||||
import eu.fosil.okupamicoche.repositories.UserRepository
|
||||
import eu.fosil.okupamicoche.spring.services.AuthService
|
||||
import eu.fosil.okupamicoche.spring.services.UseCaseService
|
||||
import eu.fosil.okupamicoche.usecases.travel.*
|
||||
import mu.KotlinLogging
|
||||
import eu.fosil.okupamicoche.usecases.travel.CancelTravel
|
||||
import eu.fosil.okupamicoche.usecases.travel.DeleteTravel
|
||||
import eu.fosil.okupamicoche.usecases.travel.EditTravel
|
||||
import eu.fosil.okupamicoche.usecases.travel.ListUserTravels
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.validation.annotation.Validated
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RequestParam
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import java.security.Principal
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/travel")
|
||||
class PrivateTravelRestController(
|
||||
private val authService: AuthService,
|
||||
private val userRepository: UserRepository,
|
||||
private val travelRepository: TravelRepository,
|
||||
private val useCaseService: UseCaseService
|
||||
private val authService: AuthService,
|
||||
private val userRepository: UserRepository,
|
||||
private val travelRepository: TravelRepository,
|
||||
private val useCaseService: UseCaseService
|
||||
) : ApiRestController {
|
||||
private val logger = KotlinLogging.logger {}
|
||||
// private val logger = KotlinLogging.logger {}
|
||||
|
||||
@RequestMapping("/create")
|
||||
suspend fun createTravel(@RequestBody @Validated travel: TravelDto): ApiResponse<Unit> {
|
||||
suspend fun createTravel(@RequestBody @Validated travel: TravelDto, principal: Principal): ApiResponse<Unit> {
|
||||
return response {
|
||||
val driver = userRepository.findByIdOrNull(authService.currentUser().id)
|
||||
?: throw UserIdNotFoundException("Current user not found.")
|
||||
val driver = userRepository.findByIdOrNull(authService.currentUser(principal).id)
|
||||
?: throw UserIdNotFoundException("Current user not found.")
|
||||
if (travel.id != null && (travelRepository.findByIdOrNull(travel.id) != null))
|
||||
throw CannotDuplicateIdException("Travel id already exists.")
|
||||
travel.driverInfo = UserInfoDto(driver)
|
||||
|
||||
val createTravel = useCaseService.getCreateTravel()
|
||||
createTravel.createTravel(travel.toTravel(userRepository))
|
||||
val useCase = useCaseService.getCreateTravel()
|
||||
useCase.createTravel(travel.toTravel(userRepository))
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/cancel")
|
||||
suspend fun cancelTravel(@RequestParam @Validated travelId: TravelId): ApiResponse<Unit> {
|
||||
suspend fun cancelTravel(@RequestParam @Validated travelId: TravelId, principal: Principal): ApiResponse<Unit> {
|
||||
return response {
|
||||
throwErrorIfCannotEditTravel(travelId)
|
||||
throwErrorIfCannotEditTravel(travelId, principal)
|
||||
CancelTravel(travelRepository).cancelTravel(travelId)
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/delete")
|
||||
suspend fun deleteTravel(@RequestParam @Validated travelId: TravelId): ApiResponse<Unit> {
|
||||
suspend fun deleteTravel(@RequestParam @Validated travelId: TravelId, principal: Principal): ApiResponse<Unit> {
|
||||
return response {
|
||||
throwErrorIfCannotEditTravel(travelId)
|
||||
throwErrorIfCannotEditTravel(travelId, principal)
|
||||
DeleteTravel(travelRepository).deleteTravel(travelId)
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/edit")
|
||||
suspend fun editTravel(@RequestBody @Validated travel: TravelDto): ApiResponse<Unit> {
|
||||
suspend fun editTravel(@RequestBody @Validated travel: TravelDto, principal: Principal): ApiResponse<Unit> {
|
||||
return response {
|
||||
throwErrorIfCannotEditTravel(travel.id)
|
||||
throwErrorIfCannotEditTravel(travel.id, principal)
|
||||
EditTravel(travelRepository).editTravel(travel.toTravel(userRepository))
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/listusertravels")
|
||||
suspend fun listUserTravels(): ApiResponse<ListDto<TravelDto>> {
|
||||
suspend fun listUserTravels(
|
||||
@RequestParam @Validated filter: String?,
|
||||
@RequestParam @Validated sortColumn: String?,
|
||||
@RequestParam @Validated sortAscending: Boolean?,
|
||||
@RequestParam @Validated pageIndex: Int?,
|
||||
@RequestParam @Validated pageSize: Int?,
|
||||
principal: Principal
|
||||
): ApiResponse<ListDto<TravelDto>> {
|
||||
return response {
|
||||
val userId = authService.currentUser().id
|
||||
val userId = authService.currentUser(principal).id
|
||||
val useCase = ListUserTravels(travelRepository)
|
||||
val travels = useCase.listUserTravels(
|
||||
userId, filter, sortColumn, sortAscending, pageIndex, pageSize
|
||||
).map { t -> TravelDto(t) }
|
||||
ListDto(useCase.countUserTravels(userId, filter), travels)
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/listallusertravels")
|
||||
suspend fun listAllUserTravels(principal: Principal): ApiResponse<ListDto<TravelDto>> {
|
||||
return response {
|
||||
val userId = authService.currentUser(principal).id
|
||||
val useCase = ListUserTravels(travelRepository)
|
||||
val travels = useCase.listUserTravels(userId).map { t -> TravelDto(t) }
|
||||
logger.debug { "travels=$travels" }
|
||||
ListDto(useCase.countUserTravels(userId), travels)
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/join")
|
||||
suspend fun join(@RequestParam @Validated travelId: TravelId): ApiResponse<Unit> {
|
||||
suspend fun join(@RequestParam @Validated travelId: TravelId, principal: Principal): ApiResponse<Unit> {
|
||||
return response {
|
||||
val userId = authService.currentUser().id
|
||||
AddTraveler(userRepository, travelRepository).addTraveler(travelId, userId)
|
||||
val userId = authService.currentUser(principal).id
|
||||
val useCase = useCaseService.getAddTraveler()
|
||||
useCase.addTraveler(travelId, userId)
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/leave")
|
||||
suspend fun leave(@RequestParam @Validated travelId: TravelId): ApiResponse<Unit> {
|
||||
suspend fun leave(@RequestParam @Validated travelId: TravelId, principal: Principal): ApiResponse<Unit> {
|
||||
return response {
|
||||
val userId = authService.currentUser().id
|
||||
RemoveTraveler(userRepository, travelRepository).removeTraveler(travelId, userId)
|
||||
val userId = authService.currentUser(principal).id
|
||||
val useCase = useCaseService.getRemoveTraveler()
|
||||
useCase.removeTraveler(travelId, userId)
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/addtraveler")
|
||||
suspend fun addTraveler(
|
||||
@RequestParam @Validated travelId: TravelId,
|
||||
@RequestParam @Validated userId: UserId
|
||||
@RequestParam @Validated travelId: TravelId,
|
||||
@RequestParam @Validated userId: UserId,
|
||||
principal: Principal
|
||||
): ApiResponse<Unit> {
|
||||
throwErrorIfCannotEditTravel(travelId, principal)
|
||||
return response {
|
||||
throwErrorIfCannotEditTravel(travelId)
|
||||
AddTraveler(userRepository, travelRepository).addTraveler(travelId, userId)
|
||||
throwErrorIfCannotEditTravel(travelId, principal)
|
||||
val useCase = useCaseService.getAddTraveler()
|
||||
useCase.addTraveler(travelId, userId)
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/removetraveler")
|
||||
suspend fun removeTraveler(
|
||||
@RequestParam @Validated travelId: TravelId,
|
||||
@RequestParam @Validated userId: UserId
|
||||
@RequestParam @Validated travelId: TravelId,
|
||||
@RequestParam @Validated userId: UserId,
|
||||
principal: Principal
|
||||
): ApiResponse<Unit> {
|
||||
throwErrorIfCannotEditTravel(travelId, principal)
|
||||
return response {
|
||||
throwErrorIfCannotEditTravel(travelId)
|
||||
RemoveTraveler(userRepository, travelRepository).removeTraveler(travelId, userId)
|
||||
val useCase = useCaseService.getRemoveTraveler()
|
||||
useCase.removeTraveler(travelId, userId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun throwErrorIfCannotEditTravel(
|
||||
travelId: TravelId?,
|
||||
message: String = "Only admins and travel driver can modify this travel."
|
||||
travelId: TravelId?,
|
||||
principal: Principal,
|
||||
message: String = "Only admins and travel driver can modify this travel."
|
||||
) {
|
||||
if (!authService.canEditTravel(travelId))
|
||||
if (!authService.canEditTravel(travelId, principal))
|
||||
throw InsufficientPermissions(message)
|
||||
}
|
||||
}
|
||||
@@ -13,18 +13,19 @@ import org.springframework.validation.annotation.Validated
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import java.security.Principal
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/user")
|
||||
class PrivateUserRestController(
|
||||
private val authService: AuthService,
|
||||
private val userRepository: UserRepository
|
||||
private val authService: AuthService,
|
||||
private val userRepository: UserRepository
|
||||
) : ApiRestController {
|
||||
|
||||
@RequestMapping("/user")
|
||||
suspend fun getCurrentUserCreateIfNeeded(): ApiResponse<UserDto> {
|
||||
suspend fun getCurrentUserCreateIfNeeded(principal: Principal): ApiResponse<UserDto> {
|
||||
return response {
|
||||
val userKeycloak = authService.currentUser()
|
||||
val userKeycloak = authService.currentUser(principal)
|
||||
var user = userRepository.findByIdOrNull(userKeycloak.id)
|
||||
|
||||
if (user == null) {
|
||||
@@ -37,9 +38,12 @@ class PrivateUserRestController(
|
||||
}
|
||||
|
||||
@RequestMapping("/create")
|
||||
suspend fun createUser(@RequestBody @Validated createUserDto: CreateUserDto): ApiResponse<Unit> {
|
||||
suspend fun createUser(
|
||||
@RequestBody @Validated createUserDto: CreateUserDto,
|
||||
principal: Principal
|
||||
): ApiResponse<Unit> {
|
||||
return response {
|
||||
if (!authService.isAdmin())
|
||||
if (!authService.isAdmin(principal))
|
||||
throw InsufficientPermissions("Only admins can create users.")
|
||||
CreateUser(userRepository).createUser(createUserDto.toUser())
|
||||
}
|
||||
@@ -53,17 +57,17 @@ class PrivateUserRestController(
|
||||
}
|
||||
|
||||
@RequestMapping("/delete")
|
||||
suspend fun deleteUser(@RequestBody @Validated userId: UserId): ApiResponse<Unit> {
|
||||
suspend fun deleteUser(@RequestBody @Validated userId: UserId, principal: Principal): ApiResponse<Unit> {
|
||||
return response {
|
||||
throwErrorIfCannotEditUser(userId)
|
||||
throwErrorIfCannotEditUser(userId, principal)
|
||||
DeleteUser(userRepository).deleteUser(userId)
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/edit")
|
||||
suspend fun editUser(@RequestBody @Validated userDto: UserDto): ApiResponse<Unit> {
|
||||
suspend fun editUser(@RequestBody @Validated userDto: UserDto, principal: Principal): ApiResponse<Unit> {
|
||||
return response {
|
||||
throwErrorIfCannotEditUser(userDto.id)
|
||||
throwErrorIfCannotEditUser(userDto.id, principal)
|
||||
EditUser(userRepository).editUser(userDto.toUser(userRepository))
|
||||
}
|
||||
}
|
||||
@@ -76,10 +80,11 @@ class PrivateUserRestController(
|
||||
}
|
||||
|
||||
private fun throwErrorIfCannotEditUser(
|
||||
userId: UserId?,
|
||||
message: String = "Only admins and travel driver can modify this user."
|
||||
userId: UserId?,
|
||||
principal: Principal,
|
||||
message: String = "Only admins and travel driver can modify this user."
|
||||
) {
|
||||
if (!authService.canEditUser(userId))
|
||||
if (!authService.canEditUser(userId, principal))
|
||||
throw InsufficientPermissions(message)
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,43 @@
|
||||
package eu.fosil.okupamicoche.spring.controller
|
||||
|
||||
import eu.fosil.okupamicoche.dto.TravelDto
|
||||
import eu.fosil.okupamicoche.dto.ListDto
|
||||
import eu.fosil.okupamicoche.dto.TravelDto
|
||||
import eu.fosil.okupamicoche.entities.ApiResponse
|
||||
import eu.fosil.okupamicoche.entities.TravelId
|
||||
import eu.fosil.okupamicoche.repositories.TravelRepository
|
||||
import eu.fosil.okupamicoche.usecases.travel.ListTravels
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.validation.annotation.Validated
|
||||
import org.springframework.web.bind.annotation.CrossOrigin
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RequestParam
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/public")
|
||||
@CrossOrigin(origins = ["http://localhost:4200"])
|
||||
class PublicRestController(private val travelRepository: TravelRepository) : ApiRestController {
|
||||
|
||||
@RequestMapping("/list")
|
||||
suspend fun listTravels(
|
||||
@RequestParam @Validated filter: String?,
|
||||
@RequestParam @Validated sortColumn: String?,
|
||||
@RequestParam @Validated sortAscending: Boolean?,
|
||||
@RequestParam @Validated pageIndex: Int?,
|
||||
@RequestParam @Validated pageSize: Int?,
|
||||
@RequestParam @Validated filter: String?,
|
||||
@RequestParam @Validated sortColumn: String?,
|
||||
@RequestParam @Validated sortAscending: Boolean?,
|
||||
@RequestParam @Validated pageIndex: Int?,
|
||||
@RequestParam @Validated pageSize: Int?,
|
||||
): ApiResponse<ListDto<TravelDto>> {
|
||||
return response {
|
||||
val travels =
|
||||
ListTravels(travelRepository).listTravels(
|
||||
val usecase = ListTravels(travelRepository)
|
||||
val count = usecase.countTravels(filter)
|
||||
val travels = usecase.listTravels(
|
||||
filter, sortColumn, sortAscending, pageIndex, pageSize
|
||||
).map { t -> TravelDto(t) }
|
||||
).map { t -> TravelDto(t) }
|
||||
ListDto(count, travels)
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/listall")
|
||||
suspend fun listTravels(): ApiResponse<ListDto<TravelDto>> {
|
||||
return response {
|
||||
val travels = ListTravels(travelRepository).listTravels().map { t -> TravelDto(t) }
|
||||
ListDto(travelRepository.count(), travels)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +1,43 @@
|
||||
package eu.fosil.okupamicoche.spring.services
|
||||
|
||||
import eu.fosil.okupamicoche.entities.*
|
||||
import eu.fosil.okupamicoche.entities.TravelId
|
||||
import eu.fosil.okupamicoche.entities.UserId
|
||||
import eu.fosil.okupamicoche.entities.UserIdNotFoundException
|
||||
import eu.fosil.okupamicoche.entities.UserKeycloak
|
||||
import eu.fosil.okupamicoche.repositories.TravelRepository
|
||||
import eu.fosil.okupamicoche.repositories.UserRepository
|
||||
import mu.KotlinLogging
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.security.oauth2.jwt.Jwt
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken
|
||||
import org.springframework.stereotype.Service
|
||||
import java.security.Principal
|
||||
|
||||
@Service
|
||||
class AuthService(
|
||||
private val userRepository: UserRepository,
|
||||
private val travelRepository: TravelRepository
|
||||
private val travelRepository: TravelRepository
|
||||
) {
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
/**
|
||||
* Devuelve el id del usuario actual.
|
||||
*/
|
||||
fun currentUser(): UserKeycloak {
|
||||
val authentication = SecurityContextHolder.getContext().authentication
|
||||
if (authentication.principal is Jwt) {
|
||||
val jwt = authentication.principal as Jwt
|
||||
return UserKeycloak(jwt.claims)
|
||||
fun currentUser(principal: Principal): UserKeycloak {
|
||||
if (principal is JwtAuthenticationToken) {
|
||||
return UserKeycloak(principal.token.claims)
|
||||
}
|
||||
throw UserIdNotFoundException()
|
||||
}
|
||||
|
||||
fun isAdmin(): Boolean {
|
||||
return currentUser().admin
|
||||
fun isAdmin(principal: Principal): Boolean {
|
||||
return currentUser(principal).admin
|
||||
}
|
||||
|
||||
fun canEditTravel(travelId: TravelId?): Boolean {
|
||||
fun canEditTravel(travelId: TravelId?, principal: Principal): Boolean {
|
||||
val travel = travelRepository.findByIdOrNull(travelId) ?: return false
|
||||
return currentUser().admin || currentUser().id == travel.driver.id
|
||||
return currentUser(principal).admin || currentUser(principal).id == travel.driver.id
|
||||
}
|
||||
|
||||
fun canEditUser(userId: UserId?): Boolean {
|
||||
fun canEditUser(userId: UserId?, principal: Principal): Boolean {
|
||||
if (userId == null) return false
|
||||
return currentUser().admin || currentUser().id == userId
|
||||
return currentUser(principal).admin || currentUser(principal).id == userId
|
||||
}
|
||||
}
|
||||
@@ -3,23 +3,23 @@ package eu.fosil.okupamicoche.spring.services
|
||||
import eu.fosil.okupamicoche.entities.User
|
||||
import eu.fosil.okupamicoche.usecases.matrix.MatrixApi
|
||||
import mu.KotlinLogging
|
||||
import net.folivo.matrix.core.model.MatrixId
|
||||
import net.folivo.matrix.restclient.MatrixClient
|
||||
import net.folivo.trixnity.client.rest.MatrixClient
|
||||
import net.folivo.trixnity.core.model.MatrixId
|
||||
import org.springframework.stereotype.Service
|
||||
import java.util.stream.Collectors
|
||||
|
||||
@Service
|
||||
class MatrixService(private val matrixClient: MatrixClient): MatrixApi {
|
||||
class MatrixService(private val matrixClient: MatrixClient) : MatrixApi {
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
override suspend fun createRoom(name: String, alias: String, usersToInvite: Set<User>, topic: String?): String {
|
||||
logger.debug { "Creating room name=$name alias=$alias" }
|
||||
val usersToInviteId = usersToInvite.stream().map { user -> MatrixId.UserId(user.matrixId) }
|
||||
val roomId = matrixClient.roomsApi.createRoom(
|
||||
name = name,
|
||||
roomAliasId = MatrixId.RoomAliasId("#$alias:synapse"),
|
||||
// invite = usersToInviteId.collect(Collectors.toSet()),
|
||||
topic = topic
|
||||
val roomId = matrixClient.room.createRoom(
|
||||
name = name,
|
||||
roomAliasId = MatrixId.RoomAliasId("#$alias:okupamicoche-synapse"),
|
||||
invite = usersToInviteId.collect(Collectors.toSet()),
|
||||
topic = topic
|
||||
)
|
||||
return roomId.full
|
||||
}
|
||||
@@ -27,6 +27,12 @@ class MatrixService(private val matrixClient: MatrixClient): MatrixApi {
|
||||
override suspend fun inviteUser(roomId: String, user: User) {
|
||||
val matrixUserId = MatrixId.UserId(user.matrixId)
|
||||
logger.debug { "Invite user $matrixUserId to room $roomId" }
|
||||
matrixClient.roomsApi.inviteUser(MatrixId.RoomId(roomId), matrixUserId)
|
||||
matrixClient.room.inviteUser(MatrixId.RoomId(roomId), matrixUserId)
|
||||
}
|
||||
|
||||
override suspend fun kickUser(roomId: String, user: User) {
|
||||
val matrixUserId = MatrixId.UserId(user.matrixId)
|
||||
logger.debug { "Kick user $matrixUserId from room $roomId" }
|
||||
matrixClient.room.leaveRoom(MatrixId.RoomId(roomId), matrixUserId) // TODO should be kickUser
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,20 @@
|
||||
package eu.fosil.okupamicoche.spring.services
|
||||
|
||||
import eu.fosil.okupamicoche.repositories.TravelRepository
|
||||
import eu.fosil.okupamicoche.repositories.UserRepository
|
||||
import eu.fosil.okupamicoche.usecases.UseCaseFactory
|
||||
import eu.fosil.okupamicoche.usecases.matrix.CreateRoomForTravel
|
||||
import eu.fosil.okupamicoche.usecases.travel.AddTraveler
|
||||
import eu.fosil.okupamicoche.usecases.travel.CreateTravel
|
||||
import eu.fosil.okupamicoche.usecases.travel.RemoveTraveler
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class UseCaseService(
|
||||
private val travelRepository: TravelRepository,
|
||||
private val matrixService: MatrixService
|
||||
): UseCaseFactory {
|
||||
private val travelRepository: TravelRepository,
|
||||
private val userRepository: UserRepository,
|
||||
private val matrixService: MatrixService
|
||||
) : UseCaseFactory {
|
||||
override fun getCreateTravel(): CreateTravel {
|
||||
return CreateTravel(travelRepository, getCreateRoomForTravel())
|
||||
}
|
||||
@@ -18,4 +22,12 @@ class UseCaseService(
|
||||
override fun getCreateRoomForTravel(): CreateRoomForTravel {
|
||||
return CreateRoomForTravel(matrixService)
|
||||
}
|
||||
|
||||
override fun getAddTraveler(): AddTraveler {
|
||||
return AddTraveler(userRepository, travelRepository, matrixService)
|
||||
}
|
||||
|
||||
override fun getRemoveTraveler(): RemoveTraveler {
|
||||
return RemoveTraveler(userRepository, travelRepository, matrixService)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
package eu.fosil.okupamicoche.usecases
|
||||
|
||||
import eu.fosil.okupamicoche.usecases.matrix.CreateRoomForTravel
|
||||
import eu.fosil.okupamicoche.usecases.travel.AddTraveler
|
||||
import eu.fosil.okupamicoche.usecases.travel.CreateTravel
|
||||
import eu.fosil.okupamicoche.usecases.travel.RemoveTraveler
|
||||
|
||||
interface UseCaseFactory {
|
||||
fun getCreateTravel(): CreateTravel
|
||||
|
||||
fun getCreateRoomForTravel(): CreateRoomForTravel
|
||||
fun getAddTraveler(): AddTraveler
|
||||
fun getRemoveTraveler(): RemoveTraveler
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package eu.fosil.okupamicoche.usecases.matrix
|
||||
|
||||
import eu.fosil.okupamicoche.entities.Travel
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
const val ROOM_NAME_PREFIX = "Viaje"
|
||||
const val ROOM_ALIAS_PREFIX = "viaje"
|
||||
@@ -13,11 +14,15 @@ class CreateRoomForTravel(private val matrixApi: MatrixApi) {
|
||||
}
|
||||
|
||||
private fun createRoomName(travel: Travel): String {
|
||||
return "$ROOM_NAME_PREFIX ${travel.origin} - ${travel.destination}"
|
||||
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm")
|
||||
val formattedDate = travel.departureDate.format(formatter)
|
||||
return "$ROOM_NAME_PREFIX ${travel.origin} - ${travel.destination} $formattedDate"
|
||||
}
|
||||
|
||||
private fun createRoomAlias(travel: Travel): String {
|
||||
val alias = "$ROOM_ALIAS_PREFIX-${travel.origin}-${travel.destination}"
|
||||
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_hh'H'mm")
|
||||
val formattedDate = travel.departureDate.format(formatter)
|
||||
val alias = "${ROOM_ALIAS_PREFIX}_${travel.origin}-${travel.destination}_${formattedDate}"
|
||||
return alias.decapitalize().replace(' ', '_')
|
||||
}
|
||||
}
|
||||
@@ -10,4 +10,6 @@ interface MatrixApi {
|
||||
suspend fun createRoom(name: String, alias: String, usersToInvite: Set<User>, topic: String?): String
|
||||
|
||||
suspend fun inviteUser(roomId: String, user: User)
|
||||
|
||||
suspend fun kickUser(roomId: String, user: User)
|
||||
}
|
||||
@@ -4,16 +4,21 @@ import eu.fosil.okupamicoche.entities.TravelId
|
||||
import eu.fosil.okupamicoche.entities.UserId
|
||||
import eu.fosil.okupamicoche.repositories.TravelRepository
|
||||
import eu.fosil.okupamicoche.repositories.UserRepository
|
||||
import eu.fosil.okupamicoche.usecases.matrix.MatrixApi
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
|
||||
class AddTraveler(
|
||||
private val userRepository: UserRepository,
|
||||
private val travelRepository: TravelRepository
|
||||
private val travelRepository: TravelRepository,
|
||||
private val matrixApi: MatrixApi
|
||||
) {
|
||||
fun addTraveler(travelId: TravelId, userId: UserId) {
|
||||
suspend fun addTraveler(travelId: TravelId, userId: UserId) {
|
||||
val user = userRepository.findByIdOrNull(userId)
|
||||
val travel = travelRepository.findByIdOrNull(travelId)
|
||||
if ((travel?.travelers?.contains(user) == false) && (user != null)) {
|
||||
|
||||
val traveler = travel?.travelers?.find { it.id == userId }
|
||||
if ((traveler == null) && (travel != null) && (user != null)) {
|
||||
matrixApi.inviteUser(travel.matrixRoomId, user)
|
||||
travel.travelers.add(user)
|
||||
travelRepository.save(travel)
|
||||
}
|
||||
|
||||
@@ -11,28 +11,32 @@ class ListTravels(private val travelRepository: TravelRepository) {
|
||||
}
|
||||
|
||||
fun listTravels(
|
||||
filter: String?,
|
||||
sortColumn: String?,
|
||||
sortAscending: Boolean?,
|
||||
pageIndex: Int?,
|
||||
pageSize: Int?
|
||||
filter: String?,
|
||||
sortColumn: String?,
|
||||
sortAscending: Boolean?,
|
||||
pageIndex: Int?,
|
||||
pageSize: Int?
|
||||
): List<Travel> {
|
||||
val sort = if (sortColumn == null) {
|
||||
Sort.unsorted()
|
||||
} else {
|
||||
Sort.by(
|
||||
if (sortAscending != false) Sort.Direction.ASC else Sort.Direction.DESC,
|
||||
sortColumn
|
||||
if (sortAscending != false) Sort.Direction.ASC else Sort.Direction.DESC,
|
||||
sortColumn
|
||||
)
|
||||
}
|
||||
return travelRepository.findByOriginContainingOrDestinationContainingAllIgnoreCase(
|
||||
filter ?: "",
|
||||
filter ?: "",
|
||||
PageRequest.of(
|
||||
pageIndex ?: 0,
|
||||
pageSize ?: 10,
|
||||
sort
|
||||
)
|
||||
filter ?: "",
|
||||
filter ?: "",
|
||||
PageRequest.of(
|
||||
pageIndex ?: 0,
|
||||
pageSize ?: 10,
|
||||
sort
|
||||
)
|
||||
).toList()
|
||||
}
|
||||
|
||||
fun countTravels(filter: String?): Long {
|
||||
return travelRepository.countTravels(filter ?: "")
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,46 @@ package eu.fosil.okupamicoche.usecases.travel
|
||||
import eu.fosil.okupamicoche.entities.Travel
|
||||
import eu.fosil.okupamicoche.entities.UserId
|
||||
import eu.fosil.okupamicoche.repositories.TravelRepository
|
||||
import org.springframework.data.domain.PageRequest
|
||||
import org.springframework.data.domain.Sort
|
||||
|
||||
class ListUserTravels(private val travelRepository: TravelRepository) {
|
||||
fun listUserTravels(idUser: UserId): List<Travel> {
|
||||
return listOf(
|
||||
travelRepository.findUserTravelsAsDriver(idUser),
|
||||
travelRepository.findUserTravelsAsTraveler(idUser)
|
||||
).flatten()
|
||||
return travelRepository.findUserTravels(idUser)
|
||||
}
|
||||
|
||||
fun countUserTravels(idUser: UserId): Long {
|
||||
return travelRepository.countUserTravelsAsDriver(idUser) +
|
||||
travelRepository.countUserTravelsAsTraveler(idUser)
|
||||
return travelRepository.countUserTravels(idUser)
|
||||
}
|
||||
|
||||
fun listUserTravels(
|
||||
userId: UserId,
|
||||
filter: String?,
|
||||
sortColumn: String?,
|
||||
sortAscending: Boolean?,
|
||||
pageIndex: Int?,
|
||||
pageSize: Int?
|
||||
): List<Travel> {
|
||||
val sort = if (sortColumn == null) {
|
||||
Sort.unsorted()
|
||||
} else {
|
||||
Sort.by(
|
||||
if (sortAscending != false) Sort.Direction.ASC else Sort.Direction.DESC,
|
||||
sortColumn
|
||||
)
|
||||
}
|
||||
return travelRepository.findUserTravels(
|
||||
userId,
|
||||
filter ?: "",
|
||||
PageRequest.of(
|
||||
pageIndex ?: 0,
|
||||
pageSize ?: 10,
|
||||
sort
|
||||
)
|
||||
).toList()
|
||||
}
|
||||
|
||||
fun countUserTravels(idUser: UserId, filter: String?): Long {
|
||||
return travelRepository.countUserTravels(idUser, filter ?: "")
|
||||
}
|
||||
}
|
||||
@@ -4,17 +4,24 @@ import eu.fosil.okupamicoche.entities.TravelId
|
||||
import eu.fosil.okupamicoche.entities.UserId
|
||||
import eu.fosil.okupamicoche.repositories.TravelRepository
|
||||
import eu.fosil.okupamicoche.repositories.UserRepository
|
||||
import eu.fosil.okupamicoche.usecases.matrix.MatrixApi
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
|
||||
class RemoveTraveler(
|
||||
private val userRepository: UserRepository,
|
||||
private val travelRepository: TravelRepository
|
||||
private val travelRepository: TravelRepository,
|
||||
private val matrixApi: MatrixApi
|
||||
) {
|
||||
fun removeTraveler(travelId: TravelId, userId: UserId) {
|
||||
suspend fun removeTraveler(travelId: TravelId, userId: UserId, kickFromChat: Boolean = false) {
|
||||
val user = userRepository.findByIdOrNull(userId)
|
||||
val travel = travelRepository.findByIdOrNull(travelId)
|
||||
if ((user != null) && (travel != null)) {
|
||||
travel.travelers.remove(user)
|
||||
|
||||
println("userId=$userId user=$user travel=$travel contains=${travel?.travelers?.contains(user)}")
|
||||
|
||||
val traveler = travel?.travelers?.find { it.id == userId }
|
||||
if ((traveler != null) && (user != null)) {
|
||||
if (kickFromChat) matrixApi.kickUser(travel.matrixRoomId, user)
|
||||
travel.travelers.remove(traveler)
|
||||
travelRepository.save(travel)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,16 +13,21 @@ spring:
|
||||
oauth2:
|
||||
resourceserver:
|
||||
jwt:
|
||||
issuer-uri: http://localhost:8080/auth/realms/okupamicoche
|
||||
issuer-uri: https://okupamicoche-keycloak:8443/auth/realms/okupamicoche
|
||||
jackson:
|
||||
serialization:
|
||||
write-dates-as-timestamps: false
|
||||
|
||||
logging:
|
||||
level:
|
||||
org:
|
||||
springframework: INFO
|
||||
eu.fosil.okupamicoche: DEBUG
|
||||
|
||||
matrix:
|
||||
bot:
|
||||
# The domain-part of matrix-ids. E. g. example.org when your userIds look like @unicorn:example.org
|
||||
serverName: synapse
|
||||
# The domain-part of matrix-ids.E.g. example.org when your userIds look like @unicorn:example.org
|
||||
serverName: okupamicoche-synapse
|
||||
# The localpart (username) of the user associated with the application service
|
||||
# or just the username of your bot.
|
||||
username: okupamicoche
|
||||
@@ -51,7 +56,7 @@ matrix:
|
||||
client:
|
||||
homeServer:
|
||||
# The hostname of your Homeserver.
|
||||
hostname: synapse
|
||||
hostname: okupamicoche-synapse
|
||||
# (optional) The port of your Homeserver. Default is 443.
|
||||
port: 8008
|
||||
# (optional) Use http or https. Default is true (so uses https).
|
||||
|
||||
Reference in New Issue
Block a user