308 Commits

Author SHA1 Message Date
1c013e3e15 lint 2022-02-25 23:48:33 +01:00
003aa9ff05 update gradle plugin 2022-02-25 23:48:33 +01:00
44c5f1b15b Merge pull request #104 from flecomte/sibling
Rename findVersionsByVersionId to findSiblingVersions
2022-02-25 23:45:45 +01:00
2f3a2f9b8e Rename findVersionsByVersionId to findSiblingVersions 2022-02-25 23:17:03 +01:00
1a62c5ec9a Merge pull request #103 from flecomte/update_gradle2
gradle dependencies fix
2022-02-25 22:55:12 +01:00
55674cbef1 upgrade jacoco 2022-02-25 22:44:38 +01:00
ac5dbbc384 update gradle to 7.4 2022-02-25 22:44:26 +01:00
9460992f37 update gradle to 7.2 2022-02-25 22:43:49 +01:00
8013cfb266 gradle dependencies fix 2022-02-25 22:42:32 +01:00
f577ea70b3 Merge pull request #96 from flecomte/60
#60 Can follow citizen
2021-04-27 21:48:16 +02:00
2673cf527a Clean useless error 2021-04-27 21:30:06 +02:00
371483ccde Improve query findFollowsByTarget & add tests 2021-04-27 18:52:36 +02:00
76e4033a22 deduplicate follow output 2021-04-18 02:36:14 +02:00
fee5e5784b Refactoring of Notification system 2021-04-18 02:16:36 +02:00
1c33c026f0 #60 Can follow citizen 2021-04-17 01:37:32 +02:00
4871e7d780 Merge pull request #95 from flecomte/61
#61 Fix version date returned for the article.createdAt
2021-04-16 21:44:03 +02:00
359450ad8f #61 Fix version date returned for the article.createdAt 2021-04-16 21:23:43 +02:00
11903a4cda Merge pull request #94 from flecomte/62
#62 if not connected, you not must view the articles draft
2021-04-16 18:30:15 +02:00
1a8b544cdb #62 if not connected, you not must view the articles draft 2021-04-16 18:15:22 +02:00
e2c1f15ab8 Merge pull request #93 from flecomte/dependencies
Use dynamic dependencies
2021-04-16 17:25:52 +02:00
dc87c95bb4 Enable zip64 for jar 2021-04-16 16:59:13 +02:00
d4cc3f21da fix CI 2021-04-16 16:19:04 +02:00
59c050d14d Update dependencies
Fix for koin 3.0
2021-04-16 16:09:59 +02:00
cb9bd0c14b Use gradle Lock file 2021-04-16 16:09:58 +02:00
1ce3a18d8e Update gradle plugins versions 2021-04-16 16:09:58 +02:00
be6fb8dc12 Update gradle to 7.0 2021-04-16 16:09:58 +02:00
cd9fd569d7 launch CI on master 2021-04-16 03:40:39 +02:00
2920186352 Merge pull request #91 from flecomte/21-valid-input
Valider les resource entrente
2021-04-16 03:27:10 +02:00
cccabb2cc9 improve sonarqube action 2021-04-16 03:17:38 +02:00
620cd73fec Change intellij tasks 2021-04-16 03:09:56 +02:00
e474a40068 Change tests task and CI 2021-04-16 03:09:55 +02:00
242bf9c9b3 Fix commentSqlTest 2021-04-16 02:53:05 +02:00
543f3fb9bb Add retry for viewsTest 2021-04-16 02:53:04 +02:00
994e266b52 Add validation on route CreateWorkgroup 2021-04-16 00:08:57 +02:00
3f392eece6 Add validation on route EditWorkgroup 2021-04-15 23:45:47 +02:00
518b59e9aa Add validation on route GetWorkgroups 2021-04-15 22:20:16 +02:00
596b7ff0c9 Extract Workgroup Member test into external file 2021-04-15 20:52:34 +02:00
87175eb8ea clean route comment 2021-04-15 02:53:32 +02:00
1118866856 Add validation on route PutVoteOnConstitution 2021-04-15 02:42:29 +02:00
367f59ee18 Add validation on route PutVoteOnComment 2021-04-15 02:33:46 +02:00
0588f88f9a Add validation on route PutVoteOnArticle 2021-04-15 02:20:57 +02:00
496cf50d88 Add validation on route GetCitizenVotesOnArticle 2021-04-15 01:27:48 +02:00
13253e4af1 Add validation on route GetMyOpinionsArticle 2021-04-15 01:06:46 +02:00
39c665b7a9 Add Test for Notification routes
Add @JsonSubTypes on Notification
return all creator on request find_follows_article_by_target
Add testNotifications task
2021-04-14 23:51:44 +02:00
50b4cf1816 Add testFollow task 2021-04-12 01:03:57 +02:00
6a5e00bb4d Add validation on Constitution routes 2021-04-11 00:54:09 +02:00
0c8bcbd634 Add limit on content field (comment request) 2021-04-11 00:54:08 +02:00
8223dd21bb Add validation on route CreateComments & EditComment
rename POST /comments/{comment}/children
method edit and create comment of repository return edited/created comment
2021-04-10 01:16:09 +02:00
27e405c585 Move tests 2021-04-09 18:43:59 +02:00
34513e25b6 Add validation on route CreateConstitutionComment & GetConstitutionCommentRequest 2021-04-09 18:39:03 +02:00
f5c1aa29e8 Add validation on route GetArticleComments 2021-04-09 18:06:32 +02:00
875d0bfffa Add test 404 for GetArticle route 2021-04-09 16:43:46 +02:00
fb7b07340a Improve test of password validation 2021-04-09 01:09:09 +02:00
a07b19a3cb Add validation on route CreateCommentArticle 2021-04-09 00:58:35 +02:00
13cdaaf01a Add validation on route FindCitizens 2021-04-08 22:25:43 +02:00
e473e62068 remove CodeFactor & Codacy 2021-04-08 18:08:48 +02:00
9d3eeeb04b Add validation on route ChangePasswordCitizenRequest 2021-04-08 18:02:27 +02:00
eb399392c9 remove parallel run for tests 2021-04-08 03:03:04 +02:00
1ec1c59c8c remove useless log 2021-04-08 03:02:03 +02:00
9511331cd2 Add validation on route Register 2021-04-08 02:10:45 +02:00
33a8cdb169 Add email validation 2021-04-08 02:02:46 +02:00
6aa3ddb28d Add Password validation 2021-04-08 01:55:10 +02:00
708d241a26 Add tags on tests 2021-04-07 20:53:51 +02:00
e4745e71c2 Add validation on route UpsertArticle 2021-04-07 20:53:21 +02:00
e26710898e add example on openapi 400 error 2021-04-06 23:35:36 +02:00
fe11384ad2 Add validation on route GetOneArticle 2021-04-06 23:04:02 +02:00
61a7091736 Add validation on route Article versions 2021-04-06 00:36:08 +02:00
2ef9f65f2c Clean BadRequest response 2021-04-05 01:40:12 +02:00
b5fc3d25bb Improve Article validation & test on BadRequest 2021-04-05 00:50:02 +02:00
3faf2e5f0d Add function to respond on BadRequest 2021-04-05 00:48:58 +02:00
ab418ae300 Add openapi response of error 400 2021-04-05 00:48:11 +02:00
395d64a44a create testArticle gradle task 2021-04-04 21:02:02 +02:00
a300e275d4 Valid FindArticles request with Konform 2021-04-04 21:02:02 +02:00
3a18ef0554 Improve articles request test 2021-04-04 21:01:57 +02:00
921a545877 Merge pull request #92 from flecomte/sonarq
Sonarcloud
2021-04-04 21:01:27 +02:00
ef942b956e Use sonarcloud 2021-04-04 01:35:02 +02:00
ff74ad7e47 Merge pull request #90 from flecomte/improve-test
Improve tests
2021-04-03 00:39:16 +02:00
2bb90ced03 Refactor 'the response should contain list' 2021-04-03 00:31:24 +02:00
a48cd52652 Add Tags on tests 2021-04-03 00:10:01 +02:00
dd4c2dadab Fix parameters schema validation 2021-04-02 23:47:20 +02:00
c81b63aef2 Merge pull request #89 from flecomte/ArticleViewManager
ArticleViewRepository
2021-04-02 12:39:34 +02:00
cb762a446a Move ArticleViewRepository 2021-04-02 12:29:50 +02:00
db810ab0c6 Rename ArticleViewManager to ArticleViewRepository 2021-04-02 12:29:11 +02:00
01c5b78325 Merge pull request #87 from flecomte/jwt-token-into-env
move JWT secret into ENV
2021-03-31 18:23:13 +02:00
1bc7293660 move JWT secret into ENV 2021-03-31 17:58:47 +02:00
55c890aca5 Merge pull request #86
move "Check auth on all routes" extension into the class
2021-03-31 12:31:51 +02:00
c0e364637a move "Check auth on all routes" extension into the class 2021-03-31 12:30:37 +02:00
0a1ed9ba82 Merge pull request #85 from flecomte/optimise-testsql
Opimize testSql
2021-03-31 03:09:12 +02:00
620085fda8 Optimise gradle task TestSql 2021-03-31 02:58:37 +02:00
3b5c1cf68a Merge pull request #84 from flecomte/69
Error codes
2021-03-31 02:53:58 +02:00
a0d07e88a1 Fix all security routes 2021-03-31 02:43:43 +02:00
f17277c0e9 Test all security of routes #76 2021-03-31 02:35:59 +02:00
9f13213a35 Fix error text when openapi definition was not found 2021-03-27 21:57:53 +01:00
5f0b8de159 #69 Format HTTP error
add 403 for /articles route
2021-03-26 01:53:41 +01:00
6b66130ddc #69 Move HttpStatusPage catch 2021-03-25 23:40:05 +01:00
7f93ec5044 Merge pull request #82 from flecomte/lint
Optimize CI
2021-03-25 02:07:52 +01:00
1be608e6b2 Add Codacy badge 2021-03-25 02:05:05 +01:00
b13cd5544c add coveralls on CI 2021-03-25 01:53:57 +01:00
104f0fb3fc remove distZip & distTar 2021-03-24 23:06:38 +01:00
b2f40ff421 Restrict CI on pull_request on master 2021-03-24 21:56:58 +01:00
09e81620a1 rollback lintCheck after test, create task testAll 2021-03-24 21:32:28 +01:00
7e16c7bb74 Merge pull request #81
Lint
2021-03-24 19:49:34 +01:00
fe953fc967 lintCheck after test 2021-03-24 19:48:14 +01:00
453fd2225c Merge pull request #80
rename openapi file
2021-03-24 19:39:23 +01:00
70fd54d831 Fix destination installation doc 2021-03-24 19:35:11 +01:00
dcf7a2bc06 Rename openapi file 2021-03-24 19:34:39 +01:00
118af0170a Remove unused openapi file 2021-03-24 19:34:00 +01:00
0aa8089a9a Merge pull request #79
Add codefactor badge
2021-03-24 19:29:44 +01:00
fef5f3b396 CodeFactor badge 2021-03-24 19:27:09 +01:00
1838b90ac9 Merge pull request #78
Create CI
2021-03-24 19:12:41 +01:00
73fa2be91f Split CI task test 2021-03-24 19:11:04 +01:00
52183abd08 Lint 2021-03-24 19:08:41 +01:00
e19266d4cc Create CI Action 2021-03-24 19:07:02 +01:00
f458d7b674 Move SQL test files 2021-03-24 19:07:01 +01:00
29d4d6ec25 Merge pull request #77 from flecomte/refactoring-component-and-immutable
Big refactoring
2021-03-24 19:06:06 +01:00
03f68213e8 Test openapi schema of route /workgroup/*/members 2021-03-24 19:01:12 +01:00
66fa1ba840 Test openapi schema of route /workgroup/*
add test and fix update workgroup
2021-03-24 01:15:19 +01:00
89b2abc10e Test openapi schema of route /workgroup/* 2021-03-23 22:08:13 +01:00
b04408219d Test openapi schema of route /votes/* 2021-03-22 20:28:53 +01:00
5ef2345ea6 Test openapi schema of route /opinions/* 2021-03-22 02:57:33 +01:00
50b5ca03c6 Fix schema validator for parameters 2021-03-22 02:44:44 +01:00
9862e112eb Test openapi schema of GET /constitutions/{constitution}/follows 2021-03-22 00:52:23 +01:00
5dc1518cfc Test openapi schema of GET /citizens/{citizen}/follows/articles 2021-03-22 00:30:31 +01:00
fbd18e4c2e update wrapper 2021-03-21 22:36:52 +01:00
0e5943864d Test openapi schema of /follow/* 2021-03-20 02:43:53 +01:00
46cc61fc25 update kotlin 2021-03-20 02:00:05 +01:00
786b0bc949 create comment.toOutput() 2021-03-20 01:57:10 +01:00
8aa809c37e fix FindArticles schema 2021-03-20 01:25:23 +01:00
fdd69a687b create CitizenCreatorI.toOutput() 2021-03-20 01:20:58 +01:00
4c1ab796e4 Test openapi schema of /constitutions/* 2021-03-20 01:14:39 +01:00
c1a3590b2b Improve BitMaskI 2021-03-20 00:58:51 +01:00
c9ce2a9dc7 Refactor constitution entity 2021-03-20 00:55:39 +01:00
8701815288 Fix badRequest 2021-03-20 00:54:33 +01:00
d03b585372 Improve BitMaskI 2021-03-20 00:54:01 +01:00
c9879be72c create openapi schema ArticleListingResponse 2021-03-19 21:47:00 +01:00
ec8abf44b8 Idea config 2021-03-19 21:46:12 +01:00
776e0257fb add updatedAt for comment response 2021-03-19 21:19:53 +01:00
8f1f1f10d9 add required for paginated in openapi 2021-03-19 21:05:49 +01:00
cba3f1f4bc Change article.createdBy response 2021-03-19 21:04:55 +01:00
316b1e8318 Idea config 2021-03-18 21:09:55 +01:00
78a6cc417c Test openapi schema of
POST/GET /constitutions/{constitution}/comments
GET /citizens/{citizen}/comments/constitutions
2021-03-17 22:07:14 +01:00
564d612e9a Test openapi schema of GET /comments/{comment}/children 2021-03-17 20:55:58 +01:00
65bf9a75f0 Fix CommentConstitutionRepository repo 2021-03-17 18:37:39 +01:00
33ceb13cde Test openapi schema of GET /citizens/{citizen}/comments/articles 2021-03-17 18:30:46 +01:00
7765e6d27a Test openapi schema of PUT /comments/{comment} 2021-03-17 18:25:55 +01:00
ca402dbea7 Test openapi schema of /comments/{comment} 2021-03-17 18:09:05 +01:00
07ae50c40a Test openapi schema of /articles/{article}/comments 2021-03-17 17:48:42 +01:00
42dbd940a0 Test openapi schema of /articles/{article}/comments 2021-03-17 02:17:37 +01:00
0f768f3e4c Test openapi schema of /citizens/{citizen}/password/change 2021-03-17 00:46:05 +01:00
5fce37f269 Test openapi schema of /citizens/{id} 2021-03-17 00:28:01 +01:00
52bdcd0990 Test openapi schema of /citizens/current 2021-03-16 18:51:41 +01:00
1655f47044 Test openapi schema of /citizens 2021-03-16 18:23:40 +01:00
c07a57a591 Test openapi schema of Auth passwordless 2021-03-16 01:28:26 +01:00
0cf1aea9bf Test openapi schema of Register
Fix some routes
Improve Schema Validation
2021-03-16 00:53:10 +01:00
235de4e5ff Improve error on "no path found" in openapi file 2021-03-15 10:13:38 +01:00
869093ab25 Fix tests 2021-03-15 10:13:01 +01:00
189aa8d549 Test openapi schema response of Login 2021-03-15 02:02:26 +01:00
97b07fb424 Test openapi schema requestBody 2021-03-15 02:01:39 +01:00
9c88adbabd Test openapi schema response of FindArticlesVersion,GetOneArticle,UpsertArticle
change snack_case to camelCase
2021-03-12 23:32:32 +01:00
ed0873837b Test openapi schema parameters in path 2021-03-09 03:49:59 +01:00
6988365473 Test openapi schema parameters 2021-03-09 01:53:01 +01:00
4762275b5b Test openapi schema response of FindArticles 2021-03-08 23:13:48 +01:00
97c1e47db2 Fix openapi.yaml 2021-03-08 23:07:23 +01:00
bb637dd96a #71 Use response object for route FindArticles 2021-03-05 00:39:49 +01:00
9fc21f5459 clean warnings 2021-03-03 03:16:09 +01:00
d9deb4836e #72 Move Entity and repository on the same package 2021-03-03 02:46:51 +01:00
79feed54dd #68 Clean vote and citizen Entity
remove last warnings
2021-03-03 02:25:24 +01:00
2e8215eafc Add command to change vm.max_map_count before run docker 2021-03-03 01:25:23 +01:00
4c00095118 #68 Clean workgroup Entity 2021-03-02 23:25:00 +01:00
bc772f168f #68 Clean opinion Entity 2021-03-02 00:53:02 +01:00
8d93fc8b3c #68 Clean follow Entity 2021-03-01 22:44:17 +01:00
66dcff8f46 Fix sonar task 2021-02-28 23:31:11 +01:00
c61b31cc58 Change codestyle 2021-02-28 02:07:12 +01:00
78604301c3 Remove pitest 2021-02-28 02:05:19 +01:00
d382a89905 Fix tests 2021-02-28 01:42:11 +01:00
7446bd506a create gradle tasks "test", "testSql", "migrations" and run docker before tasks 2021-02-27 23:20:57 +01:00
c25cf64f4b #68 Clean Entities 2021-02-25 18:32:17 +01:00
c1af949204 fix sonarqube 2021-02-25 01:33:20 +01:00
7985ea67e5 remove cucumber 2021-02-25 01:09:44 +01:00
9a3a308841 Change code style 2021-02-25 00:53:20 +01:00
d83ba2d54d Add Integration test for workgroup routes 2021-02-25 00:48:52 +01:00
7b4066b928 Add Integration test for vote routes 2021-02-24 00:21:29 +01:00
9fb2262107 Add Integration test for opinion routes 2021-02-23 22:51:16 +01:00
a27099177d Add SQL request find_citizen_by_name 2021-02-23 22:06:05 +01:00
b0aec9bea0 Add Integration test for follow constitution routes 2021-02-23 17:24:12 +01:00
a17bd11e9e Add Integration test for follow article routes 2021-02-19 23:30:04 +01:00
8cf79a791e Rename annonymous to anonymous 2021-02-19 22:27:47 +01:00
bf4e01e318 Add Integration test for constitution routes 2021-02-19 22:27:47 +01:00
d29bb4467a Add/fix tags to integration tests 2021-02-19 21:58:06 +01:00
0ecf0c205f Add Integration test for comment 2021-02-19 00:42:10 +01:00
55aa512aa5 Change error text 2021-02-13 01:43:47 +01:00
addb3cddff refactor idea run's 2021-02-13 01:34:05 +01:00
f7b6cc4eb3 fix DB test script 2021-02-13 01:28:05 +01:00
28b9ac4e54 Install pitest 2021-02-13 01:27:40 +01:00
02879291e8 Sonarqube and detekt 2021-02-11 01:50:14 +01:00
066b01e86f Move all file in fr.dcproject. 2021-02-11 01:50:14 +01:00
c85401aa86 move createCitizen of Integration test 2021-02-10 18:10:21 +01:00
34a7310944 move Integration step test 2021-02-10 17:48:32 +01:00
e8716a1e7f Add Integration test for article 2021-02-10 14:37:57 +01:00
f8ecd69582 Rename tests 2021-02-10 01:24:34 +01:00
99438b1ff9 Fix engine start/stop for integration tests 2021-02-10 01:08:23 +01:00
ec0115d613 Add Integration test for citizen 2021-02-10 00:58:42 +01:00
55bfbb619d Add Integration test for Register 2021-02-09 20:56:27 +01:00
edf0c00cf1 Init Integration test without cucumber 2021-02-09 03:11:43 +01:00
dcf35eaccd Clean Citizen entities
Change plainPassword to just password
Add request Input for /login
2021-02-09 00:39:26 +01:00
905330a722 Move last package into common/component 2021-02-06 01:25:59 +01:00
5979337bc3 Remove last converter for Workgroup 2021-02-06 01:06:46 +01:00
8c228f666f Lint 2021-02-06 00:56:02 +01:00
678bdf7087 Remove converter for OpinionChoice 2021-02-06 00:45:54 +01:00
507698c7ea use always receiveOrBadRequest 2021-02-06 00:32:07 +01:00
fdd4742b28 Remove converter for Citizen
Add receiveOrBadRequest
2021-02-06 00:23:36 +01:00
0bbe37c6d5 Remove converter for CitizenRef 2021-02-05 23:13:37 +01:00
192411a69a Remove converter for Constitution 2021-02-05 22:18:32 +01:00
929d248841 Remove converter for ConstitutionRef 2021-02-05 21:52:10 +01:00
8ead83941f Remove converter for CommentRef 2021-02-05 21:48:33 +01:00
aeaab860b2 Remove converter for article 2021-02-05 00:32:19 +01:00
16eadc0921 Optimise GetOneArticle 2021-02-04 23:58:53 +01:00
f2445f3b25 Optimise ArticleVersionsRequest 2021-02-04 23:53:17 +01:00
bb212f9c6c move notification to component 2021-02-04 23:34:20 +01:00
89c15eb1cf cleanup and refactoring of notification
close rabbit and redis connexion on application close
Refactoring of Configuration class
fix notification id increment
Add builder for NotificationPush
Add close to notificationPush to remove listener
Clean tags of tests
purge queue before functional tests
2021-02-04 02:37:29 +01:00
a05b5edc86 update redis to stable version 2021-02-03 15:35:34 +01:00
5704eb9e07 Clean config in test 2021-02-03 15:35:14 +01:00
3580c33891 Rename NotificationConsumer 2021-02-03 01:49:12 +01:00
3b3a71f6eb Schema for notifications 2021-02-03 01:22:20 +01:00
d479cf6bca Refactor Notification System
Add Tests for notification system
2021-02-03 01:21:13 +01:00
b54a40cef4 Rename event to notification 2021-01-27 01:08:09 +01:00
1c644768e6 remove raiseEvent for notifications
Add Test for EventNotification
Add application.conf for test
2021-01-26 23:58:25 +01:00
aa95de7a6a move some part of KoinModule in components 2021-01-23 23:26:01 +01:00
dd6433306d Remove Configuration object to koin 2021-01-23 22:47:02 +01:00
bfc0b7e796 Move comment constitution to component 2021-01-23 22:38:47 +01:00
81e14f1a84 Move some interface to common package 2021-01-23 22:28:48 +01:00
d9f19a9c23 reword 2021-01-23 22:20:44 +01:00
1e5598cb91 Move constitution to component 2021-01-23 21:18:42 +01:00
f34407962b Remove Deprecated Article Entities 2021-01-23 00:54:53 +01:00
49a03a57cb Rename Voter to AccessControl 2021-01-22 22:07:25 +01:00
c1b8b508ac Move vote to component 2021-01-22 21:45:02 +01:00
c92d0b5640 Move opinions to component 2021-01-22 21:11:04 +01:00
73e96c0c46 Use interface PaginatedRequestI 2021-01-22 20:37:47 +01:00
fac27d0725 move database config env in object 2021-01-22 20:25:32 +01:00
97ccb6ee51 ktlint 2021-01-22 17:29:36 +01:00
93aa47c6cc move routes installation into component bis 2021-01-21 22:01:10 +01:00
667339979b move routes installation into component 2021-01-21 21:55:24 +01:00
3ba4a195ba Update gradle and dependencycheck 2021-01-21 16:26:15 +01:00
6a32895571 Move Follow to a component 2021-01-18 21:45:48 +01:00
6cdc526335 upgrade klint and format code (remove wildcard import 2021-01-18 17:23:16 +01:00
a79e1ec086 upgrade kotlin, ktor, sendgrid 2021-01-18 17:13:24 +01:00
4b435b925e upgrade java-jwt, kasechange-jvm, amqp-client, lettuce 2021-01-18 13:30:25 +01:00
78e01ba981 upgrade logback, corouties, json-path, mockk, junit-jupiter 2021-01-18 13:24:51 +01:00
56818189ae upgrade jackson 2021-01-18 13:17:11 +01:00
fbea05218b upgrade cucumber 2021-01-18 13:15:12 +01:00
c78dfc0f7f upgrade jasync-sql 2021-01-18 13:12:47 +01:00
425d01c0df Remove ktor-voter 2021-01-18 13:12:29 +01:00
64fa0912b8 Refactoring of OpinionChoiceVoter 2021-01-18 13:03:01 +01:00
ba673943d8 Refactoring of OpinionVoter 2021-01-18 09:51:48 +01:00
c196bfadbc Fix Move Views config into component 2021-01-18 01:08:11 +01:00
e9f56412c5 Move Views config into component 2021-01-18 01:07:02 +01:00
d12c9c2166 Move installation of JWT to external file in auth component 2021-01-18 00:09:23 +01:00
55cd97078a Refactoring of FollowVoter 2021-01-17 23:46:51 +01:00
d6840e8064 Refactoring of VoteVoter 2021-01-17 23:32:43 +01:00
308a284280 Refactoring of ConstitutionVoter 2021-01-17 23:06:18 +01:00
1b6549eae3 Rename wrong naming SSO to Passwordless 2021-01-17 22:46:43 +01:00
b028ff05b9 Move files
Move Application and configurations file to the application package
Move JWT files to the auth.jwt package
Move ApplicationContext to auth package an rename to CitizenContext
2021-01-17 22:29:32 +01:00
c380ba47a5 Refactoring of WorkgroupVoter 2021-01-17 15:01:49 +01:00
ecda29abe5 Move Workgroup to a component 2021-01-17 14:18:19 +01:00
bec73561e7 Fix IDEA commands 2021-01-17 14:17:53 +01:00
299495a03c ktlint 2021-01-17 00:10:51 +01:00
d87b433398 Move Comment article to a Component 2021-01-17 00:05:37 +01:00
b61fc3c7d1 Fix Auth request 2021-01-17 00:04:48 +01:00
b421b03575 Fix Double token generation in SSO 2021-01-15 23:43:49 +01:00
128510fe88 Add TODO's 2021-01-15 23:43:49 +01:00
ce90884758 Move Auth to a Component 2021-01-15 23:27:47 +01:00
42440c0041 Fix sql-test launcher 2021-01-15 02:46:10 +01:00
459397f8e7 Move tests and create a command to run all tests 2021-01-15 02:40:41 +01:00
7c106f7cf8 Refactoring of CommentVoter 2021-01-15 01:45:32 +01:00
caadc2a969 klint 2021-01-14 22:53:48 +01:00
91ab800272 Move comments classes into comment component 2021-01-14 22:51:33 +01:00
64f74d0449 fix namespace of article refactoring 2021-01-14 22:15:51 +01:00
6a8c5bf717 Refactors Citizen into component
Refactor CitizenVoter
Split citizens routes
2021-01-14 15:24:05 +01:00
a1c1accc87 Refactors Articles and Voter
- Move files into components (article)
- Split articles routes
- Refactoring for remove ktor-voter (ArticleVoter)
- Remove mutability
- Move DataConversion to separate file (Converter.kt)
- Add Schemas for Articles routes
- Fix SQL Query for Workgroup roles
- rename container_name in docker-compose
2021-01-14 13:06:13 +01:00
03401f711e Update ktor-voter to version 2.2.0 2020-10-05 15:32:44 +02:00
74923891d0 Fix security 2020-10-04 01:10:22 +02:00
317e029f79 remove "restart: always" on docker compose 2020-10-01 15:52:08 +02:00
46ee98c97f Increase article fixtures 2020-10-01 15:51:36 +02:00
269bf09c66 update installation doc 2020-10-01 15:17:40 +02:00
9d6ad08834 Update idea config 2020-09-29 09:51:00 +02:00
06b1296192 Add commande to reset database in Makefile 2020-09-04 15:22:36 +02:00
5def84282d Improve vote count with cache 2020-09-04 15:22:15 +02:00
24d8f1d58b Fix route /citizens/current if not logged 2020-09-04 11:10:22 +02:00
a3b44588a9 Can filter workgroup by members #58
add filterNotNull to toUUID() function
2020-08-25 15:30:36 +02:00
16feab9655 #57 I can filter articles by workgroup
update lib "postgres-json:1.2.1"
2020-08-24 16:55:18 +02:00
01c3d85a17 #54 Can create article under the name of the Workgroup 2020-07-10 15:41:39 +02:00
3d319605de Fix find_workgroups SQL query 2020-06-14 00:32:39 +02:00
63c4568aeb Fix find_citizens SQL query 2020-06-14 00:30:45 +02:00
e2d1b697b7 add missing parameters in openApi definition for "GET /workgroups" route 2020-06-14 00:30:24 +02:00
70092efaf5 Improve README 2020-06-02 16:31:38 +02:00
9c10a88a36 Improve Makefile 2020-06-02 15:20:11 +02:00
2ee8b80596 Add descriptions on OpenAPI 2020-06-02 15:08:12 +02:00
ee60f5b4e7 Fix tests 2020-06-02 15:08:05 +02:00
10928251e6 Can update roles of one citizen on workgroup 2020-06-02 14:20:35 +02:00
9b79301662 update workgroup in OpenApi 2020-06-02 01:01:29 +02:00
32510652d1 Fix upsert_workgroup 2020-06-02 01:01:08 +02:00
a6c36c542e Fixture not delete table content before apply 2020-06-01 13:52:48 +02:00
7874f5cec4 #55 Can be assign a role to members of my Workgroup
Remove Owner on Workgroup (use role MASTER instead)
"find_citizen_by_id" not return user anymore, use "find_citizen_by_id_with_user" instead
2020-06-01 13:46:15 +02:00
8ff6fcc970 Add volume to docker for redis 2020-05-27 09:56:54 +02:00
bd123d03e9 Fix fixtures script 2020-05-14 13:46:55 +02:00
ac852baaf6 Improve README 2020-05-14 13:46:44 +02:00
159b9de19a Create a auto build docker image
Version of application is calculated by the git tags
2020-05-14 00:54:21 +02:00
e4a85722f1 Move Elasticsearch configuration into external function "configElasticIndexes" 2020-05-13 13:58:17 +02:00
467 changed files with 16719 additions and 9110 deletions

13
.dockerignore Normal file
View File

@@ -0,0 +1,13 @@
build
out
GH_TOKEN.txt
Makefile
var
gradle
.idea
.gradle
docker
gradlew
gradlew.bat
docker-compose.yml
src/test

5
.env
View File

@@ -1,10 +1,11 @@
NAME=dc-project
APP_NAME=dc-project
DATABASE_URL=jdbc:postgresql:dc-project
APP_PORT=8080
OPENAPI_PORT=8181
SONARQUBE_PORT=9002
SONARQUBE_DB_PORT=5434
ELASTIC_REST=9200
ELASTIC_NODES=9300
@@ -24,3 +25,5 @@ REDIS_COMMANDER_PORT=8081
RABBITMQ_PORT=5672
RABBITMQ_CONNECTION=amqp://rabbitmq:5672
RABBITMQ_MANAGEMENT_PORT=15672
SEND_GRID_KEY=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

160
.github/workflows/tests.yml vendored Normal file
View File

@@ -0,0 +1,160 @@
# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Tests
on:
push:
branches:
- 'master'
pull_request:
branches:
- 'master'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
with:
gradle-version: '7.4'
- name: Cache Gradle packages
uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Build
uses: gradle/gradle-build-action@v2
with:
gradle-version: '7.4'
arguments: build -x test -x ktlintKotlinScriptCheck -x ktlintTestSourceSetCheck -x ktlintMainSourceSetCheck -x detekt
- name: processResources
run: gradle processResources
- name: processTestResources
uses: gradle/gradle-build-action@v2
with:
gradle-version: '7.4'
arguments: processResources
- uses: actions/upload-artifact@v2
with:
name: Build
path: build
testSql:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/download-artifact@v2
with:
name: Build
path: build
- name: Composer Up
uses: gradle/gradle-build-action@v2
with:
gradle-version: '7.4'
arguments: testSqlComposeUp
- name: TestSql
uses: gradle/gradle-build-action@v2
with:
gradle-version: '7.4'
arguments: testSql
test:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/download-artifact@v2
with:
name: Build
path: build
- name: Composer Up
uses: gradle/gradle-build-action@v2
with:
gradle-version: '7.4'
arguments: testComposeUp
- name: Test
uses: gradle/gradle-build-action@v2
with:
gradle-version: '7.4'
arguments: test
- name: Coverage
uses: gradle/gradle-build-action@v2
with:
gradle-version: '7.4'
arguments: coveralls
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
- name: Cache SonarCloud packages
uses: actions/cache@v1
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Test
uses: gradle/gradle-build-action@v2
with:
gradle-version: '7.4'
arguments: test
- name: Build and analyze
uses: gradle/gradle-build-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
gradle-version: '7.4'
arguments: sonarqube --info
lint:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/download-artifact@v2
with:
name: Build
path: build
- name: Lint
uses: gradle/gradle-build-action@v2
with:
gradle-version: '7.4'
arguments: ktlintCheck

2
.gitignore vendored
View File

@@ -7,3 +7,5 @@
*.iws
dcproject.iml
/var
GH_TOKEN.txt
allSQL.sql

View File

@@ -1,17 +1,71 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value />
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<PostgresCodeStyleSettings version="2">
<option name="ALIAS_CASE" value="1" />
<SqlCodeStyleSettings version="6">
<option name="KEYWORD_CASE" value="1" />
<option name="TYPE_CASE" value="1" />
<option name="IDENTIFIER_CASE" value="1" />
</PostgresCodeStyleSettings>
<option name="TYPE_CASE" value="4" />
<option name="ALIAS_CASE" value="4" />
<option name="BUILT_IN_CASE" value="4" />
<option name="QUOTE_IDENTIFIER" value="1" />
<option name="QUERY_EL_LINE" value="0" />
<option name="QUERY_IN_ONE_STRING" value="3" />
<option name="SUBQUERY_CONTENT" value="2" />
<option name="SUBQUERY_CLOSING" value="2" />
<option name="INSERT_OPENING" value="4" />
<option name="INSERT_CLOSING" value="0" />
<option name="INSERT_VALUES_EL_LINE" value="101" />
<option name="INSERT_COLLAPSE_MULTI_ROW_VALUES" value="true" />
<option name="SET_EL_LINE" value="1" />
<option name="SET_EL_WRAP" value="0" />
<option name="WITH_EL_LINE" value="101" />
<option name="WITH_EL_WRAP" value="2" />
<option name="SELECT_EL_LINE" value="101" />
<option name="SELECT_EL_COMMA" value="2" />
<option name="SELECT_NEW_LINE_AFTER_ALL_DISTINCT" value="true" />
<option name="SELECT_KEEP_N_ITEMS_IN_LINE" value="4" />
<option name="SELECT_USE_AS_WORD" value="1" />
<option name="FROM_EL_LINE" value="1" />
<option name="FROM_EL_COMMA" value="2" />
<option name="FROM_ALIGN_JOIN_TABLES" value="true" />
<option name="FROM_INDENT_JOIN" value="false" />
<option name="FROM_PLACE_ON" value="10" />
<option name="WHERE_EL_LINE" value="1" />
<option name="WHERE_EL_WRAP" value="3" />
<option name="ORDER_EL_LINE" value="101" />
<option name="ORDER_EL_WRAP" value="1" />
<option name="ORDER_EL_COMMA" value="2" />
</SqlCodeStyleSettings>
<codeStyleSettings language="SQL">
<option name="KEEP_LINE_BREAKS" value="false" />
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<indentOptions>
<option name="SMART_TABS" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
<option name="LINE_COMMENT_ADD_SPACE" value="true" />
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

9
.idea/dataSources.xml generated
View File

@@ -11,7 +11,14 @@
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://localhost:5432/test</jdbc-url>
<jdbc-url>jdbc:postgresql://localhost:15432/test</jdbc-url>
</data-source>
<data-source source="LOCAL" name="sonar@localhost" uuid="ee78beab-120d-4740-ad21-d4d9e2121d25">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://localhost:5433/sonar</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

5
.idea/gradle.xml generated
View File

@@ -4,8 +4,8 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="delegatedBuild" value="false" />
<option name="testRunner" value="PLATFORM" />
<option name="delegatedBuild" value="true" />
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
@@ -13,7 +13,6 @@
<option value="$PROJECT_DIR$" />
</set>
</option>
<option name="useQualifiedModuleNames" value="true" />
</GradleProjectSettings>
</option>
</component>

3
.idea/misc.xml generated
View File

@@ -10,4 +10,7 @@
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="corretto-11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
<component name="TaskProjectConfiguration">
<server type="GitHub" url="https://github.com" />
</component>
</project>

37
.idea/runConfigurations/All_Tests.xml generated Normal file
View File

@@ -0,0 +1,37 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All Tests" type="JUnit" factoryName="JUnit" singleton="false" show_console_on_std_err="true">
<useClassPathOnly />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="fr.dcproject.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<option name="ALTERNATIVE_JRE_PATH" value="corretto-11" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="pattern" />
<option name="VM_PARAMETERS" value="-ea -Djdk.attach.allowAttachSelf=true" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
</option>
<envs>
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<patterns>
<pattern testClass="unit..*" />
<pattern testClass="functional..*" />
<pattern testClass="integration..*" />
</patterns>
<tag value="!functional" />
<method v="2">
<option name="Make" enabled="true" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="SQL Fixtures on DEV" run_configuration_type="ShConfigurationType" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Lint Format" run_configuration_type="GradleRunConfiguration" />
</method>
</configuration>
</component>

View File

@@ -1,25 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All Tests + Lint (offline)" type="JUnit" factoryName="JUnit" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<useClassPathOnly />
<option name="PACKAGE_NAME" value="fr.dcproject" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="tags" />
<option name="VM_PARAMETERS" value="-ea -Dcucumber.options=&quot;--tags ~@online&quot; -Djdk.attach.allowAttachSelf=true" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
</option>
<envs>
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="!online" />
<method v="2">
<option name="Make" enabled="true" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Lint" run_configuration_type="GradleRunConfiguration" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Test All SQL" run_configuration_type="ShConfigurationType" />
</method>
</configuration>
</component>

View File

@@ -2,6 +2,7 @@
<configuration default="false" name="Build and start all Docker" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
<deployment type="docker-compose.yml">
<settings>
<option name="envFilePath" value="" />
<option name="envVars">
<list>
<DockerEnvVarImpl>
@@ -11,11 +12,24 @@
</list>
</option>
<option name="commandLineOptions" value="--build" />
<option name="secondarySourceFiles">
<list>
<option value="docker-compose-sonar.yml" />
</list>
</option>
<option name="services">
<list>
<option value="app" />
<option value="db" />
<option value="elasticsearch" />
<option value="openapi" />
<option value="rabbitmq" />
<option value="redis" />
</list>
</option>
<option name="sourceFilePath" value="docker-compose.yml" />
</settings>
</deployment>
<method v="2">
<option name="Gradle.BeforeRunTask" enabled="true" tasks="build" externalProjectPath="$PROJECT_DIR$" vmOptions="" scriptParameters="" />
</method>
<method v="2" />
</configuration>
</component>

View File

@@ -4,7 +4,7 @@
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-x test -x ktlintKotlinScriptCheck -x ktlintTestSourceSetCheck -x ktlintMainSourceSetCheck" />
<option name="scriptParameters" value="-x test -x ktlintKotlinScriptCheck -x ktlintTestSourceSetCheck -x ktlintMainSourceSetCheck -x detekt" />
<option name="taskDescriptions">
<list />
</option>

View File

@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Citizen Tests" type="JUnit" factoryName="JUnit" folderName="Cucumber" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<module name="dcproject.test" />
<useClassPathOnly />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="RunCucumberTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea -Dcucumber.filter.tags=&quot;@citizen&quot;" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
</option>
<envs>
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="!online" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Comment Tests" type="JUnit" factoryName="JUnit" folderName="Cucumber" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<module name="dcproject.test" />
<useClassPathOnly />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="RunCucumberTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea -Dcucumber.filter.tags=&quot;@comment&quot;" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
</option>
<envs>
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="!online" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Constitution Tests" type="JUnit" factoryName="JUnit" folderName="Cucumber" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<module name="dcproject.test" />
<useClassPathOnly />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="RunCucumberTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea -Dcucumber.filter.tags=&quot;@constitution&quot;" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
</option>
<envs>
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="!online" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Create lock dependencies" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="--write-locks" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="dependencies" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -1,19 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Cucumber Tests" type="JUnit" factoryName="JUnit">
<output_file path="$PROJECT_DIR$/var/log/test/cucumber.out.log" />
<module name="dcproject.test" />
<useClassPathOnly />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="RunCucumberTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea -Djdk.attach.allowAttachSelf=true" />
<option name="PARAMETERS" value="" />
<envs>
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -1,30 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Cucumber Tests (offline)" type="JUnit" factoryName="JUnit" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<module name="dcproject.test" />
<useClassPathOnly />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="fr.dcproject.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="RunCucumberTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea -Dcucumber.filter.tags=&quot; not @online&quot; -Djdk.attach.allowAttachSelf=true" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
</option>
<envs>
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="!online" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

23
.idea/runConfigurations/Down_Docker.xml generated Normal file
View File

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Down Docker" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="testComposeDownForced" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Follow Tests" type="JUnit" factoryName="JUnit" folderName="Cucumber" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<module name="dcproject.test" />
<useClassPathOnly />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="RunCucumberTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea -Dcucumber.filter.tags=&quot;@follow&quot;" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
</option>
<envs>
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="!online" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -1,13 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Voter Tests" type="JUnit" factoryName="JUnit" show_console_on_std_err="true">
<configuration default="false" name="Functional Tests" type="JUnit" factoryName="JUnit" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<useClassPathOnly />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="fr.dcproject.security.voter.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="PACKAGE_NAME" value="fr.dcproject" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
@@ -21,7 +15,7 @@
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="voter" />
<tag value="functional" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -1,11 +1,11 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All Tests + Lint" type="JUnit" factoryName="JUnit" show_console_on_std_err="true">
<configuration default="false" name="Functional Tests (offline)" type="JUnit" factoryName="JUnit" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<useClassPathOnly />
<option name="PACKAGE_NAME" value="fr.dcproject" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="TEST_OBJECT" value="tags" />
<option name="VM_PARAMETERS" value="-ea -Djdk.attach.allowAttachSelf=true" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
@@ -15,10 +15,9 @@
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="functional&amp;!online" />
<method v="2">
<option name="Make" enabled="true" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Lint" run_configuration_type="GradleRunConfiguration" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Test All SQL" run_configuration_type="ShConfigurationType" />
</method>
</configuration>
</component>

View File

@@ -1,13 +1,13 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Article Tests" type="JUnit" factoryName="JUnit" folderName="Cucumber" show_console_on_std_err="true">
<configuration default="false" name="Integration Tests" type="JUnit" factoryName="JUnit" singleton="false" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<module name="dcproject.test" />
<useClassPathOnly />
<option name="ALTERNATIVE_JRE_PATH" value="corretto-11" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="RunCucumberTest" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea -Dcucumber.filter.tags=&quot;@article&quot; -Dstrict" />
<option name="TEST_OBJECT" value="pattern" />
<option name="VM_PARAMETERS" value="-ea -Djdk.attach.allowAttachSelf=true" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
@@ -16,7 +16,10 @@
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="!online" />
<patterns>
<pattern testClass="integration..*" />
</patterns>
<tag value="!functional" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -1,31 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Lint" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="ktlintCheck" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<extension name="net.ashald.envfile">
<option name="IS_ENABLED" value="false" />
<option name="IS_SUBST" value="false" />
<option name="IS_PATH_MACRO_SUPPORTED" value="false" />
<option name="IS_IGNORE_MISSING_FILES" value="false" />
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" />
<ENTRIES>
<ENTRY IS_ENABLED="true" PARSER="runconfig" />
</ENTRIES>
</extension>
<GradleScriptDebugEnabled>true</GradleScriptDebugEnabled>
<method v="2" />
</configuration>
</component>

23
.idea/runConfigurations/Lint_Format.xml generated Normal file
View File

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Lint Format" type="GradleRunConfiguration" factoryName="Gradle" singleton="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="ktlintFormat" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -1,39 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Lint+Test+Sonar &amp; Run" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="env">
<map>
<entry key="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</map>
</option>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="run" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<extension name="net.ashald.envfile">
<option name="IS_ENABLED" value="false" />
<option name="IS_SUBST" value="false" />
<option name="IS_PATH_MACRO_SUPPORTED" value="false" />
<option name="IS_IGNORE_MISSING_FILES" value="false" />
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" />
<ENTRIES>
<ENTRY IS_ENABLED="true" PARSER="runconfig" />
</ENTRIES>
</extension>
<GradleScriptDebugEnabled>true</GradleScriptDebugEnabled>
<method v="2">
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All Tests + Lint" run_configuration_type="JUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Sonarqube" run_configuration_type="GradleRunConfiguration" />
</method>
</configuration>
</component>

View File

@@ -1,38 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Lint, Test &amp; Run" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="env">
<map>
<entry key="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</map>
</option>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="run" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<extension name="net.ashald.envfile">
<option name="IS_ENABLED" value="false" />
<option name="IS_SUBST" value="false" />
<option name="IS_PATH_MACRO_SUPPORTED" value="false" />
<option name="IS_IGNORE_MISSING_FILES" value="false" />
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" />
<ENTRIES>
<ENTRY IS_ENABLED="true" PARSER="runconfig" />
</ENTRIES>
</extension>
<GradleScriptDebugEnabled>true</GradleScriptDebugEnabled>
<method v="2">
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All Tests + Lint" run_configuration_type="JUnit" />
</method>
</configuration>
</component>

View File

@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Mark as @error" type="JUnit" factoryName="JUnit" folderName="Cucumber" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<module name="dcproject.test" />
<useClassPathOnly />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="RunCucumberTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea -Dcucumber.filter.tags=&quot;@error&quot; -Dstrict" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
</option>
<envs>
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="!online" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

23
.idea/runConfigurations/Migration.xml generated Normal file
View File

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Migration" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="migration" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Opinion Tests" type="JUnit" factoryName="JUnit" folderName="Cucumber" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<module name="dcproject.test" />
<useClassPathOnly />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="RunCucumberTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea -Dcucumber.filter.tags=&quot;@opinion&quot;" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
</option>
<envs>
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="!online" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -6,8 +6,10 @@
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/src/main/resources/sql" />
<option name="INDEPENDENT_INTERPRETER_PATH" value="false" />
<option name="INTERPRETER_PATH" value="C:/Program Files/Git/bin/bash.exe" />
<option name="INTERPRETER_PATH" value="$PROJECT_DIR$/../../../../Program Files/Git/bin/bash.exe" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="EXECUTE_IN_TERMINAL" value="false" />
<envs />
<method v="2" />
</configuration>
</component>

View File

@@ -2,6 +2,7 @@
<configuration default="false" name="Run dependencies" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
<deployment type="docker-compose.yml">
<settings>
<option name="envFilePath" value="" />
<option name="envVars">
<list>
<DockerEnvVarImpl>
@@ -11,12 +12,18 @@
</list>
</option>
<option name="commandLineOptions" value="--build" />
<option name="secondarySourceFiles">
<list>
<option value="docker-compose-sonar.yml" />
</list>
</option>
<option name="services">
<list>
<option value="db" />
<option value="elasticsearch" />
<option value="rabbitmq" />
<option value="redis" />
<option value="openapi" />
</list>
</option>
<option name="sourceFilePath" value="docker-compose.yml" />

View File

@@ -6,8 +6,10 @@
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/src/main/resources/sql/fixtures/" />
<option name="INDEPENDENT_INTERPRETER_PATH" value="false" />
<option name="INTERPRETER_PATH" value="C:/Program Files/Git/bin/bash.exe" />
<option name="INTERPRETER_PATH" value="$PROJECT_DIR$/../../../../Program Files/Git/bin/bash.exe" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="EXECUTE_IN_TERMINAL" value="false" />
<envs />
<method v="2" />
</configuration>
</component>

View File

@@ -1,10 +1,15 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Sonarqube" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="env">
<map>
<entry key="SONAR_TOKEN" value="15ad34f46763706727d884ced12c48d5222fe639" />
</map>
</option>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-x test" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
@@ -15,7 +20,9 @@
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<GradleScriptDebugEnabled>true</GradleScriptDebugEnabled>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Sonarqube (Send without run test)" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-x test -x ktlintKotlinScriptCheck -x ktlintTestSourceSetCheck -x ktlintMainSourceSetCheck" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="sonarqube" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Start Db" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
<deployment type="docker-compose.yml">
<settings>
<option name="envVars">
<list>
<DockerEnvVarImpl>
<option name="name" value="SEND_GRID_KEY" />
<option name="value" value="$SEND_GRID_KEY$" />
</DockerEnvVarImpl>
</list>
</option>
<option name="commandLineOptions" value="--build" />
<option name="services">
<list>
<option value="db" />
</list>
</option>
<option name="sourceFilePath" value="docker-compose.yml" />
</settings>
</deployment>
<method v="2" />
</configuration>
</component>

View File

@@ -1,16 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Start Elasticsearch" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
<deployment type="docker-compose.yml">
<settings>
<option name="commandLineOptions" value="--build" />
<option name="services">
<list>
<option value="elasticsearch" />
</list>
</option>
<option name="sourceFilePath" value="docker-compose.yml" />
</settings>
</deployment>
<method v="2" />
</configuration>
</component>

View File

@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Start RabbitMQ" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
<deployment type="docker-compose.yml">
<settings>
<option name="envVars">
<list>
<DockerEnvVarImpl>
<option name="name" value="SEND_GRID_KEY" />
<option name="value" value="$SEND_GRID_KEY$" />
</DockerEnvVarImpl>
</list>
</option>
<option name="commandLineOptions" value="--build" />
<option name="services">
<list>
<option value="rabbitmq" />
</list>
</option>
<option name="sourceFilePath" value="docker-compose.yml" />
</settings>
</deployment>
<method v="2" />
</configuration>
</component>

View File

@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Start Redis" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
<deployment type="docker-compose.yml">
<settings>
<option name="envVars">
<list>
<DockerEnvVarImpl>
<option name="name" value="SEND_GRID_KEY" />
<option name="value" value="$SEND_GRID_KEY$" />
</DockerEnvVarImpl>
</list>
</option>
<option name="commandLineOptions" value="--build" />
<option name="services">
<list>
<option value="redis" />
</list>
</option>
<option name="sourceFilePath" value="docker-compose.yml" />
</settings>
</deployment>
<method v="2" />
</configuration>
</component>

28
.idea/runConfigurations/Test.xml generated Normal file
View File

@@ -0,0 +1,28 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Test" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="env">
<map>
<entry key="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</map>
</option>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="test" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

23
.idea/runConfigurations/TestSql.xml generated Normal file
View File

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="TestSql" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="testSql" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -1,13 +1,17 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Test All SQL" type="ShConfigurationType">
<configuration default="false" name="Test All SQL" type="ShConfigurationType" singleton="false">
<option name="SCRIPT_TEXT" value="" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/test/sql/test.sh" />
<option name="SCRIPT_OPTIONS" value="1" />
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/src/test/sql" />
<option name="INDEPENDENT_INTERPRETER_PATH" value="false" />
<option name="INTERPRETER_PATH" value="C:/Program Files/Git/bin/bash.exe" />
<option name="INTERPRETER_PATH" value="$PROJECT_DIR$/../../../../Program Files/Git/bin/bash.exe" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="EXECUTE_IN_TERMINAL" value="false" />
<option name="EXECUTE_SCRIPT_FILE" value="true" />
<envs />
<method v="2" />
</configuration>
</component>

View File

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Test With Dependencies" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="testWithDependencies" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -1,13 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Vote Tests" type="JUnit" factoryName="JUnit" folderName="Cucumber" show_console_on_std_err="true">
<configuration default="false" name="Unit Tests" type="JUnit" factoryName="JUnit" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<module name="dcproject.test" />
<useClassPathOnly />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="RunCucumberTest" />
<option name="PACKAGE_NAME" value="fr.dcproject" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea -Dcucumber.filter.tags=&quot;@vote&quot;" />
<option name="TEST_OBJECT" value="tags" />
<option name="VM_PARAMETERS" value="-ea -Djdk.attach.allowAttachSelf=true" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
@@ -16,7 +15,7 @@
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="!online" />
<tag value="unit" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -0,0 +1,30 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Unit, functional and integration tests" type="JUnit" factoryName="JUnit" singleton="false" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<useClassPathOnly />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<option name="ALTERNATIVE_JRE_PATH" value="corretto-11" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="pattern" />
<option name="VM_PARAMETERS" value="-ea -Djdk.attach.allowAttachSelf=true" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
</option>
<envs>
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<patterns>
<pattern testClass="unit..*" />
<pattern testClass="functional..*" />
<pattern testClass="integration..*" />
</patterns>
<tag value="!functional" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -1,13 +1,13 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Auth Tests" type="JUnit" factoryName="JUnit" folderName="Cucumber" show_console_on_std_err="true">
<configuration default="false" name="Unit and functional tests" type="JUnit" factoryName="JUnit" singleton="false" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<module name="dcproject.test" />
<useClassPathOnly />
<option name="ALTERNATIVE_JRE_PATH" value="corretto-11" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="RunCucumberTest" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea -Dcucumber.filter.tags=&quot;@auth&quot;" />
<option name="TEST_OBJECT" value="pattern" />
<option name="VM_PARAMETERS" value="-ea -Djdk.attach.allowAttachSelf=true" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
@@ -16,7 +16,11 @@
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="!online" />
<patterns>
<pattern testClass="unit..*" />
<pattern testClass="functional..*" />
</patterns>
<tag value="!functional" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Update Dependency" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="--update-locks *:*" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="classes" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -1,30 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Workgroup test" type="JUnit" factoryName="JUnit" folderName="Cucumber" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<module name="dcproject.test" />
<useClassPathOnly />
<extension name="coverage" sample_coverage="false">
<pattern>
<option name="PATTERN" value="fr.dcproject.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="RunCucumberTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea -Dcucumber.filter.tags=&quot;@workgroup&quot;" />
<option name="PARAMETERS" value="" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" />
</option>
<envs>
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</envs>
<dir value="$PROJECT_DIR$" />
<tag value="!online" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

59
Makefile Normal file
View File

@@ -0,0 +1,59 @@
.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 (alias: bd)
docker build -t dc-project -f docker/app/Dockerfile .
pd: publish-docker
publish-docker: build-docker ## Publish docker image of application to Github (alias: pd)
@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 (alias: rd)
docker-compose up -d --build
rdd: run-docker-dependencies
run-docker-dependencies: ## Build and Run dependencies docker services (alias: rdd)
docker-compose up -d --build openapi rabbitmq redis elasticsearch db sonarqube_db sonarqube
pm: publish-maven
publish-maven: ## Publish JAR file to Github (alias: pm)
@git diff --quiet --exit-code || (echo "The git is DIRTY !!! You cannot publish this crap!" && exit 1)
gradlew publish
f: fixtures
fixtures: ## Import fixtures (alias: f)
bash src/main/resources/sql/fixtures/fixtures.sh
reset-database: ## Reset database !!!
cd src/main/resources/sql/ ; bash resetDB.sh
test-sql: ## Test sql
cd src/test/sql/ ; bash test.sh 1
v: version
version: ## Show current version (alias: v)
@echo ${VERSION}

35
README.md Normal file
View File

@@ -0,0 +1,35 @@
# DC Project
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=dc-project&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=dc-project)
[![Tests](https://github.com/flecomte/dc-project/actions/workflows/tests.yml/badge.svg)](https://github.com/flecomte/dc-project/actions/workflows/tests.yml)
[![Coverage Status](https://coveralls.io/repos/github/flecomte/dc-project/badge.svg?branch=master)](https://coveralls.io/github/flecomte/dc-project?branch=master)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=dc-project&metric=coverage)](https://sonarcloud.io/dashboard?id=dc-project)
[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=dc-project&metric=ncloc)](https://sonarcloud.io/dashboard?id=dc-project)
[Installation](./doc/installation/Installation.md)
### 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
```

View File

@@ -1,40 +1,166 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.typesafe.config.ConfigFactory
import fr.postgresjson.connexion.Connection
import fr.postgresjson.connexion.Requester
import fr.postgresjson.migration.Migrations
import io.gitlab.arturbosch.detekt.Detekt
import org.gradle.internal.os.OperatingSystem
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.owasp.dependencycheck.reporting.ReportGenerator
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.slf4j.LoggerFactory
val ktor_version: String by project
val kotlin_version: String by project
val coroutinesVersion: String by project
val logback_version: String by project
val koinVersion: String by project
val jackson_version: String by project
val cucumber_version: String by project
val ktorVersion = "1.5.4"
val kotlinVersion = "1.5.31"
val coroutinesVersion = "1.5.2"
val logbackVersion = "1.2.3"
val koinVersion = "3.1.5"
val jacksonVersion = "2.13.1"
group = "com.github.flecomte"
version = "0.0.1"
version = versioning.info.run {
if (dirty) {
versioning.info.full
} else {
versioning.info.lastTag
}
}
plugins {
jacoco
application
`maven-publish`
id("maven-publish")
id("org.jetbrains.kotlin.jvm") version "1.3.50"
kotlin("jvm") version "1.5.31"
kotlin("plugin.serialization") version "1.5.31"
id("com.github.johnrengelman.shadow") version "5.2.0"
id("org.jlleitschuh.gradle.ktlint") version "8.2.0"
id("org.owasp.dependencycheck") version "5.1.0"
id("org.sonarqube") version "2.7"
id("com.github.johnrengelman.shadow") version "7.1.2"
id("org.jlleitschuh.gradle.ktlint") version "10.2.1"
id("org.owasp.dependencycheck") version "6.1.5"
id("org.sonarqube") version "3.3"
id("net.nemerosa.versioning") version "2.15.1"
id("io.gitlab.arturbosch.detekt") version "1.19.0"
id("com.avast.gradle.docker-compose") version "0.15.1"
id("com.github.kt3k.coveralls") version "2.12.0"
}
dependencyLocking {
lockAllConfigurations()
// lockMode.set(LockMode.STRICT)
}
application {
mainClassName = "io.ktor.server.jetty.EngineMain"
}
buildscript {
repositories {
mavenLocal()
mavenCentral()
jcenter()
maven { url = uri("https://jitpack.io") }
}
dependencies {
classpath("com.typesafe:config:1.4.2")
classpath("com.github.flecomte:postgres-json:2.1.2")
}
}
tasks.distZip.configure { enabled = false }
tasks.distTar.configure { enabled = false }
tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = "11"
}
}
val migration by tasks.registering {
group = "application"
dependsOn(tasks.named("composeUp"))
doLast {
val config = ConfigFactory.parseFile(file("$buildDir/resources/main/application.conf")).resolve()
val connection = Connection(
host = config.getString("db.host"),
port = config.getInt("db.port"),
database = config.getString("db.database"),
username = config.getString("db.username"),
password = config.getString("db.password")
)
Migrations(
connection,
file("$buildDir/resources/main/sql/migrations").toURI(),
file("$buildDir/resources/main/sql/functions").toURI()
).run {
run()
}
}
}
val migrationTest by tasks.registering {
group = "tests"
dependsOn(tasks.named("testComposeUp"))
finalizedBy(tasks.named("testComposeDown"))
doLast {
val config = ConfigFactory.parseFile(file("$buildDir/resources/test/application-test.conf")).resolve()
val connection = Connection(
host = config.getString("db.host"),
port = config.getInt("db.port"),
database = config.getString("db.database"),
username = config.getString("db.username"),
password = config.getString("db.password")
)
Migrations(
connection,
file("$buildDir/resources/main/sql/migrations").toURI(),
file("$buildDir/resources/main/sql/functions").toURI()
).run {
run()
connection.disconnect()
}
}
}
val testSql by tasks.registering {
group = "tests"
dependsOn(tasks.named("processResources"))
dependsOn(tasks.named("processTestResources"))
doLast {
val config = ConfigFactory.parseFile(file("$buildDir/resources/test/application-test.conf")).resolve()
val connection = Connection(
host = config.getString("db.host"),
port = config.getInt("db.port"),
database = config.getString("db.database"),
username = config.getString("db.username"),
password = config.getString("db.password")
)
Migrations(
connection,
file("$buildDir/resources/main/sql/migrations").toURI(),
file("$buildDir/resources/main/sql/functions").toURI(),
file("$buildDir/resources/test/sql/fixtures").toURI()
).run()
Requester.RequesterFactory(
connection = connection,
queriesDirectory = file("$buildDir/resources/test/sql").toURI()
).createRequester().run {
getQueries().map {
try {
it.sendQuery() == 0
} catch (e: Exception) {
false
}
}
}
connection.disconnect()
}
}
tasks.withType<Jar> {
manifest {
attributes(
@@ -43,21 +169,215 @@ tasks.withType<Jar> {
)
)
}
isZip64 = true
}
tasks {
named<ShadowJar>("shadowJar") {
mergeServiceFiles("META-INF/services")
tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = "11"
sourceCompatibility = "11"
targetCompatibility = "11"
}
}
tasks.named<ShadowJar>("shadowJar") {
mergeServiceFiles("META-INF/services")
archiveFileName.set("${archiveBaseName.get()}-latest-all.${archiveExtension.get()}")
isZip64 = true
}
tasks.sonarqube.configure {
dependsOn(tasks.jacocoTestReport)
}
val sourcesJar by tasks.registering(Jar::class) {
group = "build"
archiveClassifier.set("sources")
from(sourceSets.getByName("main").allSource)
}
tasks.test {
useJUnit()
useJUnitPlatform()
systemProperty("junit.jupiter.execution.parallel.enabled", true)
finalizedBy(tasks.jacocoTestReport) // report is always generated after tests run
}
coveralls {
sourceDirs.add("src/main/kotlin")
}
apply(plugin = "docker-compose")
dockerCompose {
projectName = "dc-project"
useComposeFiles = listOf("docker-compose.yml")
startedServices = listOf("db", "elasticsearch", "rabbitmq", "redis")
stopContainers = false
removeVolumes = false
removeContainers = false
isRequiredBy(project.tasks.run)
createNested("testSql").apply {
projectName = "dc-project_test"
useComposeFiles = listOf("docker-compose-test.yml")
startedServices = listOf("db", "elasticsearch")
stopContainers = false
}
createNested("test").apply {
projectName = "dc-project_test"
useComposeFiles = listOf("docker-compose-test.yml")
stopContainers = false
}
}
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 (${versioning.info.full})")
}
}
jacoco {
toolVersion = "0.8.3"
toolVersion = "0.8.7"
applyTo(tasks.run.get())
}
tasks.register<JacocoReport>("applicationCodeCoverageReport") {
executionData(tasks.run.get())
sourceSets(sourceSets.main.get())
}
tasks.jacocoTestReport {
dependsOn(tasks.test)
reports {
xml.isEnabled = true
html.isEnabled = true
}
}
detekt {
buildUponDefaultConfig = true // preconfigure defaults
ignoreFailures = true
// config = files("$projectDir/config/detekt.yml") // point to your custom config defining rules to run, overwriting default behavior
// baseline = file("$projectDir/config/baseline.xml") // a way of suppressing issues before introducing detekt
reports {
html.enabled = true // observe findings in your browser with structure and code snippets
xml.enabled = true // checkstyle like format mainly for integrations like Jenkins
txt.enabled = true // similar to the console output, contains issue signature to manually edit baseline files
sarif.enabled = true // standardized SARIF format (https://sarifweb.azurewebsites.net/) to support integrations with Github Code Scanning
}
}
tasks.withType<Detekt> {
// Target version of the generated JVM bytecode. It is used for type resolution.
this.jvmTarget = "11"
ignoreFailures = true
}
val setMaxMapCount = tasks.create<Exec>("setMaxMapCount") {
group = "docker"
doFirst {
if (OperatingSystem.current().isWindows) {
commandLine("cmd", "/c", "Powershell -ExecutionPolicy Bypass; wsl -d docker-desktop sysctl -w vm.max_map_count=262144")
} else if (OperatingSystem.current().isLinux) {
commandLine("sysctl -w vm.max_map_count=262144")
}
}
}
tasks.named("testComposeUp").configure {
if (OperatingSystem.current().isWindows) {
dependsOn(setMaxMapCount)
}
}
tasks.register("testWithDependencies", Test::class) {
group = "tests"
dependsOn(tasks.named("testComposeUp"))
dependsOn(tasks.ktlintCheck)
dependsOn(testSql)
dependsOn(tasks.jacocoTestReport)
finalizedBy(tasks.sonarqube) // report is always generated after tests run
}
tasks.register("testArticles", Test::class) {
group = "tests"
useJUnitPlatform {
includeTags("article")
}
}
tasks.register("testCitizens", Test::class) {
group = "tests"
useJUnitPlatform {
includeTags("citizen")
}
}
tasks.register("testComments", Test::class) {
group = "tests"
useJUnitPlatform {
includeTags("comment")
}
}
tasks.register("testConstitutions", Test::class) {
group = "tests"
useJUnitPlatform {
includeTags("constitution")
}
}
tasks.register("testFollows", Test::class) {
group = "tests"
useJUnitPlatform {
includeTags("follow")
}
}
tasks.register("testNotifications", Test::class) {
group = "tests"
useJUnitPlatform {
includeTags("notification")
}
}
tasks.register("testOpinions", Test::class) {
group = "tests"
useJUnitPlatform {
includeTags("opinion")
}
}
tasks.register("testVotes", Test::class) {
group = "tests"
useJUnitPlatform {
includeTags("vote")
}
}
tasks.register("testWorkgroups", Test::class) {
group = "tests"
useJUnitPlatform {
includeTags("workgroup")
}
}
tasks.register("testViews", Test::class) {
group = "tests"
useJUnitPlatform {
includeTags("view")
}
}
@@ -68,46 +388,51 @@ dependencyCheck {
repositories {
mavenLocal()
jcenter()
maven { url = uri("https://kotlin.bintray.com/ktor") }
maven { url = uri("https://jitpack.io") }
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version")
implementation(gradleApi())
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$coroutinesVersion")
implementation("io.ktor:ktor-server-jetty:$ktor_version")
implementation("io.ktor:ktor-client-jetty:$ktor_version")
implementation("ch.qos.logback:logback-classic:$logback_version")
implementation("io.ktor:ktor-server-core:$ktor_version")
implementation("io.ktor:ktor-locations:$ktor_version")
implementation("io.ktor:ktor-auth:$ktor_version")
implementation("io.ktor:ktor-auth-jwt:$ktor_version")
implementation("io.ktor:ktor-gson:$ktor_version")
implementation("io.ktor:ktor-auth-jwt:$ktor_version")
implementation("io.ktor:ktor-websockets:$ktor_version")
implementation("org.koin:koin-ktor:$koinVersion")
implementation("io.ktor:ktor-jackson:$ktor_version")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version")
implementation("net.pearx.kasechange:kasechange-jvm:1.1.0")
implementation("com.auth0:java-jwt:3.8.2")
implementation("com.github.jasync-sql:jasync-postgresql:1.0.7")
implementation("com.github.flecomte:postgres-json:1.1.1")
implementation("com.github.flecomte:ktor-voter:1.0.1")
implementation("com.sendgrid:sendgrid-java:4.4.1")
implementation("io.lettuce:lettuce-core:5.2.2.RELEASE")
implementation("com.rabbitmq:amqp-client:5.8.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1")
implementation("io.ktor:ktor-server-jetty:$ktorVersion")
implementation("io.ktor:ktor-client-jetty:$ktorVersion")
implementation("ch.qos.logback:logback-classic:$logbackVersion")
implementation("io.ktor:ktor-server-core:$ktorVersion")
implementation("io.ktor:ktor-locations:$ktorVersion")
implementation("io.ktor:ktor-auth:$ktorVersion")
implementation("io.ktor:ktor-auth-jwt:$ktorVersion")
implementation("io.ktor:ktor-websockets:$ktorVersion")
implementation("io.insert-koin:koin-ktor:$koinVersion")
implementation("io.ktor:ktor-jackson:$ktorVersion")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jacksonVersion")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-joda:$jacksonVersion")
implementation("net.pearx.kasechange:kasechange-jvm:1.3.0")
implementation("com.auth0:java-jwt:3.12.0")
implementation("com.github.jasync-sql:jasync-postgresql:1.1.6")
implementation("com.github.flecomte:postgres-json:2.1.2")
implementation("com.sendgrid:sendgrid-java:4.7.1")
implementation("io.lettuce:lettuce-core:5.3.6.RELEASE") // TODO update to 6.0.2
implementation("com.rabbitmq:amqp-client:5.10.0")
implementation("org.elasticsearch.client:elasticsearch-rest-client:6.7.1")
implementation("com.jayway.jsonpath:json-path:2.4.0")
implementation("com.jayway.jsonpath:json-path:2.5.0")
implementation("com.avast.gradle:gradle-docker-compose-plugin:0.14.0")
implementation("io.konform:konform:0.3.0")
testImplementation("io.ktor:ktor-server-tests:$ktor_version")
testImplementation("io.ktor:ktor-client-mock:$ktor_version")
testImplementation("io.ktor:ktor-client-mock-jvm:$ktor_version")
testImplementation("org.koin:koin-test:$koinVersion")
testImplementation("io.mockk:mockk:1.9.3")
testImplementation("org.junit.jupiter:junit-jupiter:5.5.0")
testImplementation("org.amshove.kluent:kluent:1.4")
testImplementation("io.cucumber:cucumber-java8:$cucumber_version")
testImplementation("io.cucumber:cucumber-junit:$cucumber_version")
testImplementation("io.ktor:ktor-server-tests:$ktorVersion")
testImplementation("io.ktor:ktor-client-mock:$ktorVersion")
testImplementation("io.ktor:ktor-client-mock-jvm:$ktorVersion")
testImplementation("io.insert-koin:koin-test:$koinVersion")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
testImplementation("org.amshove.kluent:kluent:1.68")
testImplementation("io.mockk:mockk:1.12.2")
testImplementation("io.mockk:mockk-agent-api:1.12.2")
testImplementation("io.mockk:mockk-agent-jvm:1.12.2")
testImplementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
testImplementation("com.thedeanda:lorem:2.1")
testImplementation("org.openapi4j:openapi-operation-validator:1.0.6")
testImplementation("org.openapi4j:openapi-parser:1.0.6")
}

View File

@@ -0,0 +1,20 @@
Installation on Linux (debian)
=====================
## Prerequisites
```bash
apt-get update
```
### Install docker
See: [docs.docker.com/get-docker](https://docs.docker.com/get-docker/)
```bash
apt-get install docker
apt-get install docker-compose
```
### Install Git
See: [git-scm.com/downloads](https://git-scm.com/downloads)
```powershell
apt-get install git
```

View File

@@ -0,0 +1,50 @@
Installation on Windows
============
## Prerequisites
### Install chocolaty (optional)
First install Chocolaty => [https://chocolatey.org/install](https://chocolatey.org/install)
```powershell
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
```
### Install make (optional)
Install make with chocolaty
```powershell
chocolatey install make
```
Install make for gitbash
[https://gist.github.com/evanwill/0207876c3243bbb6863e65ec5dc3f058#make]()
### Install awk (optional)
Install awk with chocolaty
```powershell
chocolatey install awk
```
### Install docker
See: [docs.docker.com/get-docker](https://docs.docker.com/get-docker/)
```powershell
choco install docker-desktop
```
If you use docker with WSL2, you need to change config for elasticsearch:
```powershell
wsl -d docker-desktop
sysctl -w vm.max_map_count=262144
echo "vm.max_map_count = 262144" > /etc/sysctl.d/99-docker-desktop.conf
```
then restart docker-desktop
### Install Git
See: [git-scm.com/downloads](https://git-scm.com/downloads)
```powershell
choco install git
```
### 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";
```

View File

@@ -0,0 +1,7 @@
Installation
============
1. [Installation on Windows](Installation-windows.md)
2. [Installation on Linux](Installation-linux.md)
3. [Problems in installations](Problems.md)

View File

@@ -0,0 +1,29 @@
Problems
========
1. [max_map_count](#max_map_count)
max_map_count
-------------
**Context**:
Elasticsearch in Docker on WSL2
**Error**:
```
max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
```
**Resolution**:
[Stackoverflow](https://stackoverflow.com/questions/42111566/elasticsearch-in-windows-docker-image-vm-max-map-count)
In Powershell:
```powershell
wsl -d docker-desktop
sysctl -w vm.max_map_count=262144
echo "vm.max_map_count = 262144" > /etc/sysctl.d/99-docker-desktop.conf
```
restart docker-desktop

98
doc/schema/Article.puml Normal file
View File

@@ -0,0 +1,98 @@
@startuml
title Search / Get articles
actor Front
box Article API
control Controller
control Repository
entity Article
database Postgres
endbox
box View System
control ArticleViewManager
database Elasticsearch
endbox
box Notification System
control EventNotification
database RabbitMQ
database Redis
endbox
Front -> Controller++: GET /articles?page=1
Controller -> Repository++: find
Repository -> Postgres++: find_articles()
return
return
return: 200, Articles
newpage Create / Update Article
Front -> Controller: POST /article
activate Controller
Controller -> Controller: Convert dto to Entity
Controller -> Controller: Check Authorization
alt Authorize
Controller -> Repository++: upsert(entity)
Repository -> Postgres++: upsert_article
return
return
Controller -> Controller: Convert to dto
Front <-- Controller: 200, New Article
else not authorize
Front <-- Controller: 403, "Forbidden"
end
Controller -> EventNotification: raiseEvent(ArticleUpdate)
deactivate Controller
activate EventNotification
EventNotification ->> RabbitMQ
deactivate EventNotification
...
RabbitMQ -->> EventNotification++
EventNotification ->> : Send Email
EventNotification ->> Redis : Push Event Notification
return <<ACK>>
newpage get one article by id
Front -> Controller: GET /article/{article}
activate Controller
Controller -> Repository++: findById()
Repository -> Postgres++: find_article_by_id()
return
return
Controller -> Controller: Check Authorization
alt Authorize
Controller -> ArticleViewManager++: getViewsCount(Article)
ArticleViewManager -> Elasticsearch++
return
return
Controller -> Controller: Convert Article and Views to dto
Front <<-- Controller: 200, Article
else not authorize
Front <<-- Controller: 403, "Forbidden"
end
Controller -> ArticleViewManager++: increment the view counter
ArticleViewManager -> Elasticsearch++
return
return
deactivate Controller
newpage get article versions by id
Front -> Controller: GET /articles/{article}/versions
activate Controller
Controller -> Controller: Check Authorization
alt Authorize
Controller -> Repository++: findVersionsByVersionId
Repository -> Postgres++: find_articles_versions_by_version_id
return
return
Controller -> Controller: Convert to dto
Front <-- Controller: 200, Articles versions
else not authorize
Front <-- Controller: 403, "Forbidden"
end
deactivate Controller
@enduml

View File

@@ -0,0 +1,66 @@
@startuml
title Notification
|Server|
partition Event {
start
:Article is modified;
:Send message to "notification" exchange (RabbitMQ);
:RabbitMQ send message to "push" and "email" queue;
stop
}
split
partition Email {
-[hidden]->
:Consume "email" queue<
repeat :get next notification;
:Get followers of article from DB;
while (loop on followers)
:Send email to the citizen>
endwhile
:ACK>
repeat while()
detach
}
splitagain
partition Push {
-[hidden]->
:Consume "email" queue<
repeat :get next notification;
:Get followers of article from DB;
while (loop on followers)
:Send notification message to redis>
endwhile
:ACK>
repeat while()
detach
}
splitagain
partition "Notification direct" {
-[hidden]->
|Client|
start
:Client arrive on the web site;
:Connect to the websocket;
|Server|
:Get citizen notification
from redis;
while (on each notifications)
:Send notification to websocket>
endwhile(no notification left)
|Client|
:show notification;
|Server|
:Subscribe to redis event;
repeat :On new notification;
:Get new notification from redis;
:Send notification to websocket>
|Client|
:show notification;
|Server|
repeat while (wait notification)
detach
}
endsplit
@enduml

44
docker-compose-test.yml Normal file
View File

@@ -0,0 +1,44 @@
version: '3.3'
services:
rabbitmq:
container_name: ${APP_NAME}_rabbitmq_test
image: rabbitmq:management-alpine
ports:
- 5673:5672
- 15673:15672
redis:
container_name: ${APP_NAME}_redis_test
image: redis:6-alpine
ports:
- 6380:6379
elasticsearch:
container_name: ${APP_NAME}_elasticsearch_test
image: elasticsearch:6.7.1
ports:
- 9201:9200
- 9301:9300
healthcheck:
test: ["CMD", "curl", "-f", "http://elasticsearch:9200"]
interval: 3s
timeout: 2s
retries: 20
db:
container_name: ${APP_NAME}_postgresql_test
build:
context: docker/postgresql
ports:
- 15432:5432
environment:
POSTGRES_PASSWORD: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_DB: ${DB_PWD}
depends_on:
- elasticsearch
healthcheck:
test: [ "CMD", "pg_isready", "-q", "-d", "${DB_NAME}", "-U", "${DB_USER}" ]
interval: 3s
timeout: 2s
retries: 20

View File

@@ -1,44 +1,35 @@
# To execute this docker-compose yml file use docker-compose -f <file_name> up
# Add the "-d" flag at the end for detached execution
version: '3.7'
version: '3.8'
services:
sonarqube:
container_name: sonarqube_${NAME}
image: sonarqube
restart: always
ports:
- ${SONARQUBE_PORT}:9000
openapi:
container_name: openapi_${NAME}
container_name: ${APP_NAME}_openapi
image: swaggerapi/swagger-ui
restart: always
ports:
- ${OPENAPI_PORT}:8080
environment:
URL: "http://localhost:8080"
rabbitmq:
container_name: rabbitmq_${NAME}
container_name: ${APP_NAME}_rabbitmq
image: rabbitmq:management-alpine
restart: always
ports:
- ${RABBITMQ_PORT}:5672
- ${RABBITMQ_MANAGEMENT_PORT}:15672
redis:
container_name: redis_${NAME}
image: redis:6.0-rc-alpine
restart: always
container_name: ${APP_NAME}_redis
image: redis:6-alpine
ports:
- ${REDIS_PORT}:6379
volumes:
- redis-data:/var/lib/redis:rw
app:
container_name: app_${NAME}
container_name: ${APP_NAME}_app
build:
context: ./build
dockerfile: ../docker/app/Dockerfile
restart: always
context: .
dockerfile: docker/app/Dockerfile
ports:
- ${APP_PORT}:8080
environment:
@@ -47,6 +38,9 @@ services:
REDIS_CONNECTION: ${REDIS_CONNECTION}
RABBITMQ_CONNECTION: ${RABBITMQ_CONNECTION}
ELASTICSEARCH_CONNECTION: ${ELASTICSEARCH_CONNECTION}
JWT_SECRET: ${JWT_SECRET}
JWT_ISSUER: ${JWT_ISSUER}
JWT_VALIDITY: ${JWT_VALIDITY}
depends_on:
- elasticsearch
- db
@@ -54,19 +48,21 @@ services:
- rabbitmq
elasticsearch:
container_name: elasticsearch_${NAME}
container_name: ${APP_NAME}_elasticsearch
image: elasticsearch:6.7.1
restart: always
ports:
- ${ELASTIC_REST}:9200
- ${ELASTIC_NODES}:9300
healthcheck:
test: ["CMD", "curl", "-f", "http://elasticsearch:9200"]
interval: 3s
timeout: 2s
retries: 20
# Database
db:
container_name: postgresql_${NAME}
container_name: ${APP_NAME}_postgresql
build:
context: docker/postgresql
restart: always
ports:
- ${POSTGRESQL_PORT}:5432
environment:
@@ -75,11 +71,15 @@ services:
POSTGRES_DB: ${DB_PWD}
volumes:
- ./var/log/postgresql:/var/log/postgresql:rw
- ./var/postgresql/data:/var/lib/postgresql/data:rw
- db-data:/var/lib/postgresql/data:rw
depends_on:
- elasticsearch
healthcheck:
test: ["CMD", "curl", "-f", "http://elasticsearch:9200/"]
test: [ "CMD", "pg_isready", "-q", "-d", "${DB_NAME}", "-U", "${DB_USER}" ]
interval: 3s
timeout: 2s
retries: 20
volumes:
db-data:
redis-data:

View File

@@ -1,5 +1,13 @@
FROM adoptopenjdk/openjdk11:jre-11.0.4_11-alpine
#### BUILD ####
FROM gradle:6.8-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 gradle shadowJar
#### RUN ####
FROM amazoncorretto:11-alpine as run
ENV APPLICATION_USER ktor
RUN adduser -D -g '' $APPLICATION_USER
@@ -8,7 +16,7 @@ RUN chown -R $APPLICATION_USER /app
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
CMD ["java", "-server", "-XX:+UnlockExperimentalVMOptions", "-XX:InitialRAMFraction=2", "-XX:MinRAMFraction=2", "-XX:MaxRAMFraction=2", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=100", "-XX:+UseStringDeduplication", "-jar", "dcproject.jar"]

275
gradle.lockfile Normal file
View File

@@ -0,0 +1,275 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
ch.qos.logback:logback-classic:1.2.3=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
ch.qos.logback:logback-core:1.2.3=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.auth0:java-jwt:3.12.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.auth0:jwks-rsa:0.9.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.avast.gradle:gradle-docker-compose-plugin:0.14.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.beust:jcommander:1.81=detekt
com.fasterxml.jackson.core:jackson-annotations:2.13.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-core:2.13.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-databind:2.13.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.1=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-joda:2.13.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.fasterxml.jackson.module:jackson-module-kotlin:2.13.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.fasterxml.jackson:jackson-bom:2.13.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.github.flecomte:postgres-json:2.1.2=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.github.jasync-sql:jasync-common:1.1.6=compileClasspath,implementationDependenciesMetadata,testCompileClasspath,testImplementationDependenciesMetadata
com.github.jasync-sql:jasync-common:1.1.7=runtimeClasspath,testRuntimeClasspath
com.github.jasync-sql:jasync-pool:1.1.6=compileClasspath,implementationDependenciesMetadata,testCompileClasspath,testImplementationDependenciesMetadata
com.github.jasync-sql:jasync-pool:1.1.7=runtimeClasspath,testRuntimeClasspath
com.github.jasync-sql:jasync-postgresql:1.1.6=compileClasspath,implementationDependenciesMetadata,testCompileClasspath,testImplementationDependenciesMetadata
com.github.jasync-sql:jasync-postgresql:1.1.7=runtimeClasspath,testRuntimeClasspath
com.github.shyiko.klob:klob:0.2.1=ktlint
com.google.code.findbugs:jsr305:3.0.2=runtimeClasspath,testRuntimeClasspath
com.google.errorprone:error_prone_annotations:2.2.0=runtimeClasspath,testRuntimeClasspath
com.google.guava:failureaccess:1.0.1=runtimeClasspath,testRuntimeClasspath
com.google.guava:guava:27.1-jre=runtimeClasspath,testRuntimeClasspath
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=runtimeClasspath,testRuntimeClasspath
com.google.j2objc:j2objc-annotations:1.1=runtimeClasspath,testRuntimeClasspath
com.googlecode.json-simple:json-simple:1.1.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.jayway.jsonpath:json-path:2.5.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.ongres.scram:client:2.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.ongres.scram:common:2.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.ongres.stringprep:saslprep:1.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.ongres.stringprep:stringprep:1.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.pinterest.ktlint:ktlint-core:0.42.1=ktlint,ktlintBaselineReporter
com.pinterest.ktlint:ktlint-reporter-baseline:0.42.1=ktlint,ktlintBaselineReporter
com.pinterest.ktlint:ktlint-reporter-checkstyle:0.42.1=ktlint
com.pinterest.ktlint:ktlint-reporter-html:0.42.1=ktlint
com.pinterest.ktlint:ktlint-reporter-json:0.42.1=ktlint
com.pinterest.ktlint:ktlint-reporter-plain:0.42.1=ktlint
com.pinterest.ktlint:ktlint-reporter-sarif:0.42.1=ktlint
com.pinterest.ktlint:ktlint-ruleset-experimental:0.42.1=ktlint
com.pinterest.ktlint:ktlint-ruleset-standard:0.42.1=ktlint
com.pinterest.ktlint:ktlint-ruleset-test:0.42.1=ktlint
com.pinterest:ktlint:0.42.1=ktlint
com.rabbitmq:amqp-client:5.10.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.sendgrid:java-http-client:4.3.6=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.sendgrid:sendgrid-java:4.7.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.thedeanda:lorem:2.1=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.typesafe:config:1.3.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
commons-codec:commons-codec:1.11=compileClasspath,implementationDependenciesMetadata,testCompileClasspath,testImplementationDependenciesMetadata
commons-codec:commons-codec:1.14=runtimeClasspath,testRuntimeClasspath
commons-io:commons-io:2.6=runtimeClasspath,testRuntimeClasspath
commons-logging:commons-logging:1.2=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
info.picocli:picocli:3.9.6=ktlint
io.github.detekt.sarif4k:sarif4k:0.0.1=detekt,ktlint
io.github.microutils:kotlin-logging:1.7.6=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.gitlab.arturbosch.detekt:detekt-api:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-cli:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-core:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-metrics:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-parser:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-psi-utils:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-report-html:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-report-sarif:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-report-txt:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-report-xml:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-complexity:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-coroutines:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-documentation:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-empty:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-errorprone:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-exceptions:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-naming:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-performance:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-style:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules:1.19.0=detekt
io.gitlab.arturbosch.detekt:detekt-tooling:1.19.0=detekt
io.insert-koin:koin-core-jvm:3.1.5=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.insert-koin:koin-core:3.1.5=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.insert-koin:koin-ktor:3.1.5=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.insert-koin:koin-test-jvm:3.1.5=testCompileClasspath,testRuntimeClasspath
io.insert-koin:koin-test:3.1.5=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.konform:konform-jvm:0.3.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.konform:konform:0.3.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-auth-jwt-kotlinMultiplatform:1.5.4=implementationDependenciesMetadata,testImplementationDependenciesMetadata
io.ktor:ktor-auth-jwt:1.5.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-auth-kotlinMultiplatform:1.5.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-auth:1.5.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-client-cio-jvm:1.5.4=testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-client-cio:1.5.4=testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-client-core-jvm:1.5.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-client-core:1.5.4=compileClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-client-jetty-kotlinMultiplatform:1.5.4=implementationDependenciesMetadata,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-client-jetty:1.5.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-client-mock-jvm:1.5.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-client-mock:1.5.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-http-cio-jvm:1.5.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-http-cio:1.5.4=compileClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-http-jvm:1.6.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-http:1.6.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-io-jvm:1.6.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-io:1.6.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-jackson-kotlinMultiplatform:1.5.4=implementationDependenciesMetadata,testImplementationDependenciesMetadata
io.ktor:ktor-jackson:1.5.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-locations-kotlinMultiplatform:1.5.4=implementationDependenciesMetadata,testImplementationDependenciesMetadata
io.ktor:ktor-locations:1.5.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-network-jvm:1.5.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-network-tls-certificates-kotlinMultiplatform:1.5.4=testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-network-tls-certificates:1.5.4=testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-network-tls-jvm:1.5.4=testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-network-tls:1.5.4=testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-network:1.5.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-server-core-kotlinMultiplatform:1.5.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-server-core:1.6.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-server-host-common-kotlinMultiplatform:1.5.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-server-host-common:1.5.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-server-jetty-kotlinMultiplatform:1.5.4=implementationDependenciesMetadata,testImplementationDependenciesMetadata
io.ktor:ktor-server-jetty:1.5.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-server-servlet-kotlinMultiplatform:1.5.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-server-servlet:1.5.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-server-test-host-kotlinMultiplatform:1.5.4=testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-server-test-host:1.5.4=testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-server-tests-kotlinMultiplatform:1.5.4=testImplementationDependenciesMetadata
io.ktor:ktor-server-tests:1.5.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-utils-jvm:1.6.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.ktor:ktor-utils:1.6.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-websockets-kotlinMultiplatform:1.5.4=implementationDependenciesMetadata,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.ktor:ktor-websockets:1.5.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.lettuce:lettuce-core:5.3.6.RELEASE=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.mockk:mockk-agent-api:1.12.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.mockk:mockk-agent-common:1.12.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.mockk:mockk-agent-jvm:1.12.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.mockk:mockk-common:1.12.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.mockk:mockk-dsl-jvm:1.12.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.mockk:mockk-dsl:1.12.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.mockk:mockk:1.12.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.netty:netty-buffer:4.1.56.Final=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.netty:netty-codec:4.1.56.Final=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.netty:netty-common:4.1.56.Final=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.netty:netty-handler:4.1.56.Final=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.netty:netty-resolver:4.1.56.Final=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.netty:netty-transport:4.1.56.Final=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.projectreactor:reactor-core:3.4.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
javax.servlet:javax.servlet-api:3.1.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
joda-time:joda-time:2.10.8=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
junit:junit:4.12=testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy-agent:1.12.5=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.bytebuddy:byte-buddy:1.12.5=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.java.dev.jna:jna-platform:5.5.0=testRuntimeClasspath
net.java.dev.jna:jna:5.5.0=testRuntimeClasspath
net.minidev:accessors-smart:1.2=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.minidev:json-smart:2.3=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.pearx.kasechange:kasechange-jvm:1.3.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.pearx.kasechange:kasechange-metadata:1.3.0=implementationDependenciesMetadata,testImplementationDependenciesMetadata
org.amshove.kluent:kluent-common:1.68=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.amshove.kluent:kluent:1.68=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apache.httpcomponents:httpasyncclient:4.1.2=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apache.httpcomponents:httpclient:4.5.12=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apache.httpcomponents:httpcore-nio:4.4.5=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apache.httpcomponents:httpcore:4.4.13=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata
org.bouncycastle:bcprov-jdk15on:1.67=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.checkerframework:checker-qual:2.5.2=runtimeClasspath,testRuntimeClasspath
org.codehaus.mojo:animal-sniffer-annotations:1.17=runtimeClasspath,testRuntimeClasspath
org.ec4j.core:ec4j-core:0.3.0=ktlint,ktlintBaselineReporter
org.eclipse.jetty.http2:http2-client:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty.http2:http2-common:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty.http2:http2-hpack:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty.http2:http2-http-client-transport:9.4.31.v20200723=testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty.http2:http2-server:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-alpn-client:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-alpn-java-client:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-alpn-java-server:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-alpn-openjdk8-client:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-alpn-openjdk8-server:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-alpn-server:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-client:9.4.31.v20200723=testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-continuation:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-http:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-io:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-server:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-servlets:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-util:9.4.31.v20200723=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.elasticsearch.client:elasticsearch-rest-client:6.7.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.fusesource.jansi:jansi:2.3.4=runtimeClasspath,testRuntimeClasspath
org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath
org.jacoco:org.jacoco.agent:0.8.7=jacocoAgent,jacocoAnt
org.jacoco:org.jacoco.ant:0.8.7=jacocoAnt
org.jacoco:org.jacoco.core:0.8.7=jacocoAnt
org.jacoco:org.jacoco.report:0.8.7=jacocoAnt
org.jetbrains.intellij.deps:trove4j:1.0.20181211=detekt,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,ktlint,ktlintBaselineReporter
org.jetbrains.kotlin:kotlin-compiler-embeddable:1.5.20=ktlint,ktlintBaselineReporter
org.jetbrains.kotlin:kotlin-compiler-embeddable:1.5.31=detekt,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-daemon-embeddable:1.5.20=ktlint,ktlintBaselineReporter
org.jetbrains.kotlin:kotlin-daemon-embeddable:1.5.31=detekt,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.5.31=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:1.5.31=kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-native-utils:1.5.31=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-project-model:1.5.31=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-reflect:1.5.20=ktlint,ktlintBaselineReporter
org.jetbrains.kotlin:kotlin-reflect:1.5.30=compileClasspath,implementationDependenciesMetadata,runtimeClasspath
org.jetbrains.kotlin:kotlin-reflect:1.5.31=detekt,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-script-runtime:1.5.20=ktlint,ktlintBaselineReporter
org.jetbrains.kotlin:kotlin-script-runtime:1.5.31=detekt,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-scripting-common:1.5.31=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.5.31=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.5.31=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-jvm:1.5.31=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-serialization:1.5.31=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-stdlib-common:1.5.20=ktlint,ktlintBaselineReporter
org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=compileClasspath,detekt,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.0=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.20=ktlint,ktlintBaselineReporter
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.31=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.0=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.20=ktlint,ktlintBaselineReporter
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.31=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib:1.5.20=ktlint,ktlintBaselineReporter
org.jetbrains.kotlin:kotlin-stdlib:1.5.31=compileClasspath,detekt,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-test-annotations-common:1.5.31=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-test-common:1.5.31=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-test-junit:1.5.31=testCompileClasspath,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-test:1.5.31=testCompileClasspath,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-util-io:1.5.31=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.4.2=implementationDependenciesMetadata,testImplementationDependenciesMetadata
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.0=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core-metadata:1.4.2=implementationDependenciesMetadata,testImplementationDependenciesMetadata
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-debug:1.5.2=testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.5.1-native-mt=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-reactive:1.5.2=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.5.2=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-html-jvm:0.7.3=detekt
org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.0.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.1.0=detekt,ktlint
org.jetbrains.kotlinx:kotlinx-serialization-core-metadata:1.0.1=implementationDependenciesMetadata,testImplementationDependenciesMetadata
org.jetbrains.kotlinx:kotlinx-serialization-core:1.0.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-serialization-core:1.1.0=detekt,ktlint
org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.0.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.1.0=detekt,ktlint
org.jetbrains.kotlinx:kotlinx-serialization-json-metadata:1.0.1=implementationDependenciesMetadata,testImplementationDependenciesMetadata
org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0=detekt,ktlint
org.jetbrains:annotations:13.0=compileClasspath,detekt,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,ktlint,ktlintBaselineReporter,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.joda:joda-convert:1.8.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.8.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.8.2=testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.8.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter:5.8.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.8.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.8.2=testRuntimeClasspath
org.junit:junit-bom:5.8.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.objenesis:objenesis:3.1=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.openapi4j:openapi-core:1.0.6=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.openapi4j:openapi-operation-validator:1.0.6=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.openapi4j:openapi-parser:1.0.6=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.openapi4j:openapi-schema-validator:1.0.6=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.opentest4j:opentest4j:1.2.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.ow2.asm:asm-analysis:9.1=jacocoAnt
org.ow2.asm:asm-commons:9.1=jacocoAnt
org.ow2.asm:asm-tree:9.1=jacocoAnt
org.ow2.asm:asm:5.0.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.ow2.asm:asm:9.1=jacocoAnt
org.reactivestreams:reactive-streams:1.0.3=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.slf4j:slf4j-api:1.7.30=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.yaml:snakeyaml:1.27=runtimeClasspath
org.yaml:snakeyaml:1.28=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.yaml:snakeyaml:1.29=detekt
empty=annotationProcessor,apiDependenciesMetadata,compileOnly,compileOnlyDependenciesMetadata,detektPlugins,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,ktlintReporter,ktlintRuleset,runtimeOnlyDependenciesMetadata,shadow,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnly,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDef,testKotlinScriptDefExtensions,testRuntimeOnlyDependenciesMetadata

View File

@@ -1,10 +1,7 @@
ktor_version=1.2.2
kotlin.code.style=official
kotlin_version=1.3.40
coroutinesVersion=1.3.3
logback_version=1.2.1
koinVersion=2.0.1
jackson_version=2.9.9
cucumber_version=5.1.3
systemProp.sonar.host.url=http://localhost:9000
systemProp.sonar.login=1196e8015c20035f1aa91e881b95ce9d6e879c8a
systemProp.sonar.host.url=https://sonarcloud.io
systemProp.sonar.projectKey=dc-project
systemProp.sonar.projectName=DC Project
systemProp.sonar.organization=flecomte
systemProp.sonar.java.coveragePlugin=jacoco
systemProp.sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

31
gradlew vendored
View File

@@ -82,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -129,6 +130,7 @@ fi
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@@ -154,19 +156,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -175,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

25
gradlew.bat vendored
View File

@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -51,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -61,28 +64,14 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell

12
hook/version.sh Normal file
View 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

View File

@@ -1,364 +0,0 @@
package fr.dcproject
import com.fasterxml.jackson.core.util.DefaultIndenter
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.PropertyNamingStrategy
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.datatype.joda.JodaModule
import com.github.jasync.sql.db.postgresql.exceptions.GenericDatabaseException
import fr.dcproject.Env.PROD
import fr.dcproject.entity.*
import fr.dcproject.event.EventNotification
import fr.dcproject.event.EventSubscriber
import fr.dcproject.routes.*
import fr.dcproject.security.voter.*
import fr.ktorVoter.AuthorizationVoter
import fr.ktorVoter.ForbiddenException
import fr.postgresjson.migration.Migrations
import io.ktor.application.Application
import io.ktor.application.ApplicationCall
import io.ktor.application.call
import io.ktor.application.install
import io.ktor.auth.Authentication
import io.ktor.auth.authenticate
import io.ktor.auth.jwt.jwt
import io.ktor.client.HttpClient
import io.ktor.client.engine.jetty.Jetty
import io.ktor.features.*
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpMethod
import io.ktor.http.HttpStatusCode
import io.ktor.http.auth.HttpAuthHeader
import io.ktor.jackson.jackson
import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Locations
import io.ktor.response.respond
import io.ktor.routing.Routing
import io.ktor.util.KtorExperimentalAPI
import io.ktor.websocket.WebSockets
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.ktor.ext.Koin
import org.koin.ktor.ext.get
import org.slf4j.event.Level
import java.time.Duration
import java.util.*
import java.util.concurrent.CompletionException
import fr.dcproject.entity.Workgroup as WorkgroupEntity
import fr.dcproject.repository.Article as RepositoryArticle
import fr.dcproject.repository.Citizen as RepositoryCitizen
import fr.dcproject.repository.Constitution as RepositoryConstitution
import fr.dcproject.repository.OpinionChoice as OpinionChoiceRepository
import fr.dcproject.repository.User as UserRepository
import fr.dcproject.repository.Workgroup as WorkgroupRepository
fun main(args: Array<String>): Unit = io.ktor.server.jetty.EngineMain.main(args)
enum class Env { PROD, TEST, CUCUMBER }
@KtorExperimentalAPI
@KtorExperimentalLocationsAPI
@Suppress("unused") // Referenced in application.conf
fun Application.module(env: Env = PROD) {
install(Koin) {
Slf4jLog()
modules(Module)
}
install(CallLogging) {
level = Level.INFO
}
install(DataConversion) {
convert<UUID> {
decode { values, _ ->
values.singleOrNull()?.let { UUID.fromString(it) }
}
encode { value ->
when (value) {
null -> listOf()
is UUID -> listOf(value.toString())
else -> throw InternalError("Cannot convert $value as UUID")
}
}
}
// TODO: create generic convert for entityI
convert<Article> {
decode { values, _ ->
values.singleOrNull()?.let {
get<RepositoryArticle>().findById(UUID.fromString(it))
?: throw NotFoundException("Article $values not found")
} ?: throw NotFoundException("Article $values not found")
}
}
convert<ArticleRef> {
decode { values, _ ->
values.singleOrNull()?.let {
ArticleRef(UUID.fromString(it))
} ?: throw NotFoundException("""UUID "$values" is not valid for Article""")
}
}
convert<CommentRef> {
decode { values, _ ->
values.singleOrNull()?.let {
CommentRef(UUID.fromString(it))
} ?: throw NotFoundException("""UUID "$values" is not valid for Comment""")
}
}
convert<ConstitutionRef> {
decode { values, _ ->
values.singleOrNull()?.let {
ConstitutionRef(UUID.fromString(it))
} ?: throw NotFoundException("""UUID "$values" is not valid for Constitution""")
}
}
convert<Constitution> {
decode { values, _ ->
val id = values.singleOrNull()?.let { UUID.fromString(it) }
?: throw InternalError("Cannot convert $values to UUID")
get<RepositoryConstitution>().findById(id) ?: throw NotFoundException("Constitution $values not found")
}
}
convert<Citizen> {
decode { values, _ ->
val id = values.singleOrNull()?.let { UUID.fromString(it) }
?: throw InternalError("Cannot convert $values to UUID")
get<RepositoryCitizen>().findById(id, true) ?: throw NotFoundException("Citizen $values not found")
}
}
convert<CitizenRef> {
decode { values, _ ->
values.singleOrNull()?.let {
CitizenRef(UUID.fromString(it))
} ?: throw NotFoundException("""UUID "$values" is not valid for Citizen""")
}
}
convert<OpinionChoice> {
decode { values, _ ->
val id = values.singleOrNull()?.let { UUID.fromString(it) }
?: throw InternalError("Cannot convert $values to UUID")
get<OpinionChoiceRepository>().findOpinionChoiceById(id)
?: throw NotFoundException("OpinionChoice $values not found")
}
}
convert<WorkgroupRef> {
decode { values, _ ->
values.singleOrNull()?.let {
WorkgroupRef(UUID.fromString(it))
} ?: throw NotFoundException("""UUID "$values" is not valid for Workgroup""")
}
}
convert<WorkgroupEntity> {
decode { values, _ ->
val id = values.singleOrNull()?.let { UUID.fromString(it) }
?: throw InternalError("Cannot convert $values to UUID")
get<WorkgroupRepository>().findById(id)
?: throw NotFoundException("Workgroup $values not found")
}
}
}
install(Locations) {
}
install(AuthorizationVoter) {
voters = mutableListOf(
ArticleVoter(),
ConstitutionVoter(),
CitizenVoter(),
CommentVoter(),
VoteVoter(),
FollowVoter(),
OpinionVoter(),
OpinionChoiceVoter(),
WorkgroupVoter()
)
}
HttpClient(Jetty) {
engine {
}
}
/* Create index if not exist */
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) {
pingPeriod = Duration.ofSeconds(60) // Disabled (null) by default
timeout = Duration.ofSeconds(15)
maxFrameSize = Long.MAX_VALUE // Disabled (max value). The connection will be closed if surpassed this length.
masking = false
}
install(EventSubscriber) {
EventNotification(this, get(), get(), get(), get(), get()).config()
}
install(Authentication) {
/**
* Setup the JWT authentication to be used in [Routing].
* If the token is valid, the corresponding [User] is fetched from the database.
* The [User] can then be accessed in each [ApplicationCall].
*/
jwt {
verifier(JwtConfig.verifier)
realm = "dc-project.fr"
validate {
it.payload.getClaim("id").asString()?.let { id ->
get<UserRepository>().findById(UUID.fromString(id))
}
}
}
jwt("url") {
verifier(JwtConfig.verifier)
realm = "dc-project.fr"
authHeader { call ->
call.request.queryParameters.get("token")?.let {
HttpAuthHeader.Single("Bearer", it)
}
}
validate {
it.payload.getClaim("id").asString()?.let { id ->
get<UserRepository>().findById(UUID.fromString(id))
}
}
}
}
install(AutoHeadResponse)
install(ContentNegotiation) {
jackson {
propertyNamingStrategy = PropertyNamingStrategy.SNAKE_CASE
registerModule(JodaModule())
disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
configure(SerializationFeature.INDENT_OUTPUT, true)
setDefaultPrettyPrinter(DefaultPrettyPrinter().apply {
indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance)
indentObjectsWith(DefaultIndenter(" ", "\n"))
})
}
}
install(Routing) {
// trace { application.log.trace(it.buildText()) }
authenticate(optional = true) {
article(get(), get())
auth(get(), get(), get())
citizen(get(), get())
constitution(get())
followArticle(get())
followConstitution(get())
comment(get())
commentArticle(get())
commentConstitution(get())
voteArticle(get(), get(), get())
voteConstitution(get())
opinionArticle(get())
opinionChoice(get())
workgroup(get())
definition()
}
authenticate("url") {
notificationArticle(get(), get(named("ws")))
}
}
install(StatusPages) {
// TODO move to postgresJson lib
exception<CompletionException> { e ->
val parent = e.cause?.cause
if (parent is GenericDatabaseException) {
call.respond(HttpStatusCode.BadRequest, parent.errorMessage.message!!)
} else {
throw e
}
}
exception<NotFoundException> { e ->
call.respond(HttpStatusCode.NotFound, e.message!!)
}
exception<ForbiddenException> {
call.respond(HttpStatusCode.Forbidden)
}
}
install(CORS) {
method(HttpMethod.Options)
method(HttpMethod.Put)
method(HttpMethod.Delete)
header(HttpHeaders.Authorization)
anyHost()
// host("localhost:4200", schemes = listOf("http", "https"))
allowCredentials = true
allowSameOrigin = true
maxAge = Duration.ofDays(1)
}
if (env == PROD) {
get<Migrations>().run()
}
}

