replace Article entity by Article request for the HTTP request
Add draft
This commit is contained in:
@@ -10,6 +10,8 @@ class Article(
|
|||||||
var content: String?,
|
var content: String?,
|
||||||
var description: String?,
|
var description: String?,
|
||||||
var tags: List<String> = emptyList(),
|
var tags: List<String> = emptyList(),
|
||||||
|
var draft: Boolean = false,
|
||||||
|
var lastVersion: Boolean = false,
|
||||||
createdBy: Citizen?
|
createdBy: Citizen?
|
||||||
):
|
):
|
||||||
UuidEntity(id),
|
UuidEntity(id),
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ class Constitution(
|
|||||||
var title: String?,
|
var title: String?,
|
||||||
var anonymous: Boolean? = true,
|
var anonymous: Boolean? = true,
|
||||||
var titles: List<Title> = listOf(),
|
var titles: List<Title> = listOf(),
|
||||||
|
var draft: Boolean = false,
|
||||||
|
var lastVersion: Boolean = false,
|
||||||
createdBy: Citizen?
|
createdBy: Citizen?
|
||||||
): UuidEntity(id),
|
): UuidEntity(id),
|
||||||
EntityVersioning<UUID, Int> by UuidEntityVersioning(),
|
EntityVersioning<UUID, Int> by UuidEntityVersioning(),
|
||||||
|
|||||||
41
src/main/kotlin/fr/dcproject/entity/request/Article.kt
Normal file
41
src/main/kotlin/fr/dcproject/entity/request/Article.kt
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package fr.dcproject.entity.request
|
||||||
|
|
||||||
|
import fr.dcproject.entity.Citizen
|
||||||
|
import java.util.*
|
||||||
|
import fr.dcproject.entity.Article as ArticleEntity
|
||||||
|
|
||||||
|
class Article(
|
||||||
|
val id: UUID?,
|
||||||
|
val title: String,
|
||||||
|
val anonymous: Boolean? = true,
|
||||||
|
val content: String,
|
||||||
|
val description: String,
|
||||||
|
val tags: List<String> = emptyList(),
|
||||||
|
val draft: Boolean = false,
|
||||||
|
val versionId: UUID?
|
||||||
|
):
|
||||||
|
Request {
|
||||||
|
|
||||||
|
fun merge(article: ArticleEntity) {
|
||||||
|
article.title = this.title
|
||||||
|
article.content = this.content
|
||||||
|
article.description = this.description
|
||||||
|
article.tags = this.tags.distinct()
|
||||||
|
article.anonymous = this.anonymous
|
||||||
|
article.draft = this.draft
|
||||||
|
article.versionId = this.versionId ?: UUID.randomUUID()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create(createdBy: Citizen): ArticleEntity {
|
||||||
|
return ArticleEntity(
|
||||||
|
id ?: UUID.randomUUID(),
|
||||||
|
title,
|
||||||
|
anonymous,
|
||||||
|
content,
|
||||||
|
description,
|
||||||
|
tags,
|
||||||
|
draft,
|
||||||
|
createdBy = createdBy
|
||||||
|
).apply { this.versionId = this@Article.versionId ?: UUID.randomUUID() }
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/main/kotlin/fr/dcproject/entity/request/Request.kt
Normal file
3
src/main/kotlin/fr/dcproject/entity/request/Request.kt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package fr.dcproject.entity.request
|
||||||
|
|
||||||
|
interface Request
|
||||||
@@ -14,6 +14,7 @@ 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 fr.dcproject.entity.Article as ArticleEntity
|
import fr.dcproject.entity.Article as ArticleEntity
|
||||||
|
import fr.dcproject.entity.request.Article as ArticleEntityRequest
|
||||||
import fr.dcproject.repository.Article as ArticleRepository
|
import fr.dcproject.repository.Article as ArticleRepository
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@@ -53,8 +54,8 @@ fun Route.article(repo: ArticleRepository) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
post<ArticlesPaths.PostArticleRequest> {
|
post<ArticlesPaths.PostArticleRequest> {
|
||||||
val article = call.receive<ArticleEntity>()
|
val request = call.receive<ArticleEntityRequest>()
|
||||||
article.createdBy = citizen
|
val article = request.create(citizen)
|
||||||
|
|
||||||
assertCan(CREATE, article)
|
assertCan(CREATE, article)
|
||||||
|
|
||||||
|
|||||||
@@ -560,6 +560,13 @@ components:
|
|||||||
version_id:
|
version_id:
|
||||||
$ref: '#/components/schemas/UUID'
|
$ref: '#/components/schemas/UUID'
|
||||||
|
|
||||||
|
lastVersion:
|
||||||
|
properties:
|
||||||
|
last_version:
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
|
||||||
Paginated:
|
Paginated:
|
||||||
properties:
|
properties:
|
||||||
result:
|
result:
|
||||||
@@ -696,6 +703,10 @@ components:
|
|||||||
type: boolean
|
type: boolean
|
||||||
required: false
|
required: false
|
||||||
default: true
|
default: true
|
||||||
|
draft:
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
- $ref: '#/components/schemas/versionId'
|
- $ref: '#/components/schemas/versionId'
|
||||||
ArticleResponse:
|
ArticleResponse:
|
||||||
type: object
|
type: object
|
||||||
@@ -704,6 +715,7 @@ components:
|
|||||||
- $ref: '#/components/schemas/UuidEntity'
|
- $ref: '#/components/schemas/UuidEntity'
|
||||||
- $ref: '#/components/schemas/CreatedBy'
|
- $ref: '#/components/schemas/CreatedBy'
|
||||||
- $ref: '#/components/schemas/CreatedAt'
|
- $ref: '#/components/schemas/CreatedAt'
|
||||||
|
- $ref: '#/components/schemas/lastVersion'
|
||||||
ArticleRequest:
|
ArticleRequest:
|
||||||
$ref: '#/components/schemas/ArticleBase'
|
$ref: '#/components/schemas/ArticleBase'
|
||||||
|
|
||||||
@@ -727,6 +739,10 @@ components:
|
|||||||
type: boolean
|
type: boolean
|
||||||
required: false
|
required: false
|
||||||
default: true
|
default: true
|
||||||
|
draft:
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
- $ref: '#/components/schemas/versionId'
|
- $ref: '#/components/schemas/versionId'
|
||||||
ConstitutionResponse:
|
ConstitutionResponse:
|
||||||
type: object
|
type: object
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ begin
|
|||||||
delete from article_relations;
|
delete from article_relations;
|
||||||
delete from article;
|
delete from article;
|
||||||
|
|
||||||
insert into article (id, version_id, created_by_id, title, anonymous, content, description, tags, created_at, is_draft)
|
insert into article (id, version_id, created_by_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),
|
||||||
uuid_in(md5('article_v'||row_number() over () % (_citizen_count / 2))::cstring),
|
uuid_in(md5('article_v'||row_number() over () % (_citizen_count / 2))::cstring),
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ create or replace function find_articles(
|
|||||||
) language plpgsql as
|
) language plpgsql as
|
||||||
$$
|
$$
|
||||||
begin
|
begin
|
||||||
select json_agg(t), (select count(id) from article a where (_search is null or _search = '' or a ==> dsl.multi_match('{title^3, content, description}', _search)) and a.is_last_version = true)
|
select json_agg(t), (select count(id) from article a where (_search is null or _search = '' or a ==> dsl.multi_match('{title^3, content, description}', _search)) and a.last_version = true)
|
||||||
into resource, total
|
into resource, total
|
||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
@@ -21,7 +21,7 @@ begin
|
|||||||
_search is null
|
_search is null
|
||||||
or _search = ''
|
or _search = ''
|
||||||
or a ==> dsl.multi_match('{title^3, content, description}', _search)
|
or a ==> dsl.multi_match('{title^3, content, description}', _search)
|
||||||
) and a.is_last_version = true
|
) and a.last_version = true
|
||||||
order by
|
order by
|
||||||
_score desc,
|
_score desc,
|
||||||
case direction when 'asc' then
|
case direction when 'asc' then
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ begin
|
|||||||
into resource
|
into resource
|
||||||
from article as a
|
from article as a
|
||||||
where a.version_id = _version_id
|
where a.version_id = _version_id
|
||||||
and a.is_draft = false
|
and a.draft = false
|
||||||
and a.deleted_at is null
|
and a.deleted_at is null
|
||||||
order by a.version_number desc
|
order by a.version_number desc
|
||||||
limit 1
|
limit 1
|
||||||
|
|||||||
@@ -4,17 +4,32 @@ $$
|
|||||||
declare
|
declare
|
||||||
new_id uuid;
|
new_id uuid;
|
||||||
_id_exist boolean;
|
_id_exist boolean;
|
||||||
|
_existing_draft article = (
|
||||||
|
select a from article a
|
||||||
|
where a.version_id = (resource->>'version_id')::uuid
|
||||||
|
and a.draft = true
|
||||||
|
);
|
||||||
begin
|
begin
|
||||||
-- check if version id already exist
|
-- check if version id already exist
|
||||||
select count(*) >= 1
|
select count(*) >= 1
|
||||||
into _id_exist
|
into _id_exist
|
||||||
from article
|
from article
|
||||||
where (resource->>'id')::uuid is not null
|
where (resource->>'id')::uuid is not null
|
||||||
and id = (resource->>'id')::uuid
|
and id = (resource->>'id')::uuid;
|
||||||
-- and draft = false
|
|
||||||
;
|
|
||||||
|
|
||||||
insert into article (id, version_id, created_by_id, title, anonymous, content, description, tags)
|
if (_existing_draft.id is not null) then
|
||||||
|
update article a2 set
|
||||||
|
title = a.title,
|
||||||
|
anonymous = a.anonymous,
|
||||||
|
content = a.content,
|
||||||
|
description = a.description,
|
||||||
|
tags = a.tags,
|
||||||
|
draft = a.draft
|
||||||
|
from json_populate_record(null::article, resource) a
|
||||||
|
where a2.id = (_existing_draft.id)::uuid
|
||||||
|
returning a2.id into new_id;
|
||||||
|
else
|
||||||
|
insert into article (id, version_id, created_by_id, title, anonymous, content, description, tags, draft)
|
||||||
select
|
select
|
||||||
case when _id_exist then uuid_generate_v4()
|
case when _id_exist then uuid_generate_v4()
|
||||||
else coalesce(id, uuid_generate_v4()) end,
|
else coalesce(id, uuid_generate_v4()) end,
|
||||||
@@ -24,9 +39,11 @@ begin
|
|||||||
anonymous,
|
anonymous,
|
||||||
content,
|
content,
|
||||||
description,
|
description,
|
||||||
tags
|
tags,
|
||||||
|
draft
|
||||||
from json_populate_record(null::article, resource)
|
from json_populate_record(null::article, resource)
|
||||||
returning id into new_id;
|
returning id into new_id;
|
||||||
|
end if;
|
||||||
|
|
||||||
if resource->>'relations' is not null then
|
if resource->>'relations' is not null then
|
||||||
delete from article_relations
|
delete from article_relations
|
||||||
|
|||||||
@@ -13,11 +13,7 @@ begin
|
|||||||
into _id_exist
|
into _id_exist
|
||||||
from constitution
|
from constitution
|
||||||
where (resource->>'id')::uuid is not null
|
where (resource->>'id')::uuid is not null
|
||||||
and id = (resource->>'id')::uuid
|
and id = (resource->>'id')::uuid;
|
||||||
-- and draft = false
|
|
||||||
;
|
|
||||||
|
|
||||||
raise notice '%', _id_exist;
|
|
||||||
|
|
||||||
insert into constitution (id, version_id, created_by_id, title, anonymous)
|
insert into constitution (id, version_id, created_by_id, title, anonymous)
|
||||||
select
|
select
|
||||||
|
|||||||
@@ -94,12 +94,14 @@ declare
|
|||||||
begin
|
begin
|
||||||
if (tablename = 'article'::regclass) then
|
if (tablename = 'article'::regclass) then
|
||||||
update article a
|
update article a
|
||||||
set is_last_version = false
|
set last_version = false
|
||||||
where a.version_id = _version_id and a.is_last_version = true;
|
where a.version_id = _version_id
|
||||||
|
and a.last_version = true;
|
||||||
elseif (tablename = 'constitution'::regclass) then
|
elseif (tablename = 'constitution'::regclass) then
|
||||||
update constitution c
|
update constitution c
|
||||||
set is_last_version = false
|
set last_version = false
|
||||||
where c.version_id = _version_id and c.is_last_version = true;
|
where c.version_id = _version_id
|
||||||
|
and c.last_version = true;
|
||||||
else
|
else
|
||||||
raise exception '% is not implemented', tablename::text;
|
raise exception '% is not implemented', tablename::text;
|
||||||
end if;
|
end if;
|
||||||
@@ -116,28 +118,32 @@ begin
|
|||||||
|
|
||||||
if (tablename = 'article'::regclass) then
|
if (tablename = 'article'::regclass) then
|
||||||
update article a1
|
update article a1
|
||||||
set is_last_version = true
|
set last_version = true
|
||||||
from (
|
from (
|
||||||
select id from article a2
|
select id
|
||||||
|
from article a2
|
||||||
where a2.version_id = _version_id
|
where a2.version_id = _version_id
|
||||||
and a2.is_draft = false
|
and a2.draft = false
|
||||||
and a2.deleted_at is null
|
and a2.deleted_at is null
|
||||||
order by version_number desc
|
order by version_number desc
|
||||||
limit 1
|
limit 1
|
||||||
) as a3
|
) as a3
|
||||||
where a1.version_id = _version_id and a1.id = a3.id;
|
where a1.version_id = _version_id
|
||||||
|
and a1.id = a3.id;
|
||||||
elseif (tablename = 'constitution'::regclass) then
|
elseif (tablename = 'constitution'::regclass) then
|
||||||
update constitution c1
|
update constitution c1
|
||||||
set is_last_version = true
|
set last_version = true
|
||||||
from (
|
from (
|
||||||
select id from constitution c2
|
select id
|
||||||
|
from constitution c2
|
||||||
where c2.version_id = _version_id
|
where c2.version_id = _version_id
|
||||||
and c2.is_draft = false
|
and c2.draft = false
|
||||||
and c2.deleted_at is null
|
and c2.deleted_at is null
|
||||||
order by version_number desc
|
order by version_number desc
|
||||||
limit 1
|
limit 1
|
||||||
) as c3
|
) as c3
|
||||||
where c1.version_id = _version_id and c1.id = c3.id;
|
where c1.version_id = _version_id
|
||||||
|
and c1.id = c3.id;
|
||||||
else
|
else
|
||||||
raise exception '% is not implemented', tablename::text;
|
raise exception '% is not implemented', tablename::text;
|
||||||
end if;
|
end if;
|
||||||
@@ -158,11 +164,11 @@ create or replace function set_to_last_version() returns trigger
|
|||||||
language plpgsql as
|
language plpgsql as
|
||||||
$$
|
$$
|
||||||
begin
|
begin
|
||||||
if (new.is_draft = false and new.deleted_at is null) then
|
if (new.draft = false and new.deleted_at is null) then
|
||||||
perform set_all_version_to_old(tg_table_name::regclass, new.version_id);
|
perform set_all_version_to_old(tg_table_name::regclass, new.version_id);
|
||||||
new.is_last_version = true;
|
new.last_version = true;
|
||||||
else
|
else
|
||||||
new.is_last_version = false;
|
new.last_version = false;
|
||||||
end if;
|
end if;
|
||||||
return new;
|
return new;
|
||||||
end;
|
end;
|
||||||
@@ -172,7 +178,7 @@ create or replace function set_last_version() returns trigger
|
|||||||
language plpgsql as
|
language plpgsql as
|
||||||
$$
|
$$
|
||||||
begin
|
begin
|
||||||
if (new.is_draft != old.is_draft or new.deleted_at != old.deleted_at) then
|
if (new.draft != old.draft or new.deleted_at != old.deleted_at) then
|
||||||
perform set_correct_last_version(tg_table_name::regclass, new.version_id);
|
perform set_correct_last_version(tg_table_name::regclass, new.version_id);
|
||||||
end if;
|
end if;
|
||||||
return new;
|
return new;
|
||||||
@@ -195,12 +201,12 @@ create table article
|
|||||||
description text null check ( description != '' and length(description) < 4096 ),
|
description text null check ( description != '' and length(description) < 4096 ),
|
||||||
tags varchar(32)[] default '{}' not null,
|
tags varchar(32)[] default '{}' not null,
|
||||||
deleted_at timestamptz default null null,
|
deleted_at timestamptz default null null,
|
||||||
is_draft boolean default false not null,
|
draft boolean default false not null,
|
||||||
is_last_version boolean default false not null,
|
last_version boolean default false not null,
|
||||||
unique (version_id, version_number)
|
unique (version_id, version_number)
|
||||||
);
|
);
|
||||||
|
|
||||||
create unique index last_version_article_idx on article (is_last_version, version_id) where is_last_version = true;
|
create unique index last_version_article_idx on article (last_version, version_id) where last_version = true;
|
||||||
|
|
||||||
create trigger generate_version_number_trigger
|
create trigger generate_version_number_trigger
|
||||||
before insert
|
before insert
|
||||||
@@ -235,12 +241,12 @@ create table constitution
|
|||||||
intro text null check ( length(intro) < 4096 ),
|
intro text null check ( length(intro) < 4096 ),
|
||||||
anonymous boolean default false not null,
|
anonymous boolean default false not null,
|
||||||
deleted_at timestamptz default null null,
|
deleted_at timestamptz default null null,
|
||||||
is_draft boolean default false not null,
|
draft boolean default false not null,
|
||||||
is_last_version boolean default false not null,
|
last_version boolean default false not null,
|
||||||
unique (version_id, version_number)
|
unique (version_id, version_number)
|
||||||
);
|
);
|
||||||
|
|
||||||
create unique index last_version_constitution_idx on constitution (is_last_version, version_id) where is_last_version = true;
|
create unique index last_version_constitution_idx on constitution (last_version, version_id) where last_version = true;
|
||||||
|
|
||||||
create trigger generate_version_number_trigger
|
create trigger generate_version_number_trigger
|
||||||
before insert
|
before insert
|
||||||
|
|||||||
@@ -28,13 +28,13 @@ begin
|
|||||||
select upsert_article(created_article) into created_article;
|
select upsert_article(created_article) into created_article;
|
||||||
assert created_article->>'version_id' is not null, 'version_id should not be null';
|
assert created_article->>'version_id' is not null, 'version_id should not be null';
|
||||||
assert (created_article->>'version_number')::int = 1, format('version_number must be equal to 1, %s instead', created_article->>'version_number');
|
assert (created_article->>'version_number')::int = 1, format('version_number must be equal to 1, %s instead', created_article->>'version_number');
|
||||||
assert (created_article->>'is_last_version')::bool = true, 'The first insert must be set to the last version';
|
assert (created_article->>'last_version')::bool = true, 'The first insert must be set to the last version';
|
||||||
first_article_id = (created_article->>'id')::uuid;
|
first_article_id = (created_article->>'id')::uuid;
|
||||||
|
|
||||||
-- try to create new version
|
-- try to create new version
|
||||||
select upsert_article(created_article) into created_article_v2;
|
select upsert_article(created_article) into created_article_v2;
|
||||||
assert (created_article_v2->>'version_number')::int = 2, format('version_number must be equal to 2, %s instead', created_article_v2->>'version_number');
|
assert (created_article_v2->>'version_number')::int = 2, format('version_number must be equal to 2, %s instead', created_article_v2->>'version_number');
|
||||||
assert (created_article_v2->>'is_last_version')::bool = true, 'The second insert must be set to the last version';
|
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;
|
second_article_id = (created_article_v2->>'id')::uuid;
|
||||||
|
|
||||||
-- get articles versions by version_id
|
-- get articles versions by version_id
|
||||||
@@ -60,14 +60,14 @@ begin
|
|||||||
|
|
||||||
-- update to draft, then the last_version column must be change
|
-- update to draft, then the last_version column must be change
|
||||||
update article
|
update article
|
||||||
set is_draft = true
|
set draft = true
|
||||||
where id = second_article_id;
|
where id = second_article_id;
|
||||||
|
|
||||||
select find_last_article_by_version_id((created_article_v2->>'version_id')::uuid) into selected_article;
|
select find_last_article_by_version_id((created_article_v2->>'version_id')::uuid) into selected_article;
|
||||||
assert (selected_article->>'version_number')::int = 1, format('version_id must be 1, %s instead', selected_article->>'version_number');
|
assert (selected_article->>'version_number')::int = 1, format('version_id must be 1, %s instead', selected_article->>'version_number');
|
||||||
|
|
||||||
update article
|
update article
|
||||||
set is_draft = false
|
set draft = false
|
||||||
where id = second_article_id;
|
where id = second_article_id;
|
||||||
|
|
||||||
select find_last_article_by_version_id((created_article_v2->>'version_id')::uuid) into selected_article;
|
select find_last_article_by_version_id((created_article_v2->>'version_id')::uuid) into selected_article;
|
||||||
|
|||||||
Reference in New Issue
Block a user