Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 70092efaf5 | |||
| 9c10a88a36 | |||
| 2ee8b80596 | |||
| ee60f5b4e7 | |||
| 10928251e6 | |||
| 9b79301662 | |||
| 32510652d1 | |||
| a6c36c542e | |||
| 7874f5cec4 | |||
| 8ff6fcc970 | |||
| bd123d03e9 | |||
| ac852baaf6 | |||
| 159b9de19a | |||
| e4a85722f1 |
13
.dockerignore
Normal file
13
.dockerignore
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
build
|
||||||
|
out
|
||||||
|
GH_TOKEN.txt
|
||||||
|
Makefile
|
||||||
|
var
|
||||||
|
gradle
|
||||||
|
.idea
|
||||||
|
.gradle
|
||||||
|
docker
|
||||||
|
gradlew
|
||||||
|
gradlew.bat
|
||||||
|
docker-compose.yml
|
||||||
|
src/test
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,3 +7,5 @@
|
|||||||
*.iws
|
*.iws
|
||||||
dcproject.iml
|
dcproject.iml
|
||||||
/var
|
/var
|
||||||
|
GH_TOKEN.txt
|
||||||
|
allSQL.sql
|
||||||
@@ -14,8 +14,6 @@
|
|||||||
<option name="sourceFilePath" value="docker-compose.yml" />
|
<option name="sourceFilePath" value="docker-compose.yml" />
|
||||||
</settings>
|
</settings>
|
||||||
</deployment>
|
</deployment>
|
||||||
<method v="2">
|
<method v="2" />
|
||||||
<option name="Gradle.BeforeRunTask" enabled="true" tasks="build" externalProjectPath="$PROJECT_DIR$" vmOptions="" scriptParameters="" />
|
|
||||||
</method>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
48
Makefile
Normal file
48
Makefile
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
.EXPORT_ALL_VARIABLES:
|
||||||
|
VERSION=$(shell ./hook/version.sh)
|
||||||
|
GITHUB_USERNAME=$(shell git config user.email)
|
||||||
|
GITHUB_TOKEN=$(shell cat ./GH_TOKEN.txt)
|
||||||
|
|
||||||
|
# HELP
|
||||||
|
# This will output the help for each task
|
||||||
|
# thanks to https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
|
||||||
|
.PHONY: help
|
||||||
|
|
||||||
|
help: ## This help.
|
||||||
|
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := help
|
||||||
|
|
||||||
|
bd: build-docker
|
||||||
|
|
||||||
|
build-docker: ## Build the docker image of application
|
||||||
|
docker build -t dc-project -f docker/app/Dockerfile .
|
||||||
|
|
||||||
|
pd: publish-docker
|
||||||
|
|
||||||
|
publish-docker: build-docker ## Publish docker image of application to Github
|
||||||
|
git diff --quiet --exit-code || (echo "The git is DIRTY !!! You cannot publish this crap!" && exit 1)
|
||||||
|
cat ./GH_TOKEN.txt | docker login docker.pkg.github.com -u ${GITHUB_USERNAME} --password-stdin
|
||||||
|
docker tag dc-project docker.pkg.github.com/flecomte/dc-project/dc-project:${VERSION}
|
||||||
|
docker push docker.pkg.github.com/flecomte/dc-project/dc-project:${VERSION}
|
||||||
|
|
||||||
|
rd: run-docker
|
||||||
|
|
||||||
|
run-docker: ## Build and Run all docker services
|
||||||
|
docker-compose up -d --build
|
||||||
|
|
||||||
|
pm: publish-maven
|
||||||
|
|
||||||
|
publish-maven: ## Publish JAR file to Github
|
||||||
|
@git diff --quiet --exit-code || (echo "The git is DIRTY !!! You cannot publish this crap!" && exit 1)
|
||||||
|
gradlew publish
|
||||||
|
|
||||||
|
f: fixtures
|
||||||
|
|
||||||
|
fixtures: ## Import fixtures
|
||||||
|
bash src/main/resources/sql/fixtures/fixtures.sh
|
||||||
|
|
||||||
|
v: vertion
|
||||||
|
|
||||||
|
vertion: ## Show current version
|
||||||
|
@echo ${VERSION}
|
||||||
42
README.md
Normal file
42
README.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# DC Project
|
||||||
|
|
||||||
|
## Installation of Development environment
|
||||||
|
### On windows
|
||||||
|
1. Install git
|
||||||
|
- Download and install: https://git-scm.com/download/win
|
||||||
|
2. Install Make
|
||||||
|
- Go to [ezwinports](https://sourceforge.net/projects/ezwinports/files/).
|
||||||
|
- Download `make-4.1-2-without-guile-w32-bin.zip` (get the version without guile).
|
||||||
|
- Extract zip.
|
||||||
|
- Copy the contents to your `Git\mingw64\` merging the folders, but **do NOT overwrite/replace** any existing files.
|
||||||
|
|
||||||
|
### Add JAVA_HOME path
|
||||||
|
In CMD (Not Powershell)
|
||||||
|
```cmd
|
||||||
|
$ setx -m JAVA_HOME "C:\Users\%USERNAME%\.jdks\corretto-11.0.7"
|
||||||
|
$ setx -m PATH "%PATH%;%JAVA_HOME%\bin";
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run dockers
|
||||||
|
```bash
|
||||||
|
$ make run-docker
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add fixtures
|
||||||
|
```bash
|
||||||
|
$ make fixtures
|
||||||
|
```
|
||||||
|
|
||||||
|
## Publish package
|
||||||
|
1. Got to [https://github.com](https://github.com/settings/tokens/new) and create a new token with packages scopes
|
||||||
|
2. Create a file `GH_TOKEN.txt` and put it the github token
|
||||||
|
|
||||||
|
### Maven
|
||||||
|
```bash
|
||||||
|
$ make publish-maven
|
||||||
|
```
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ make publish-docker
|
||||||
|
```
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
import org.owasp.dependencycheck.reporting.ReportGenerator
|
import org.owasp.dependencycheck.reporting.ReportGenerator
|
||||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
val ktor_version: String by project
|
val ktor_version: String by project
|
||||||
val kotlin_version: String by project
|
val kotlin_version: String by project
|
||||||
@@ -11,7 +12,13 @@ val jackson_version: String by project
|
|||||||
val cucumber_version: String by project
|
val cucumber_version: String by project
|
||||||
|
|
||||||
group = "com.github.flecomte"
|
group = "com.github.flecomte"
|
||||||
version = "0.0.1"
|
version = versioning.info.run {
|
||||||
|
if (dirty) {
|
||||||
|
versioning.info.full
|
||||||
|
} else {
|
||||||
|
versioning.info.lastTag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
jacoco
|
jacoco
|
||||||
@@ -24,6 +31,7 @@ plugins {
|
|||||||
id("org.jlleitschuh.gradle.ktlint") version "8.2.0"
|
id("org.jlleitschuh.gradle.ktlint") version "8.2.0"
|
||||||
id("org.owasp.dependencycheck") version "5.1.0"
|
id("org.owasp.dependencycheck") version "5.1.0"
|
||||||
id("org.sonarqube") version "2.7"
|
id("org.sonarqube") version "2.7"
|
||||||
|
id("net.nemerosa.versioning") version "2.13.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
@@ -48,6 +56,38 @@ tasks.withType<Jar> {
|
|||||||
tasks {
|
tasks {
|
||||||
named<ShadowJar>("shadowJar") {
|
named<ShadowJar>("shadowJar") {
|
||||||
mergeServiceFiles("META-INF/services")
|
mergeServiceFiles("META-INF/services")
|
||||||
|
archiveFileName.set("${archiveBaseName.get()}-latest-all.${archiveExtension.get()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val sourcesJar by tasks.creating(Jar::class) {
|
||||||
|
archiveClassifier.set("sources")
|
||||||
|
from(sourceSets.getByName("main").allSource)
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
if (versioning.info.dirty == false) {
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
name = "dc-project"
|
||||||
|
group = "com.github.flecomte"
|
||||||
|
url = uri("https://maven.pkg.github.com/flecomte/dc-project")
|
||||||
|
credentials {
|
||||||
|
username = System.getenv("GITHUB_USERNAME")
|
||||||
|
password = System.getenv("GITHUB_TOKEN")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publications {
|
||||||
|
create<MavenPublication>("dc-project") {
|
||||||
|
from(components["java"])
|
||||||
|
artifact(sourcesJar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LoggerFactory.getLogger("gradle")
|
||||||
|
.warn("The git is DIRTY !!! You cannot publish this crap! (${versioning.info.full})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,12 +32,14 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- ${REDIS_PORT}:6379
|
- ${REDIS_PORT}:6379
|
||||||
|
volumes:
|
||||||
|
- redis-data:/var/lib/redis:rw
|
||||||
|
|
||||||
app:
|
app:
|
||||||
container_name: app_${NAME}
|
container_name: app_${NAME}
|
||||||
build:
|
build:
|
||||||
context: ./build
|
context: .
|
||||||
dockerfile: ../docker/app/Dockerfile
|
dockerfile: docker/app/Dockerfile
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- ${APP_PORT}:8080
|
- ${APP_PORT}:8080
|
||||||
@@ -60,8 +62,12 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- ${ELASTIC_REST}:9200
|
- ${ELASTIC_REST}:9200
|
||||||
- ${ELASTIC_NODES}:9300
|
- ${ELASTIC_NODES}:9300
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://elasticsearch:9200"]
|
||||||
|
interval: 3s
|
||||||
|
timeout: 2s
|
||||||
|
retries: 20
|
||||||
|
|
||||||
# Database
|
|
||||||
db:
|
db:
|
||||||
container_name: postgresql_${NAME}
|
container_name: postgresql_${NAME}
|
||||||
build:
|
build:
|
||||||
@@ -75,11 +81,15 @@ services:
|
|||||||
POSTGRES_DB: ${DB_PWD}
|
POSTGRES_DB: ${DB_PWD}
|
||||||
volumes:
|
volumes:
|
||||||
- ./var/log/postgresql:/var/log/postgresql:rw
|
- ./var/log/postgresql:/var/log/postgresql:rw
|
||||||
- ./var/postgresql/data:/var/lib/postgresql/data:rw
|
- db-data:/var/lib/postgresql/data:rw
|
||||||
depends_on:
|
depends_on:
|
||||||
- elasticsearch
|
- elasticsearch
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://elasticsearch:9200/"]
|
test: [ "CMD", "pg_isready", "-q", "-d", "${DB_NAME}", "-U", "${DB_USER}" ]
|
||||||
interval: 3s
|
interval: 3s
|
||||||
timeout: 2s
|
timeout: 2s
|
||||||
retries: 20
|
retries: 20
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db-data:
|
||||||
|
redis-data:
|
||||||
@@ -1,5 +1,12 @@
|
|||||||
FROM adoptopenjdk/openjdk11:jre-11.0.4_11-alpine
|
#### BUILD ####
|
||||||
|
FROM gradle:5.6.4-jdk11 AS build
|
||||||
|
COPY --chown=gradle:gradle . /home/gradle/src
|
||||||
|
|
||||||
|
WORKDIR /home/gradle/src
|
||||||
|
RUN gradle build -x test -x ktlintKotlinScriptCheck -x ktlintTestSourceSetCheck -x ktlintMainSourceSetCheck --no-daemon
|
||||||
|
|
||||||
|
#### RUN ####
|
||||||
|
FROM adoptopenjdk/openjdk11:jre-11.0.4_11-alpine
|
||||||
ENV APPLICATION_USER ktor
|
ENV APPLICATION_USER ktor
|
||||||
RUN adduser -D -g '' $APPLICATION_USER
|
RUN adduser -D -g '' $APPLICATION_USER
|
||||||
|
|
||||||
@@ -8,7 +15,7 @@ RUN chown -R $APPLICATION_USER /app
|
|||||||
|
|
||||||
USER $APPLICATION_USER
|
USER $APPLICATION_USER
|
||||||
|
|
||||||
COPY ./libs/dcproject-0.0.1-all.jar /app/dcproject.jar
|
COPY --from=build /home/gradle/src/build/libs/dcproject-latest-all.jar /app/dcproject.jar
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
CMD ["java", "-server", "-XX:+UnlockExperimentalVMOptions", "-XX:InitialRAMFraction=2", "-XX:MinRAMFraction=2", "-XX:MaxRAMFraction=2", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=100", "-XX:+UseStringDeduplication", "-jar", "dcproject.jar"]
|
CMD ["java", "-server", "-XX:+UnlockExperimentalVMOptions", "-XX:InitialRAMFraction=2", "-XX:MinRAMFraction=2", "-XX:MaxRAMFraction=2", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=100", "-XX:+UseStringDeduplication", "-jar", "dcproject.jar"]
|
||||||
|
|||||||
12
hook/version.sh
Normal file
12
hook/version.sh
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ $(git describe --tags --dirty) =~ ^V?([0-9][0-9.]*(-dirty)?)$ ]]; then
|
||||||
|
VERSION="${BASH_REMATCH[1]}"
|
||||||
|
elif [[ $(git describe --tags --dirty) =~ ^V?([0-9][0-9.]*)-([0-9]+)-g(.+(-dirty)?)$ ]]; then
|
||||||
|
VERSION="${BASH_REMATCH[1]}-${BASH_REMATCH[3]}"
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $VERSION
|
||||||
@@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.SerializationFeature
|
|||||||
import com.fasterxml.jackson.datatype.joda.JodaModule
|
import com.fasterxml.jackson.datatype.joda.JodaModule
|
||||||
import com.github.jasync.sql.db.postgresql.exceptions.GenericDatabaseException
|
import com.github.jasync.sql.db.postgresql.exceptions.GenericDatabaseException
|
||||||
import fr.dcproject.Env.PROD
|
import fr.dcproject.Env.PROD
|
||||||
|
import fr.dcproject.elasticsearch.configElasticIndexes
|
||||||
import fr.dcproject.entity.*
|
import fr.dcproject.entity.*
|
||||||
import fr.dcproject.event.EventNotification
|
import fr.dcproject.event.EventNotification
|
||||||
import fr.dcproject.event.EventSubscriber
|
import fr.dcproject.event.EventSubscriber
|
||||||
@@ -38,8 +39,6 @@ import io.ktor.routing.Routing
|
|||||||
import io.ktor.util.KtorExperimentalAPI
|
import io.ktor.util.KtorExperimentalAPI
|
||||||
import io.ktor.websocket.WebSockets
|
import io.ktor.websocket.WebSockets
|
||||||
import org.eclipse.jetty.util.log.Slf4jLog
|
import org.eclipse.jetty.util.log.Slf4jLog
|
||||||
import org.elasticsearch.client.Request
|
|
||||||
import org.elasticsearch.client.RestClient
|
|
||||||
import org.koin.core.qualifier.named
|
import org.koin.core.qualifier.named
|
||||||
import org.koin.ktor.ext.Koin
|
import org.koin.ktor.ext.Koin
|
||||||
import org.koin.ktor.ext.get
|
import org.koin.ktor.ext.get
|
||||||
@@ -131,7 +130,7 @@ fun Application.module(env: Env = PROD) {
|
|||||||
decode { values, _ ->
|
decode { values, _ ->
|
||||||
val id = values.singleOrNull()?.let { UUID.fromString(it) }
|
val id = values.singleOrNull()?.let { UUID.fromString(it) }
|
||||||
?: throw InternalError("Cannot convert $values to UUID")
|
?: throw InternalError("Cannot convert $values to UUID")
|
||||||
get<RepositoryCitizen>().findById(id, true) ?: throw NotFoundException("Citizen $values not found")
|
get<RepositoryCitizen>().findById(id) ?: throw NotFoundException("Citizen $values not found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,56 +191,7 @@ fun Application.module(env: Env = PROD) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create index if not exist */
|
configElasticIndexes(get())
|
||||||
get<RestClient>().run {
|
|
||||||
if (performRequest(Request("HEAD", "/views?include_type_name=false")).statusLine.statusCode == 404) {
|
|
||||||
Request(
|
|
||||||
"PUT",
|
|
||||||
"/views?include_type_name=false"
|
|
||||||
).apply {
|
|
||||||
//language=JSON
|
|
||||||
setJsonEntity(
|
|
||||||
"""
|
|
||||||
{
|
|
||||||
"settings": {
|
|
||||||
"number_of_shards": 5
|
|
||||||
},
|
|
||||||
"mappings": {
|
|
||||||
"properties": {
|
|
||||||
"logged": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"user_ref": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"version_id": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"ip": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"citizen_id": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"view_at": {
|
|
||||||
"type": "date"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
}.let {
|
|
||||||
performRequest(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
install(WebSockets) {
|
install(WebSockets) {
|
||||||
pingPeriod = Duration.ofSeconds(60) // Disabled (null) by default
|
pingPeriod = Duration.ofSeconds(60) // Disabled (null) by default
|
||||||
|
|||||||
83
src/main/kotlin/elasticsearch/Config.kt
Normal file
83
src/main/kotlin/elasticsearch/Config.kt
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package fr.dcproject.elasticsearch
|
||||||
|
|
||||||
|
import org.elasticsearch.client.Request
|
||||||
|
import org.elasticsearch.client.RestClient
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
|
fun waitElasticsearchIsUp(client: RestClient) {
|
||||||
|
val logger: Logger = LoggerFactory.getLogger("fr.dcproject.elasticsearch")
|
||||||
|
val request = Request("GET", "/_cluster/health")
|
||||||
|
repeat(40) {
|
||||||
|
runCatching {
|
||||||
|
client.performRequest(request).statusLine.statusCode
|
||||||
|
}.onSuccess {
|
||||||
|
if (it == 200) {
|
||||||
|
logger.debug("Elasticsearch is Ready! Continue...")
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
logger.debug("sleep 2s and retry...")
|
||||||
|
Thread.sleep(2000)
|
||||||
|
}
|
||||||
|
}.onFailure {
|
||||||
|
logger.debug("${it.message}, sleep 2s and retry...")
|
||||||
|
Thread.sleep(2000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error("Elasticsearch is not ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun configElasticIndexes(client: RestClient) {
|
||||||
|
waitElasticsearchIsUp(client)
|
||||||
|
|
||||||
|
/* Create index if not exist */
|
||||||
|
client.run {
|
||||||
|
if (performRequest(Request("HEAD", "/views?include_type_name=false")).statusLine.statusCode == 404) {
|
||||||
|
Request(
|
||||||
|
"PUT",
|
||||||
|
"/views?include_type_name=false"
|
||||||
|
).apply {
|
||||||
|
//language=JSON
|
||||||
|
setJsonEntity(
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"settings": {
|
||||||
|
"number_of_shards": 5
|
||||||
|
},
|
||||||
|
"mappings": {
|
||||||
|
"properties": {
|
||||||
|
"logged": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"user_ref": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"version_id": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"ip": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"citizen_id": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"view_at": {
|
||||||
|
"type": "date"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}.let {
|
||||||
|
performRequest(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,12 @@ class Citizen(
|
|||||||
) : CitizenFull,
|
) : CitizenFull,
|
||||||
CitizenBasic(id, name, email, birthday, voteAnonymous, followAnonymous, user),
|
CitizenBasic(id, name, email, birthday, voteAnonymous, followAnonymous, user),
|
||||||
EntityCreatedAt by EntityCreatedAtImp() {
|
EntityCreatedAt by EntityCreatedAtImp() {
|
||||||
var workgroups: List<WorkgroupSimple<CitizenRef>> = emptyList()
|
var workgroups: List<WorkgroupAndRoles> = emptyList()
|
||||||
|
|
||||||
|
class WorkgroupAndRoles(
|
||||||
|
val roles: List<String>,
|
||||||
|
val workgroup: WorkgroupSimple<CitizenRef>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
open class CitizenBasic(
|
open class CitizenBasic(
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package fr.dcproject.entity
|
package fr.dcproject.entity
|
||||||
|
|
||||||
|
import fr.dcproject.entity.WorkgroupWithMembersI.Member
|
||||||
|
import fr.dcproject.entity.WorkgroupWithMembersI.Member.Role
|
||||||
|
import fr.postgresjson.entity.EntityI
|
||||||
import fr.postgresjson.entity.immutable.*
|
import fr.postgresjson.entity.immutable.*
|
||||||
import fr.postgresjson.entity.mutable.EntityDeletedAt
|
import fr.postgresjson.entity.mutable.EntityDeletedAt
|
||||||
import fr.postgresjson.entity.mutable.EntityDeletedAtImp
|
import fr.postgresjson.entity.mutable.EntityDeletedAtImp
|
||||||
@@ -11,9 +14,8 @@ class Workgroup(
|
|||||||
description: String,
|
description: String,
|
||||||
logo: String? = null,
|
logo: String? = null,
|
||||||
anonymous: Boolean = true,
|
anonymous: Boolean = true,
|
||||||
owner: CitizenBasic,
|
|
||||||
createdBy: CitizenBasic,
|
createdBy: CitizenBasic,
|
||||||
override var members: List<CitizenBasic> = emptyList()
|
override var members: List<Member<CitizenBasic>> = emptyList()
|
||||||
) : WorkgroupWithAuthI<CitizenBasic>,
|
) : WorkgroupWithAuthI<CitizenBasic>,
|
||||||
WorkgroupSimple<CitizenBasic>(
|
WorkgroupSimple<CitizenBasic>(
|
||||||
id,
|
id,
|
||||||
@@ -21,7 +23,6 @@ class Workgroup(
|
|||||||
description,
|
description,
|
||||||
logo,
|
logo,
|
||||||
anonymous,
|
anonymous,
|
||||||
owner,
|
|
||||||
createdBy
|
createdBy
|
||||||
),
|
),
|
||||||
EntityCreatedAt by EntityCreatedAtImp(),
|
EntityCreatedAt by EntityCreatedAtImp(),
|
||||||
@@ -33,7 +34,6 @@ open class WorkgroupSimple<Z : CitizenRef>(
|
|||||||
var description: String,
|
var description: String,
|
||||||
var logo: String? = null,
|
var logo: String? = null,
|
||||||
var anonymous: Boolean = true,
|
var anonymous: Boolean = true,
|
||||||
var owner: Z,
|
|
||||||
createdBy: Z
|
createdBy: Z
|
||||||
) : WorkgroupRef(id),
|
) : WorkgroupRef(id),
|
||||||
EntityCreatedBy<Z> by EntityCreatedByImp(createdBy),
|
EntityCreatedBy<Z> by EntityCreatedByImp(createdBy),
|
||||||
@@ -45,19 +45,51 @@ open class WorkgroupRef(
|
|||||||
|
|
||||||
interface WorkgroupWithAuthI<Z : CitizenWithUserI> : WorkgroupWithMembersI<Z>, EntityCreatedBy<Z>, EntityDeletedAt {
|
interface WorkgroupWithAuthI<Z : CitizenWithUserI> : WorkgroupWithMembersI<Z>, EntityCreatedBy<Z>, EntityDeletedAt {
|
||||||
val anonymous: Boolean
|
val anonymous: Boolean
|
||||||
val owner: Z
|
|
||||||
|
|
||||||
fun isMember(user: UserI): Boolean =
|
fun isMember(user: UserI): Boolean = members.isMember(user)
|
||||||
members.map { it.user.id }.contains(user.id) || owner.user.id == user.id
|
fun isMember(citizen: CitizenWithUserI): Boolean = members.isMember(citizen)
|
||||||
|
|
||||||
fun isMember(citizen: CitizenWithUserI): Boolean =
|
fun hasRole(expectedRole: Role, user: UserI): Boolean = members.hasRole(expectedRole, user)
|
||||||
isMember(citizen.user)
|
fun hasRole(expectedRole: Role, citizen: CitizenI): Boolean = members.hasRole(expectedRole, citizen)
|
||||||
|
|
||||||
|
fun getRoles(user: UserI): List<Role> = members.getRoles(user)
|
||||||
|
fun getRoles(citizen: CitizenI): List<Role> = members.getRoles(citizen)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WorkgroupWithMembersI<Z : CitizenI> : WorkgroupI {
|
interface WorkgroupWithMembersI<Z : CitizenI> : WorkgroupI {
|
||||||
var members: List<Z>
|
var members: List<Member<Z>>
|
||||||
|
|
||||||
|
class Member<C : CitizenI> (
|
||||||
|
val citizen: C,
|
||||||
|
val roles: List<Role> = emptyList()
|
||||||
|
) : EntityI {
|
||||||
|
enum class Role {
|
||||||
|
MASTER,
|
||||||
|
MANAGER,
|
||||||
|
EDITOR,
|
||||||
|
REPORTER
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun List<CitizenI>.asCitizen(citizen: CitizenI): Boolean = this.map { it.id }.contains(citizen.id)
|
fun List<CitizenI>.hasCitizen(citizen: CitizenI): Boolean = this.map { it.id }.contains(citizen.id)
|
||||||
|
|
||||||
|
fun <Z : CitizenWithUserI> List<Member<Z>>.isMember(user: UserI): Boolean =
|
||||||
|
map { it.citizen.user.id }.contains(user.id)
|
||||||
|
|
||||||
|
fun <Z : CitizenI> List<Member<Z>>.isMember(citizen: CitizenI): Boolean =
|
||||||
|
map { it.citizen.id }.contains(citizen.id)
|
||||||
|
|
||||||
|
fun <Z : CitizenI> List<Member<Z>>.hasRole(expectedRole: Role, citizen: CitizenI): Boolean =
|
||||||
|
any { member -> member.citizen.id == citizen.id && member.roles.any { it == expectedRole } }
|
||||||
|
|
||||||
|
fun <Z : CitizenWithUserI> List<Member<Z>>.hasRole(expectedRole: Role, user: UserI): Boolean =
|
||||||
|
any { member -> member.citizen.user.id == user.id && member.roles.any { it == expectedRole } }
|
||||||
|
|
||||||
|
fun <Z : CitizenWithUserI> List<Member<Z>>.getRoles(user: UserI): List<Role> =
|
||||||
|
firstOrNull { it.citizen.user.id == user.id }?.roles ?: emptyList()
|
||||||
|
|
||||||
|
fun <Z : CitizenWithUserI> List<Member<Z>>.getRoles(citizen: CitizenI): List<Role> =
|
||||||
|
firstOrNull { it.citizen.id == citizen.id }?.roles ?: emptyList()
|
||||||
|
|
||||||
interface WorkgroupI : UuidEntityI
|
interface WorkgroupI : UuidEntityI
|
||||||
@@ -12,29 +12,21 @@ import java.util.*
|
|||||||
import fr.dcproject.entity.Citizen as CitizenEntity
|
import fr.dcproject.entity.Citizen as CitizenEntity
|
||||||
|
|
||||||
class Citizen(override var requester: Requester) : RepositoryI {
|
class Citizen(override var requester: Requester) : RepositoryI {
|
||||||
fun findById(id: UUID, withUser: Boolean = false): CitizenEntity? {
|
fun findById(id: UUID): CitizenEntity? = requester
|
||||||
return requester
|
.getFunction("find_citizen_by_id_with_user_and_workgroups")
|
||||||
.getFunction(if (withUser) "find_citizen_by_id_with_user" else "find_citizen_by_id")
|
|
||||||
.selectOne("id" to id)
|
.selectOne("id" to id)
|
||||||
}
|
|
||||||
|
|
||||||
fun findByUser(user: UserI): CitizenEntity? {
|
fun findByUser(user: UserI): CitizenEntity? = requester
|
||||||
return requester
|
|
||||||
.getFunction("find_citizen_by_user_id")
|
.getFunction("find_citizen_by_user_id")
|
||||||
.selectOne("user_id" to user.id)
|
.selectOne("user_id" to user.id)
|
||||||
}
|
|
||||||
|
|
||||||
fun findByUsername(unsername: String): CitizenEntity? {
|
fun findByUsername(unsername: String): CitizenEntity? = requester
|
||||||
return requester
|
|
||||||
.getFunction("find_citizen_by_username")
|
.getFunction("find_citizen_by_username")
|
||||||
.selectOne("username" to unsername)
|
.selectOne("username" to unsername)
|
||||||
}
|
|
||||||
|
|
||||||
fun findByEmail(email: String): CitizenEntity? {
|
fun findByEmail(email: String): CitizenEntity? = requester
|
||||||
return requester
|
|
||||||
.getFunction("find_citizen_by_email")
|
.getFunction("find_citizen_by_email")
|
||||||
.selectOne("email" to email)
|
.selectOne("email" to email)
|
||||||
}
|
|
||||||
|
|
||||||
fun find(
|
fun find(
|
||||||
page: Int = 1,
|
page: Int = 1,
|
||||||
@@ -42,8 +34,7 @@ class Citizen(override var requester: Requester) : RepositoryI {
|
|||||||
sort: String? = null,
|
sort: String? = null,
|
||||||
direction: Direction? = null,
|
direction: Direction? = null,
|
||||||
search: String? = null
|
search: String? = null
|
||||||
): Paginated<CitizenBasic> {
|
): Paginated<CitizenBasic> = requester
|
||||||
return requester
|
|
||||||
.getFunction("find_citizens")
|
.getFunction("find_citizens")
|
||||||
.select(
|
.select(
|
||||||
page, limit,
|
page, limit,
|
||||||
@@ -51,17 +42,12 @@ class Citizen(override var requester: Requester) : RepositoryI {
|
|||||||
"direction" to direction,
|
"direction" to direction,
|
||||||
"search" to search
|
"search" to search
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
fun upsert(citizen: CitizenFull): CitizenEntity? {
|
fun upsert(citizen: CitizenFull): CitizenEntity? = requester
|
||||||
return requester
|
|
||||||
.getFunction("upsert_citizen")
|
.getFunction("upsert_citizen")
|
||||||
.selectOne("resource" to citizen)
|
.selectOne("resource" to citizen)
|
||||||
}
|
|
||||||
|
|
||||||
fun insertWithUser(citizen: CitizenFull): CitizenEntity? {
|
fun insertWithUser(citizen: CitizenFull): CitizenEntity? = requester
|
||||||
return requester
|
|
||||||
.getFunction("insert_citizen_with_user")
|
.getFunction("insert_citizen_with_user")
|
||||||
.selectOne("resource" to citizen)
|
.selectOne("resource" to citizen)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package fr.dcproject.repository
|
package fr.dcproject.repository
|
||||||
|
|
||||||
import fr.dcproject.entity.*
|
import fr.dcproject.entity.*
|
||||||
|
import fr.dcproject.entity.WorkgroupWithMembersI.Member
|
||||||
import fr.postgresjson.connexion.Paginated
|
import fr.postgresjson.connexion.Paginated
|
||||||
import fr.postgresjson.connexion.Requester
|
import fr.postgresjson.connexion.Requester
|
||||||
import fr.postgresjson.entity.Parameter
|
import fr.postgresjson.entity.Parameter
|
||||||
@@ -44,36 +45,43 @@ class Workgroup(override var requester: Requester) : RepositoryI {
|
|||||||
.getFunction("delete_workgroup")
|
.getFunction("delete_workgroup")
|
||||||
.perform("id" to workgroup.id)
|
.perform("id" to workgroup.id)
|
||||||
|
|
||||||
fun addMember(workgroup: WorkgroupI, member: CitizenI): List<CitizenBasic> =
|
fun addMember(workgroup: WorkgroupI, member: Member<CitizenI>): Member<CitizenBasic>? =
|
||||||
addMembers(workgroup, listOf(member))
|
addMember(workgroup, member.citizen, member.roles)
|
||||||
|
|
||||||
fun addMembers(workgroup: WorkgroupI, members: List<CitizenI>): List<CitizenBasic> = requester
|
fun addMember(workgroup: WorkgroupI, citizen: CitizenI, roles: List<Member.Role>): Member<CitizenBasic>? = requester
|
||||||
|
.getFunction("add_workgroup_member")
|
||||||
|
.selectOne(
|
||||||
|
"id" to workgroup.id,
|
||||||
|
"members" to Member(citizen, roles).serialize()
|
||||||
|
)
|
||||||
|
|
||||||
|
fun <Z : CitizenI> addMembers(workgroup: WorkgroupI, members: List<Member<Z>>): List<Member<CitizenBasic>> = requester
|
||||||
.getFunction("add_workgroup_members")
|
.getFunction("add_workgroup_members")
|
||||||
.select(
|
.select(
|
||||||
"id" to workgroup.id,
|
"id" to workgroup.id,
|
||||||
"resource" to members.serialize()
|
"members" to members.serialize()
|
||||||
)
|
)
|
||||||
|
|
||||||
fun removeMember(workgroup: WorkgroupI, memberToDelete: CitizenI): List<CitizenBasic> =
|
fun <Z : CitizenI> removeMember(workgroup: WorkgroupI, memberToDelete: Member<Z>): List<Member<CitizenBasic>> =
|
||||||
removeMembers(workgroup, listOf(memberToDelete))
|
removeMembers(workgroup, listOf(memberToDelete))
|
||||||
|
|
||||||
fun removeMembers(workgroup: WorkgroupI, membersToDelete: List<CitizenI>): List<CitizenBasic> = requester
|
fun <Z : CitizenI> removeMembers(workgroup: WorkgroupI, membersToDelete: List<Member<Z>>): List<Member<CitizenBasic>> = requester
|
||||||
.getFunction("remove_workgroup_members")
|
.getFunction("remove_workgroup_members")
|
||||||
.select(
|
.select(
|
||||||
"id" to workgroup.id,
|
"id" to workgroup.id,
|
||||||
"resource" to membersToDelete
|
"members" to membersToDelete
|
||||||
)
|
)
|
||||||
|
|
||||||
fun updateMembers(workgroup: WorkgroupI, members: List<CitizenI>): List<CitizenBasic> = requester
|
fun <Z : CitizenI> updateMembers(workgroup: WorkgroupI, members: List<Member<Z>>): List<Member<CitizenBasic>> = requester
|
||||||
.getFunction("update_workgroup_members")
|
.getFunction("update_workgroup_members")
|
||||||
.select(
|
.select(
|
||||||
"id" to workgroup.id,
|
"id" to workgroup.id,
|
||||||
"resource" to members
|
"members" to members
|
||||||
)
|
)
|
||||||
|
|
||||||
fun <W : WorkgroupWithMembersI<CitizenI>> updateMembers(workgroup: W): W {
|
fun <W : WorkgroupWithMembersI<Z>, Z : CitizenI> updateMembers(workgroup: W): W {
|
||||||
updateMembers(workgroup, workgroup.members).let {
|
updateMembers(workgroup, workgroup.members).let {
|
||||||
workgroup.members = it
|
workgroup.members = it as List<Member<Z>>
|
||||||
}
|
}
|
||||||
|
|
||||||
return workgroup
|
return workgroup
|
||||||
|
|||||||
@@ -3,31 +3,27 @@ package fr.dcproject.routes
|
|||||||
import fr.dcproject.citizen
|
import fr.dcproject.citizen
|
||||||
import fr.dcproject.entity.CitizenRef
|
import fr.dcproject.entity.CitizenRef
|
||||||
import fr.dcproject.entity.WorkgroupSimple
|
import fr.dcproject.entity.WorkgroupSimple
|
||||||
|
import fr.dcproject.entity.WorkgroupWithMembersI.Member
|
||||||
|
import fr.dcproject.entity.WorkgroupWithMembersI.Member.Role
|
||||||
import fr.dcproject.repository.Workgroup.Filter
|
import fr.dcproject.repository.Workgroup.Filter
|
||||||
import fr.dcproject.security.voter.WorkgroupVoter.Action.VIEW
|
|
||||||
import fr.dcproject.security.voter.WorkgroupVoter.Action.CREATE
|
import fr.dcproject.security.voter.WorkgroupVoter.Action.CREATE
|
||||||
import fr.dcproject.security.voter.WorkgroupVoter.Action.UPDATE
|
import fr.dcproject.security.voter.WorkgroupVoter.Action.UPDATE
|
||||||
import fr.dcproject.security.voter.WorkgroupVoter.ActionMembers.ADD as ADD_MEMBERS
|
import fr.dcproject.security.voter.WorkgroupVoter.Action.VIEW
|
||||||
import fr.dcproject.security.voter.WorkgroupVoter.ActionMembers.UPDATE as UPDATE_MEMBERS
|
|
||||||
import fr.dcproject.security.voter.WorkgroupVoter.ActionMembers.REMOVE as REMOVE_MEMBERS
|
|
||||||
import fr.ktorVoter.assertCan
|
import fr.ktorVoter.assertCan
|
||||||
import fr.dcproject.utils.toUUID
|
|
||||||
import fr.postgresjson.repository.RepositoryI
|
import fr.postgresjson.repository.RepositoryI
|
||||||
import io.ktor.application.ApplicationCall
|
import io.ktor.application.ApplicationCall
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.locations.KtorExperimentalLocationsAPI
|
import io.ktor.locations.*
|
||||||
import io.ktor.locations.Location
|
|
||||||
import io.ktor.locations.get
|
|
||||||
import io.ktor.locations.post
|
|
||||||
import io.ktor.locations.put
|
|
||||||
import io.ktor.locations.delete
|
|
||||||
import io.ktor.request.receive
|
import io.ktor.request.receive
|
||||||
import io.ktor.response.respond
|
import io.ktor.response.respond
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import fr.dcproject.entity.Workgroup as WorkgroupEntity
|
import fr.dcproject.entity.Workgroup as WorkgroupEntity
|
||||||
import fr.dcproject.repository.Workgroup as WorkgroupRepository
|
import fr.dcproject.repository.Workgroup as WorkgroupRepository
|
||||||
|
import fr.dcproject.security.voter.WorkgroupVoter.ActionMembers.ADD as ADD_MEMBERS
|
||||||
|
import fr.dcproject.security.voter.WorkgroupVoter.ActionMembers.REMOVE as REMOVE_MEMBERS
|
||||||
|
import fr.dcproject.security.voter.WorkgroupVoter.ActionMembers.UPDATE as UPDATE_MEMBERS
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
object WorkgroupsPaths {
|
object WorkgroupsPaths {
|
||||||
@@ -54,8 +50,7 @@ object WorkgroupsPaths {
|
|||||||
val name: String,
|
val name: String,
|
||||||
val description: String,
|
val description: String,
|
||||||
val logo: String?,
|
val logo: String?,
|
||||||
val anonymous: Boolean?,
|
val anonymous: Boolean?
|
||||||
val owner: UUID?
|
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun getNewWorkgroup(call: ApplicationCall): WorkgroupSimple<CitizenRef> = call.receive<Body>().run {
|
suspend fun getNewWorkgroup(call: ApplicationCall): WorkgroupSimple<CitizenRef> = call.receive<Body>().run {
|
||||||
@@ -65,7 +60,6 @@ object WorkgroupsPaths {
|
|||||||
description,
|
description,
|
||||||
logo,
|
logo,
|
||||||
anonymous ?: true,
|
anonymous ?: true,
|
||||||
owner?.let { CitizenRef(it) } ?: call.citizen,
|
|
||||||
call.citizen
|
call.citizen
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -77,8 +71,7 @@ object WorkgroupsPaths {
|
|||||||
val name: String?,
|
val name: String?,
|
||||||
val description: String?,
|
val description: String?,
|
||||||
val logo: String?,
|
val logo: String?,
|
||||||
val anonymous: Boolean?,
|
val anonymous: Boolean?
|
||||||
val owner: UUID?
|
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun updateWorkgroup(call: ApplicationCall): Unit = call.receive<Body>().run {
|
suspend fun updateWorkgroup(call: ApplicationCall): Unit = call.receive<Body>().run {
|
||||||
@@ -98,13 +91,18 @@ object WorkgroupsMembersPaths {
|
|||||||
@Location("/workgroups/{workgroup}/members")
|
@Location("/workgroups/{workgroup}/members")
|
||||||
class WorkgroupsMembersRequest(val workgroup: WorkgroupEntity) {
|
class WorkgroupsMembersRequest(val workgroup: WorkgroupEntity) {
|
||||||
class Body : MutableList<Body.Item> by mutableListOf() {
|
class Body : MutableList<Body.Item> by mutableListOf() {
|
||||||
class Item(id: String) {
|
class Item(val citizen: CitizenRef, roles: List<String> = emptyList()) {
|
||||||
val id = id.toUUID()
|
val roles: List<Role> = roles.map {
|
||||||
|
Role.valueOf(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getMembers(call: ApplicationCall): List<CitizenRef> = call.receive<Body>().map {
|
suspend fun getMembers(call: ApplicationCall): List<Member<CitizenRef>> = call.receive<Body>().map {
|
||||||
CitizenRef(it.id)
|
Member(
|
||||||
|
citizen = it.citizen,
|
||||||
|
roles = it.roles
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,8 +153,8 @@ fun Route.workgroup(repo: WorkgroupRepository) {
|
|||||||
.let { members ->
|
.let { members ->
|
||||||
assertCan(ADD_MEMBERS, it.workgroup)
|
assertCan(ADD_MEMBERS, it.workgroup)
|
||||||
repo.addMembers(it.workgroup, members)
|
repo.addMembers(it.workgroup, members)
|
||||||
}.let {
|
}.let { members ->
|
||||||
call.respond(HttpStatusCode.Created, it)
|
call.respond(HttpStatusCode.Created, members)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,8 +164,8 @@ fun Route.workgroup(repo: WorkgroupRepository) {
|
|||||||
.let { members ->
|
.let { members ->
|
||||||
assertCan(REMOVE_MEMBERS, it.workgroup)
|
assertCan(REMOVE_MEMBERS, it.workgroup)
|
||||||
repo.removeMembers(it.workgroup, members)
|
repo.removeMembers(it.workgroup, members)
|
||||||
}.let {
|
}.let { members ->
|
||||||
call.respond(HttpStatusCode.OK, it)
|
call.respond(HttpStatusCode.OK, members)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,8 +175,8 @@ fun Route.workgroup(repo: WorkgroupRepository) {
|
|||||||
.let { members ->
|
.let { members ->
|
||||||
assertCan(UPDATE_MEMBERS, it.workgroup)
|
assertCan(UPDATE_MEMBERS, it.workgroup)
|
||||||
repo.updateMembers(it.workgroup, members)
|
repo.updateMembers(it.workgroup, members)
|
||||||
}.let {
|
}.let { members ->
|
||||||
call.respond(HttpStatusCode.OK, it)
|
call.respond(HttpStatusCode.OK, members)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package fr.dcproject.security.voter
|
package fr.dcproject.security.voter
|
||||||
|
|
||||||
import fr.dcproject.citizenOrNull
|
|
||||||
import fr.dcproject.entity.*
|
import fr.dcproject.entity.*
|
||||||
|
import fr.dcproject.entity.WorkgroupWithMembersI.Member.Role
|
||||||
import fr.dcproject.user
|
import fr.dcproject.user
|
||||||
import fr.ktorVoter.ActionI
|
import fr.ktorVoter.ActionI
|
||||||
import fr.ktorVoter.Vote
|
import fr.ktorVoter.Vote
|
||||||
@@ -46,11 +46,11 @@ class WorkgroupVoter : Voter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (subject is WorkgroupWithAuthI<*>) {
|
if (subject is WorkgroupWithAuthI<*>) {
|
||||||
if (action == Action.DELETE && user is UserI && subject.owner.user.id == user.id) {
|
if (action == Action.DELETE && user is UserI && subject.hasRole(Role.MASTER, user)) {
|
||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == Action.UPDATE && user is UserI && subject.owner.user.id == user.id) {
|
if (action == Action.UPDATE && user is UserI && subject.hasRole(Role.MASTER, user)) {
|
||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,32 +61,29 @@ class WorkgroupVoter : Voter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action == ActionMembers.ADD) {
|
if (action == ActionMembers.ADD) {
|
||||||
val citizen = call.citizenOrNull
|
|
||||||
// TODO create ROLES
|
// TODO create ROLES
|
||||||
return Vote.isGranted {
|
return Vote.isGranted {
|
||||||
citizen != null &&
|
user is UserI &&
|
||||||
subject is WorkgroupWithMembersI<*> &&
|
subject is WorkgroupWithAuthI<*> &&
|
||||||
subject.members.asCitizen(citizen)
|
subject.hasRole(Role.MASTER, user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == ActionMembers.UPDATE) {
|
if (action == ActionMembers.UPDATE) {
|
||||||
val citizen = call.citizenOrNull
|
|
||||||
// TODO create ROLES
|
// TODO create ROLES
|
||||||
return Vote.isGranted {
|
return Vote.isGranted {
|
||||||
citizen != null &&
|
user is UserI &&
|
||||||
subject is WorkgroupWithMembersI<*> &&
|
subject is WorkgroupWithAuthI<*> &&
|
||||||
subject.members.asCitizen(citizen)
|
subject.hasRole(Role.MASTER, user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == ActionMembers.REMOVE) {
|
if (action == ActionMembers.REMOVE) {
|
||||||
val citizen = call.citizenOrNull
|
|
||||||
// TODO create ROLES
|
// TODO create ROLES
|
||||||
return Vote.isGranted {
|
return Vote.isGranted {
|
||||||
citizen != null &&
|
user is UserI &&
|
||||||
subject is WorkgroupWithMembersI<*> &&
|
subject is WorkgroupWithAuthI<*> &&
|
||||||
subject.members.asCitizen(citizen)
|
subject.hasRole(Role.MASTER, user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -844,6 +844,7 @@ paths:
|
|||||||
|
|
||||||
/workgroups:
|
/workgroups:
|
||||||
get:
|
get:
|
||||||
|
summary: Get all Workgroup (Paginated)
|
||||||
security:
|
security:
|
||||||
- {}
|
- {}
|
||||||
- JWTAuth: []
|
- JWTAuth: []
|
||||||
@@ -864,6 +865,7 @@ paths:
|
|||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/WorkgroupSimple'
|
$ref: '#/components/schemas/WorkgroupSimple'
|
||||||
post:
|
post:
|
||||||
|
summary: Create new Workgroup
|
||||||
security:
|
security:
|
||||||
- JWTAuth: []
|
- JWTAuth: []
|
||||||
tags:
|
tags:
|
||||||
@@ -925,6 +927,7 @@ paths:
|
|||||||
parameters:
|
parameters:
|
||||||
- $ref: '#/components/parameters/workgroup'
|
- $ref: '#/components/parameters/workgroup'
|
||||||
get:
|
get:
|
||||||
|
summary: Get one workgroup by ID
|
||||||
security:
|
security:
|
||||||
- {}
|
- {}
|
||||||
- JWTAuth: []
|
- JWTAuth: []
|
||||||
@@ -939,6 +942,7 @@ paths:
|
|||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/Workgroup'
|
- $ref: '#/components/schemas/Workgroup'
|
||||||
put:
|
put:
|
||||||
|
summary: Edit one workgroup
|
||||||
security:
|
security:
|
||||||
- JWTAuth: []
|
- JWTAuth: []
|
||||||
tags:
|
tags:
|
||||||
@@ -993,6 +997,7 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
delete:
|
delete:
|
||||||
|
summary: Delete one workgroup
|
||||||
security:
|
security:
|
||||||
- JWTAuth: []
|
- JWTAuth: []
|
||||||
tags:
|
tags:
|
||||||
@@ -1004,6 +1009,7 @@ paths:
|
|||||||
parameters:
|
parameters:
|
||||||
- $ref: '#/components/parameters/workgroup'
|
- $ref: '#/components/parameters/workgroup'
|
||||||
post:
|
post:
|
||||||
|
summary: Add members to the workgroup
|
||||||
security:
|
security:
|
||||||
- JWTAuth: []
|
- JWTAuth: []
|
||||||
tags:
|
tags:
|
||||||
@@ -1012,24 +1018,16 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: array
|
$ref: '#/components/schemas/MembersRequest'
|
||||||
items:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: 6434f4f9-f570-f22a-c134-8668350651ff
|
|
||||||
responses:
|
responses:
|
||||||
201:
|
201:
|
||||||
description: the list of members
|
description: the list of members
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: array
|
$ref: '#/components/schemas/MembersResponse'
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/CitizenResponse'
|
|
||||||
put:
|
put:
|
||||||
|
summary: Updates ALL members. PLEASE NOTE this removes all members who are not in request!
|
||||||
security:
|
security:
|
||||||
- JWTAuth: []
|
- JWTAuth: []
|
||||||
tags:
|
tags:
|
||||||
@@ -1038,24 +1036,16 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: array
|
$ref: '#/components/schemas/MembersRequest'
|
||||||
items:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: 6434f4f9-f570-f22a-c134-8668350651ff
|
|
||||||
responses:
|
responses:
|
||||||
201:
|
201:
|
||||||
description: the list of members
|
description: the list of members
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: array
|
$ref: '#/components/schemas/MembersResponse'
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/CitizenResponse'
|
|
||||||
delete:
|
delete:
|
||||||
|
summary: Delete members of workgroup
|
||||||
security:
|
security:
|
||||||
- JWTAuth: []
|
- JWTAuth: []
|
||||||
tags:
|
tags:
|
||||||
@@ -1064,23 +1054,14 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: array
|
$ref: '#/components/schemas/MembersRequest'
|
||||||
items:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: 6434f4f9-f570-f22a-c134-8668350651ff
|
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: the list of members
|
description: the list of members
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: array
|
$ref: '#/components/schemas/MembersResponse'
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/CitizenResponse'
|
|
||||||
|
|
||||||
components:
|
components:
|
||||||
responses:
|
responses:
|
||||||
@@ -1708,8 +1689,6 @@ components:
|
|||||||
anonymous:
|
anonymous:
|
||||||
type: boolean
|
type: boolean
|
||||||
example: false
|
example: false
|
||||||
owner:
|
|
||||||
$ref: '#/components/schemas/CitizenResponse'
|
|
||||||
- $ref: '#/components/schemas/CreatedBy'
|
- $ref: '#/components/schemas/CreatedBy'
|
||||||
- $ref: '#/components/schemas/DeletedAt'
|
- $ref: '#/components/schemas/DeletedAt'
|
||||||
Workgroup:
|
Workgroup:
|
||||||
@@ -1719,11 +1698,51 @@ components:
|
|||||||
- type: object
|
- type: object
|
||||||
properties:
|
properties:
|
||||||
members:
|
members:
|
||||||
type: array
|
$ref: '#/components/schemas/MembersResponse'
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/CitizenResponse'
|
|
||||||
- $ref: '#/components/schemas/CreatedAt'
|
- $ref: '#/components/schemas/CreatedAt'
|
||||||
- $ref: '#/components/schemas/UpdatedAt'
|
- $ref: '#/components/schemas/UpdatedAt'
|
||||||
|
MembersRequest:
|
||||||
|
description: members of workgroup
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/MemberRequest'
|
||||||
|
MembersResponse:
|
||||||
|
description: members of workgroup
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/MemberResponse'
|
||||||
|
MemberResponse:
|
||||||
|
description: Member of workgroup
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
citizen:
|
||||||
|
$ref: '#/components/schemas/CitizenResponse'
|
||||||
|
roles:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- MASTER
|
||||||
|
- MANAGER
|
||||||
|
- EDITOR
|
||||||
|
- REPORTER
|
||||||
|
example: MASTER
|
||||||
|
MemberRequest:
|
||||||
|
description: Member of workgroup
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
citizen:
|
||||||
|
$ref: '#/components/schemas/UuidEntity'
|
||||||
|
roles:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- MASTER
|
||||||
|
- MANAGER
|
||||||
|
- EDITOR
|
||||||
|
- REPORTER
|
||||||
|
example: MASTER
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ declare
|
|||||||
_password text := crypt('azerty', gen_salt('bf', 8));
|
_password text := crypt('azerty', gen_salt('bf', 8));
|
||||||
multiple int = coalesce(current_setting('fixture.quantity.multiple', true), '50')::int;
|
multiple int = coalesce(current_setting('fixture.quantity.multiple', true), '50')::int;
|
||||||
begin
|
begin
|
||||||
delete from "user";
|
|
||||||
insert into "user" (id, username, password, blocked_at, roles)
|
insert into "user" (id, username, password, blocked_at, roles)
|
||||||
select
|
select
|
||||||
uuid_in(md5('user'||rn::text)::cstring),
|
uuid_in(md5('user'||rn::text)::cstring),
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
do
|
do
|
||||||
$$
|
$$
|
||||||
begin
|
begin
|
||||||
delete from citizen;
|
|
||||||
insert into citizen (id, name, birthday, user_id, vote_anonymous, follow_anonymous, email)
|
insert into citizen (id, name, birthday, user_id, vote_anonymous, follow_anonymous, email)
|
||||||
select
|
select
|
||||||
uuid_in(md5('citizen'||row_number() over ()::text)::cstring),
|
uuid_in(md5('citizen'||row_number() over ()::text)::cstring),
|
||||||
|
|||||||
@@ -2,27 +2,37 @@ do
|
|||||||
$$
|
$$
|
||||||
declare
|
declare
|
||||||
citizen_count int = (select count(*) from citizen);
|
citizen_count int = (select count(*) from citizen);
|
||||||
|
_roles text[] = $roles$
|
||||||
|
{
|
||||||
|
"MANAGER", "EDITOR", "REPORTER"
|
||||||
|
}
|
||||||
|
$roles$;
|
||||||
begin
|
begin
|
||||||
delete from citizen_in_workgroup;
|
insert into workgroup (id, created_by_id, name, description, anonymous)
|
||||||
delete from workgroup;
|
|
||||||
|
|
||||||
insert into workgroup (id, created_by_id, name, description, anonymous, owner_id)
|
|
||||||
select
|
select
|
||||||
uuid_in(md5('workgroup'||rn::text)::cstring),
|
uuid_in(md5('workgroup'||rn::text)::cstring),
|
||||||
z.id,
|
z.id,
|
||||||
'name' || rn,
|
'name' || rn,
|
||||||
'description' || rn,
|
'description' || rn,
|
||||||
rn % 3 = 1,
|
rn % 3 = 1
|
||||||
z.id
|
|
||||||
from (select *, row_number() over () rn from citizen) z;
|
from (select *, row_number() over () rn from citizen) z;
|
||||||
|
|
||||||
insert into citizen_in_workgroup (citizen_id, workgroup_id)
|
insert into citizen_in_workgroup (citizen_id, workgroup_id, roles)
|
||||||
select
|
select
|
||||||
z.id,
|
z.id,
|
||||||
w.id
|
w.id,
|
||||||
|
'{MASTER}'
|
||||||
from (select *, row_number() over ()+5 % citizen_count rn from citizen) z
|
from (select *, row_number() over ()+5 % citizen_count rn from citizen) z
|
||||||
join (select *, row_number() over () rn from workgroup) w using (rn);
|
join (select *, row_number() over () rn from workgroup) w using (rn);
|
||||||
|
|
||||||
|
insert into citizen_in_workgroup (citizen_id, workgroup_id, roles)
|
||||||
|
select
|
||||||
|
z.id,
|
||||||
|
w.id,
|
||||||
|
_roles[(row_number() over () % 3)+1:(row_number() over () % 3)+1]
|
||||||
|
from (select *, row_number() over ()+10 % citizen_count rn from citizen) z
|
||||||
|
join (select *, row_number() over () rn from workgroup) w using (rn);
|
||||||
|
|
||||||
raise notice 'workgroup fixtures done';
|
raise notice 'workgroup fixtures done';
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ declare
|
|||||||
_citizen_count int = (select count(z) from citizen z);
|
_citizen_count int = (select count(z) from citizen z);
|
||||||
_workgroup_count int = (select count(w) from workgroup w);
|
_workgroup_count int = (select count(w) from workgroup w);
|
||||||
begin
|
begin
|
||||||
delete from article_relations;
|
|
||||||
delete from article;
|
|
||||||
|
|
||||||
insert into article (id, version_id, created_by_id, workgroup_id, title, anonymous, content, description, tags, created_at, draft)
|
insert into article (id, version_id, created_by_id, workgroup_id, title, anonymous, content, description, tags, created_at, draft)
|
||||||
select
|
select
|
||||||
uuid_in(md5('article'||row_number() over ())::cstring),
|
uuid_in(md5('article'||row_number() over ())::cstring),
|
||||||
|
|||||||
@@ -3,10 +3,6 @@ $$
|
|||||||
declare
|
declare
|
||||||
article_count int = (select count(*) from article);
|
article_count int = (select count(*) from article);
|
||||||
begin
|
begin
|
||||||
delete from article_in_title;
|
|
||||||
delete from title;
|
|
||||||
delete from constitution;
|
|
||||||
|
|
||||||
insert into constitution (id, version_id, created_by_id, title, anonymous, created_at)
|
insert into constitution (id, version_id, created_by_id, title, anonymous, created_at)
|
||||||
select
|
select
|
||||||
uuid_in(md5('constitution'||row_number() over ())::cstring),
|
uuid_in(md5('constitution'||row_number() over ())::cstring),
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ $$
|
|||||||
declare
|
declare
|
||||||
article_count int = (select count(*) from article);
|
article_count int = (select count(*) from article);
|
||||||
begin
|
begin
|
||||||
delete from follow;
|
|
||||||
|
|
||||||
insert into follow_article (id, created_by_id, target_id)
|
insert into follow_article (id, created_by_id, target_id)
|
||||||
select
|
select
|
||||||
uuid_in(md5('follow_article'||row_number() over ())::cstring),
|
uuid_in(md5('follow_article'||row_number() over ())::cstring),
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ $$
|
|||||||
declare
|
declare
|
||||||
article_count int = (select count(*) from article);
|
article_count int = (select count(*) from article);
|
||||||
begin
|
begin
|
||||||
delete from comment;
|
|
||||||
|
|
||||||
insert into comment_on_article (id, created_by_id, target_id, content)
|
insert into comment_on_article (id, created_by_id, target_id, content)
|
||||||
select
|
select
|
||||||
uuid_in(md5('comment_on_article'||row_number() over ())::cstring),
|
uuid_in(md5('comment_on_article'||row_number() over ())::cstring),
|
||||||
|
|||||||
@@ -3,11 +3,6 @@ $$
|
|||||||
declare
|
declare
|
||||||
article_count int = (select count(*) from article);
|
article_count int = (select count(*) from article);
|
||||||
begin
|
begin
|
||||||
delete from vote_for_article;
|
|
||||||
delete from vote_for_constitution;
|
|
||||||
delete from vote_for_comment_on_article;
|
|
||||||
delete from vote_for_comment_on_constitution;
|
|
||||||
|
|
||||||
insert into vote_for_article (id, created_by_id, target_id, note, anonymous)
|
insert into vote_for_article (id, created_by_id, target_id, note, anonymous)
|
||||||
select
|
select
|
||||||
uuid_in(md5('vote_for_article'||row_number() over ())::cstring),
|
uuid_in(md5('vote_for_article'||row_number() over ())::cstring),
|
||||||
|
|||||||
@@ -3,9 +3,6 @@ $$
|
|||||||
declare
|
declare
|
||||||
article_count int = (select count(*) from article);
|
article_count int = (select count(*) from article);
|
||||||
begin
|
begin
|
||||||
delete from opinion_on_article;
|
|
||||||
delete from opinion_choice;
|
|
||||||
|
|
||||||
insert into opinion_choice (id, name, target)
|
insert into opinion_choice (id, name, target)
|
||||||
select
|
select
|
||||||
uuid_in(md5('opinion_choice'||row_number() over ())::cstring),
|
uuid_in(md5('opinion_choice'||row_number() over ())::cstring),
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#bin/bash
|
#!/usr/bin/env bash
|
||||||
echo "Start fixtures"
|
awk 'FNR==1{print "--------------------"}1' `dirname $0`/*.sql > ./allSQL.sql
|
||||||
awk 'FNR==1{print "--------------------"}1' ./*.sql > ./allSQL.sql
|
|
||||||
docker exec -i postgresql_dc-project psql dc-project dc-project -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql
|
docker exec -i postgresql_dc-project psql dc-project dc-project -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql
|
||||||
rm ./allSQL.sql
|
rm ./allSQL.sql
|
||||||
echo "End fixtures"
|
echo "End fixtures"
|
||||||
@@ -7,7 +7,7 @@ begin
|
|||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
a.*,
|
a.*,
|
||||||
find_citizen_by_id(a.created_by_id) as created_by,
|
find_citizen_by_id_with_user(a.created_by_id) as created_by,
|
||||||
find_workgroup_by_id(a.workgroup_id) as workgroup,
|
find_workgroup_by_id(a.workgroup_id) as workgroup,
|
||||||
count_vote(a.id) as votes,
|
count_vote(a.id) as votes,
|
||||||
count_opinion(a.id) as opinions
|
count_opinion(a.id) as opinions
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ begin
|
|||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
a.*,
|
a.*,
|
||||||
find_citizen_by_id(a.created_by_id) as created_by,
|
find_citizen_by_id_with_user(a.created_by_id) as created_by,
|
||||||
find_workgroup_by_id(a.workgroup_id) as workgroup,
|
find_workgroup_by_id(a.workgroup_id) as workgroup,
|
||||||
count_vote(a.id) as votes,
|
count_vote(a.id) as votes,
|
||||||
count_opinion(a.id) as opinions,
|
count_opinion(a.id) as opinions,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ begin
|
|||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
a.*,
|
a.*,
|
||||||
find_citizen_by_id(a.created_by_id) as created_by,
|
find_citizen_by_id_with_user(a.created_by_id) as created_by,
|
||||||
find_workgroup_by_id(a.workgroup_id) as workgroup,
|
find_workgroup_by_id(a.workgroup_id) as workgroup,
|
||||||
count_vote(a.id) as votes
|
count_vote(a.id) as votes
|
||||||
from article as a
|
from article as a
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ begin
|
|||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
a.*,
|
a.*,
|
||||||
find_citizen_by_id(a.created_by_id) as created_by,
|
find_citizen_by_id_with_user(a.created_by_id) as created_by,
|
||||||
find_workgroup_by_id(a.workgroup_id) as workgroup,
|
find_workgroup_by_id(a.workgroup_id) as workgroup,
|
||||||
count_vote(a.id) as votes
|
count_vote(a.id) as votes
|
||||||
into resource
|
into resource
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ begin
|
|||||||
select to_json(t) into resource
|
select to_json(t) into resource
|
||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
z.*,
|
z.*
|
||||||
find_user_by_id(z.user_id) as "user",
|
|
||||||
array_agg(find_workgroup_by_id_simple(ciw.workgroup_id)) as "workgroups"
|
|
||||||
from citizen as z
|
from citizen as z
|
||||||
left join citizen_in_workgroup ciw on z.id = ciw.citizen_id
|
left join citizen_in_workgroup ciw on z.id = ciw.citizen_id
|
||||||
where z.id = _id
|
where z.id = _id
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ begin
|
|||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
z.*,
|
z.*,
|
||||||
find_user_by_id(z.user_id) as "user",
|
find_user_by_id(z.user_id) as "user"
|
||||||
array_agg(find_workgroup_by_id_simple(ciw.workgroup_id)) as "workgroups"
|
|
||||||
from citizen as z
|
from citizen as z
|
||||||
left join citizen_in_workgroup ciw on z.id = ciw.citizen_id
|
left join citizen_in_workgroup ciw on z.id = ciw.citizen_id
|
||||||
where z.id = _id
|
where z.id = _id
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
create or replace function find_citizen_by_id_with_user_and_workgroups(in id uuid, out resource json) language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_id alias for id;
|
||||||
|
begin
|
||||||
|
select to_json(t) into resource
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
z.*,
|
||||||
|
find_user_by_id(z.user_id) as "user",
|
||||||
|
case when ciw.workgroup_id is null then '{}' else array_agg(json_build_object(
|
||||||
|
'roles', ciw.roles,
|
||||||
|
'workgroup', find_workgroup_by_id_simple(ciw.workgroup_id)
|
||||||
|
)) end as "workgroups"
|
||||||
|
from citizen as z
|
||||||
|
left join citizen_in_workgroup ciw on z.id = ciw.citizen_id
|
||||||
|
where z.id = _id
|
||||||
|
group by z.id, ciw.workgroup_id
|
||||||
|
) as t;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ begin
|
|||||||
email = excluded.email
|
email = excluded.email
|
||||||
returning id into new_id;
|
returning id into new_id;
|
||||||
|
|
||||||
select find_citizen_by_id(new_id) into resource;
|
select find_citizen_by_id_with_user(new_id) into resource;
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ begin
|
|||||||
select
|
select
|
||||||
com.*,
|
com.*,
|
||||||
find_reference_by_id(com.target_id, com.target_reference) as target,
|
find_reference_by_id(com.target_id, com.target_reference) as target,
|
||||||
find_citizen_by_id(com.created_by_id) as created_by,
|
find_citizen_by_id_with_user(com.created_by_id) as created_by,
|
||||||
count_vote(com.id) as votes
|
count_vote(com.id) as votes
|
||||||
from "comment" as com
|
from "comment" as com
|
||||||
where id = _id
|
where id = _id
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ begin
|
|||||||
select
|
select
|
||||||
com.*,
|
com.*,
|
||||||
find_reference_by_id(com.target_id, _reference) as target,
|
find_reference_by_id(com.target_id, _reference) as target,
|
||||||
find_citizen_by_id(com.created_by_id) as created_by,
|
find_citizen_by_id_with_user(com.created_by_id) as created_by,
|
||||||
count_vote(com.id) as votes
|
count_vote(com.id) as votes
|
||||||
|
|
||||||
from "comment" as com
|
from "comment" as com
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ begin
|
|||||||
com.*,
|
com.*,
|
||||||
(select count(*) from "comment" c2 where c2.parents_ids @> array[com.id]) as children_count,
|
(select count(*) from "comment" c2 where c2.parents_ids @> array[com.id]) as children_count,
|
||||||
find_reference_by_id(com.target_id, com.target_reference) as target,
|
find_reference_by_id(com.target_id, com.target_reference) as target,
|
||||||
find_citizen_by_id(com.created_by_id) as created_by,
|
find_citizen_by_id_with_user(com.created_by_id) as created_by,
|
||||||
count_vote(com.id) as votes
|
count_vote(com.id) as votes
|
||||||
from "comment" as com
|
from "comment" as com
|
||||||
where parent_id = _parent_id
|
where parent_id = _parent_id
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ begin
|
|||||||
com.*,
|
com.*,
|
||||||
(select count(c2) from "comment" c2 where c2.parent_comment_id = com.id) as children_count,
|
(select count(c2) from "comment" c2 where c2.parent_comment_id = com.id) as children_count,
|
||||||
find_reference_by_id(com.target_id, com.target_reference) as target,
|
find_reference_by_id(com.target_id, com.target_reference) as target,
|
||||||
find_citizen_by_id(com.created_by_id) as created_by,
|
find_citizen_by_id_with_user(com.created_by_id) as created_by,
|
||||||
count_vote(com.id) as votes
|
count_vote(com.id) as votes
|
||||||
from "comment" as com
|
from "comment" as com
|
||||||
where com.parent_id = _target_id
|
where com.parent_id = _target_id
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ begin
|
|||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
c.*,
|
c.*,
|
||||||
find_citizen_by_id(c.created_by_id) as created_by,
|
find_citizen_by_id_with_user(c.created_by_id) as created_by,
|
||||||
find_constitution_titles_by_id(c.id) as titles
|
find_constitution_titles_by_id(c.id) as titles
|
||||||
into resource
|
into resource
|
||||||
from constitution as c
|
from constitution as c
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ begin
|
|||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
c.*,
|
c.*,
|
||||||
find_citizen_by_id(c.created_by_id) as created_by,
|
find_citizen_by_id_with_user(c.created_by_id) as created_by,
|
||||||
find_constitution_titles_by_id(c.id) as titles,
|
find_constitution_titles_by_id(c.id) as titles,
|
||||||
zdb.score(c.ctid) _score
|
zdb.score(c.ctid) _score
|
||||||
from constitution as c
|
from constitution as c
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ begin
|
|||||||
select
|
select
|
||||||
f.*,
|
f.*,
|
||||||
json_build_object('id', f.target_id, 'reference', f.target_reference) as target,
|
json_build_object('id', f.target_id, 'reference', f.target_reference) as target,
|
||||||
find_citizen_by_id(f.created_by_id) as created_by
|
find_citizen_by_id_with_user(f.created_by_id) as created_by
|
||||||
from follow as f
|
from follow as f
|
||||||
where f.created_by_id = _citizen_id
|
where f.created_by_id = _citizen_id
|
||||||
and array[f.target_id] <@ _target_ids
|
and array[f.target_id] <@ _target_ids
|
||||||
@@ -32,7 +32,7 @@ begin
|
|||||||
select
|
select
|
||||||
f.*,
|
f.*,
|
||||||
json_build_object('id', f.target_id, 'reference', f.target_reference) as target,
|
json_build_object('id', f.target_id, 'reference', f.target_reference) as target,
|
||||||
find_citizen_by_id(f.created_by_id) as created_by
|
find_citizen_by_id_with_user(f.created_by_id) as created_by
|
||||||
from follow as f
|
from follow as f
|
||||||
where f.created_by_id = _citizen_id
|
where f.created_by_id = _citizen_id
|
||||||
and f.target_id = _target_id
|
and f.target_id = _target_id
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ begin
|
|||||||
select
|
select
|
||||||
f.*,
|
f.*,
|
||||||
find_article_by_id(f.target_id) as target,
|
find_article_by_id(f.target_id) as target,
|
||||||
find_citizen_by_id(f.created_by_id) as created_by
|
find_citizen_by_id_with_user(f.created_by_id) as created_by
|
||||||
from follow as f
|
from follow as f
|
||||||
where created_by_id = _created_by_id
|
where created_by_id = _created_by_id
|
||||||
order by created_at desc,
|
order by created_at desc,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ begin
|
|||||||
select
|
select
|
||||||
f.*,
|
f.*,
|
||||||
json_build_object('id', f.target_id) as target,
|
json_build_object('id', f.target_id) as target,
|
||||||
find_citizen_by_id(f.created_by_id) as created_by
|
find_citizen_by_id_with_user(f.created_by_id) as created_by
|
||||||
from follow as f
|
from follow as f
|
||||||
where created_by_id = _created_by_id
|
where created_by_id = _created_by_id
|
||||||
order by created_at desc,
|
order by created_at desc,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ begin
|
|||||||
select
|
select
|
||||||
f.*,
|
f.*,
|
||||||
find_constitution_by_id(f.target_id) as target,
|
find_constitution_by_id(f.target_id) as target,
|
||||||
find_citizen_by_id(f.created_by_id) as created_by
|
find_citizen_by_id_with_user(f.created_by_id) as created_by
|
||||||
from follow as f
|
from follow as f
|
||||||
where created_by_id = _created_by_id
|
where created_by_id = _created_by_id
|
||||||
order by created_at desc,
|
order by created_at desc,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ begin
|
|||||||
select
|
select
|
||||||
o.*,
|
o.*,
|
||||||
find_reference_by_id(o.target_id, o.target_reference) as target,
|
find_reference_by_id(o.target_id, o.target_reference) as target,
|
||||||
find_citizen_by_id(o.created_by_id) as created_by,
|
find_citizen_by_id_with_user(o.created_by_id) as created_by,
|
||||||
to_json(ol) as choice
|
to_json(ol) as choice
|
||||||
from opinion as o
|
from opinion as o
|
||||||
join opinion_choice ol on o.choice_id = ol.id
|
join opinion_choice ol on o.choice_id = ol.id
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ begin
|
|||||||
select
|
select
|
||||||
o.*,
|
o.*,
|
||||||
find_reference_by_id(o.target_id, o.target_reference) as target,
|
find_reference_by_id(o.target_id, o.target_reference) as target,
|
||||||
find_citizen_by_id(o.created_by_id) as created_by,
|
find_citizen_by_id_with_user(o.created_by_id) as created_by,
|
||||||
to_json(ol) as choice
|
to_json(ol) as choice
|
||||||
from opinion as o
|
from opinion as o
|
||||||
join opinion_choice ol on o.choice_id = ol.id
|
join opinion_choice ol on o.choice_id = ol.id
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ begin
|
|||||||
select
|
select
|
||||||
o.*,
|
o.*,
|
||||||
find_reference_by_id(o.target_id, o.target_reference) as target,
|
find_reference_by_id(o.target_id, o.target_reference) as target,
|
||||||
find_citizen_by_id(o.created_by_id) as created_by,
|
find_citizen_by_id_with_user(o.created_by_id) as created_by,
|
||||||
to_json(ol) as choice
|
to_json(ol) as choice
|
||||||
from opinion as o
|
from opinion as o
|
||||||
join opinion_choice ol on o.choice_id = ol.id
|
join opinion_choice ol on o.choice_id = ol.id
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ begin
|
|||||||
select
|
select
|
||||||
o.*,
|
o.*,
|
||||||
find_reference_by_id(o.target_id, o.target_reference) as target,
|
find_reference_by_id(o.target_id, o.target_reference) as target,
|
||||||
find_citizen_by_id(o.created_by_id) as created_by,
|
find_citizen_by_id_with_user(o.created_by_id) as created_by,
|
||||||
to_json(ol) as choice
|
to_json(ol) as choice
|
||||||
from "opinion" as o
|
from "opinion" as o
|
||||||
join opinion_choice ol on o.choice_id = ol.id
|
join opinion_choice ol on o.choice_id = ol.id
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ begin
|
|||||||
select
|
select
|
||||||
o.*,
|
o.*,
|
||||||
find_reference_by_id(o.target_id, o.target_reference) as target,
|
find_reference_by_id(o.target_id, o.target_reference) as target,
|
||||||
find_citizen_by_id(o.created_by_id) as created_by,
|
find_citizen_by_id_with_user(o.created_by_id) as created_by,
|
||||||
to_json(ol) as choice
|
to_json(ol) as choice
|
||||||
from "opinion" as o
|
from "opinion" as o
|
||||||
join opinion_choice ol on o.choice_id = ol.id
|
join opinion_choice ol on o.choice_id = ol.id
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ begin
|
|||||||
select
|
select
|
||||||
v.*,
|
v.*,
|
||||||
find_reference_by_id(v.target_id, v.target_reference) as target,
|
find_reference_by_id(v.target_id, v.target_reference) as target,
|
||||||
find_citizen_by_id(v.created_by_id) as created_by
|
find_citizen_by_id_with_user(v.created_by_id) as created_by
|
||||||
|
|
||||||
from vote as v
|
from vote as v
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ begin
|
|||||||
select
|
select
|
||||||
v.*,
|
v.*,
|
||||||
find_reference_by_id(v.target_id, _reference) as target,
|
find_reference_by_id(v.target_id, _reference) as target,
|
||||||
find_citizen_by_id(v.created_by_id) as created_by
|
find_citizen_by_id_with_user(v.created_by_id) as created_by
|
||||||
|
|
||||||
from vote as v
|
from vote as v
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
create or replace function add_workgroup_member(in _id uuid, inout member json)
|
||||||
|
language plpgsql as
|
||||||
|
$$
|
||||||
|
begin
|
||||||
|
insert into citizen_in_workgroup (workgroup_id, citizen_id, roles)
|
||||||
|
values (
|
||||||
|
_id,
|
||||||
|
(member#>>'{citizen, id}')::uuid,
|
||||||
|
(select array_agg(t) from json_array_elements_text(member#>'{roles}') t)
|
||||||
|
)
|
||||||
|
on conflict (workgroup_id, citizen_id) do update set
|
||||||
|
roles = excluded.roles;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
@@ -1,16 +1,11 @@
|
|||||||
create or replace function add_workgroup_members(in _id uuid, inout resource json)
|
create or replace function add_workgroup_members(in _id uuid, inout members json)
|
||||||
language plpgsql as
|
language plpgsql as
|
||||||
$$
|
$$
|
||||||
begin
|
begin
|
||||||
insert into citizen_in_workgroup (citizen_id, workgroup_id)
|
perform add_workgroup_member(_id, b)
|
||||||
select
|
from json_array_elements(members) b;
|
||||||
(z->>'id')::uuid,
|
|
||||||
_id::uuid
|
|
||||||
from json_array_elements(resource) z
|
|
||||||
where (z->>'id') is not null
|
|
||||||
on conflict do nothing;
|
|
||||||
|
|
||||||
select find_workgroup_members(_id) into resource;
|
select find_workgroup_members(_id) into members;
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ begin
|
|||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
w.*,
|
w.*,
|
||||||
find_citizen_by_id(w.created_by_id) as created_by,
|
find_citizen_by_id_with_user(w.created_by_id) as created_by,
|
||||||
find_citizen_by_id(w.owner_id) as owner,
|
|
||||||
find_workgroup_members(w.id) as members
|
find_workgroup_members(w.id) as members
|
||||||
into resource
|
into resource
|
||||||
from workgroup as w
|
from workgroup as w
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ begin
|
|||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
w.*,
|
w.*,
|
||||||
json_build_object('id', w.created_by_id) as created_by,
|
json_build_object('id', w.created_by_id) as created_by
|
||||||
json_build_object('id', w.owner_id) as owner
|
|
||||||
into resource
|
into resource
|
||||||
from workgroup as w
|
from workgroup as w
|
||||||
join citizen_in_workgroup ciw on w.id = ciw.workgroup_id
|
join citizen_in_workgroup ciw on w.id = ciw.workgroup_id
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ begin
|
|||||||
select json_agg(t) into resource
|
select json_agg(t) into resource
|
||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
z.*,
|
w.id as id,
|
||||||
find_user_by_id(z.user_id) as "user"
|
find_citizen_by_id_with_user(z.id) as citizen,
|
||||||
|
ciw.roles as roles
|
||||||
from citizen_in_workgroup as ciw
|
from citizen_in_workgroup as ciw
|
||||||
join workgroup as w on ciw.workgroup_id = w.id
|
join workgroup as w on ciw.workgroup_id = w.id
|
||||||
join citizen z on z.id = ciw.citizen_id
|
join citizen z on z.id = ciw.citizen_id
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ begin
|
|||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
w.*,
|
w.*,
|
||||||
find_citizen_by_id(w.created_by_id) as created_by,
|
find_citizen_by_id_with_user(w.created_by_id) as created_by,
|
||||||
find_citizen_by_id(w.owner_id) as owner,
|
|
||||||
zdb.score(w.ctid) _score
|
zdb.score(w.ctid) _score
|
||||||
from workgroup as w
|
from workgroup as w
|
||||||
where deleted_at is null
|
where deleted_at is null
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
create or replace function remove_workgroup_members(in _id uuid, inout resource json)
|
create or replace function remove_workgroup_members(in _id uuid, inout members json)
|
||||||
language plpgsql as
|
language plpgsql as
|
||||||
$$
|
$$
|
||||||
begin
|
begin
|
||||||
@@ -6,11 +6,11 @@ begin
|
|||||||
where workgroup_id = _id
|
where workgroup_id = _id
|
||||||
and citizen_id in (
|
and citizen_id in (
|
||||||
select
|
select
|
||||||
(z->>'id')::uuid
|
(b#>>'{citizen, id}')::uuid
|
||||||
from json_array_elements(resource) z
|
from json_array_elements(members) b
|
||||||
);
|
);
|
||||||
|
|
||||||
select find_workgroup_members(_id) into resource;
|
select find_workgroup_members(_id) into members;
|
||||||
end
|
end
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,20 @@
|
|||||||
create or replace function update_workgroup_members(in _id uuid, inout resource json)
|
create or replace function update_workgroup_members(in _id uuid, inout members json)
|
||||||
language plpgsql as
|
language plpgsql as
|
||||||
$$
|
$$
|
||||||
begin
|
begin
|
||||||
insert into citizen_in_workgroup (citizen_id, workgroup_id)
|
perform add_workgroup_member(_id, b)
|
||||||
select
|
from json_array_elements(members) b;
|
||||||
(z->>'id')::uuid,
|
|
||||||
_id::uuid
|
|
||||||
from json_array_elements(resource) z
|
|
||||||
where (z->>'id') is not null
|
|
||||||
on conflict do nothing;
|
|
||||||
|
|
||||||
delete from citizen_in_workgroup
|
delete from citizen_in_workgroup
|
||||||
where workgroup_id = _id
|
where workgroup_id = _id
|
||||||
and citizen_id not in(
|
and citizen_id not in(
|
||||||
select
|
select
|
||||||
(z->>'id')::uuid
|
(b#>>'{citizen, id}')::uuid
|
||||||
from json_array_elements(resource) z
|
from json_array_elements(members) b
|
||||||
where (z->>'id') is not null
|
where (b#>>'{citizen, id}')::uuid is not null
|
||||||
);
|
);
|
||||||
|
|
||||||
select find_workgroup_members(_id) into resource;
|
select find_workgroup_members(_id) into members;
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
|
|||||||
@@ -3,29 +3,39 @@ create or replace function upsert_workgroup(inout resource json)
|
|||||||
$$
|
$$
|
||||||
declare
|
declare
|
||||||
new_id uuid = coalesce((resource->>'id')::uuid, uuid_generate_v4());
|
new_id uuid = coalesce((resource->>'id')::uuid, uuid_generate_v4());
|
||||||
|
exists boolean = case when (select true from workgroup where id = new_id) is null then true else false end;
|
||||||
begin
|
begin
|
||||||
insert into workgroup (id, created_by_id, name, description, anonymous, logo, owner_id)
|
insert into workgroup (id, created_by_id, name, description, anonymous, logo)
|
||||||
select
|
select
|
||||||
new_id,
|
new_id,
|
||||||
(resource#>>'{created_by, id}')::uuid,
|
(resource#>>'{created_by, id}')::uuid,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
anonymous,
|
anonymous,
|
||||||
logo,
|
logo
|
||||||
(resource#>>'{owner, id}')::uuid
|
|
||||||
from json_populate_record(null::workgroup, resource)
|
from json_populate_record(null::workgroup, resource)
|
||||||
on conflict (id) do update set
|
on conflict (id) do update set
|
||||||
name = excluded.name,
|
name = excluded.name,
|
||||||
description = excluded.description,
|
description = excluded.description,
|
||||||
anonymous = excluded.anonymous,
|
anonymous = excluded.anonymous,
|
||||||
logo = excluded.logo,
|
logo = excluded.logo;
|
||||||
owner_id = excluded.owner_id;
|
|
||||||
|
|
||||||
-- insert into citizen_in_workgroup (citizen_id, workgroup_id)
|
insert into citizen_in_workgroup (workgroup_id, citizen_id, roles)
|
||||||
-- select
|
select
|
||||||
-- (resource->>'id')::uuid,
|
new_id::uuid,
|
||||||
-- new_id::uuid
|
citizen_id,
|
||||||
-- from json_populate_recordset(null::workgroup, resource->'members');
|
roles
|
||||||
|
from json_populate_recordset(null::citizen_in_workgroup, resource->'members') m;
|
||||||
|
|
||||||
|
-- insert master if no members
|
||||||
|
if (exists) then
|
||||||
|
insert into citizen_in_workgroup (workgroup_id, citizen_id, roles)
|
||||||
|
select
|
||||||
|
new_id::uuid,
|
||||||
|
(resource#>>'{created_by, id}')::uuid,
|
||||||
|
'{MASTER}'
|
||||||
|
on conflict do nothing;
|
||||||
|
end if;
|
||||||
|
|
||||||
select find_workgroup_by_id(new_id) into resource;
|
select find_workgroup_by_id(new_id) into resource;
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -32,14 +32,14 @@ create table workgroup
|
|||||||
name varchar(128) not null,
|
name varchar(128) not null,
|
||||||
description text null,
|
description text null,
|
||||||
anonymous boolean default false not null,
|
anonymous boolean default false not null,
|
||||||
logo text null,
|
logo text null
|
||||||
owner_id uuid not null references citizen (id)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
create table citizen_in_workgroup
|
create table citizen_in_workgroup
|
||||||
(
|
(
|
||||||
citizen_id uuid not null references citizen (id),
|
citizen_id uuid not null references citizen (id),
|
||||||
workgroup_id uuid not null references workgroup (id),
|
workgroup_id uuid not null references workgroup (id),
|
||||||
|
roles text[] not null,
|
||||||
created_at timestamptz default now() not null,
|
created_at timestamptz default now() not null,
|
||||||
primary key (citizen_id, workgroup_id)
|
primary key (citizen_id, workgroup_id)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package feature
|
package feature
|
||||||
|
|
||||||
import fr.dcproject.entity.*
|
import fr.dcproject.entity.*
|
||||||
|
import fr.dcproject.entity.WorkgroupWithMembersI.Member
|
||||||
import fr.dcproject.utils.toUUID
|
import fr.dcproject.utils.toUUID
|
||||||
import io.cucumber.datatable.DataTable
|
import io.cucumber.datatable.DataTable
|
||||||
import io.cucumber.java8.En
|
import io.cucumber.java8.En
|
||||||
@@ -16,7 +17,10 @@ class WorkgroupSteps : En, KoinTest {
|
|||||||
init {
|
init {
|
||||||
When("I have members in workgroup {string}:") { workgroupId: String, members: DataTable ->
|
When("I have members in workgroup {string}:") { workgroupId: String, members: DataTable ->
|
||||||
val membersRefs = members.asList()
|
val membersRefs = members.asList()
|
||||||
.map { CitizenRef(it.toUUID()) }
|
.map { Member(
|
||||||
|
citizen = CitizenRef(it.toUUID()),
|
||||||
|
roles = listOf(Member.Role.MASTER)
|
||||||
|
) }
|
||||||
|
|
||||||
get<WorkgroupRepository>().addMembers(WorkgroupRef(workgroupId.toUUID()), membersRefs)
|
get<WorkgroupRepository>().addMembers(WorkgroupRef(workgroupId.toUUID()), membersRefs)
|
||||||
}
|
}
|
||||||
@@ -42,16 +46,11 @@ class WorkgroupSteps : En, KoinTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val owner = data["owner"]?.let {
|
|
||||||
get<CitizenRepository>().findByUsername(it.toLowerCase().replace(' ', '-'))
|
|
||||||
} ?: creator
|
|
||||||
|
|
||||||
val workgroup = WorkgroupSimple<CitizenRef>(
|
val workgroup = WorkgroupSimple<CitizenRef>(
|
||||||
id = UUID.fromString(data["id"] ?: UUID.randomUUID().toString()),
|
id = UUID.fromString(data["id"] ?: UUID.randomUUID().toString()),
|
||||||
name = data["name"] ?: "Les Incoruptible",
|
name = data["name"] ?: "Les Incoruptible",
|
||||||
description = data["description"] ?: "La vie est notre jeux",
|
description = data["description"] ?: "La vie est notre jeux",
|
||||||
createdBy = creator,
|
createdBy = creator,
|
||||||
owner = owner,
|
|
||||||
anonymous = (data["anonymous"] ?: false) == true
|
anonymous = (data["anonymous"] ?: false) == true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -55,15 +55,15 @@ internal class WorkgroupVoterTest {
|
|||||||
createdBy = tesla,
|
createdBy = tesla,
|
||||||
description = "Super desc",
|
description = "Super desc",
|
||||||
name = "super name",
|
name = "super name",
|
||||||
owner = tesla,
|
anonymous = false,
|
||||||
anonymous = false
|
members = listOf(WorkgroupWithMembersI.Member(tesla, listOf(WorkgroupWithMembersI.Member.Role.MASTER)))
|
||||||
)
|
)
|
||||||
|
|
||||||
private val workgroupAnon = WorkgroupEntity(
|
private val workgroupAnon = WorkgroupEntity(
|
||||||
createdBy = tesla,
|
createdBy = tesla,
|
||||||
description = "Super desc",
|
description = "Super desc",
|
||||||
name = "super name",
|
name = "super name",
|
||||||
owner = tesla,
|
members = listOf(WorkgroupWithMembersI.Member(tesla, listOf(WorkgroupWithMembersI.Member.Role.MASTER))),
|
||||||
anonymous = true
|
anonymous = true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,23 @@ Feature: Workgroup
|
|||||||
|
|
||||||
Scenario: Can get one workgroup
|
Scenario: Can get one workgroup
|
||||||
Given I have citizen Stephen Hawking
|
Given I have citizen Stephen Hawking
|
||||||
|
And I have citizen Sadi Carnot with ID "be3b0926-8628-4426-804a-75188a6eb315"
|
||||||
|
And I have citizen Joseph Fourier with ID "d9671eca-abaf-4b67-9230-3ece700c1ddb"
|
||||||
And I am authenticated as Stephen Hawking
|
And I am authenticated as Stephen Hawking
|
||||||
And I have workgroup:
|
And I have workgroup:
|
||||||
| id | ab469134-bf14-4856-b093-ae1aa990f977 |
|
| id | ab469134-bf14-4856-b093-ae1aa990f977 |
|
||||||
| name | Les Mousquets |
|
| name | Les Mousquets |
|
||||||
|
| created_by | Stephen Hawking |
|
||||||
|
And I have members in workgroup "ab469134-bf14-4856-b093-ae1aa990f977":
|
||||||
|
| be3b0926-8628-4426-804a-75188a6eb315 |
|
||||||
|
| d9671eca-abaf-4b67-9230-3ece700c1ddb |
|
||||||
When I send a GET request to "/workgroups/ab469134-bf14-4856-b093-ae1aa990f977"
|
When I send a GET request to "/workgroups/ab469134-bf14-4856-b093-ae1aa990f977"
|
||||||
Then the response status code should be 200
|
Then the response status code should be 200
|
||||||
And the JSON should contain:
|
And the response should contain object:
|
||||||
| id | ab469134-bf14-4856-b093-ae1aa990f977 |
|
| $.id | ab469134-bf14-4856-b093-ae1aa990f977 |
|
||||||
| name | Les Mousquets |
|
| $.name | Les Mousquets |
|
||||||
|
| $.members[0].citizen.name.first_name | Stephen |
|
||||||
|
| $.members[1].citizen.name.first_name | Sadi |
|
||||||
|
|
||||||
Scenario: Can create a workgroup
|
Scenario: Can create a workgroup
|
||||||
Given I have citizen Werner Heisenberg
|
Given I have citizen Werner Heisenberg
|
||||||
@@ -60,12 +68,17 @@ Feature: Workgroup
|
|||||||
And I have workgroup:
|
And I have workgroup:
|
||||||
| id | b0ea1922-3bc6-44e2-aa7c-40158998cfbb |
|
| id | b0ea1922-3bc6-44e2-aa7c-40158998cfbb |
|
||||||
| name | Les bonobos |
|
| name | Les bonobos |
|
||||||
| owner | Blaise Pascal |
|
|
||||||
When I send a POST request to "/workgroups/b0ea1922-3bc6-44e2-aa7c-40158998cfbb/members" with body:
|
When I send a POST request to "/workgroups/b0ea1922-3bc6-44e2-aa7c-40158998cfbb/members" with body:
|
||||||
"""
|
"""
|
||||||
[
|
[
|
||||||
{"id":"6d883fe7-5fc0-4a50-8858-72230673eba4"},
|
{
|
||||||
{"id":"b5bac515-45d4-4aeb-9b6d-2627a0bbc419"}
|
"citizen": {"id":"6d883fe7-5fc0-4a50-8858-72230673eba4"},
|
||||||
|
"roles": ["MASTER"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"citizen": {"id":"b5bac515-45d4-4aeb-9b6d-2627a0bbc419"},
|
||||||
|
"roles": ["MASTER"]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
"""
|
"""
|
||||||
Then the response status code should be 201
|
Then the response status code should be 201
|
||||||
@@ -78,20 +91,22 @@ Feature: Workgroup
|
|||||||
And I have workgroup:
|
And I have workgroup:
|
||||||
| id | b6c975df-dd44-4e99-adc1-f605746b0e11 |
|
| id | b6c975df-dd44-4e99-adc1-f605746b0e11 |
|
||||||
| name | Les Tacos |
|
| name | Les Tacos |
|
||||||
| owner | Heinrich Hertz |
|
|
||||||
And I have members in workgroup "b6c975df-dd44-4e99-adc1-f605746b0e11":
|
And I have members in workgroup "b6c975df-dd44-4e99-adc1-f605746b0e11":
|
||||||
| 87909ba3-2069-431c-9924-219fd8411cf2 |
|
| 87909ba3-2069-431c-9924-219fd8411cf2 |
|
||||||
| 1baf48bb-02bc-4d8f-ac86-33335354f5e7 |
|
| 1baf48bb-02bc-4d8f-ac86-33335354f5e7 |
|
||||||
When I send a DELETE request to "/workgroups/b6c975df-dd44-4e99-adc1-f605746b0e11/members" with body:
|
When I send a DELETE request to "/workgroups/b6c975df-dd44-4e99-adc1-f605746b0e11/members" with body:
|
||||||
"""
|
"""
|
||||||
[
|
[
|
||||||
{"id":"87909ba3-2069-431c-9924-219fd8411cf2"}
|
{
|
||||||
|
"citizen": {"id":"87909ba3-2069-431c-9924-219fd8411cf2"},
|
||||||
|
"roles": ["MASTER"]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
"""
|
"""
|
||||||
Then the response status code should be 200
|
Then the response status code should be 200
|
||||||
And the response should contain object:
|
And the response should contain object:
|
||||||
| $.[0]id | 1baf48bb-02bc-4d8f-ac86-33335354f5e7 |
|
| $.[0]citizen.id | 1baf48bb-02bc-4d8f-ac86-33335354f5e7 |
|
||||||
And the JSON should have 1 items
|
And the JSON should have 2 items
|
||||||
|
|
||||||
Scenario: Can update members on workgroup
|
Scenario: Can update members on workgroup
|
||||||
Given I have citizen Leon Foucault
|
Given I have citizen Leon Foucault
|
||||||
@@ -102,19 +117,24 @@ Feature: Workgroup
|
|||||||
And I have workgroup:
|
And I have workgroup:
|
||||||
| id | 784fe6bc-7635-4ae2-b080-3a4743b998bf |
|
| id | 784fe6bc-7635-4ae2-b080-3a4743b998bf |
|
||||||
| name | Les Tacos |
|
| name | Les Tacos |
|
||||||
| owner | Leon Foucault |
|
|
||||||
And I have members in workgroup "784fe6bc-7635-4ae2-b080-3a4743b998bf":
|
And I have members in workgroup "784fe6bc-7635-4ae2-b080-3a4743b998bf":
|
||||||
| be3b0926-8628-4426-804a-75188a6eb315 |
|
| be3b0926-8628-4426-804a-75188a6eb315 |
|
||||||
| d9671eca-abaf-4b67-9230-3ece700c1ddb |
|
| d9671eca-abaf-4b67-9230-3ece700c1ddb |
|
||||||
When I send a PUT request to "/workgroups/784fe6bc-7635-4ae2-b080-3a4743b998bf/members" with body:
|
When I send a PUT request to "/workgroups/784fe6bc-7635-4ae2-b080-3a4743b998bf/members" with body:
|
||||||
"""
|
"""
|
||||||
[
|
[
|
||||||
{"id":"be3b0926-8628-4426-804a-75188a6eb315"},
|
{
|
||||||
{"id":"b49e20c1-8393-45d6-a6a0-3fa5c71cbdc1"}
|
"citizen": {"id":"be3b0926-8628-4426-804a-75188a6eb315"},
|
||||||
|
"roles": ["MASTER"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"citizen": {"id":"b49e20c1-8393-45d6-a6a0-3fa5c71cbdc1"},
|
||||||
|
"roles": ["MASTER"]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
"""
|
"""
|
||||||
Then the response status code should be 200
|
Then the response status code should be 200
|
||||||
And the response should contain object:
|
And the response should contain object:
|
||||||
| $.[0]id | be3b0926-8628-4426-804a-75188a6eb315 |
|
| $.[0]citizen.id | be3b0926-8628-4426-804a-75188a6eb315 |
|
||||||
| $.[1]id | b49e20c1-8393-45d6-a6a0-3fa5c71cbdc1 |
|
| $.[1]citizen.id | b49e20c1-8393-45d6-a6a0-3fa5c71cbdc1 |
|
||||||
And the JSON should have 2 items
|
And the JSON should have 2 items
|
||||||
@@ -19,7 +19,6 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
|
|
||||||
created_workgroup := jsonb_set(created_workgroup::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json;
|
created_workgroup := jsonb_set(created_workgroup::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json;
|
||||||
created_workgroup := jsonb_set(created_workgroup::jsonb, '{owner}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json;
|
|
||||||
assert created_workgroup#>>'{created_by, id}' = _citizen_id::text, format('citizenId in workgroup must be the same as citizen, %s != %s', created_workgroup#>>'{created_by, id}', _citizen_id::text);
|
assert created_workgroup#>>'{created_by, id}' = _citizen_id::text, format('citizenId in workgroup must be the same as citizen, %s != %s', created_workgroup#>>'{created_by, id}', _citizen_id::text);
|
||||||
|
|
||||||
-- upsert workgroup
|
-- upsert workgroup
|
||||||
|
|||||||
@@ -16,19 +16,19 @@ declare
|
|||||||
}';
|
}';
|
||||||
selected_workgroup json;
|
selected_workgroup json;
|
||||||
members json;
|
members json;
|
||||||
|
selected_citizen json;
|
||||||
begin
|
begin
|
||||||
created_workgroup := jsonb_set(created_workgroup::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json;
|
created_workgroup := jsonb_set(created_workgroup::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json;
|
||||||
created_workgroup := jsonb_set(created_workgroup::jsonb, '{owner}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json;
|
|
||||||
assert created_workgroup#>>'{created_by, id}' = _citizen_id::text, format('citizenId in workgroup must be the same as citizen, %s != %s', created_workgroup#>>'{created_by, id}', _citizen_id::text);
|
assert created_workgroup#>>'{created_by, id}' = _citizen_id::text, format('citizenId in workgroup must be the same as citizen, %s != %s', created_workgroup#>>'{created_by, id}', _citizen_id::text);
|
||||||
|
|
||||||
-- upsert workgroup
|
-- upsert workgroup
|
||||||
select upsert_workgroup(created_workgroup) into created_workgroup;
|
select upsert_workgroup(created_workgroup) into created_workgroup;
|
||||||
assert created_workgroup->>'description' is not null, 'description should not be null';
|
assert created_workgroup->>'description' is not null, 'description should not be null';
|
||||||
assert (created_workgroup->>'name') = 'Le groupe des vert', format('name must be equal to "Le groupe des vert", %s instead', created_workgroup->>'name');
|
assert (created_workgroup->>'name') = 'Le groupe des vert', format('name must be equal to "Le groupe des vert", %s instead', created_workgroup->>'name');
|
||||||
|
assert (created_workgroup#>>'{members, 0, citizen, id}') = _citizen_id::text, 'workgroup must have creator in members on creation';
|
||||||
|
|
||||||
-- insert another workgroup
|
-- insert another workgroup
|
||||||
created_workgroup_2 := jsonb_set(created_workgroup_2::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json;
|
created_workgroup_2 := jsonb_set(created_workgroup_2::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json;
|
||||||
created_workgroup_2 := jsonb_set(created_workgroup_2::jsonb, '{owner}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json;
|
|
||||||
assert created_workgroup_2#>>'{created_by, id}' = _citizen_id::text, format('citizenId in workgroup must be the same as citizen, %s != %s', created_workgroup_2#>>'{created_by, id}', _citizen_id::text);
|
assert created_workgroup_2#>>'{created_by, id}' = _citizen_id::text, format('citizenId in workgroup must be the same as citizen, %s != %s', created_workgroup_2#>>'{created_by, id}', _citizen_id::text);
|
||||||
select upsert_workgroup(created_workgroup_2) into created_workgroup_2;
|
select upsert_workgroup(created_workgroup_2) into created_workgroup_2;
|
||||||
|
|
||||||
@@ -47,44 +47,61 @@ begin
|
|||||||
|
|
||||||
-- add
|
-- add
|
||||||
select m into members from add_workgroup_members((created_workgroup->>'id')::uuid, json_build_array(
|
select m into members from add_workgroup_members((created_workgroup->>'id')::uuid, json_build_array(
|
||||||
json_build_object('id', _citizen_id2),
|
json_build_object('citizen', json_build_object('id', _citizen_id2), 'roles', '{MASTER}'::text[]),
|
||||||
json_build_object('id', _citizen_id3)
|
json_build_object('citizen', json_build_object('id', _citizen_id3), 'roles', '{MASTER}'::text[])
|
||||||
)) m;
|
)) m;
|
||||||
|
|
||||||
assert json_array_length(members) = 2, 'The members count must be equal to 2';
|
assert json_array_length(members) = 3, 'The members count must be equal to 3';
|
||||||
assert members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id3)),
|
assert (members::jsonb) @> jsonb_build_array(jsonb_build_object(
|
||||||
|
'id', (created_workgroup->>'id'),
|
||||||
|
'citizen', jsonb_build_object('id', _citizen_id3),
|
||||||
|
'roles', jsonb_build_array('MASTER')
|
||||||
|
)),
|
||||||
'Members must contain citizen3';
|
'Members must contain citizen3';
|
||||||
|
|
||||||
-- Check if "find_citizen_by_id" retrun workgroups of citizen
|
-- Check if "find_citizen_by_id" retrun citizen
|
||||||
assert (select find_citizen_by_id(_citizen_id2)#>>'{workgroups, 0, id}') = (created_workgroup->>'id'), 'find_citizen_by_id must return workgroups';
|
assert (select find_citizen_by_id(_citizen_id2)#>>'{id}')::uuid = _citizen_id2, 'find_citizen_by_id must return citizen';
|
||||||
|
|
||||||
|
-- Check if "find_citizen_by_id_with_user_and_workgroups" retrun workgroups of citizen
|
||||||
|
select find_citizen_by_id_with_user_and_workgroups(_citizen_id3) into selected_citizen;
|
||||||
|
assert selected_citizen#>>'{workgroups, 0, roles, 0}' = 'MASTER', format('workgroup must have MASTER role, %s', selected_citizen#>>'{workgroups, 0, roles, 0}');
|
||||||
|
|
||||||
-- update
|
-- update
|
||||||
select m into members from update_workgroup_members((created_workgroup->>'id')::uuid, json_build_array(
|
select m into members from update_workgroup_members((created_workgroup->>'id')::uuid, json_build_array(
|
||||||
json_build_object('id', _citizen_id2),
|
json_build_object('citizen', json_build_object('id', _citizen_id2), 'roles', '{MASTER}'::text[]),
|
||||||
json_build_object('id', _citizen_id)
|
json_build_object('citizen', json_build_object('id', _citizen_id), 'roles', '{MASTER}'::text[])
|
||||||
)) m;
|
)) m;
|
||||||
assert json_array_length(members) = 2, 'The members count must be equal to 2';
|
assert json_array_length(members) = 2, 'The members count must be equal to 2';
|
||||||
assert members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id)),
|
assert (members::jsonb) @> jsonb_build_array(jsonb_build_object(
|
||||||
'Members must contain citizen2';
|
'id', (created_workgroup->>'id'),
|
||||||
assert not members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id3)),
|
'citizen', jsonb_build_object('id', _citizen_id),
|
||||||
'Members must NOT contain citizen3';
|
'roles', jsonb_build_array('MASTER')
|
||||||
|
)), 'Members must contain citizen1';
|
||||||
|
assert not (members::jsonb) @> jsonb_build_array(jsonb_build_object(
|
||||||
|
'citizen', jsonb_build_object('id', _citizen_id3)
|
||||||
|
)), 'Members must NOT contain citizen3';
|
||||||
|
|
||||||
-- remove
|
-- remove
|
||||||
select m into members from remove_workgroup_members((created_workgroup->>'id')::uuid, json_build_array(
|
select m into members from remove_workgroup_members((created_workgroup->>'id')::uuid, json_build_array(jsonb_build_object(
|
||||||
json_build_object('id', _citizen_id2)
|
'citizen', json_build_object('id', _citizen_id2)
|
||||||
)) m;
|
))) m;
|
||||||
assert json_array_length(members) = 1, 'The members count must be equal to 1';
|
assert json_array_length(members) = 1, 'The members count must be equal to 1';
|
||||||
assert members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id)),
|
assert (members::jsonb) @> jsonb_build_array(jsonb_build_object(
|
||||||
'Members must contain citizen1';
|
'citizen', jsonb_build_object('id', _citizen_id)
|
||||||
assert not members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id2)),
|
)), 'Members must contain citizen1';
|
||||||
'Members must NOT contain citizen2';
|
assert not (members::jsonb) @> jsonb_build_array(jsonb_build_object(
|
||||||
|
'citizen', jsonb_build_object('id', _citizen_id2)
|
||||||
|
)), 'Members must NOT contain citizen2';
|
||||||
|
|
||||||
select m into members from find_workgroup_members((created_workgroup->>'id')::uuid) m;
|
select m into members from find_workgroup_members((created_workgroup->>'id')::uuid) m;
|
||||||
assert json_array_length(members) = 1, 'The members count must be equal to 1';
|
assert json_array_length(members) = 1, 'The members count must be equal to 1';
|
||||||
assert members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id)),
|
assert (members::jsonb) @> jsonb_build_array(jsonb_build_object(
|
||||||
'Members must contain citizen1';
|
'citizen', jsonb_build_object('id', _citizen_id)
|
||||||
assert not members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id2)),
|
)), 'Members must contain citizen1';
|
||||||
'Members must NOT contain citizen2';
|
assert not (members::jsonb) @> jsonb_build_array(jsonb_build_object(
|
||||||
|
'citizen', jsonb_build_object('id', _citizen_id2)
|
||||||
|
)), 'Members must NOT contain citizen2';
|
||||||
|
|
||||||
-- Check if find_workgroup_by_id return members
|
-- Check if find_workgroup_by_id return members
|
||||||
select find_workgroup_by_id((created_workgroup->>'id')::uuid) into selected_workgroup;
|
select find_workgroup_by_id((created_workgroup->>'id')::uuid) into selected_workgroup;
|
||||||
assert json_array_length(selected_workgroup->'members') = 1, 'Workgroup must have members';
|
assert json_array_length(selected_workgroup->'members') = 1, 'Workgroup must have members';
|
||||||
|
|||||||
Reference in New Issue
Block a user