View File

@@ -1,31 +0,0 @@
package fr.dcproject
import fr.dcproject.entity.User
import fr.dcproject.entity.UserI
import fr.ktorVoter.ForbiddenException
import io.ktor.application.ApplicationCall
import io.ktor.auth.authentication
import io.ktor.util.AttributeKey
import io.ktor.util.pipeline.PipelineContext
import org.koin.core.context.GlobalContext
import fr.dcproject.entity.Citizen as CitizenEntity
import fr.dcproject.repository.Citizen as CitizenRepository
private val citizenAttributeKey = AttributeKey<CitizenEntity>("CitizenContext")
val ApplicationCall.citizen: CitizenEntity
get() = attributes.computeIfAbsent(citizenAttributeKey) {
val user = authentication.principal<UserI>() ?: throw ForbiddenException()
GlobalContext.get().koin.get<CitizenRepository>().findByUser(user)
?: throw ForbiddenException("Citizen not found for this user id \"${user.id}\"")
}
val ApplicationCall.citizenOrNull: CitizenEntity?
get() = authentication.principal<UserI>()?.let {
GlobalContext.get().koin.get<CitizenRepository>().findByUser(it)
}
val PipelineContext<Unit, ApplicationCall>.citizen get() = context.citizen
val PipelineContext<Unit, ApplicationCall>.citizenOrNull get() = context.citizenOrNull
val ApplicationCall.user get() = authentication.principal<User>()

