#57 I can filter articles by workgroup

update lib "postgres-json:1.2.1"
This commit is contained in:
2020-08-24 15:58:48 +02:00
parent 01c3d85a17
commit 16feab9655
19 changed files with 125 additions and 32 deletions

View File

@@ -8,7 +8,7 @@ import fr.postgresjson.entity.mutable.UuidEntityVersioning
import java.util.*
class Article(
id: UUID = UUID.randomUUID(),
id: UUID? = null,
title: String,
override var anonymous: Boolean = true,
override var content: String,
@@ -27,8 +27,22 @@ class Article(
}
}
class ArticleForUpdate(
id: UUID?,
val title: String,
val anonymous: Boolean = true,
val content: String,
val description: String,
tags: List<String> = emptyList(),
val draft: Boolean = false,
val createdBy: CitizenRef,
val workgroup: WorkgroupRef? = null
) : ArticleRefVersioning(id) {
val tags: List<String> = tags.distinct()
}
open class ArticleSimple(
id: UUID = UUID.randomUUID(),
id: UUID? = null,
override var title: String,
override val createdBy: CitizenBasic,
override var draft: Boolean = false,
@@ -43,14 +57,14 @@ open class ArticleSimple(
Opinionable by OpinionableImp()
open class ArticleRefVersioning(
id: UUID = UUID.randomUUID(),
id: UUID? = null,
versionNumber: Int? = null,
versionId: UUID = UUID.randomUUID()
) : ArticleRef(id),
EntityVersioning<UUID, Int> by UuidEntityVersioning(versionNumber, versionId)
open class ArticleRef(
id: UUID = UUID.randomUUID()
id: UUID? = null
) : ArticleI, TargetRef(id)
interface ArticleI : UuidEntityI, TargetI

View File

@@ -3,6 +3,8 @@ package fr.dcproject.entity
import fr.postgresjson.entity.immutable.*
import fr.postgresjson.entity.mutable.EntityDeletedAt
import fr.postgresjson.entity.mutable.EntityDeletedAtImp
import fr.postgresjson.entity.mutable.EntityVersioning
import fr.postgresjson.entity.mutable.UuidEntityVersioning
import java.util.*
class Constitution(
@@ -41,7 +43,7 @@ open class ConstitutionSimple<Cr : CitizenRefWithUser, T : ConstitutionSimple.Ti
override val createdBy: Cr,
versionId: UUID = UUID.randomUUID()
) : ConstitutionRef(id),
EntityVersioning<UUID, Int?> by UuidEntityVersioning(versionId = versionId),
EntityVersioning<UUID, Int> by UuidEntityVersioning(versionId = versionId),
EntityCreatedAt by EntityCreatedAtImp(),
EntityCreatedBy<Cr> by EntityCreatedByImp(createdBy),
EntityDeletedAt by EntityDeletedAtImp() {

View File

@@ -15,7 +15,7 @@ interface ExtraI<T : TargetI, C : CitizenI> :
val target: T
}
open class TargetRef(id: UUID = UUID.randomUUID(), reference: String = "") : TargetI, UuidEntity(id) {
open class TargetRef(id: UUID? = null, reference: String = "") : TargetI, UuidEntity(id) {
final override val reference: String
get() = if (field != "") field else TargetI.getReference(this)

View File

@@ -1,6 +1,6 @@
package fr.dcproject.repository
import fr.dcproject.entity.ArticleFull
import fr.dcproject.entity.ArticleForUpdate
import fr.dcproject.entity.ArticleSimple
import fr.postgresjson.connexion.Paginated
import fr.postgresjson.connexion.Requester
@@ -42,13 +42,14 @@ class Article(override var requester: Requester) : RepositoryI {
)
}
fun upsert(article: ArticleFull): ArticleEntity? {
fun upsert(article: ArticleForUpdate): ArticleEntity? {
return requester
.getFunction("upsert_article")
.selectOne("resource" to article)
}
class Filter(
val createdById: String? = null
val createdById: String? = null,
val workgroupId: String? = null
) : Parameter
}

View File

@@ -2,6 +2,7 @@ package fr.dcproject.routes
import fr.dcproject.citizen
import fr.dcproject.citizenOrNull
import fr.dcproject.entity.ArticleForUpdate
import fr.dcproject.entity.CitizenRef
import fr.dcproject.entity.WorkgroupRef
import fr.dcproject.entity.WorkgroupSimple
@@ -39,7 +40,8 @@ object ArticlesPaths {
val sort: String? = null,
val direction: RepositoryI.Direction? = null,
val search: String? = null,
val createdBy: String? = null
val createdBy: String? = null,
val workgroup: String? = null
) {
val page: Int = if (page < 1) 1 else page
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
@@ -62,7 +64,7 @@ object ArticlesPaths {
}
@Location("/articles")
class PostArticleRequest: KoinComponent {
class PostArticleRequest : KoinComponent {
class Article(
val id: UUID?,
val title: String,
@@ -77,8 +79,8 @@ object ArticlesPaths {
private val workgroupRepository: WorkgroupRepository by inject()
suspend fun getNewArticle(call: ApplicationCall): ArticleEntity = call.receive<Article>().run {
ArticleEntity(
suspend fun getNewArticle(call: ApplicationCall): ArticleForUpdate = call.receive<Article>().run {
ArticleForUpdate(
id ?: UUID.randomUUID(),
title,
anonymous,
@@ -98,8 +100,14 @@ object ArticlesPaths {
@KtorExperimentalLocationsAPI
fun Route.article(repo: ArticleRepository, viewManager: ArticleViewManager) {
get<ArticlesPaths.ArticlesRequest> {
val articles =
repo.find(it.page, it.limit, it.sort, it.direction, it.search, Filter(createdById = it.createdBy))
val articles = repo.find(
it.page,
it.limit,
it.sort,
it.direction,
it.search,
Filter(createdById = it.createdBy, workgroupId = it.workgroup)
)
assertCan(VIEW, articles.result)
call.respond(articles)
}
@@ -127,9 +135,9 @@ fun Route.article(repo: ArticleRepository, viewManager: ArticleViewManager) {
post<ArticlesPaths.PostArticleRequest> {
it.getNewArticle(call).also { article ->
assertCan(CREATE, article)
repo.upsert(article)
val newArticle = repo.upsert(article) ?: error("Article not updated")
call.respond(article)
raiseEvent(ArticleUpdate.event, ArticleUpdate(article))
raiseEvent(ArticleUpdate.event, ArticleUpdate(newArticle))
}
}
}

View File

@@ -218,6 +218,14 @@ paths:
- $ref: '#/components/parameters/direction'
- $ref: '#/components/parameters/search'
- $ref: '#/components/parameters/createdBy'
- name: workgroup
in: query
description: ID of workgroup
example: 82a0e60a-bb55-dbc0-1c3d-0a804df2b5df
required: false
schema:
type: string
format: uuid
responses:
200:
description: The Article objects

View File

@@ -15,6 +15,7 @@ begin
from article a
where (_search is null or _search = '' or a ==> dsl.multi_match('{title^3, content, description, tags}', _search))
and (_filter->>'created_by_id' is null or a.created_by_id = (_filter->>'created_by_id')::uuid)
and (_filter->>'workgroup_id' is null or a.workgroup_id = (_filter->>'workgroup_id')::uuid)
and a.last_version = true
)
into resource, total
@@ -33,6 +34,7 @@ begin
or a ==> dsl.multi_match('{title^3, content, description, tags}', _search)
)
and (_filter->>'created_by_id' is null or a.created_by_id = (_filter->>'created_by_id')::uuid)
and (_filter->>'workgroup_id' is null or a.workgroup_id = (_filter->>'workgroup_id')::uuid)
and a.last_version = true
order by

View File

@@ -31,6 +31,10 @@ class ArticleSteps : En, KoinTest {
createArticle(id = UUID.fromString(id))
}
Given("I have article created by workgroup ID {string}") { id: String ->
createArticle(workgroup = WorkgroupRef(UUID.fromString(id)))
}
Given("I have comment created by {word} {word} on article {string}:") { firstName: String, lastName: String, articleId: String, extraData: DataTable? ->
commentArticle(articleId, firstName, lastName, extraData)
}
@@ -39,7 +43,7 @@ class ArticleSteps : En, KoinTest {
}
}
private fun createArticle(extraData: DataTable? = null, id: UUID? = null) {
private fun createArticle(extraData: DataTable? = null, id: UUID? = null, workgroup: WorkgroupRef? = null) {
val params = extraData?.asMap<String, String>(String::class.java, String::class.java)
val createdByUsername = params?.get("createdBy")
val username = (createdByUsername ?: "username" + UUID.randomUUID().toString())
@@ -63,12 +67,13 @@ class ArticleSteps : En, KoinTest {
}
}
val article = ArticleEntity(
id = id ?: params?.get("id")?.toUUID() ?: UUID.randomUUID(),
val article = ArticleForUpdate(
id = id ?: params?.get("id")?.toUUID(),
title = "hello",
content = "bla bla bla",
description = "A super article",
createdBy = createdBy
createdBy = createdBy,
workgroup = workgroup
)
get<ArticleRepository>().upsert(article)
}

View File

@@ -6,6 +6,18 @@ Feature: articles routes
When I send a GET request to "/articles"
Then the response status code should be 200
Scenario: Can get articles filtered by workgroup
Given I have 3 article
And I have workgroup:
| id | 2bccd5a7-9082-4b31-88f8-e25d70b22b12 |
| name | Les papy |
And I have article created by workgroup ID "2bccd5a7-9082-4b31-88f8-e25d70b22b12"
When I send a GET request to "/articles?workgroup=2bccd5a7-9082-4b31-88f8-e25d70b22b12"
Then the response status code should be 200
And the JSON should contain:
| total | 1 |
| result[0]workgroup.name | Les papy |
Scenario: Can get versions of article by the id
Given I have article
| id | 13e6091c-8fed-4600-b079-a97a6b7a9800 |

View File

@@ -2,7 +2,9 @@ do
$$
declare
_citizen_id uuid := fixture_citizen();
_workgroup_id uuid := fixture_workgroup(_citizen_id => _citizen_id);
created_article json := '{"version_id":"933b6a1b-50c9-42b6-989f-c02a57814ef9", "title": "Love the world", "anonymous": false, "content": "bla bal bla", "tags": ["love", "test"], "draft":false}';
created_article_grouped json := '{"version_id":"35f5c4c3-0629-4405-9956-12557020c9f5", "title": "Love my group", "anonymous": false, "content": "groupy groupy", "tags": ["love", "group"], "draft":false}';
created_article_v2 json;
first_article_id uuid;
second_article_id uuid;
@@ -25,12 +27,21 @@ begin
assert (created_article_v2->>'last_version')::bool = true, 'The second insert must be set to the last version';
second_article_id = (created_article_v2->>'id')::uuid;
created_article_grouped := jsonb_set(created_article_grouped::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json;
created_article_grouped := jsonb_set(created_article_grouped::jsonb, '{workgroup}'::text[], jsonb_build_object('id', _workgroup_id::text), true)::json;
select upsert_article(created_article_grouped) into created_article_grouped;
-- get articles versions by version_id
select resource, total into selected_article, selected_total from find_articles_versions_by_version_id((created_article->>'version_id')::uuid);
assert selected_article#>>'{0,title}' = 'Love the world', format('title must be "Love the world", %s', selected_article#>>'{0,title}');
assert (selected_article#>>'{0,version_number}')::int = 2, format('version_id must be 2, %s instead', selected_article#>>'{0,version_number}');
assert selected_total = 2, format('the total must be 2, %s instead', selected_total);
-- get articles by workgroup id
select resource, total into selected_article, selected_total from find_articles(_filter => json_build_object('workgroup_id', _workgroup_id));
assert selected_article#>>'{0,title}' = 'Love my group', format('title must be "Love my group", %s', selected_article#>>'{0,title}');
assert selected_total = 1, format('the total must be 1, %s instead', selected_total);
-- get articles versions by id
select resource, total into selected_article, selected_total from find_articles_versions_by_id((created_article->>'id')::uuid);
assert selected_article#>>'{0,title}' = 'Love the world', format('title must be "Love the world", %s', selected_article#>>'{0,title}');

View File

@@ -1,4 +1,4 @@
create or replace function fixture_workgroup(in name text default 'vert', _citizen_id uuid default fixture_citizen(), out _article_id uuid)
create or replace function fixture_workgroup(in name text default 'vert', _citizen_id uuid default fixture_citizen(), out _workgroup_id uuid)
language plpgsql as
$$
declare
@@ -23,6 +23,7 @@ begin
-- upsert workgroup
select upsert_workgroup(created_workgroup) into created_workgroup;
select (created_workgroup->>'id')::uuid into _workgroup_id;
assert created_workgroup->>'description' is not null, 'description should not be null';
end;
$$;