View File

@@ -1,62 +0,0 @@
package fr.dcproject
import com.auth0.jwt.JWT
import com.auth0.jwt.JWTVerifier
import com.auth0.jwt.algorithms.Algorithm
import com.typesafe.config.ConfigFactory
import fr.dcproject.entity.UserI
import java.util.*
import java.net.URI
object Config {
private var config = ConfigFactory.load()
object Sql {
val migrationFiles: URI = this::class.java.getResource("/sql/migrations").toURI()
val functionFiles: URI = this::class.java.getResource("/sql/functions").toURI()
val fixtureFiles: URI = this::class.java.getResource("/sql/fixtures").toURI()
}
val envName: String = config.getString("app.envName")
val domain: String = config.getString("app.domain")
val host: String = config.getString("db.host")
var database: String = config.getString("db.database")
var username: String = config.getString("db.username")
var password: String = config.getString("db.password")
val port: Int = config.getInt("db.port")
val redis: String = config.getString("redis.connection")
val elasticsearch: String = config.getString("elasticsearch.connection")
val rabbitmq: String = config.getString("rabbitmq.connection")
val exchangeNotificationName = "notification"
val sendGridKey: String = config.getString("mail.sendGrid.key")
}
object JwtConfig {
private const val secret = "zAP5MBA4B4Ijz0MZaS48"
const val issuer = "dc-project.fr"
private const val validityInMs = 3_600_000 * 10 // 10 hours
// TODO change to RSA512
val algorithm = Algorithm.HMAC512(secret)
val verifier: JWTVerifier = JWT
.require(algorithm)
.withIssuer(issuer)
.build()
/**
* Produce a token for this combination of User and Account
*/
fun makeToken(user: UserI): String = JWT.create()
.withSubject("Authentication")
.withIssuer(issuer)
.withClaim("id", user.id.toString())
.withExpiresAt(getExpiration())
.sign(algorithm)
/**
* Calculate the expiration Date based on current time + the given validity
*/
private fun getExpiration() = Date(System.currentTimeMillis() + validityInMs)
}

View File

@@ -1,135 +0,0 @@
package fr.dcproject
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.PropertyNamingStrategy
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.datatype.joda.JodaModule
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.rabbitmq.client.ConnectionFactory
import fr.dcproject.event.publisher.Publisher
import fr.dcproject.messages.Mailer
import fr.dcproject.messages.NotificationEmailSender
import fr.dcproject.messages.SsoManager
import fr.dcproject.views.ArticleViewManager
import fr.postgresjson.connexion.Connection
import fr.postgresjson.connexion.Requester
import fr.postgresjson.migration.Migrations
import io.ktor.client.HttpClient
import io.ktor.client.features.websocket.WebSockets
import io.ktor.util.KtorExperimentalAPI
import io.lettuce.core.RedisClient
import io.lettuce.core.api.async.RedisAsyncCommands
import org.apache.http.HttpHost
import org.elasticsearch.client.RestClient
import org.koin.core.qualifier.named
import org.koin.dsl.module
import fr.dcproject.repository.Article as ArticleRepository
import fr.dcproject.repository.Citizen as CitizenRepository
import fr.dcproject.repository.CommentArticle as CommentArticleRepository
import fr.dcproject.repository.CommentConstitution as CommentConstitutionRepository
import fr.dcproject.repository.CommentGeneric as CommentGenericRepository
import fr.dcproject.repository.Constitution as ConstitutionRepository
import fr.dcproject.repository.FollowArticle as FollowArticleRepository
import fr.dcproject.repository.FollowConstitution as FollowConstitutionRepository
import fr.dcproject.repository.OpinionArticle as OpinionArticleRepository
import fr.dcproject.repository.OpinionChoice as OpinionChoiceRepository
import fr.dcproject.repository.User as UserRepository
import fr.dcproject.repository.VoteArticle as VoteArticleRepository
import fr.dcproject.repository.VoteComment as VoteCommentRepository
import fr.dcproject.repository.VoteConstitution as VoteConstitutionRepository
import fr.dcproject.repository.Workgroup as WorkgroupRepository
@KtorExperimentalAPI
val Module = module {
single { Config }
// SQL connection
single {
Connection(
host = Config.host,
port = Config.port,
database = Config.database,
username = Config.username,
password = Config.password
)
}
// Launch Database migration
single { Migrations(get(), Config.Sql.migrationFiles, Config.Sql.functionFiles) }
// Redis client
single<RedisAsyncCommands<String, String>> {
RedisClient.create(Config.redis).connect()?.async() ?: error("Unable to connect to redis")
}
// RabbitMQ
single<ConnectionFactory> {
ConnectionFactory().apply { setUri(Config.rabbitmq) }
}
// JsonSerializer
single<ObjectMapper> {
jacksonObjectMapper().apply {
registerModule(SimpleModule())
propertyNamingStrategy = PropertyNamingStrategy.SNAKE_CASE
registerModule(JodaModule())
disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true)
}
}
// Client HTTP for WebSockets
single(named("ws")) {
HttpClient {
install(WebSockets)
}
}
// SQL Requester (postgresJson)
single {
Requester.RequesterFactory(
connection = get(),
functionsDirectory = Config.Sql.functionFiles
).createRequester()
}
// Repositories
single { UserRepository(get()) }
single { ArticleRepository(get()) }
single { CitizenRepository(get()) }
single { ConstitutionRepository(get()) }
single { FollowArticleRepository(get()) }
single { FollowConstitutionRepository(get()) }
single { CommentGenericRepository(get()) }
single { CommentArticleRepository(get()) }
single { CommentConstitutionRepository(get()) }
single { VoteArticleRepository(get()) }
single { VoteConstitutionRepository(get()) }
single { VoteCommentRepository(get()) }
single { OpinionChoiceRepository(get()) }
single { OpinionArticleRepository(get()) }
single { WorkgroupRepository(get()) }
// Elasticsearch Client
single<RestClient> {
RestClient.builder(
HttpHost.create(Config.elasticsearch)
).build()
}
single { ArticleViewManager(get()) }
// Mailler
single { Mailer(Config.sendGridKey) }
// SSO Manager for connection
single { SsoManager(get<Mailer>(), Config.domain, get()) }
single { Publisher(get(), get()) }
single { NotificationEmailSender(get<Mailer>(), Config.domain, get(), get()) }
}

View File

@@ -1,85 +0,0 @@
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 Article(
id: UUID = UUID.randomUUID(),
title: String,
override var anonymous: Boolean = true,
override var content: String,
override var description: String,
override var tags: List<String> = emptyList(),
draft: Boolean = false,
override var lastVersion: Boolean = false,
override val createdBy: CitizenBasic
) : ArticleFull,
ArticleAuthI<CitizenBasicI>,
ArticleSimple(id, title, createdBy, draft),
Viewable by ViewableImp() {
init {
tags = tags.distinct()
}
}
open class ArticleSimple(
id: UUID = UUID.randomUUID(),
override var title: String,
override val createdBy: CitizenBasic,
override var draft: Boolean = false
) : ArticleSimpleI,
ArticleAuthI<CitizenBasicI>,
ArticleRefVersioning(id),
EntityCreatedAt by EntityCreatedAtImp(),
EntityCreatedBy<CitizenBasicI> by EntityCreatedByImp(createdBy),
EntityDeletedAt by EntityDeletedAtImp(),
Votable by VotableImp(),
Opinionable by OpinionableImp()
open class ArticleRefVersioning(
id: UUID = UUID.randomUUID(),
versionNumber: Int? = null,
versionId: UUID = UUID.randomUUID()
) : ArticleRef(id),
EntityVersioning<UUID, Int> by UuidEntityVersioning(versionNumber, versionId)
open class ArticleRef(
id: UUID = UUID.randomUUID()
) : ArticleI, TargetRef(id)
interface ArticleI : UuidEntityI, TargetI
interface ArticleSimpleI :
ArticleI,
EntityVersioning<UUID, Int>,
EntityCreatedBy<CitizenBasicI>,
EntityCreatedAt,
EntityDeletedAt,
Votable {
var title: String
}
interface ArticleBasicI :
ArticleSimpleI {
var anonymous: Boolean
var content: String
var description: String
var tags: List<String>
}
interface ArticleFull :
ArticleBasicI {
var draft: Boolean
var lastVersion: Boolean
}
interface ArticleAuthI<U : CitizenWithUserI> :
ArticleI,
EntityCreatedBy<U>,
EntityDeletedAt {
var draft: Boolean
}

View File

@@ -1,80 +0,0 @@
package fr.dcproject.entity
import fr.dcproject.entity.CitizenI.Name
import fr.postgresjson.entity.immutable.EntityCreatedAt
import fr.postgresjson.entity.immutable.EntityCreatedAtImp
import fr.postgresjson.entity.immutable.UuidEntity
import fr.postgresjson.entity.immutable.UuidEntityI
import fr.postgresjson.entity.mutable.EntityDeletedAt
import fr.postgresjson.entity.mutable.EntityDeletedAtImp
import org.joda.time.DateTime
import java.util.*
class Citizen(
id: UUID = UUID.randomUUID(),
name: Name,
email: String,
birthday: DateTime,
voteAnonymous: Boolean = true,
followAnonymous: Boolean = true,
override val user: User
) : CitizenFull,
CitizenBasic(id, name, email, birthday, voteAnonymous, followAnonymous, user),
EntityCreatedAt by EntityCreatedAtImp() {
var workgroups: List<WorkgroupSimple<CitizenRef>> = emptyList()
}
open class CitizenBasic(
id: UUID = UUID.randomUUID(),
name: Name,
override var email: String,
override var birthday: DateTime,
override var voteAnonymous: Boolean = true,
override var followAnonymous: Boolean = true,
override val user: User
) : CitizenBasicI,
CitizenSimple(id, name, user)
open class CitizenSimple(
id: UUID = UUID.randomUUID(),
var name: Name,
user: UserRef
) : CitizenRefWithUser(id, user)
open class CitizenRefWithUser(
id: UUID = UUID.randomUUID(),
override val user: UserRef
) : CitizenWithUserI,
CitizenRef(id),
EntityDeletedAt by EntityDeletedAtImp()
open class CitizenRef(
id: UUID = UUID.randomUUID()
) : UuidEntity(id),
CitizenI
interface CitizenI : UuidEntityI {
data class Name(
var firstName: String,
var lastName: String,
var civility: String? = null
) {
fun getFullName(): String = "${civility ?: ""} $firstName $lastName".trim()
}
}
interface CitizenBasicI : CitizenWithUserI, EntityDeletedAt {
var name: Name
var email: String
var birthday: DateTime
var voteAnonymous: Boolean
var followAnonymous: Boolean
}
interface CitizenFull : CitizenBasicI {
override val user: User
}
interface CitizenWithUserI : CitizenI {
val user: UserI
}

View File

@@ -1,39 +0,0 @@
package fr.dcproject.entity
import fr.postgresjson.entity.immutable.*
import fr.postgresjson.entity.mutable.EntityDeletedAt
import fr.postgresjson.entity.mutable.EntityDeletedAtImp
import java.util.*
open class Comment<T : TargetI>(
id: UUID = UUID.randomUUID(),
override val createdBy: CitizenBasic,
override var target: T,
var content: String,
val responses: List<Comment<T>>? = null,
var parent: Comment<T>? = null,
val parentsIds: List<UUID>? = null,
val childrenCount: Int? = null
) : ExtraI<T, CitizenBasicI>,
CommentRef(id),
EntityCreatedAt by EntityCreatedAtImp(),
EntityCreatedBy<CitizenBasicI> by EntityCreatedByImp(createdBy),
EntityUpdatedAt by EntityUpdatedAtImp(),
EntityDeletedAt by EntityDeletedAtImp(),
Votable by VotableImp(),
TargetI {
constructor(
createdBy: CitizenBasic,
parent: Comment<T>,
content: String
) : this(
createdBy = createdBy,
parent = parent,
target = parent.target,
content = content
)
}
open class CommentRef(id: UUID = UUID.randomUUID()) : CommentS(id)
sealed class CommentS(id: UUID) : TargetRef(id)

View File

@@ -1,69 +0,0 @@
package fr.dcproject.entity
import fr.postgresjson.entity.immutable.*
import fr.postgresjson.entity.mutable.EntityDeletedAt
import fr.postgresjson.entity.mutable.EntityDeletedAtImp
import java.util.*
class Constitution(
id: UUID = UUID.randomUUID(),
title: String,
anonymous: Boolean = true,
titles: MutableList<TitleSimple<ArticleSimple>> = mutableListOf(),
draft: Boolean = false,
lastVersion: Boolean = false,
override val createdBy: CitizenSimple
) : ConstitutionSimple<CitizenSimple, ConstitutionSimple.TitleSimple<ArticleSimple>>(
id,
title = title,
anonymous = anonymous,
titles = titles,
draft = draft,
lastVersion = lastVersion,
createdBy = createdBy
) {
class Title(
id: UUID = UUID.randomUUID(),
name: String,
rank: Int? = null,
override val articles: MutableList<ArticleSimple> = mutableListOf()
) : ConstitutionSimple.TitleSimple<ArticleSimple>(id, name, rank)
}
open class ConstitutionSimple<Cr : CitizenRefWithUser, T : ConstitutionSimple.TitleSimple<*>>(
id: UUID = UUID.randomUUID(),
var title: String,
var anonymous: Boolean = true,
open var titles: MutableList<T> = mutableListOf(),
var draft: Boolean = false,
var lastVersion: Boolean = false,
override val createdBy: Cr,
versionId: UUID = UUID.randomUUID()
) : ConstitutionRef(id),
EntityVersioning<UUID, Int?> by UuidEntityVersioning(versionId = versionId),
EntityCreatedAt by EntityCreatedAtImp(),
EntityCreatedBy<Cr> by EntityCreatedByImp(createdBy),
EntityDeletedAt by EntityDeletedAtImp() {
init {
titles.forEachIndexed { index, title ->
title.rank = index
}
}
open class TitleSimple<A : ArticleI>(
id: UUID = UUID.randomUUID(),
var name: String,
var rank: Int? = null,
open val articles: MutableList<A> = mutableListOf()
) : TitleRef(id)
}
open class ConstitutionRef(id: UUID = UUID.randomUUID()) : ConstitutionS(id) {
open class TitleRef(
id: UUID = UUID.randomUUID()
) : UuidEntity(id)
}
sealed class ConstitutionS(id: UUID = UUID.randomUUID()) : TargetRef(id), TargetI

View File

@@ -1,20 +0,0 @@
package fr.dcproject.entity
import fr.postgresjson.entity.immutable.*
import java.util.*
class Follow<T : TargetI>(
id: UUID = UUID.randomUUID(),
override val createdBy: CitizenBasic,
override var target: T
) : ExtraI<T, CitizenBasicI>,
FollowSimple<T, CitizenBasicI>(id, createdBy, target)
open class FollowSimple<T : TargetI, C : CitizenI>(
id: UUID = UUID.randomUUID(),
override val createdBy: C,
override var target: T
) : ExtraI<T, C>,
UuidEntity(id),
EntityCreatedAt by EntityCreatedAtImp(),
EntityCreatedBy<C> by EntityCreatedByImp(createdBy)

View File

@@ -1,27 +0,0 @@
package fr.dcproject.entity
import fr.postgresjson.entity.immutable.EntityCreatedAt
import fr.postgresjson.entity.immutable.EntityCreatedAtImp
import fr.postgresjson.entity.immutable.EntityCreatedBy
import fr.postgresjson.entity.immutable.EntityCreatedByImp
import java.util.*
open class Opinion<T : TargetI>(
id: UUID = UUID.randomUUID(),
override val createdBy: CitizenBasic,
override val target: T,
val choice: OpinionChoice
) : ExtraI<T, CitizenBasicI>,
TargetRef(id),
EntityCreatedAt by EntityCreatedAtImp(),
EntityCreatedBy<CitizenBasicI> by EntityCreatedByImp(createdBy) {
fun getName(): String = choice.name
}
class OpinionArticle(
id: UUID = UUID.randomUUID(),
createdBy: CitizenBasic,
target: ArticleRef,
choice: OpinionChoice
) : Opinion<ArticleRef>(id, createdBy, target, choice)

View File

@@ -1,20 +0,0 @@
package fr.dcproject.entity
import fr.postgresjson.entity.immutable.EntityCreatedAt
import fr.postgresjson.entity.immutable.EntityCreatedAtImp
import fr.postgresjson.entity.immutable.UuidEntity
import fr.postgresjson.entity.mutable.EntityDeletedAt
import fr.postgresjson.entity.mutable.EntityDeletedAtImp
import java.util.*
class OpinionChoice(
id: UUID? = null,
val name: String,
val target: List<String>?
) : OpinionChoiceRef(id),
EntityCreatedAt by EntityCreatedAtImp(),
EntityDeletedAt by EntityDeletedAtImp()
open class OpinionChoiceRef(
id: UUID?
) : UuidEntity(id ?: UUID.randomUUID())

View File

@@ -1,15 +0,0 @@
package fr.dcproject.entity
import fr.postgresjson.entity.EntityI
class OpinionAggregation(
private val underlying: MutableMap<String, Any> = mutableMapOf()
) : MutableMap<String, Any> by underlying, EntityI
interface Opinionable {
var opinions: MutableMap<String, Int>
}
class OpinionableImp : Opinionable {
override var opinions: MutableMap<String, Int> = mutableMapOf()
}

View File

@@ -1,41 +0,0 @@
package fr.dcproject.entity
import fr.dcproject.entity.UserI.Roles
import fr.postgresjson.entity.immutable.*
import io.ktor.auth.Principal
import org.joda.time.DateTime
import java.util.*
class User(
id: UUID = UUID.randomUUID(),
username: String,
blockedAt: DateTime? = null,
override var plainPassword: String? = null,
override var roles: List<Roles> = emptyList()
) : UserFull, UserBasic(id, username, blockedAt),
EntityCreatedAt by EntityCreatedAtImp(),
EntityUpdatedAt by EntityUpdatedAtImp()
open class UserBasic(
id: UUID = UUID.randomUUID(),
override var username: String,
override var blockedAt: DateTime? = null
) : UserBasicI, UserRef(id)
open class UserRef(
id: UUID = UUID.randomUUID()
) : UserI, UuidEntity(id)
interface UserI : UuidEntityI, Principal {
enum class Roles { ROLE_USER, ROLE_ADMIN }
}
interface UserBasicI : UserI {
var username: String
var blockedAt: DateTime?
}
interface UserFull : UserBasicI, EntityCreatedAt, EntityUpdatedAt {
var plainPassword: String?
var roles: List<Roles>
}

View File

@@ -1,13 +0,0 @@
package fr.dcproject.entity
import fr.postgresjson.entity.EntityI
import fr.postgresjson.entity.immutable.EntityUpdatedAt
import fr.postgresjson.entity.immutable.EntityUpdatedAtImp
open class ViewAggregation(
val total: Int,
val unique: Int
) : EntityI,
EntityUpdatedAt by EntityUpdatedAtImp() {
constructor() : this(0, 0)
}

View File

@@ -1,9 +0,0 @@
package fr.dcproject.entity
interface Viewable {
var views: ViewAggregation
}
class ViewableImp : Viewable {
override var views: ViewAggregation = ViewAggregation()
}

View File

@@ -1,9 +0,0 @@
package fr.dcproject.entity
interface Votable {
var votes: VoteAggregation
}
class VotableImp : Votable {
override var votes: VoteAggregation = VoteAggregation()
}

View File

@@ -1,22 +0,0 @@
package fr.dcproject.entity
import fr.postgresjson.entity.immutable.*
import java.util.*
open class Vote<T : TargetI>(
id: UUID = UUID.randomUUID(),
override val createdBy: CitizenBasic,
override var target: T,
var note: Int,
var anonymous: Boolean = true
) : ExtraI<T, CitizenBasicI>,
UuidEntity(id),
EntityCreatedAt by EntityCreatedAtImp(),
EntityCreatedBy<CitizenBasicI> by EntityCreatedByImp(createdBy),
EntityUpdatedAt by EntityUpdatedAtImp() {
init {
if (note > 1 && note < -1) {
error("note must be 1, 0 or -1")
}
}
}

View File

@@ -1,16 +0,0 @@
package fr.dcproject.entity
import fr.postgresjson.entity.EntityI
import fr.postgresjson.entity.mutable.EntityUpdatedAt
import fr.postgresjson.entity.mutable.EntityUpdatedAtImp
open class VoteAggregation(
val up: Int,
val neutral: Int,
val down: Int,
val total: Int,
val score: Int
) : EntityI,
EntityUpdatedAt by EntityUpdatedAtImp() {
constructor() : this(0, 0, 0, 0, 0)
}

View File

@@ -1,63 +0,0 @@
package fr.dcproject.entity
import fr.postgresjson.entity.immutable.*
import fr.postgresjson.entity.mutable.EntityDeletedAt
import fr.postgresjson.entity.mutable.EntityDeletedAtImp
import java.util.*
class Workgroup(
id: UUID? = null,
name: String,
description: String,
logo: String? = null,
anonymous: Boolean = true,
owner: CitizenBasic,
createdBy: CitizenBasic,
override var members: List<CitizenBasic> = emptyList()
) : WorkgroupWithAuthI<CitizenBasic>,
WorkgroupSimple<CitizenBasic>(
id,
name,
description,
logo,
anonymous,
owner,
createdBy
),
EntityCreatedAt by EntityCreatedAtImp(),
EntityUpdatedAt by EntityUpdatedAtImp()
open class WorkgroupSimple<Z : CitizenRef>(
id: UUID? = null,
var name: String,
var description: String,
var logo: String? = null,
var anonymous: Boolean = true,
var owner: Z,
createdBy: Z
) : WorkgroupRef(id),
EntityCreatedBy<Z> by EntityCreatedByImp(createdBy),
EntityDeletedAt by EntityDeletedAtImp()
open class WorkgroupRef(
id: UUID? = null
) : UuidEntity(id ?: UUID.randomUUID()), WorkgroupI
interface WorkgroupWithAuthI<Z : CitizenWithUserI> : WorkgroupWithMembersI<Z>, EntityCreatedBy<Z>, EntityDeletedAt {
val anonymous: Boolean
val owner: Z
fun isMember(user: UserI): Boolean =
members.map { it.user.id }.contains(user.id) || owner.user.id == user.id
fun isMember(citizen: CitizenWithUserI): Boolean =
isMember(citizen.user)
}
interface WorkgroupWithMembersI<Z : CitizenI> : WorkgroupI {
var members: List<Z>
}
fun List<CitizenI>.asCitizen(citizen: CitizenI): Boolean = this.map { it.id }.contains(citizen.id)
interface WorkgroupI : UuidEntityI

View File

@@ -1,133 +0,0 @@
package fr.dcproject.event
import com.rabbitmq.client.*
import com.rabbitmq.client.BuiltinExchangeType.DIRECT
import fr.dcproject.Config
import fr.dcproject.entity.Article
import fr.dcproject.entity.CitizenRef
import fr.dcproject.entity.FollowSimple
import fr.dcproject.entity.TargetRef
import fr.dcproject.event.publisher.Publisher
import fr.dcproject.messages.NotificationEmailSender
import fr.dcproject.repository.Follow
import fr.postgresjson.serializer.deserialize
import io.ktor.application.ApplicationCall
import io.ktor.application.EventDefinition
import io.ktor.application.application
import io.ktor.util.pipeline.PipelineContext
import io.lettuce.core.api.async.RedisAsyncCommands
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.io.errors.IOException
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import fr.dcproject.repository.FollowArticle as FollowArticleRepository
class ArticleUpdate(
target: Article
) : EntityEvent(target, "article", "update") {
companion object {
val event = EventDefinition<ArticleUpdate>()
}
}
fun <T : Event> PipelineContext<Unit, ApplicationCall>.raiseEvent(definition: EventDefinition<T>, value: T) =
application.environment.monitor.raise(definition, value)
class EventNotification(
private val config: EventSubscriber.Configuration,
private val rabbitFactory: ConnectionFactory,
private val redis: RedisAsyncCommands<String, String>,
private val followRepo: FollowArticleRepository,
private val publisher: Publisher,
private val notificationEmailSender: NotificationEmailSender
) {
private val logger: Logger = LoggerFactory.getLogger(Publisher::class.qualifiedName)
fun config() {
/* Config Rabbit */
val exchangeName = Config.exchangeNotificationName
rabbitFactory.newConnection().use { connection ->
connection.createChannel().use { channel ->
channel.queueDeclare("push", true, false, false, null)
channel.queueDeclare("email", true, false, false, null)
channel.exchangeDeclare(exchangeName, DIRECT, true)
channel.queueBind("push", exchangeName, "")
channel.queueBind("email", exchangeName, "")
}
}
/* Declare publisher on event */
config.subscribe(ArticleUpdate.event) {
publisher.publish(it)
}
/* Launch Consumer */
GlobalScope.launch {
val rabbitChannel = rabbitFactory.newConnection().createChannel()
val consumerPush: Consumer = object : DefaultConsumer(rabbitChannel) {
@Throws(IOException::class)
override fun handleDelivery(
consumerTag: String,
envelope: Envelope,
properties: AMQP.BasicProperties,
body: ByteArray
) = runBlocking {
decodeEvent(body) {
redis.zadd(
"notification:${follow.createdBy.id}",
event.id,
rawEvent
)
}
rabbitChannel.basicAck(envelope.deliveryTag, false)
}
}
val consumerEmail: Consumer = object : DefaultConsumer(rabbitChannel) {
@Throws(IOException::class)
override fun handleDelivery(
consumerTag: String,
envelope: Envelope,
properties: AMQP.BasicProperties,
body: ByteArray
) {
runBlocking {
decodeEvent(body) {
logger.debug("EmailSend to: ${follow.createdBy.id}")
notificationEmailSender.sendEmail(follow)
}
}
rabbitChannel.basicAck(envelope.deliveryTag, false)
}
}
rabbitChannel.basicConsume("push", false, consumerPush) // The front consume the redis via Websocket
rabbitChannel.basicConsume("email", false, consumerEmail)
}
}
private suspend fun decodeEvent(body: ByteArray, action: suspend Msg.() -> Unit) {
val rawEvent = body.toString(Charsets.UTF_8)
val event = rawEvent.deserialize<EntityEvent>() ?: error("Unable to unserialise event message from rabbit")
val repo = when (event.type) {
"article" -> followRepo
else -> error("event '${event.type}' not implemented")
} as Follow<*, *>
repo
.findFollowsByTarget(event.target)
.collect {
Msg(event, rawEvent, it).action()
}
}
private class Msg(
val event: EntityEvent,
val rawEvent: String,
val follow: FollowSimple<out TargetRef, CitizenRef>
)
}

View File

@@ -1,54 +0,0 @@
package fr.dcproject.event
import fr.postgresjson.entity.Serializable
import fr.postgresjson.entity.immutable.UuidEntity
import io.ktor.application.*
import io.ktor.util.AttributeKey
import io.ktor.util.KtorExperimentalAPI
import kotlinx.coroutines.DisposableHandle
import org.joda.time.DateTime
import kotlin.random.Random.Default.nextInt
open class Event(
val type: String,
val createdAt: DateTime = DateTime.now()
) : Serializable {
val id: Double = randId(createdAt.millis)
private fun randId(time: Long): Double {
return (time.toString() + nextInt(1000, 9999).toString()).toDouble()
}
}
open class EntityEvent(
val target: UuidEntity,
type: String,
val action: String
) : Event(type)
/**
* Installation Class
*/
class EventSubscriber {
class Configuration(private val monitor: ApplicationEvents) {
private val subscribers = mutableListOf<DisposableHandle>()
fun <T : Event> subscribe(definition: EventDefinition<T>, handler: EventHandler<T>): DisposableHandle {
return monitor.subscribe(definition, handler).also {
subscribers.add(it)
}
}
}
companion object Feature : ApplicationFeature<Application, Configuration, EventSubscriber> {
override val key = AttributeKey<EventSubscriber>("EventSubscriber")
@KtorExperimentalAPI
override fun install(
pipeline: Application,
configure: Configuration.() -> Unit
): EventSubscriber {
Configuration(pipeline.environment.monitor).apply(configure)
return EventSubscriber()
}
}
}

View File

@@ -1,32 +0,0 @@
package fr.dcproject.event.publisher
import com.fasterxml.jackson.databind.ObjectMapper
import com.rabbitmq.client.ConnectionFactory
import fr.dcproject.Config
import fr.dcproject.event.EntityEvent
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.slf4j.Logger
import org.slf4j.LoggerFactory
class Publisher(
private val mapper: ObjectMapper,
private val factory: ConnectionFactory,
private val logger: Logger = LoggerFactory.getLogger(Publisher::class.qualifiedName)
) {
fun <T : EntityEvent> publish(it: T): Job {
return GlobalScope.launch {
factory.newConnection().use { connection ->
connection.createChannel().use { channel ->
channel.basicPublish(Config.exchangeNotificationName, "", null, it.serialize().toByteArray())
logger.debug("Publish message ${it.target.id}")
}
}
}
}
private fun EntityEvent.serialize(): String {
return mapper.writeValueAsString(this) ?: error("Unable tu serialize message")
}
}

View File

@@ -0,0 +1,190 @@
package fr.dcproject.application
import com.fasterxml.jackson.core.util.DefaultIndenter
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.PropertyNamingStrategies
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.datatype.joda.JodaModule
import fr.dcproject.application.Env.PROD
import fr.dcproject.application.Env.TEST
import fr.dcproject.application.http.statusPagesInstallation
import fr.dcproject.common.utils.onApplicationStopped
import fr.dcproject.component.article.articleKoinModule
import fr.dcproject.component.article.routes.installArticleRoutes
import fr.dcproject.component.auth.authKoinModule
import fr.dcproject.component.auth.jwt.jwtInstallation
import fr.dcproject.component.auth.routes.installAuthRoutes
import fr.dcproject.component.citizen.citizenKoinModule
import fr.dcproject.component.citizen.routes.installCitizenRoutes
import fr.dcproject.component.comment.article.routes.installCommentArticleRoutes
import fr.dcproject.component.comment.commentKoinModule
import fr.dcproject.component.comment.constitution.routes.installCommentConstitutionRoutes
import fr.dcproject.component.comment.generic.routes.installCommentRoutes
import fr.dcproject.component.constitution.constitutionKoinModule
import fr.dcproject.component.constitution.routes.installConstitutionRoutes
import fr.dcproject.component.doc.routes.installDocRoutes
import fr.dcproject.component.follow.followKoinModule
import fr.dcproject.component.follow.routes.article.installFollowArticleRoutes
import fr.dcproject.component.follow.routes.citizen.installFollowCitizenRoutes
import fr.dcproject.component.follow.routes.constitution.installFollowConstitutionRoutes
import fr.dcproject.component.notification.email.NotificationEmailConsumer
import fr.dcproject.component.notification.push.NotificationPushConsumer
import fr.dcproject.component.notification.routes.installNotificationsRoutes
import fr.dcproject.component.opinion.opinionKoinModule
import fr.dcproject.component.opinion.routes.installOpinionRoutes
import fr.dcproject.component.views.viewKoinModule
import fr.dcproject.component.vote.routes.installVoteRoutes
import fr.dcproject.component.vote.voteKoinModule
import fr.dcproject.component.workgroup.routes.installWorkgroupRoutes
import fr.dcproject.component.workgroup.workgroupKoinModule
import fr.postgresjson.migration.Migrations
import io.ktor.application.Application
import io.ktor.application.install
import io.ktor.auth.Authentication
import io.ktor.client.HttpClient
import io.ktor.client.engine.jetty.Jetty
import io.ktor.features.AutoHeadResponse
import io.ktor.features.CORS
import io.ktor.features.CallLogging
import io.ktor.features.ContentNegotiation
import io.ktor.features.DataConversion
import io.ktor.features.StatusPages
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpMethod
import io.ktor.http.cio.websocket.pingPeriod
import io.ktor.http.cio.websocket.timeout
import io.ktor.jackson.jackson
import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Locations
import io.ktor.routing.Routing
import io.ktor.server.jetty.EngineMain
import io.ktor.websocket.WebSockets
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.eclipse.jetty.util.log.Slf4jLog
import org.koin.dsl.module
import org.koin.ktor.ext.Koin
import org.koin.ktor.ext.get
import org.slf4j.event.Level
import java.time.Duration
fun main(args: Array<String>): Unit = EngineMain.main(args)
enum class Env { PROD, TEST }
@ExperimentalCoroutinesApi
@KtorExperimentalLocationsAPI
@Suppress("unused") // Referenced in application.conf
fun Application.module(env: Env = PROD) {
install(Koin) {
Slf4jLog()
modules(
listOf(
if (env == TEST) module { single { Configuration("application-test.conf") } }
else module { single { Configuration() } },
KoinModule,
articleKoinModule,
authKoinModule,
citizenKoinModule,
commentKoinModule,
constitutionKoinModule,
followKoinModule,
opinionKoinModule,
viewKoinModule,
voteKoinModule,
workgroupKoinModule,
)
)
}
install(CallLogging) {
level = Level.INFO
}
install(DataConversion, converters)
install(Locations)
HttpClient(Jetty) {
engine {
}
}
install(WebSockets) {
pingPeriod = Duration.ofSeconds(60) // Disabled (null) by default
timeout = Duration.ofSeconds(15)
maxFrameSize = Long.MAX_VALUE // Disabled (max value). The connection will be closed if surpassed this length.
masking = false
}
get<NotificationEmailConsumer>().run {
start()
onApplicationStopped { close() }
}
get<NotificationPushConsumer>().run {
start()
onApplicationStopped { close() }
}
install(Authentication, jwtInstallation(get(), get()))
install(AutoHeadResponse)
install(ContentNegotiation) {
jackson {
propertyNamingStrategy = PropertyNamingStrategies.LOWER_CAMEL_CASE
registerModule(JodaModule())
disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true)
configure(SerializationFeature.INDENT_OUTPUT, true)
setDefaultPrettyPrinter(
DefaultPrettyPrinter().apply {
indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance)
indentObjectsWith(DefaultIndenter(" ", "\n"))
}
)
}
}
install(Routing.Feature) {
// trace { application.log.trace(it.buildText()) }
installArticleRoutes()
installAuthRoutes()
installCitizenRoutes()
installCommentArticleRoutes()
installCommentRoutes()
installFollowArticleRoutes()
installFollowConstitutionRoutes()
installFollowCitizenRoutes()
installWorkgroupRoutes()
installOpinionRoutes()
installVoteRoutes()
installConstitutionRoutes()
installCommentConstitutionRoutes()
installNotificationsRoutes()
installDocRoutes()
}
install(StatusPages, statusPagesInstallation())
install(CORS) {
method(HttpMethod.Options)
method(HttpMethod.Put)
method(HttpMethod.Delete)
header(HttpHeaders.Authorization)
if (env == PROD) {
host("localhost:4200", schemes = listOf("http", "https"))
} else {
anyHost()
}
allowCredentials = true
allowSameOrigin = true
maxAgeInSeconds = Duration.ofDays(1).seconds
}
if (env == PROD) {
get<Migrations>().run()
}
}

View File

@@ -0,0 +1,57 @@
package fr.dcproject.application
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import java.net.URI
class Configuration(val config: Config) {
constructor(resourceBasename: String? = null) : this(if (resourceBasename == null) ConfigFactory.load() else ConfigFactory.load(resourceBasename))
interface Sql {
val migrationFiles: URI
val functionFiles: URI
val fixtureFiles: URI
}
val sql
get() = object : Sql {
override val migrationFiles: URI = this::class.java.getResource("/sql/migrations")?.toURI() ?: error("No migrations found")
override val functionFiles: URI = this::class.java.getResource("/sql/functions")?.toURI() ?: error("No sql function found")
override val fixtureFiles: URI = this::class.java.getResource("/sql/fixtures")?.toURI() ?: error("No sql fixture found")
}
interface Database {
val host: String
val port: Int
var database: String
var username: String
var password: String
}
val database
get() = object : Database {
override val host: String = config.getString("db.host")
override val port: Int = config.getInt("db.port")
override var database: String = config.getString("db.database")
override var username: String = config.getString("db.username")
override var password: String = config.getString("db.password")
}
val envName: String = config.getString("app.envName")
val domain: String = config.getString("app.domain")
val redis: String = config.getString("redis.connection")
val elasticsearch: String = config.getString("elasticsearch.connection")
val rabbitmq: String = config.getString("rabbitmq.connection")
val exchangeNotificationName = "notification"
val sendGridKey: String = config.getString("mail.sendGrid.key")
interface Jwt {
val secret: String
val issuer: String
val validityInMs: Int
}
val jwt = object : Jwt {
override val secret = config.getString("jwt.secret")
override val issuer = config.getString("jwt.issuer")
override val validityInMs = config.getInt("jwt.validity")
}
}

View File

@@ -0,0 +1,40 @@
package fr.dcproject.application
import fr.dcproject.application.http.BadRequestException
import fr.dcproject.application.http.HttpErrorBadRequest
import fr.dcproject.application.http.HttpErrorBadRequest.InvalidParam
import io.ktor.features.DataConversion
import io.ktor.http.HttpStatusCode
import java.util.UUID
private typealias ConverterDeclaration = DataConversion.Configuration.() -> Unit
val converters: ConverterDeclaration = {
convert<UUID> {
decode { values, _ ->
try {
values.singleOrNull()?.let { UUID.fromString(it) }
} catch (e: Throwable) {
throw BadRequestException(
HttpErrorBadRequest(
HttpStatusCode.BadRequest,
invalidParams = listOf(
InvalidParam(
"ID",
"must be UUID"
)
)
)
)
}
}
encode { value ->
when (value) {
null -> listOf()
is UUID -> listOf(value.toString())
else -> throw InternalError("Cannot convert $value as UUID")
}
}
}
}

View File

@@ -0,0 +1,127 @@
package fr.dcproject.application
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.PropertyNamingStrategies
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.datatype.joda.JodaModule
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.rabbitmq.client.ConnectionFactory
import fr.dcproject.common.email.Mailer
import fr.dcproject.component.auth.jwt.JwtConfig
import fr.dcproject.component.notification.NotificationPublisherAsync
import fr.dcproject.component.notification.email.NotificationEmailConsumer
import fr.dcproject.component.notification.email.NotificationEmailSender
import fr.dcproject.component.notification.push.NotificationPushConsumer
import fr.dcproject.component.notification.push.NotificationPushListener
import fr.postgresjson.connexion.Connection
import fr.postgresjson.connexion.Requester
import fr.postgresjson.migration.Migrations
import io.ktor.client.HttpClient
import io.ktor.client.features.websocket.WebSockets
import io.lettuce.core.RedisClient
import org.koin.core.qualifier.named
import org.koin.dsl.module
val KoinModule = module {
// JWT
single {
val config: Configuration = get()
JwtConfig(
config.jwt.secret,
config.jwt.issuer,
config.jwt.validityInMs,
)
}
// JWT Verifier
single {
get<JwtConfig>().verifier
}
// SQL connection
single {
val config: Configuration = get()
Connection(
host = config.database.host,
port = config.database.port,
database = config.database.database,
username = config.database.username,
password = config.database.password
)
}
// Launch Database migration
single {
val config: Configuration = get()
Migrations(get(), config.sql.migrationFiles, config.sql.functionFiles)
}
// Redis client
single<RedisClient> {
val config: Configuration = get()
RedisClient.create(config.redis).apply {
connect().sync().configSet("notify-keyspace-events", "KEA")
}
}
single { NotificationPushListener.Builder(get()) }
single {
val config: Configuration = get()
NotificationEmailConsumer(get(), get(), get(), get(), get(), config.exchangeNotificationName)
}
single {
val config: Configuration = get()
NotificationPushConsumer(get(), get(), get(), get(), get(), config.exchangeNotificationName)
}
// RabbitMQ
single<ConnectionFactory> {
val config: Configuration = get()
ConnectionFactory().apply { setUri(config.rabbitmq) }
}
// JsonSerializer
single<ObjectMapper> {
jacksonObjectMapper().apply {
registerModule(SimpleModule())
propertyNamingStrategy = PropertyNamingStrategies.LOWER_CAMEL_CASE
registerModule(JodaModule())
disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true)
}
}
// Client HTTP for WebSockets
single(named("ws")) {
HttpClient {
install(WebSockets)
}
}
// SQL Requester (postgresJson)
single {
val config: Configuration = get()
Requester.RequesterFactory(
connection = get(),
functionsDirectory = config.sql.functionFiles
).createRequester()
}
// Mailer
single {
val config: Configuration = get()
Mailer(config.sendGridKey)
}
single {
val config: Configuration = get()
NotificationPublisherAsync(factory = get(), exchangeName = config.exchangeNotificationName)
}
single {
val config: Configuration = get()
NotificationEmailSender(get<Mailer>(), config.domain, get(), get())
}
}

View File

@@ -0,0 +1,35 @@
package fr.dcproject.application.http
import fr.dcproject.application.http.HttpErrorBadRequest.InvalidParam
import io.konform.validation.ValidationResult
import io.ktor.http.HttpStatusCode
class BadRequestException(val httpError: HttpErrorBadRequest) : Exception()
class HttpErrorBadRequest(
statusCode: HttpStatusCode,
val title: String = statusCode.description,
val invalidParams: List<InvalidParam>,
) {
val statusCode: Int = statusCode.value
data class InvalidParam(
val name: String,
val reason: String
)
}
fun ValidationResult<*>.toOutput() = HttpErrorBadRequest(
HttpStatusCode.BadRequest,
invalidParams = this.errors.map {
InvalidParam(
it.dataPath,
it.message
)
}
)
fun ValidationResult<*>.badRequestIfNotValid() {
if (errors.size > 0) {
throw BadRequestException(toOutput())
}
}

View File

@@ -0,0 +1,86 @@
package fr.dcproject.application.http
import com.github.jasync.sql.db.postgresql.exceptions.GenericDatabaseException
import fr.dcproject.common.security.AccessDeniedException
import fr.dcproject.component.auth.ForbiddenException
import fr.dcproject.component.auth.user
import io.ktor.application.call
import io.ktor.features.NotFoundException
import io.ktor.features.ParameterConversionException
import io.ktor.features.StatusPages
import io.ktor.http.HttpStatusCode
import io.ktor.response.respond
import java.util.concurrent.CompletionException
class HttpError(
statusCode: HttpStatusCode,
cause: Throwable? = null,
val title: String = cause?.message ?: statusCode.description,
) {
val statusCode: Int = statusCode.value
}
fun statusPagesInstallation(): StatusPages.Configuration.() -> Unit = {
exception<CompletionException> { e ->
val parent = e.cause?.cause
if (parent is GenericDatabaseException) {
HttpError(
HttpStatusCode.BadRequest,
cause = parent
).let {
call.respond(HttpStatusCode.BadRequest, it)
}
} else {
HttpError(
HttpStatusCode.BadRequest,
cause = e
).let {
call.respond(HttpStatusCode.InternalServerError, it)
}
}
}
exception<NotFoundException> { e ->
HttpError(
HttpStatusCode.NotFound,
cause = e
).let {
call.respond(HttpStatusCode.NotFound, it)
}
}
exception<AccessDeniedException> { e ->
if (call.user == null) {
HttpError(
HttpStatusCode.Unauthorized,
cause = e
).let {
call.respond(HttpStatusCode.Unauthorized, it)
}
} else {
HttpError(
HttpStatusCode.Forbidden,
cause = e
).let {
call.respond(HttpStatusCode.Forbidden, it)
}
}
}
exception<ForbiddenException> { e ->
HttpError(
HttpStatusCode.Forbidden,
cause = e
).let {
call.respond(HttpStatusCode.Forbidden, it)
}
}
exception<BadRequestException> { e ->
call.respond(HttpStatusCode.BadRequest, e.httpError)
}
exception<ParameterConversionException> { e ->
val parent = e.cause
if (parent is BadRequestException) {
call.respond(HttpStatusCode.BadRequest, parent.httpError)
} else {
throw e
}
}
}

View File

@@ -0,0 +1,11 @@
package fr.dcproject.common
interface BitMaskI {
val bit: Long
infix operator fun contains(which: BitMaskI): Boolean = bit and which.bit == which.bit
infix operator fun plus(mask: BitMaskI): BitMaskI = BitMask(mask.bit and this.bit)
infix operator fun minus(mask: BitMaskI): BitMaskI = BitMask(this.bit - mask.bit)
}
class BitMask(override val bit: Long) : BitMaskI

View File

@@ -1,4 +1,4 @@
package fr.dcproject.messages
package fr.dcproject.common.email
import com.sendgrid.Method
import com.sendgrid.Request
@@ -9,6 +9,9 @@ import java.io.IOException
class Mailer(
private val key: String
) {
/**
* Send email via Sendgrid
*/
fun sendEmail(action: () -> Mail): Boolean {
val mail = action()

View File

@@ -0,0 +1,28 @@
package fr.dcproject.common.entity
import fr.dcproject.component.citizen.database.CitizenI
interface Created<C : CitizenI> : CreatedAt, CreatedBy<C> {
class Imp<C : CitizenI>(createdBy: C) :
Created<C>,
CreatedBy<C> by CreatedBy.Imp(createdBy),
CreatedAt by CreatedAt.Imp()
}
interface Updated<C : CitizenI> : UpdatedAt, UpdatedBy<C> {
class Imp<C : CitizenI>(updatedAt: C) :
Updated<C>,
UpdatedBy<C> by UpdatedBy.Imp(updatedAt),
UpdatedAt by UpdatedAt.Imp()
}
interface Deleted<C : CitizenI> : DeletedAt, DeletedBy<C> {
override fun isDeleted(): Boolean = (this as DeletedAt).isDeleted()
class Imp<C : CitizenI>(deletedAt: C) :
Deleted<C>,
DeletedBy<C> by DeletedBy.Imp(deletedAt),
DeletedAt by DeletedAt.Imp() {
override fun isDeleted(): Boolean = (this as Deleted<C>).isDeleted()
}
}

View File

@@ -0,0 +1,25 @@
package fr.dcproject.common.entity
import fr.dcproject.component.citizen.database.CitizenI
interface CreatedBy<T : CitizenI> {
val createdBy: T
class Imp<T : CitizenI>(override val createdBy: T) : CreatedBy<T>
}
interface UpdatedBy<T : CitizenI> {
val updatedBy: T
class Imp<T : CitizenI>(override val updatedBy: T) : UpdatedBy<T>
}
interface DeletedBy<T : CitizenI> {
val deletedBy: T?
fun isDeleted(): Boolean {
return deletedBy?.let { true } ?: false
}
class Imp<T : CitizenI>(override val deletedBy: T?) : DeletedBy<T>
}

View File

@@ -0,0 +1,30 @@
package fr.dcproject.common.entity
import org.joda.time.DateTime
/* Interface */
interface CreatedAt {
val createdAt: DateTime
class Imp(
override val createdAt: DateTime = DateTime.now()
) : CreatedAt
}
interface UpdatedAt {
val updatedAt: DateTime
class Imp(
override val updatedAt: DateTime = DateTime.now()
) : UpdatedAt
}
interface DeletedAt {
val deletedAt: DateTime?
fun isDeleted(): Boolean {
return deletedAt?.let {
it < DateTime.now()
} ?: false
}
class Imp(
override val deletedAt: DateTime? = null
) : DeletedAt
}

Some files were not shown because too many files have changed in this diff Show More