Big refactoring #77
3
.env
3
.env
@@ -1,10 +1,11 @@
|
|||||||
NAME=dc-project
|
APP_NAME=dc-project
|
||||||
|
|
||||||
DATABASE_URL=jdbc:postgresql:dc-project
|
DATABASE_URL=jdbc:postgresql:dc-project
|
||||||
|
|
||||||
APP_PORT=8080
|
APP_PORT=8080
|
||||||
OPENAPI_PORT=8181
|
OPENAPI_PORT=8181
|
||||||
SONARQUBE_PORT=9002
|
SONARQUBE_PORT=9002
|
||||||
|
SONARQUBE_DB_PORT=5434
|
||||||
|
|
||||||
ELASTIC_REST=9200
|
ELASTIC_REST=9200
|
||||||
ELASTIC_NODES=9300
|
ELASTIC_NODES=9300
|
||||||
|
|||||||
87
.idea/codeStyles/Project.xml
generated
87
.idea/codeStyles/Project.xml
generated
@@ -1,34 +1,79 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
<option name="LINE_SEPARATOR" value=" " />
|
|
||||||
<JetCodeStyleSettings>
|
<JetCodeStyleSettings>
|
||||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||||
<value>
|
<value />
|
||||||
<package name="java.util" alias="false" withSubpackages="false" />
|
|
||||||
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
|
||||||
<package name="io.ktor" alias="false" withSubpackages="true" />
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
<option name="PACKAGES_IMPORT_LAYOUT">
|
|
||||||
<value>
|
|
||||||
<package name="" alias="false" withSubpackages="true" />
|
|
||||||
<package name="java" alias="false" withSubpackages="true" />
|
|
||||||
<package name="javax" alias="false" withSubpackages="true" />
|
|
||||||
<package name="kotlin" alias="false" withSubpackages="true" />
|
|
||||||
<package name="" alias="true" withSubpackages="true" />
|
|
||||||
</value>
|
|
||||||
</option>
|
</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" />
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
</JetCodeStyleSettings>
|
</JetCodeStyleSettings>
|
||||||
<PostgresCodeStyleSettings version="2">
|
<SqlCodeStyleSettings version="5">
|
||||||
<option name="myVersion" value="2" />
|
|
||||||
<option name="KEYWORD_CASE" value="1" />
|
<option name="KEYWORD_CASE" value="1" />
|
||||||
<option name="IDENTIFIER_CASE" value="1" />
|
<option name="IDENTIFIER_CASE" value="1" />
|
||||||
<option name="TYPE_CASE" value="1" />
|
<option name="TYPE_CASE" value="4" />
|
||||||
<option name="ALIAS_CASE" value="1" />
|
<option name="ALIAS_CASE" value="4" />
|
||||||
</PostgresCodeStyleSettings>
|
<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">
|
<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" />
|
||||||
|
<option name="CALL_PARAMETERS_WRAP" value="5" />
|
||||||
|
<option name="CALL_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
|
||||||
|
<option name="CALL_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
|
||||||
|
<option name="METHOD_PARAMETERS_WRAP" value="5" />
|
||||||
|
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
|
||||||
|
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
|
||||||
|
<option name="EXTENDS_LIST_WRAP" value="1" />
|
||||||
|
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
|
||||||
|
<option name="ASSIGNMENT_WRAP" value="1" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
</indentOptions>
|
||||||
</codeStyleSettings>
|
</codeStyleSettings>
|
||||||
</code_scheme>
|
</code_scheme>
|
||||||
</component>
|
</component>
|
||||||
9
.idea/dataSources.xml
generated
9
.idea/dataSources.xml
generated
@@ -11,7 +11,14 @@
|
|||||||
<driver-ref>postgresql</driver-ref>
|
<driver-ref>postgresql</driver-ref>
|
||||||
<synchronize>true</synchronize>
|
<synchronize>true</synchronize>
|
||||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||||
<jdbc-url>jdbc:postgresql://localhost:5432/test</jdbc-url>
|
<jdbc-url>jdbc:postgresql://localhost:5433/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>
|
</data-source>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
5
.idea/gradle.xml
generated
5
.idea/gradle.xml
generated
@@ -4,8 +4,8 @@
|
|||||||
<component name="GradleSettings">
|
<component name="GradleSettings">
|
||||||
<option name="linkedExternalProjectsSettings">
|
<option name="linkedExternalProjectsSettings">
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
<option name="delegatedBuild" value="false" />
|
<option name="delegatedBuild" value="true" />
|
||||||
<option name="testRunner" value="PLATFORM" />
|
<option name="testRunner" value="GRADLE" />
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
<option name="useQualifiedModuleNames" value="true" />
|
|
||||||
</GradleProjectSettings>
|
</GradleProjectSettings>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
@@ -10,4 +10,7 @@
|
|||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="corretto-11" project-jdk-type="JavaSDK">
|
<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" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
|
<component name="TaskProjectConfiguration">
|
||||||
|
<server type="GitHub" url="https://github.com" />
|
||||||
|
</component>
|
||||||
</project>
|
</project>
|
||||||
37
.idea/runConfigurations/All_Tests.xml
generated
Normal file
37
.idea/runConfigurations/All_Tests.xml
generated
Normal 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>
|
||||||
24
.idea/runConfigurations/Article_Tests.xml
generated
24
.idea/runConfigurations/Article_Tests.xml
generated
@@ -1,24 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Article 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="@article" -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>
|
|
||||||
24
.idea/runConfigurations/Auth_Tests.xml
generated
24
.idea/runConfigurations/Auth_Tests.xml
generated
@@ -1,24 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Auth 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="@auth"" />
|
|
||||||
<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>
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
<configuration default="false" name="Build and start all Docker" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
|
<configuration default="false" name="Build and start all Docker" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
|
||||||
<deployment type="docker-compose.yml">
|
<deployment type="docker-compose.yml">
|
||||||
<settings>
|
<settings>
|
||||||
|
<option name="envFilePath" value="" />
|
||||||
<option name="envVars">
|
<option name="envVars">
|
||||||
<list>
|
<list>
|
||||||
<DockerEnvVarImpl>
|
<DockerEnvVarImpl>
|
||||||
@@ -11,6 +12,11 @@
|
|||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
<option name="commandLineOptions" value="--build" />
|
<option name="commandLineOptions" value="--build" />
|
||||||
|
<option name="secondarySourceFiles">
|
||||||
|
<list>
|
||||||
|
<option value="docker-compose-sonar.yml" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
<option name="services">
|
<option name="services">
|
||||||
<list>
|
<list>
|
||||||
<option value="app" />
|
<option value="app" />
|
||||||
@@ -23,6 +29,8 @@
|
|||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
<option name="sourceFilePath" value="docker-compose.yml" />
|
<option name="sourceFilePath" value="docker-compose.yml" />
|
||||||
|
<option name="upExitCodeFromService" value="" />
|
||||||
|
<option name="upTimeout" value="" />
|
||||||
</settings>
|
</settings>
|
||||||
</deployment>
|
</deployment>
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
|
|||||||
9
.idea/runConfigurations/Check.xml
generated
9
.idea/runConfigurations/Check.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Check" type="CompoundRunConfigurationType">
|
|
||||||
<toRun name="Unit Tests (offline)" type="JUnit" />
|
|
||||||
<toRun name="Cucumber Tests (offline)" type="JUnit" />
|
|
||||||
<toRun name="Test All SQL" type="ShConfigurationType" />
|
|
||||||
<toRun name="Lint" type="GradleRunConfiguration" />
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
||||||
24
.idea/runConfigurations/Citizen_Tests.xml
generated
24
.idea/runConfigurations/Citizen_Tests.xml
generated
@@ -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="@citizen"" />
|
|
||||||
<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>
|
|
||||||
24
.idea/runConfigurations/Constitution_Tests.xml
generated
24
.idea/runConfigurations/Constitution_Tests.xml
generated
@@ -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="@constitution"" />
|
|
||||||
<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>
|
|
||||||
19
.idea/runConfigurations/Cucumber_Tests.xml
generated
19
.idea/runConfigurations/Cucumber_Tests.xml
generated
@@ -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>
|
|
||||||
30
.idea/runConfigurations/Cucumber_Tests__offline_.xml
generated
30
.idea/runConfigurations/Cucumber_Tests__offline_.xml
generated
@@ -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=" not @online" -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
23
.idea/runConfigurations/Down_Docker.xml
generated
Normal 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>
|
||||||
24
.idea/runConfigurations/Follow_Tests.xml
generated
24
.idea/runConfigurations/Follow_Tests.xml
generated
@@ -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="@follow"" />
|
|
||||||
<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>
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Unit Tests (offline)" 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" />
|
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
|
||||||
<useClassPathOnly />
|
<useClassPathOnly />
|
||||||
<option name="PACKAGE_NAME" value="fr.dcproject" />
|
<option name="PACKAGE_NAME" value="fr.dcproject" />
|
||||||
<option name="MAIN_CLASS_NAME" value="" />
|
<option name="MAIN_CLASS_NAME" value="" />
|
||||||
<option name="METHOD_NAME" value="" />
|
<option name="METHOD_NAME" value="" />
|
||||||
<option name="TEST_OBJECT" value="tags" />
|
<option name="TEST_OBJECT" value="tags" />
|
||||||
<option name="VM_PARAMETERS" value="-ea -Dcucumber.options="--tags ~@online" -Djdk.attach.allowAttachSelf=true" />
|
<option name="VM_PARAMETERS" value="-ea -Djdk.attach.allowAttachSelf=true" />
|
||||||
<option name="PARAMETERS" value="" />
|
<option name="PARAMETERS" value="" />
|
||||||
<option name="TEST_SEARCH_SCOPE">
|
<option name="TEST_SEARCH_SCOPE">
|
||||||
<value defaultName="wholeProject" />
|
<value defaultName="wholeProject" />
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
|
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
|
||||||
</envs>
|
</envs>
|
||||||
<dir value="$PROJECT_DIR$" />
|
<dir value="$PROJECT_DIR$" />
|
||||||
<tag value="!online" />
|
<tag value="functional" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
@@ -1,13 +1,7 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<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 (offline)" type="JUnit" factoryName="JUnit" show_console_on_std_err="true">
|
||||||
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
|
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
|
||||||
<useClassPathOnly />
|
<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="PACKAGE_NAME" value="fr.dcproject" />
|
||||||
<option name="MAIN_CLASS_NAME" value="" />
|
<option name="MAIN_CLASS_NAME" value="" />
|
||||||
<option name="METHOD_NAME" value="" />
|
<option name="METHOD_NAME" value="" />
|
||||||
@@ -21,7 +15,7 @@
|
|||||||
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
|
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
|
||||||
</envs>
|
</envs>
|
||||||
<dir value="$PROJECT_DIR$" />
|
<dir value="$PROJECT_DIR$" />
|
||||||
<tag value="voter" />
|
<tag value="functional&!online" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Opinion 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" />
|
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
|
||||||
<module name="dcproject.test" />
|
|
||||||
<useClassPathOnly />
|
<useClassPathOnly />
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH" value="corretto-11" />
|
||||||
<option name="PACKAGE_NAME" value="" />
|
<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="METHOD_NAME" value="" />
|
||||||
<option name="TEST_OBJECT" value="class" />
|
<option name="TEST_OBJECT" value="pattern" />
|
||||||
<option name="VM_PARAMETERS" value="-ea -Dcucumber.filter.tags="@opinion"" />
|
<option name="VM_PARAMETERS" value="-ea -Djdk.attach.allowAttachSelf=true" />
|
||||||
<option name="PARAMETERS" value="" />
|
<option name="PARAMETERS" value="" />
|
||||||
<option name="TEST_SEARCH_SCOPE">
|
<option name="TEST_SEARCH_SCOPE">
|
||||||
<value defaultName="wholeProject" />
|
<value defaultName="wholeProject" />
|
||||||
@@ -16,7 +16,10 @@
|
|||||||
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
|
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
|
||||||
</envs>
|
</envs>
|
||||||
<dir value="$PROJECT_DIR$" />
|
<dir value="$PROJECT_DIR$" />
|
||||||
<tag value="!online" />
|
<patterns>
|
||||||
|
<pattern testClass="integration..*" />
|
||||||
|
</patterns>
|
||||||
|
<tag value="!functional" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
31
.idea/runConfigurations/Lint.xml
generated
31
.idea/runConfigurations/Lint.xml
generated
@@ -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
23
.idea/runConfigurations/Lint_Format.xml
generated
Normal 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>
|
||||||
39
.idea/runConfigurations/Lint_Test_Sonar___Run.xml
generated
39
.idea/runConfigurations/Lint_Test_Sonar___Run.xml
generated
@@ -1,39 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Lint+Test+Sonar & 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" />
|
|
||||||
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Sonarqube" run_configuration_type="GradleRunConfiguration" />
|
|
||||||
</method>
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
||||||
38
.idea/runConfigurations/Lint__Test___Run.xml
generated
38
.idea/runConfigurations/Lint__Test___Run.xml
generated
@@ -1,38 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Lint, Test & 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" />
|
|
||||||
</method>
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
||||||
24
.idea/runConfigurations/Mark_as__error.xml
generated
24
.idea/runConfigurations/Mark_as__error.xml
generated
@@ -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="@error" -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
23
.idea/runConfigurations/Migration.xml
generated
Normal 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>
|
||||||
4
.idea/runConfigurations/Reset_DB_on_DEV.xml
generated
4
.idea/runConfigurations/Reset_DB_on_DEV.xml
generated
@@ -6,8 +6,10 @@
|
|||||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/src/main/resources/sql" />
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/src/main/resources/sql" />
|
||||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="false" />
|
<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="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="EXECUTE_IN_TERMINAL" value="false" />
|
||||||
|
<envs />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
10
.idea/runConfigurations/Run_dependencies.xml
generated
10
.idea/runConfigurations/Run_dependencies.xml
generated
@@ -2,6 +2,7 @@
|
|||||||
<configuration default="false" name="Run dependencies" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
|
<configuration default="false" name="Run dependencies" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
|
||||||
<deployment type="docker-compose.yml">
|
<deployment type="docker-compose.yml">
|
||||||
<settings>
|
<settings>
|
||||||
|
<option name="envFilePath" value="" />
|
||||||
<option name="envVars">
|
<option name="envVars">
|
||||||
<list>
|
<list>
|
||||||
<DockerEnvVarImpl>
|
<DockerEnvVarImpl>
|
||||||
@@ -11,6 +12,11 @@
|
|||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
<option name="commandLineOptions" value="--build" />
|
<option name="commandLineOptions" value="--build" />
|
||||||
|
<option name="secondarySourceFiles">
|
||||||
|
<list>
|
||||||
|
<option value="docker-compose-sonar.yml" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
<option name="services">
|
<option name="services">
|
||||||
<list>
|
<list>
|
||||||
<option value="db" />
|
<option value="db" />
|
||||||
@@ -18,9 +24,13 @@
|
|||||||
<option value="rabbitmq" />
|
<option value="rabbitmq" />
|
||||||
<option value="redis" />
|
<option value="redis" />
|
||||||
<option value="openapi" />
|
<option value="openapi" />
|
||||||
|
<option value="sonarqube" />
|
||||||
|
<option value="sonarqube_db" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
<option name="sourceFilePath" value="docker-compose.yml" />
|
<option name="sourceFilePath" value="docker-compose.yml" />
|
||||||
|
<option name="upExitCodeFromService" value="" />
|
||||||
|
<option name="upTimeout" value="" />
|
||||||
</settings>
|
</settings>
|
||||||
</deployment>
|
</deployment>
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
|
|||||||
7
.idea/runConfigurations/Run_for_dev.xml
generated
7
.idea/runConfigurations/Run_for_dev.xml
generated
@@ -1,7 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Run for dev" type="CompoundRunConfigurationType">
|
|
||||||
<toRun name="Run dependencies" type="docker-deploy" />
|
|
||||||
<toRun name="Run" type="GradleRunConfiguration" />
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
||||||
4
.idea/runConfigurations/SQL_Fixtures_on_DEV.xml
generated
4
.idea/runConfigurations/SQL_Fixtures_on_DEV.xml
generated
@@ -6,8 +6,10 @@
|
|||||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/src/main/resources/sql/fixtures/" />
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/src/main/resources/sql/fixtures/" />
|
||||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="false" />
|
<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="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="EXECUTE_IN_TERMINAL" value="false" />
|
||||||
|
<envs />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
6
.idea/runConfigurations/Sonarqube.xml
generated
6
.idea/runConfigurations/Sonarqube.xml
generated
@@ -4,7 +4,7 @@
|
|||||||
<option name="executionName" />
|
<option name="executionName" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="externalSystemIdString" value="GRADLE" />
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
<option name="scriptParameters" value="-x test" />
|
<option name="scriptParameters" value="" />
|
||||||
<option name="taskDescriptions">
|
<option name="taskDescriptions">
|
||||||
<list />
|
<list />
|
||||||
</option>
|
</option>
|
||||||
@@ -15,7 +15,9 @@
|
|||||||
</option>
|
</option>
|
||||||
<option name="vmOptions" value="" />
|
<option name="vmOptions" value="" />
|
||||||
</ExternalSystemSettings>
|
</ExternalSystemSettings>
|
||||||
<GradleScriptDebugEnabled>true</GradleScriptDebugEnabled>
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
23
.idea/runConfigurations/Sonarqube_without_test.xml
generated
Normal file
23
.idea/runConfigurations/Sonarqube_without_test.xml
generated
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Sonarqube without 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>
|
||||||
24
.idea/runConfigurations/Start_Db.xml
generated
24
.idea/runConfigurations/Start_Db.xml
generated
@@ -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>
|
|
||||||
16
.idea/runConfigurations/Start_Elasticsearch.xml
generated
16
.idea/runConfigurations/Start_Elasticsearch.xml
generated
@@ -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>
|
|
||||||
24
.idea/runConfigurations/Start_RabbitMQ.xml
generated
24
.idea/runConfigurations/Start_RabbitMQ.xml
generated
@@ -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>
|
|
||||||
24
.idea/runConfigurations/Start_Redis.xml
generated
24
.idea/runConfigurations/Start_Redis.xml
generated
@@ -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
28
.idea/runConfigurations/Test.xml
generated
Normal 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
23
.idea/runConfigurations/TestSql.xml
generated
Normal 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>
|
||||||
8
.idea/runConfigurations/Test_All_SQL.xml
generated
8
.idea/runConfigurations/Test_All_SQL.xml
generated
@@ -1,13 +1,17 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<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="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/test/sql/test.sh" />
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/test/sql/test.sh" />
|
||||||
<option name="SCRIPT_OPTIONS" value="1" />
|
<option name="SCRIPT_OPTIONS" value="1" />
|
||||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/src/test/sql" />
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/src/test/sql" />
|
||||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="false" />
|
<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="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="EXECUTE_IN_TERMINAL" value="false" />
|
||||||
|
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
||||||
|
<envs />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
3
.idea/runConfigurations/Unit_Tests.xml
generated
3
.idea/runConfigurations/Unit_Tests.xml
generated
@@ -5,7 +5,7 @@
|
|||||||
<option name="PACKAGE_NAME" value="fr.dcproject" />
|
<option name="PACKAGE_NAME" value="fr.dcproject" />
|
||||||
<option name="MAIN_CLASS_NAME" value="" />
|
<option name="MAIN_CLASS_NAME" value="" />
|
||||||
<option name="METHOD_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="VM_PARAMETERS" value="-ea -Djdk.attach.allowAttachSelf=true" />
|
||||||
<option name="PARAMETERS" value="" />
|
<option name="PARAMETERS" value="" />
|
||||||
<option name="TEST_SEARCH_SCOPE">
|
<option name="TEST_SEARCH_SCOPE">
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
|
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
|
||||||
</envs>
|
</envs>
|
||||||
<dir value="$PROJECT_DIR$" />
|
<dir value="$PROJECT_DIR$" />
|
||||||
|
<tag value="unit" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
30
.idea/runConfigurations/Unit__functional_and_integration_tests.xml
generated
Normal file
30
.idea/runConfigurations/Unit__functional_and_integration_tests.xml
generated
Normal 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>
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Comment 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" />
|
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
|
||||||
<module name="dcproject.test" />
|
|
||||||
<useClassPathOnly />
|
<useClassPathOnly />
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH" value="corretto-11" />
|
||||||
<option name="PACKAGE_NAME" value="" />
|
<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="METHOD_NAME" value="" />
|
||||||
<option name="TEST_OBJECT" value="class" />
|
<option name="TEST_OBJECT" value="pattern" />
|
||||||
<option name="VM_PARAMETERS" value="-ea -Dcucumber.filter.tags="@comment"" />
|
<option name="VM_PARAMETERS" value="-ea -Djdk.attach.allowAttachSelf=true" />
|
||||||
<option name="PARAMETERS" value="" />
|
<option name="PARAMETERS" value="" />
|
||||||
<option name="TEST_SEARCH_SCOPE">
|
<option name="TEST_SEARCH_SCOPE">
|
||||||
<value defaultName="wholeProject" />
|
<value defaultName="wholeProject" />
|
||||||
@@ -16,7 +16,11 @@
|
|||||||
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
|
<env name="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
|
||||||
</envs>
|
</envs>
|
||||||
<dir value="$PROJECT_DIR$" />
|
<dir value="$PROJECT_DIR$" />
|
||||||
<tag value="!online" />
|
<patterns>
|
||||||
|
<pattern testClass="unit..*" />
|
||||||
|
<pattern testClass="functional..*" />
|
||||||
|
</patterns>
|
||||||
|
<tag value="!functional" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
24
.idea/runConfigurations/Vote_Tests.xml
generated
24
.idea/runConfigurations/Vote_Tests.xml
generated
@@ -1,24 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Vote 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="@vote"" />
|
|
||||||
<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>
|
|
||||||
30
.idea/runConfigurations/Workgroup_test.xml
generated
30
.idea/runConfigurations/Workgroup_test.xml
generated
@@ -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="@workgroup"" />
|
|
||||||
<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>
|
|
||||||
21
Makefile
21
Makefile
@@ -15,12 +15,12 @@ help: ## This help.
|
|||||||
|
|
||||||
bd: build-docker
|
bd: build-docker
|
||||||
|
|
||||||
build-docker: ## Build the docker image of application
|
build-docker: ## Build the docker image of application (alias: bd)
|
||||||
docker build -t dc-project -f docker/app/Dockerfile .
|
docker build -t dc-project -f docker/app/Dockerfile .
|
||||||
|
|
||||||
pd: publish-docker
|
pd: publish-docker
|
||||||
|
|
||||||
publish-docker: build-docker ## Publish docker image of application to Github
|
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)
|
@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
|
@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 tag dc-project docker.pkg.github.com/flecomte/dc-project/dc-project:${VERSION}
|
||||||
@@ -28,27 +28,32 @@ publish-docker: build-docker ## Publish docker image of application to Github
|
|||||||
|
|
||||||
rd: run-docker
|
rd: run-docker
|
||||||
|
|
||||||
run-docker: ## Build and Run all docker services
|
run-docker: ## Build and Run all docker services (alias: rd)
|
||||||
docker-compose up -d --build
|
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
|
pm: publish-maven
|
||||||
|
|
||||||
publish-maven: ## Publish JAR file to Github
|
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)
|
@git diff --quiet --exit-code || (echo "The git is DIRTY !!! You cannot publish this crap!" && exit 1)
|
||||||
gradlew publish
|
gradlew publish
|
||||||
|
|
||||||
f: fixtures
|
f: fixtures
|
||||||
|
|
||||||
fixtures: ## Import fixtures
|
fixtures: ## Import fixtures (alias: f)
|
||||||
bash src/main/resources/sql/fixtures/fixtures.sh
|
bash src/main/resources/sql/fixtures/fixtures.sh
|
||||||
|
|
||||||
reset-database: ## Import fixtures
|
reset-database: ## Reset database !!!
|
||||||
cd src/main/resources/sql/ ; bash resetDB.sh
|
cd src/main/resources/sql/ ; bash resetDB.sh
|
||||||
|
|
||||||
test-sql: ## Test sql
|
test-sql: ## Test sql
|
||||||
cd src/test/sql/ ; bash test.sh 1
|
cd src/test/sql/ ; bash test.sh 1
|
||||||
|
|
||||||
v: vertion
|
v: version
|
||||||
|
|
||||||
vertion: ## Show current version
|
version: ## Show current version (alias: v)
|
||||||
@echo ${VERSION}
|
@echo ${VERSION}
|
||||||
|
|||||||
296
build.gradle.kts
296
build.gradle.kts
@@ -1,15 +1,20 @@
|
|||||||
|
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.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
import org.owasp.dependencycheck.reporting.ReportGenerator
|
import org.owasp.dependencycheck.reporting.ReportGenerator
|
||||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
val ktor_version: String by project
|
val ktorVersion = "1.5.0"
|
||||||
val kotlin_version: String by project
|
val kotlinVersion = "1.4.30"
|
||||||
val coroutinesVersion: String by project
|
val coroutinesVersion = "1.4.3"
|
||||||
val logback_version: String by project
|
val logbackVersion = "1.2.3"
|
||||||
val koinVersion: String by project
|
val koinVersion = "2.0.1"
|
||||||
val jackson_version: String by project
|
val jacksonVersion = "2.12.1"
|
||||||
val cucumber_version: String by project
|
|
||||||
|
|
||||||
group = "com.github.flecomte"
|
group = "com.github.flecomte"
|
||||||
version = versioning.info.run {
|
version = versioning.info.run {
|
||||||
@@ -23,26 +28,133 @@ version = versioning.info.run {
|
|||||||
plugins {
|
plugins {
|
||||||
jacoco
|
jacoco
|
||||||
application
|
application
|
||||||
|
maven
|
||||||
|
|
||||||
id("maven-publish")
|
id("maven-publish")
|
||||||
id("org.jetbrains.kotlin.jvm") version "1.3.50"
|
kotlin("jvm") version "1.4.30"
|
||||||
|
kotlin("plugin.serialization") version "1.4.30"
|
||||||
|
|
||||||
id("com.github.johnrengelman.shadow") version "5.2.0"
|
id("com.github.johnrengelman.shadow") version "5.2.0"
|
||||||
id("org.jlleitschuh.gradle.ktlint") version "8.2.0"
|
id("org.jlleitschuh.gradle.ktlint") version "9.4.1"
|
||||||
id("org.owasp.dependencycheck") version "5.1.0"
|
id("org.owasp.dependencycheck") version "6.1.1"
|
||||||
id("org.sonarqube") version "2.7"
|
id("org.sonarqube") version "3.1.1"
|
||||||
id("net.nemerosa.versioning") version "2.13.1"
|
id("net.nemerosa.versioning") version "2.14.0"
|
||||||
|
id("io.gitlab.arturbosch.detekt") version "1.16.0-RC1"
|
||||||
|
id("com.avast.gradle.docker-compose") version "0.14.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClassName = "io.ktor.server.jetty.EngineMain"
|
mainClassName = "io.ktor.server.jetty.EngineMain"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
mavenCentral()
|
||||||
|
jcenter()
|
||||||
|
maven { url = uri("https://jitpack.io") }
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath("com.typesafe:config:1.4.1")
|
||||||
|
classpath("com.github.flecomte:postgres-json:2.1.1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tasks.withType<KotlinCompile> {
|
tasks.withType<KotlinCompile> {
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "11"
|
jvmTarget = "11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val migration by tasks.registering {
|
||||||
|
group = "application"
|
||||||
|
dependsOn(tasks.named("composeUp"))
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
val config = ConfigFactory.parseFile(file("$buildDir/../src/main/resources/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/../src/main/resources/sql/migrations").toURI(),
|
||||||
|
file("$buildDir/../src/main/resources/sql/functions").toURI()
|
||||||
|
).run {
|
||||||
|
run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val migrationTest by tasks.registering {
|
||||||
|
group = "verification"
|
||||||
|
dependsOn(tasks.named("testComposeUp"))
|
||||||
|
finalizedBy(tasks.named("testComposeDown"))
|
||||||
|
doLast {
|
||||||
|
val config = ConfigFactory.parseFile(file("$buildDir/../src/test/resources/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/../src/main/resources/sql/migrations").toURI(),
|
||||||
|
file("$buildDir/../src/main/resources/sql/functions").toURI()
|
||||||
|
).run {
|
||||||
|
run()
|
||||||
|
connection.disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val testSql by tasks.registering {
|
||||||
|
group = "verification"
|
||||||
|
dependsOn(tasks.named("testComposeUp"))
|
||||||
|
finalizedBy(tasks.named("testComposeDown"))
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
val config = ConfigFactory.parseFile(file("$buildDir/../src/test/resources/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/../src/main/resources/sql/migrations").toURI(),
|
||||||
|
file("$buildDir/../src/main/resources/sql/functions").toURI(),
|
||||||
|
file("$buildDir/../src/test/sql/fixtures").toURI()
|
||||||
|
).run {
|
||||||
|
run()
|
||||||
|
}
|
||||||
|
|
||||||
|
Requester.RequesterFactory(
|
||||||
|
connection = connection,
|
||||||
|
queriesDirectory = file("$buildDir/../src/test/sql").toURI()
|
||||||
|
).createRequester().run {
|
||||||
|
getQueries().map {
|
||||||
|
try {
|
||||||
|
it.sendQuery() == 0
|
||||||
|
} catch (e: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tasks.withType<Jar> {
|
tasks.withType<Jar> {
|
||||||
manifest {
|
manifest {
|
||||||
attributes(
|
attributes(
|
||||||
@@ -53,23 +165,62 @@ tasks.withType<Jar> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks.withType<KotlinCompile> {
|
||||||
named<ShadowJar>("shadowJar") {
|
kotlinOptions {
|
||||||
mergeServiceFiles("META-INF/services")
|
jvmTarget = "11"
|
||||||
archiveFileName.set("${archiveBaseName.get()}-latest-all.${archiveExtension.get()}")
|
sourceCompatibility = "11"
|
||||||
|
targetCompatibility = "11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val sourcesJar by tasks.creating(Jar::class) {
|
tasks.named<ShadowJar>("shadowJar") {
|
||||||
|
mergeServiceFiles("META-INF/services")
|
||||||
|
archiveFileName.set("${archiveBaseName.get()}-latest-all.${archiveExtension.get()}")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.sonarqube.configure { dependsOn(tasks.jacocoTestReport) }
|
||||||
|
|
||||||
|
val sourcesJar by tasks.registering(Jar::class) {
|
||||||
|
group = "build"
|
||||||
archiveClassifier.set("sources")
|
archiveClassifier.set("sources")
|
||||||
from(sourceSets.getByName("main").allSource)
|
from(sourceSets.getByName("main").allSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.test {
|
tasks.test {
|
||||||
useJUnit()
|
useJUnit()
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
// maxHeapSize = "1G"
|
systemProperty("junit.jupiter.execution.parallel.enabled", true)
|
||||||
|
dependsOn(testSql)
|
||||||
|
finalizedBy(tasks.jacocoTestReport) // report is always generated after tests run
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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("test").apply {
|
||||||
|
projectName = "dc-project_test"
|
||||||
|
useComposeFiles = listOf("docker-compose-test.yml")
|
||||||
|
stopContainers = false
|
||||||
|
isRequiredBy(project.tasks.test)
|
||||||
|
isRequiredBy(project.tasks.named("testSql"))
|
||||||
|
}
|
||||||
|
createNested("sonarqube").apply {
|
||||||
|
projectName = "dc-project"
|
||||||
|
useComposeFiles = listOf("docker-compose-sonar.yml")
|
||||||
|
stopContainers = false
|
||||||
|
removeVolumes = false
|
||||||
|
removeContainers = false
|
||||||
|
// isRequiredBy(project.tasks.sonarqube)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks.sonarqube.configure { dependsOn(tasks.named("sonarqubeComposeUp")) }
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
if (versioning.info.dirty == false) {
|
if (versioning.info.dirty == false) {
|
||||||
repositories {
|
repositories {
|
||||||
@@ -97,15 +248,53 @@ publishing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
jacoco {
|
jacoco {
|
||||||
toolVersion = "0.8.3"
|
toolVersion = "0.8.6"
|
||||||
|
applyTo(tasks.run.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register<JacocoReport>("applicationCodeCoverageReport") {
|
||||||
|
executionData(tasks.run.get())
|
||||||
|
sourceSets(sourceSets.main.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.jacocoTestReport {
|
tasks.jacocoTestReport {
|
||||||
|
dependsOn(tasks.test)
|
||||||
reports {
|
reports {
|
||||||
xml.isEnabled = true
|
xml.isEnabled = true
|
||||||
|
html.isEnabled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detekt {
|
||||||
|
buildUponDefaultConfig = true // preconfigure defaults
|
||||||
|
// 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"
|
||||||
|
}
|
||||||
|
|
||||||
|
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 { dependsOn(setMaxMapCount) }
|
||||||
|
|
||||||
dependencyCheck {
|
dependencyCheck {
|
||||||
formats = listOf(ReportGenerator.Format.HTML, ReportGenerator.Format.XML)
|
formats = listOf(ReportGenerator.Format.HTML, ReportGenerator.Format.XML)
|
||||||
}
|
}
|
||||||
@@ -118,41 +307,46 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
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-core:$coroutinesVersion")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$coroutinesVersion")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$coroutinesVersion")
|
||||||
implementation("io.ktor:ktor-server-jetty:$ktor_version")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1")
|
||||||
implementation("io.ktor:ktor-client-jetty:$ktor_version")
|
implementation("io.ktor:ktor-server-jetty:$ktorVersion")
|
||||||
implementation("ch.qos.logback:logback-classic:$logback_version")
|
implementation("io.ktor:ktor-client-jetty:$ktorVersion")
|
||||||
implementation("io.ktor:ktor-server-core:$ktor_version")
|
implementation("ch.qos.logback:logback-classic:$logbackVersion")
|
||||||
implementation("io.ktor:ktor-locations:$ktor_version")
|
implementation("io.ktor:ktor-server-core:$ktorVersion")
|
||||||
implementation("io.ktor:ktor-auth:$ktor_version")
|
implementation("io.ktor:ktor-locations:$ktorVersion")
|
||||||
implementation("io.ktor:ktor-auth-jwt:$ktor_version")
|
implementation("io.ktor:ktor-auth:$ktorVersion")
|
||||||
implementation("io.ktor:ktor-gson:$ktor_version")
|
implementation("io.ktor:ktor-auth-jwt:$ktorVersion")
|
||||||
implementation("io.ktor:ktor-auth-jwt:$ktor_version")
|
implementation("io.ktor:ktor-websockets:$ktorVersion")
|
||||||
implementation("io.ktor:ktor-websockets:$ktor_version")
|
|
||||||
implementation("org.koin:koin-ktor:$koinVersion")
|
implementation("org.koin:koin-ktor:$koinVersion")
|
||||||
implementation("io.ktor:ktor-jackson:$ktor_version")
|
implementation("io.ktor:ktor-jackson:$ktorVersion")
|
||||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version")
|
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jacksonVersion")
|
||||||
implementation("com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version")
|
implementation("com.fasterxml.jackson.datatype:jackson-datatype-joda:$jacksonVersion")
|
||||||
implementation("net.pearx.kasechange:kasechange-jvm:1.1.0")
|
implementation("net.pearx.kasechange:kasechange-jvm:1.3.0")
|
||||||
implementation("com.auth0:java-jwt:3.8.2")
|
implementation("com.auth0:java-jwt:3.12.0")
|
||||||
implementation("com.github.jasync-sql:jasync-postgresql:1.0.7")
|
implementation("com.github.jasync-sql:jasync-postgresql:1.1.6")
|
||||||
implementation("com.github.flecomte:postgres-json:1.2.1")
|
implementation("com.github.flecomte:postgres-json:2.1.1")
|
||||||
implementation("com.github.flecomte:ktor-voter:1.0.1")
|
implementation("com.sendgrid:sendgrid-java:4.7.1")
|
||||||
implementation("com.sendgrid:sendgrid-java:4.4.1")
|
implementation("io.lettuce:lettuce-core:5.3.6.RELEASE") // TODO update to 6.0.2
|
||||||
implementation("io.lettuce:lettuce-core:5.2.2.RELEASE")
|
implementation("com.rabbitmq:amqp-client:5.10.0")
|
||||||
implementation("com.rabbitmq:amqp-client:5.8.0")
|
|
||||||
implementation("org.elasticsearch.client:elasticsearch-rest-client:6.7.1")
|
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")
|
||||||
|
|
||||||
testImplementation("io.ktor:ktor-server-tests:$ktor_version")
|
testImplementation("io.ktor:ktor-server-tests:$ktorVersion")
|
||||||
testImplementation("io.ktor:ktor-client-mock:$ktor_version")
|
testImplementation("io.ktor:ktor-client-mock:$ktorVersion")
|
||||||
testImplementation("io.ktor:ktor-client-mock-jvm:$ktor_version")
|
testImplementation("io.ktor:ktor-client-mock-jvm:$ktorVersion")
|
||||||
testImplementation("org.koin:koin-test:$koinVersion")
|
testImplementation("org.koin:koin-test:$koinVersion")
|
||||||
testImplementation("io.mockk:mockk:1.9.3")
|
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter:5.5.0")
|
testImplementation("io.mockk:mockk:1.10.6")
|
||||||
testImplementation("org.amshove.kluent:kluent:1.4")
|
testImplementation("org.junit.jupiter:junit-jupiter:5.7.0")
|
||||||
testImplementation("io.cucumber:cucumber-java8:$cucumber_version")
|
testImplementation("org.amshove.kluent:kluent:1.61")
|
||||||
testImplementation("io.cucumber:cucumber-junit:$cucumber_version")
|
testImplementation("io.mockk:mockk-agent-api:1.10.6")
|
||||||
|
testImplementation("io.mockk:mockk-agent-jvm:1.10.6")
|
||||||
|
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")
|
||||||
}
|
}
|
||||||
|
|||||||
98
doc/schema/Article.puml
Normal file
98
doc/schema/Article.puml
Normal 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
|
||||||
66
doc/schema/Notification.puml
Normal file
66
doc/schema/Notification.puml
Normal 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
|
||||||
48
docker-compose-sonar.yml
Normal file
48
docker-compose-sonar.yml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
sonarqube:
|
||||||
|
container_name: ${APP_NAME}_sonarqube
|
||||||
|
image: sonarqube:community
|
||||||
|
depends_on:
|
||||||
|
- sonarqube_db
|
||||||
|
ports:
|
||||||
|
- ${SONARQUBE_PORT}:9000
|
||||||
|
networks:
|
||||||
|
- sonarnet
|
||||||
|
environment:
|
||||||
|
SONAR_JDBC_URL: jdbc:postgresql://sonarqube_db:5432/sonar
|
||||||
|
SONAR_JDBC_USERNAME: sonar
|
||||||
|
SONAR_JDBC_PASSWORD: sonar
|
||||||
|
volumes:
|
||||||
|
- sonarqube_data:/opt/sonarqube/data
|
||||||
|
- sonarqube_extensions:/opt/sonarqube/extensions
|
||||||
|
- sonarqube_logs:/opt/sonarqube/logs
|
||||||
|
- sonarqube_temp:/opt/sonarqube/temp
|
||||||
|
|
||||||
|
sonarqube_db:
|
||||||
|
container_name: ${APP_NAME}_sonarqube_db
|
||||||
|
image: postgres:alpine
|
||||||
|
networks:
|
||||||
|
- sonarnet
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: sonar
|
||||||
|
POSTGRES_PASSWORD: sonar
|
||||||
|
ports:
|
||||||
|
- ${SONARQUBE_DB_PORT}:5432
|
||||||
|
volumes:
|
||||||
|
- sonarqube_postgresql:/var/lib/postgresql
|
||||||
|
# This needs explicit mapping due to https://github.com/docker-library/postgres/blob/4e48e3228a30763913ece952c611e5e9b95c8759/Dockerfile.template#L52
|
||||||
|
- sonarqube_postgresql_data:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
|
||||||
|
networks:
|
||||||
|
sonarnet:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
sonarqube_data:
|
||||||
|
sonarqube_extensions:
|
||||||
|
sonarqube_logs:
|
||||||
|
sonarqube_temp:
|
||||||
|
sonarqube_postgresql:
|
||||||
|
sonarqube_postgresql_data:
|
||||||
44
docker-compose-test.yml
Normal file
44
docker-compose-test.yml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
version: '3.8'
|
||||||
|
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
|
||||||
@@ -1,15 +1,9 @@
|
|||||||
# To execute this docker-compose yml file use docker-compose -f <file_name> up
|
# To execute this docker-compose yml file use docker-compose -f <file_name> up
|
||||||
# Add the "-d" flag at the end for detached execution
|
# Add the "-d" flag at the end for detached execution
|
||||||
version: '3.7'
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
sonarqube:
|
|
||||||
container_name: sonarqube_${NAME}
|
|
||||||
image: sonarqube
|
|
||||||
ports:
|
|
||||||
- ${SONARQUBE_PORT}:9000
|
|
||||||
|
|
||||||
openapi:
|
openapi:
|
||||||
container_name: openapi_${NAME}
|
container_name: ${APP_NAME}_openapi
|
||||||
image: swaggerapi/swagger-ui
|
image: swaggerapi/swagger-ui
|
||||||
ports:
|
ports:
|
||||||
- ${OPENAPI_PORT}:8080
|
- ${OPENAPI_PORT}:8080
|
||||||
@@ -17,22 +11,22 @@ services:
|
|||||||
URL: "http://localhost:8080"
|
URL: "http://localhost:8080"
|
||||||
|
|
||||||
rabbitmq:
|
rabbitmq:
|
||||||
container_name: rabbitmq_${NAME}
|
container_name: ${APP_NAME}_rabbitmq
|
||||||
image: rabbitmq:management-alpine
|
image: rabbitmq:management-alpine
|
||||||
ports:
|
ports:
|
||||||
- ${RABBITMQ_PORT}:5672
|
- ${RABBITMQ_PORT}:5672
|
||||||
- ${RABBITMQ_MANAGEMENT_PORT}:15672
|
- ${RABBITMQ_MANAGEMENT_PORT}:15672
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
container_name: redis_${NAME}
|
container_name: ${APP_NAME}_redis
|
||||||
image: redis:6.0-rc-alpine
|
image: redis:6-alpine
|
||||||
ports:
|
ports:
|
||||||
- ${REDIS_PORT}:6379
|
- ${REDIS_PORT}:6379
|
||||||
volumes:
|
volumes:
|
||||||
- redis-data:/var/lib/redis:rw
|
- redis-data:/var/lib/redis:rw
|
||||||
|
|
||||||
app:
|
app:
|
||||||
container_name: app_${NAME}
|
container_name: ${APP_NAME}_app
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: docker/app/Dockerfile
|
dockerfile: docker/app/Dockerfile
|
||||||
@@ -51,7 +45,7 @@ services:
|
|||||||
- rabbitmq
|
- rabbitmq
|
||||||
|
|
||||||
elasticsearch:
|
elasticsearch:
|
||||||
container_name: elasticsearch_${NAME}
|
container_name: ${APP_NAME}_elasticsearch
|
||||||
image: elasticsearch:6.7.1
|
image: elasticsearch:6.7.1
|
||||||
ports:
|
ports:
|
||||||
- ${ELASTIC_REST}:9200
|
- ${ELASTIC_REST}:9200
|
||||||
@@ -63,7 +57,7 @@ services:
|
|||||||
retries: 20
|
retries: 20
|
||||||
|
|
||||||
db:
|
db:
|
||||||
container_name: postgresql_${NAME}
|
container_name: ${APP_NAME}_postgresql
|
||||||
build:
|
build:
|
||||||
context: docker/postgresql
|
context: docker/postgresql
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
#### BUILD ####
|
#### BUILD ####
|
||||||
FROM gradle:5.6.4-jdk11 AS build
|
FROM gradle:6.8-jdk11 AS build
|
||||||
COPY --chown=gradle:gradle . /home/gradle/src
|
COPY --chown=gradle:gradle . /home/gradle/src
|
||||||
|
|
||||||
WORKDIR /home/gradle/src
|
WORKDIR /home/gradle/src
|
||||||
RUN gradle build -x test -x ktlintKotlinScriptCheck -x ktlintTestSourceSetCheck -x ktlintMainSourceSetCheck --no-daemon
|
RUN gradle build -x test -x ktlintKotlinScriptCheck -x ktlintTestSourceSetCheck -x ktlintMainSourceSetCheck --no-daemon
|
||||||
|
RUN gradle shadowJar
|
||||||
|
|
||||||
#### RUN ####
|
#### RUN ####
|
||||||
FROM adoptopenjdk/openjdk11:jre-11.0.4_11-alpine
|
FROM amazoncorretto:11-alpine as run
|
||||||
ENV APPLICATION_USER ktor
|
ENV APPLICATION_USER ktor
|
||||||
RUN adduser -D -g '' $APPLICATION_USER
|
RUN adduser -D -g '' $APPLICATION_USER
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
ktor_version=1.2.2
|
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
kotlin_version=1.3.40
|
systemProp.sonar.host.url=http://localhost:9002
|
||||||
coroutinesVersion=1.3.3
|
systemProp.sonar.login=admin
|
||||||
logback_version=1.2.1
|
systemProp.sonar.password=sonar
|
||||||
koinVersion=2.0.1
|
systemProp.sonar.projectKey=dc-project
|
||||||
jackson_version=2.9.9
|
systemProp.sonar.projectName=DC Project
|
||||||
cucumber_version=5.1.3
|
systemProp.sonar.java.coveragePlugin=jacoco
|
||||||
systemProp.sonar.host.url=http://localhost:9000
|
systemProp.sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml
|
||||||
systemProp.sonar.login=1196e8015c20035f1aa91e881b95ce9d6e879c8a
|
systemProp.sonar.kotlin.detekt.reportPaths=build/reports/detekt/detekt.xml
|
||||||
|
|||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
31
gradlew
vendored
31
gradlew
vendored
@@ -82,6 +82,7 @@ esac
|
|||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
@@ -129,6 +130,7 @@ fi
|
|||||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
@@ -154,19 +156,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
|||||||
else
|
else
|
||||||
eval `echo args$i`="\"$arg\""
|
eval `echo args$i`="\"$arg\""
|
||||||
fi
|
fi
|
||||||
i=$((i+1))
|
i=`expr $i + 1`
|
||||||
done
|
done
|
||||||
case $i in
|
case $i in
|
||||||
(0) set -- ;;
|
0) set -- ;;
|
||||||
(1) set -- "$args0" ;;
|
1) set -- "$args0" ;;
|
||||||
(2) set -- "$args0" "$args1" ;;
|
2) set -- "$args0" "$args1" ;;
|
||||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -175,14 +177,9 @@ save () {
|
|||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
echo " "
|
echo " "
|
||||||
}
|
}
|
||||||
APP_ARGS=$(save "$@")
|
APP_ARGS=`save "$@"`
|
||||||
|
|
||||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
# 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"
|
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" "$@"
|
exec "$JAVACMD" "$@"
|
||||||
|
|||||||
25
gradlew.bat
vendored
25
gradlew.bat
vendored
@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
|
|||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
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.
|
@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"
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
@@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
|||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
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_HOME=%JAVA_HOME:"=%
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
@@ -61,28 +64,14 @@ echo location of your Java installation.
|
|||||||
|
|
||||||
goto fail
|
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
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@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
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
|||||||
@@ -1,314 +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.elasticsearch.configElasticIndexes
|
|
||||||
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.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) ?: 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 {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
configElasticIndexes(get())
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -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()) }
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
package fr.dcproject.elasticsearch
|
|
||||||
|
|
||||||
import org.elasticsearch.client.Request
|
|
||||||
import org.elasticsearch.client.RestClient
|
|
||||||
import org.slf4j.Logger
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
|
|
||||||
fun waitElasticsearchIsUp(client: RestClient) {
|
|
||||||
val logger: Logger = LoggerFactory.getLogger("fr.dcproject.elasticsearch")
|
|
||||||
val request = Request("GET", "/_cluster/health")
|
|
||||||
repeat(40) {
|
|
||||||
runCatching {
|
|
||||||
client.performRequest(request).statusLine.statusCode
|
|
||||||
}.onSuccess {
|
|
||||||
if (it == 200) {
|
|
||||||
logger.debug("Elasticsearch is Ready! Continue...")
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
logger.debug("sleep 2s and retry...")
|
|
||||||
Thread.sleep(2000)
|
|
||||||
}
|
|
||||||
}.onFailure {
|
|
||||||
logger.debug("${it.message}, sleep 2s and retry...")
|
|
||||||
Thread.sleep(2000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
error("Elasticsearch is not ready")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun configElasticIndexes(client: RestClient) {
|
|
||||||
waitElasticsearchIsUp(client)
|
|
||||||
|
|
||||||
/* Create index if not exist */
|
|
||||||
client.run {
|
|
||||||
if (performRequest(Request("HEAD", "/views?include_type_name=false")).statusLine.statusCode == 404) {
|
|
||||||
Request(
|
|
||||||
"PUT",
|
|
||||||
"/views?include_type_name=false"
|
|
||||||
).apply {
|
|
||||||
//language=JSON
|
|
||||||
setJsonEntity(
|
|
||||||
"""
|
|
||||||
{
|
|
||||||
"settings": {
|
|
||||||
"number_of_shards": 5
|
|
||||||
},
|
|
||||||
"mappings": {
|
|
||||||
"properties": {
|
|
||||||
"logged": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"user_ref": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"version_id": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"ip": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"citizen_id": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"view_at": {
|
|
||||||
"type": "date"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
}.let {
|
|
||||||
performRequest(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,102 +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? = null,
|
|
||||||
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,
|
|
||||||
workgroup: WorkgroupSimple<CitizenRef>? = null
|
|
||||||
) : ArticleFull,
|
|
||||||
ArticleAuthI<CitizenBasicI>,
|
|
||||||
ArticleSimple(id, title, createdBy, draft, workgroup),
|
|
||||||
Viewable by ViewableImp() {
|
|
||||||
init {
|
|
||||||
tags = tags.distinct()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ArticleForUpdate(
|
|
||||||
id: UUID?,
|
|
||||||
val title: String,
|
|
||||||
val anonymous: Boolean = true,
|
|
||||||
val content: String,
|
|
||||||
val description: String,
|
|
||||||
tags: List<String> = emptyList(),
|
|
||||||
val draft: Boolean = false,
|
|
||||||
val createdBy: CitizenRef,
|
|
||||||
val workgroup: WorkgroupRef? = null
|
|
||||||
) : ArticleRefVersioning(id) {
|
|
||||||
val tags: List<String> = tags.distinct()
|
|
||||||
}
|
|
||||||
|
|
||||||
open class ArticleSimple(
|
|
||||||
id: UUID? = null,
|
|
||||||
override var title: String,
|
|
||||||
override val createdBy: CitizenBasic,
|
|
||||||
override var draft: Boolean = false,
|
|
||||||
override var workgroup: WorkgroupSimple<CitizenRef>? = null
|
|
||||||
) : 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? = null,
|
|
||||||
versionNumber: Int? = null,
|
|
||||||
versionId: UUID = UUID.randomUUID()
|
|
||||||
) : ArticleRef(id),
|
|
||||||
EntityVersioning<UUID, Int> by UuidEntityVersioning(versionNumber, versionId)
|
|
||||||
|
|
||||||
open class ArticleRef(
|
|
||||||
id: UUID? = null
|
|
||||||
) : ArticleI, TargetRef(id)
|
|
||||||
|
|
||||||
interface ArticleI : UuidEntityI, TargetI
|
|
||||||
|
|
||||||
interface ArticleSimpleI :
|
|
||||||
ArticleI,
|
|
||||||
EntityVersioning<UUID, Int>,
|
|
||||||
EntityCreatedBy<CitizenBasicI>,
|
|
||||||
EntityCreatedAt,
|
|
||||||
EntityDeletedAt,
|
|
||||||
Votable {
|
|
||||||
var title: String
|
|
||||||
var workgroup: WorkgroupSimple<CitizenRef>?
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,85 +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<WorkgroupAndRoles> = emptyList()
|
|
||||||
|
|
||||||
class WorkgroupAndRoles(
|
|
||||||
val roles: List<String>,
|
|
||||||
val workgroup: WorkgroupSimple<CitizenRef>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
@@ -1,71 +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 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
|
|
||||||
@@ -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)
|
|
||||||
@@ -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)
|
|
||||||
@@ -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())
|
|
||||||
@@ -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()
|
|
||||||
}
|
|
||||||
@@ -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>
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package fr.dcproject.entity
|
|
||||||
|
|
||||||
interface Viewable {
|
|
||||||
var views: ViewAggregation
|
|
||||||
}
|
|
||||||
|
|
||||||
class ViewableImp : Viewable {
|
|
||||||
override var views: ViewAggregation = ViewAggregation()
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package fr.dcproject.entity
|
|
||||||
|
|
||||||
interface Votable {
|
|
||||||
var votes: VoteAggregation
|
|
||||||
}
|
|
||||||
|
|
||||||
class VotableImp : Votable {
|
|
||||||
override var votes: VoteAggregation = VoteAggregation()
|
|
||||||
}
|
|
||||||
@@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
package fr.dcproject.entity
|
|
||||||
|
|
||||||
import fr.dcproject.entity.WorkgroupWithMembersI.Member
|
|
||||||
import fr.dcproject.entity.WorkgroupWithMembersI.Member.Role
|
|
||||||
import fr.postgresjson.entity.EntityI
|
|
||||||
import fr.postgresjson.entity.immutable.*
|
|
||||||
import fr.postgresjson.entity.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,
|
|
||||||
createdBy: CitizenBasic,
|
|
||||||
override var members: List<Member<CitizenBasic>> = emptyList()
|
|
||||||
) : WorkgroupWithAuthI<CitizenBasic>,
|
|
||||||
WorkgroupSimple<CitizenBasic>(
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
logo,
|
|
||||||
anonymous,
|
|
||||||
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,
|
|
||||||
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
|
|
||||||
|
|
||||||
fun isMember(user: UserI): Boolean = members.isMember(user)
|
|
||||||
fun isMember(citizen: CitizenWithUserI): Boolean = members.isMember(citizen)
|
|
||||||
|
|
||||||
fun hasRole(expectedRole: Role, user: UserI): Boolean = members.hasRole(expectedRole, user)
|
|
||||||
fun hasRole(expectedRole: Role, citizen: CitizenI): Boolean = members.hasRole(expectedRole, citizen)
|
|
||||||
|
|
||||||
fun getRoles(user: UserI): List<Role> = members.getRoles(user)
|
|
||||||
fun getRoles(citizen: CitizenI): List<Role> = members.getRoles(citizen)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface WorkgroupWithMembersI<Z : CitizenI> : WorkgroupI {
|
|
||||||
var members: List<Member<Z>>
|
|
||||||
|
|
||||||
class Member<C : CitizenI> (
|
|
||||||
val citizen: C,
|
|
||||||
val roles: List<Role> = emptyList()
|
|
||||||
) : EntityI {
|
|
||||||
enum class Role {
|
|
||||||
MASTER,
|
|
||||||
MANAGER,
|
|
||||||
EDITOR,
|
|
||||||
REPORTER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun List<CitizenI>.hasCitizen(citizen: CitizenI): Boolean = this.map { it.id }.contains(citizen.id)
|
|
||||||
|
|
||||||
fun <Z : CitizenWithUserI> List<Member<Z>>.isMember(user: UserI): Boolean =
|
|
||||||
map { it.citizen.user.id }.contains(user.id)
|
|
||||||
|
|
||||||
fun <Z : CitizenI> List<Member<Z>>.isMember(citizen: CitizenI): Boolean =
|
|
||||||
map { it.citizen.id }.contains(citizen.id)
|
|
||||||
|
|
||||||
fun <Z : CitizenI> List<Member<Z>>.hasRole(expectedRole: Role, citizen: CitizenI): Boolean =
|
|
||||||
any { member -> member.citizen.id == citizen.id && member.roles.any { it == expectedRole } }
|
|
||||||
|
|
||||||
fun <Z : CitizenWithUserI> List<Member<Z>>.hasRole(expectedRole: Role, user: UserI): Boolean =
|
|
||||||
any { member -> member.citizen.user.id == user.id && member.roles.any { it == expectedRole } }
|
|
||||||
|
|
||||||
fun <Z : CitizenWithUserI> List<Member<Z>>.getRoles(user: UserI): List<Role> =
|
|
||||||
firstOrNull { it.citizen.user.id == user.id }?.roles ?: emptyList()
|
|
||||||
|
|
||||||
fun <Z : CitizenWithUserI> List<Member<Z>>.getRoles(citizen: CitizenI): List<Role> =
|
|
||||||
firstOrNull { it.citizen.id == citizen.id }?.roles ?: emptyList()
|
|
||||||
|
|
||||||
interface WorkgroupI : UuidEntityI
|
|
||||||
@@ -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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
213
src/main/kotlin/fr/dcproject/application/Application.kt
Normal file
213
src/main/kotlin/fr/dcproject/application/Application.kt
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
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 com.github.jasync.sql.db.postgresql.exceptions.GenericDatabaseException
|
||||||
|
import fr.dcproject.application.Env.PROD
|
||||||
|
import fr.dcproject.application.Env.TEST
|
||||||
|
import fr.dcproject.common.security.AccessDeniedException
|
||||||
|
import fr.dcproject.component.article.articleKoinModule
|
||||||
|
import fr.dcproject.component.article.routes.installArticleRoutes
|
||||||
|
import fr.dcproject.component.auth.ForbiddenException
|
||||||
|
import fr.dcproject.component.auth.authKoinModule
|
||||||
|
import fr.dcproject.component.auth.jwt.jwtInstallation
|
||||||
|
import fr.dcproject.component.auth.routes.installAuthRoutes
|
||||||
|
import fr.dcproject.component.auth.user
|
||||||
|
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.constitution.installFollowConstitutionRoutes
|
||||||
|
import fr.dcproject.component.notification.NotificationConsumer
|
||||||
|
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.ApplicationStopped
|
||||||
|
import io.ktor.application.call
|
||||||
|
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.NotFoundException
|
||||||
|
import io.ktor.features.StatusPages
|
||||||
|
import io.ktor.http.HttpHeaders
|
||||||
|
import io.ktor.http.HttpMethod
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
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.response.respond
|
||||||
|
import io.ktor.routing.Routing
|
||||||
|
import io.ktor.server.jetty.EngineMain
|
||||||
|
import io.ktor.util.KtorExperimentalAPI
|
||||||
|
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
|
||||||
|
import java.util.concurrent.CompletionException
|
||||||
|
|
||||||
|
fun main(args: Array<String>): Unit = EngineMain.main(args)
|
||||||
|
|
||||||
|
enum class Env { PROD, TEST }
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
@KtorExperimentalAPI
|
||||||
|
@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<NotificationConsumer>().run {
|
||||||
|
start()
|
||||||
|
environment.monitor.subscribe(ApplicationStopped) {
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
install(Authentication, jwtInstallation(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()
|
||||||
|
installWorkgroupRoutes()
|
||||||
|
installOpinionRoutes()
|
||||||
|
installVoteRoutes()
|
||||||
|
installConstitutionRoutes()
|
||||||
|
installCommentConstitutionRoutes()
|
||||||
|
installNotificationsRoutes()
|
||||||
|
installDocRoutes()
|
||||||
|
}
|
||||||
|
|
||||||
|
install(StatusPages) {
|
||||||
|
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<AccessDeniedException> {
|
||||||
|
if (call.user == null) call.respond(HttpStatusCode.Unauthorized)
|
||||||
|
else call.respond(HttpStatusCode.Forbidden)
|
||||||
|
}
|
||||||
|
exception<ForbiddenException> {
|
||||||
|
call.respond(HttpStatusCode.Forbidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/main/kotlin/fr/dcproject/application/Configuration.kt
Normal file
46
src/main/kotlin/fr/dcproject/application/Configuration.kt
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
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")
|
||||||
|
}
|
||||||
31
src/main/kotlin/fr/dcproject/application/Converters.kt
Normal file
31
src/main/kotlin/fr/dcproject/application/Converters.kt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package fr.dcproject.application
|
||||||
|
|
||||||
|
import io.ktor.features.DataConversion
|
||||||
|
import io.ktor.util.KtorExperimentalAPI
|
||||||
|
import org.koin.core.context.GlobalContext
|
||||||
|
import org.koin.core.parameter.ParametersDefinition
|
||||||
|
import org.koin.core.qualifier.Qualifier
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
private typealias ConverterDeclaration = DataConversion.Configuration.() -> Unit
|
||||||
|
private inline fun <reified T> DataConversion.Configuration.get(
|
||||||
|
qualifier: Qualifier? = null,
|
||||||
|
noinline parameters: ParametersDefinition? = null
|
||||||
|
): T = GlobalContext.get().koin.rootScope.get(qualifier, parameters)
|
||||||
|
|
||||||
|
@KtorExperimentalAPI
|
||||||
|
val converters: ConverterDeclaration = {
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
110
src/main/kotlin/fr/dcproject/application/KoinModule.kt
Normal file
110
src/main/kotlin/fr/dcproject/application/KoinModule.kt
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
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.notification.NotificationConsumer
|
||||||
|
import fr.dcproject.component.notification.NotificationEmailSender
|
||||||
|
import fr.dcproject.component.notification.NotificationsPush
|
||||||
|
import fr.dcproject.component.notification.Publisher
|
||||||
|
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 org.koin.core.qualifier.named
|
||||||
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
@KtorExperimentalAPI
|
||||||
|
val KoinModule = module {
|
||||||
|
// 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 { NotificationsPush.Builder(get()) }
|
||||||
|
|
||||||
|
single {
|
||||||
|
val config: Configuration = get()
|
||||||
|
NotificationConsumer(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()
|
||||||
|
Publisher(factory = get(), exchangeName = config.exchangeNotificationName)
|
||||||
|
}
|
||||||
|
|
||||||
|
single {
|
||||||
|
val config: Configuration = get()
|
||||||
|
NotificationEmailSender(get<Mailer>(), config.domain, get(), get())
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/main/kotlin/fr/dcproject/common/BitMaskEnum.kt
Normal file
11
src/main/kotlin/fr/dcproject/common/BitMaskEnum.kt
Normal 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
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package fr.dcproject.messages
|
package fr.dcproject.common.email
|
||||||
|
|
||||||
import com.sendgrid.Method
|
import com.sendgrid.Method
|
||||||
import com.sendgrid.Request
|
import com.sendgrid.Request
|
||||||
28
src/main/kotlin/fr/dcproject/common/entity/Action.kt
Normal file
28
src/main/kotlin/fr/dcproject/common/entity/Action.kt
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/main/kotlin/fr/dcproject/common/entity/ActionBy.kt
Normal file
25
src/main/kotlin/fr/dcproject/common/entity/ActionBy.kt
Normal 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>
|
||||||
|
}
|
||||||
30
src/main/kotlin/fr/dcproject/common/entity/Date.kt
Normal file
30
src/main/kotlin/fr/dcproject/common/entity/Date.kt
Normal 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
|
||||||
|
}
|
||||||
12
src/main/kotlin/fr/dcproject/common/entity/EntityI.kt
Normal file
12
src/main/kotlin/fr/dcproject/common/entity/EntityI.kt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package fr.dcproject.common.entity
|
||||||
|
|
||||||
|
import fr.postgresjson.entity.UuidEntityI
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
interface EntityI : UuidEntityI {
|
||||||
|
override val id: UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Entity(id: UUID? = null) : EntityI {
|
||||||
|
override val id: UUID = id ?: UUID.randomUUID()
|
||||||
|
}
|
||||||
@@ -1,21 +1,25 @@
|
|||||||
package fr.dcproject.entity
|
package fr.dcproject.common.entity
|
||||||
|
|
||||||
import fr.postgresjson.entity.immutable.EntityCreatedAt
|
import fr.dcproject.component.article.database.ArticleRef
|
||||||
import fr.postgresjson.entity.immutable.EntityCreatedBy
|
import fr.dcproject.component.citizen.database.CitizenI
|
||||||
import fr.postgresjson.entity.immutable.UuidEntity
|
import fr.dcproject.component.comment.generic.database.CommentRef
|
||||||
import fr.postgresjson.entity.immutable.UuidEntityI
|
import fr.dcproject.component.constitution.database.ConstitutionRef
|
||||||
import java.util.*
|
import fr.dcproject.component.opinion.database.OpinionRef
|
||||||
|
import java.util.UUID
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.full.isSubclassOf
|
import kotlin.reflect.full.isSubclassOf
|
||||||
|
|
||||||
interface ExtraI<T : TargetI, C : CitizenI> :
|
interface ExtraI<T : TargetI, C : CitizenI> :
|
||||||
UuidEntityI,
|
EntityI,
|
||||||
EntityCreatedAt,
|
HasTarget<T>,
|
||||||
EntityCreatedBy<C> {
|
CreatedAt,
|
||||||
|
CreatedBy<C>
|
||||||
|
|
||||||
|
interface HasTarget<T : TargetI> {
|
||||||
val target: T
|
val target: T
|
||||||
}
|
}
|
||||||
|
|
||||||
open class TargetRef(id: UUID? = null, reference: String = "") : TargetI, UuidEntity(id) {
|
open class TargetRef(id: UUID? = null, reference: String = "") : TargetI, Entity(id) {
|
||||||
|
|
||||||
final override val reference: String
|
final override val reference: String
|
||||||
get() = if (field != "") field else TargetI.getReference(this)
|
get() = if (field != "") field else TargetI.getReference(this)
|
||||||
@@ -25,7 +29,7 @@ open class TargetRef(id: UUID? = null, reference: String = "") : TargetI, UuidEn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TargetI : UuidEntityI {
|
interface TargetI : EntityI {
|
||||||
enum class TargetName(val targetReference: String) {
|
enum class TargetName(val targetReference: String) {
|
||||||
Article("article"),
|
Article("article"),
|
||||||
Constitution("constitution"),
|
Constitution("constitution"),
|
||||||
@@ -39,7 +43,7 @@ interface TargetI : UuidEntityI {
|
|||||||
t.isSubclassOf(ArticleRef::class) -> TargetName.Article.targetReference
|
t.isSubclassOf(ArticleRef::class) -> TargetName.Article.targetReference
|
||||||
t.isSubclassOf(ConstitutionRef::class) -> TargetName.Constitution.targetReference
|
t.isSubclassOf(ConstitutionRef::class) -> TargetName.Constitution.targetReference
|
||||||
t.isSubclassOf(CommentRef::class) -> TargetName.Comment.targetReference
|
t.isSubclassOf(CommentRef::class) -> TargetName.Comment.targetReference
|
||||||
t.isSubclassOf(Opinion::class) -> TargetName.Opinion.targetReference
|
t.isSubclassOf(OpinionRef::class) -> TargetName.Opinion.targetReference
|
||||||
else -> throw error("target not implemented: ${t.qualifiedName} \nImplement it or return 'reference' from SQL")
|
else -> throw error("target not implemented: ${t.qualifiedName} \nImplement it or return 'reference' from SQL")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
25
src/main/kotlin/fr/dcproject/common/entity/Versionable.kt
Normal file
25
src/main/kotlin/fr/dcproject/common/entity/Versionable.kt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package fr.dcproject.common.entity
|
||||||
|
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
interface VersionableId {
|
||||||
|
val versionId: UUID
|
||||||
|
|
||||||
|
class Imp(
|
||||||
|
versionId: UUID? = null,
|
||||||
|
) : VersionableId {
|
||||||
|
override val versionId: UUID = versionId ?: UUID.randomUUID()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Versionable : VersionableId {
|
||||||
|
override val versionId: UUID
|
||||||
|
val versionNumber: Int
|
||||||
|
|
||||||
|
class Imp(
|
||||||
|
override val versionNumber: Int,
|
||||||
|
versionId: UUID? = null,
|
||||||
|
) : Versionable {
|
||||||
|
override val versionId: UUID = versionId ?: UUID.randomUUID()
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/main/kotlin/fr/dcproject/common/response/Paginated.kt
Normal file
16
src/main/kotlin/fr/dcproject/common/response/Paginated.kt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package fr.dcproject.common.response
|
||||||
|
|
||||||
|
import fr.dcproject.common.entity.EntityI
|
||||||
|
import fr.postgresjson.connexion.Paginated
|
||||||
|
|
||||||
|
fun <E : EntityI> Paginated<E>.toOutput(setup: (E) -> Any): Any {
|
||||||
|
return object {
|
||||||
|
val count = this@toOutput.count
|
||||||
|
val currentPage = this@toOutput.count
|
||||||
|
val limit = this@toOutput.limit
|
||||||
|
val offset = this@toOutput.offset
|
||||||
|
val total = this@toOutput.total
|
||||||
|
val totalPages = this@toOutput.totalPages
|
||||||
|
val result = this@toOutput.result.map { setup(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/main/kotlin/fr/dcproject/common/response/createdBy.kt
Normal file
21
src/main/kotlin/fr/dcproject/common/response/createdBy.kt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package fr.dcproject.common.response
|
||||||
|
|
||||||
|
import fr.dcproject.component.citizen.database.CitizenCreatorI
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
fun CitizenCreatorI.toOutput(): Any = this.let { c ->
|
||||||
|
object {
|
||||||
|
val id: UUID = c.id
|
||||||
|
val name: Any = c.name.let { n ->
|
||||||
|
object {
|
||||||
|
val firstName: String = n.firstName
|
||||||
|
val lastName: String = n.lastName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val user: Any = c.user.let { u ->
|
||||||
|
object {
|
||||||
|
val username: String = u.username
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package fr.dcproject.common.security
|
||||||
|
|
||||||
|
/** Responses of AccessControl */
|
||||||
|
enum class AccessDecision {
|
||||||
|
GRANTED,
|
||||||
|
DENIED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert decision to boolean
|
||||||
|
*/
|
||||||
|
fun toBoolean(): Boolean = when (this) {
|
||||||
|
GRANTED -> true
|
||||||
|
DENIED -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class AccessControl {
|
||||||
|
/**
|
||||||
|
* A Shortcut for return a GrantedResponse
|
||||||
|
*/
|
||||||
|
protected fun granted(message: String? = null, code: String? = null): GrantedResponse = GrantedResponse(this, message, code)
|
||||||
|
/**
|
||||||
|
* A Shortcut for return a DeniedResponse
|
||||||
|
*/
|
||||||
|
protected fun denied(message: String, code: String): DeniedResponse = DeniedResponse(this, message, code)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check all responses and return DENIED if one is DENIED
|
||||||
|
*
|
||||||
|
* If the list of responses is empty, return GRANTED
|
||||||
|
*/
|
||||||
|
private fun AccessResponses.getOneResponse(): AccessResponse = this.firstOrNull { it.decision == AccessDecision.DENIED } ?: granted()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An helper to convert a list of subject into one response
|
||||||
|
*/
|
||||||
|
protected fun <S : List<T>, T> canAll(items: S, action: (T) -> AccessResponse): AccessResponse = items
|
||||||
|
.map { action(it) }
|
||||||
|
.getOneResponse()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throw an Exception if AccessControl return a DENIED response
|
||||||
|
*/
|
||||||
|
fun <T : AccessControl> T.assert(action: T.() -> AccessResponse) {
|
||||||
|
action().assert()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check all responses and return DENIED if one is DENIED
|
||||||
|
*
|
||||||
|
* If the list of responses is empty, return GRANTED
|
||||||
|
*/
|
||||||
|
fun AccessResponses.getOneResponse(): AccessResponse = this.firstOrNull { it.decision == AccessDecision.DENIED } ?: GrantedResponse(first().accessControl)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throw an Exception if one response is DENIED
|
||||||
|
*/
|
||||||
|
fun AccessResponses.assert() = this.getOneResponse().assert()
|
||||||
|
|
||||||
|
class AccessDeniedException(private val accessResponses: AccessResponses) : Throwable(accessResponses.first().message) {
|
||||||
|
constructor(accessResponse: AccessResponse) : this(listOf(accessResponse))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get first response
|
||||||
|
*/
|
||||||
|
fun first(): AccessResponse = accessResponses.first()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the error code is present into the responses
|
||||||
|
*/
|
||||||
|
fun hasErrorCode(code: String): Boolean = accessResponses
|
||||||
|
.filter { it.decision == AccessDecision.DENIED }
|
||||||
|
.any { it.code == code }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find and return the response than match with the error code
|
||||||
|
*/
|
||||||
|
fun getErrorCode(code: String): AccessResponse? = accessResponses
|
||||||
|
.firstOrNull { it.decision == AccessDecision.DENIED && it.code == code }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of messages of all responses
|
||||||
|
*/
|
||||||
|
fun getMessages(): List<String> = accessResponses
|
||||||
|
.mapNotNull { it.message }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first message
|
||||||
|
*/
|
||||||
|
fun getFirstMessage(): String? = accessResponses
|
||||||
|
.first()
|
||||||
|
.message
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The response that all AccessControl method return
|
||||||
|
* @see GrantedResponse
|
||||||
|
* @see DeniedResponse
|
||||||
|
*/
|
||||||
|
sealed class AccessResponse(
|
||||||
|
val decision: AccessDecision,
|
||||||
|
val accessControl: AccessControl,
|
||||||
|
val message: String?,
|
||||||
|
val code: String?
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* Convert response as boolean
|
||||||
|
*/
|
||||||
|
fun toBoolean(): Boolean = decision.toBoolean()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throw Exception if response if DENIED
|
||||||
|
*/
|
||||||
|
fun assert() {
|
||||||
|
if (this.decision == AccessDecision.DENIED) {
|
||||||
|
throw AccessDeniedException(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GrantedResponse(
|
||||||
|
accessControl: AccessControl,
|
||||||
|
message: String? = null,
|
||||||
|
code: String? = null
|
||||||
|
) : AccessResponse(AccessDecision.GRANTED, accessControl, message, code)
|
||||||
|
|
||||||
|
class DeniedResponse(
|
||||||
|
accessControl: AccessControl,
|
||||||
|
message: String,
|
||||||
|
code: String
|
||||||
|
) : AccessResponse(AccessDecision.DENIED, accessControl, message, code)
|
||||||
|
|
||||||
|
typealias AccessResponses = List<AccessResponse>
|
||||||
6
src/main/kotlin/fr/dcproject/common/utils/DateTime.kt
Normal file
6
src/main/kotlin/fr/dcproject/common/utils/DateTime.kt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package fr.dcproject.common.utils
|
||||||
|
|
||||||
|
import org.joda.time.DateTime
|
||||||
|
import org.joda.time.format.ISODateTimeFormat
|
||||||
|
|
||||||
|
fun DateTime.toIso(): String = ISODateTimeFormat.dateTime().print(this)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package fr.dcproject.utils
|
package fr.dcproject.common.utils
|
||||||
|
|
||||||
import com.jayway.jsonpath.JsonPath
|
import com.jayway.jsonpath.JsonPath
|
||||||
import com.jayway.jsonpath.PathNotFoundException
|
import com.jayway.jsonpath.PathNotFoundException
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package fr.dcproject.utils
|
package fr.dcproject.common.utils
|
||||||
|
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
@@ -6,5 +6,5 @@ import kotlin.properties.ReadOnlyProperty
|
|||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
internal class LoggerDelegate<in R : Any> : ReadOnlyProperty<R, Logger> {
|
internal class LoggerDelegate<in R : Any> : ReadOnlyProperty<R, Logger> {
|
||||||
override fun getValue(thisRef: R, property: KProperty<*>) = LoggerFactory.getLogger(thisRef.javaClass.packageName)
|
override fun getValue(thisRef: R, property: KProperty<*>): Logger = LoggerFactory.getLogger(thisRef.javaClass.packageName)
|
||||||
}
|
}
|
||||||
27
src/main/kotlin/fr/dcproject/common/utils/Request.kt
Normal file
27
src/main/kotlin/fr/dcproject/common/utils/Request.kt
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package fr.dcproject.common.utils
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException
|
||||||
|
import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException
|
||||||
|
import io.ktor.application.ApplicationCall
|
||||||
|
import io.ktor.application.log
|
||||||
|
import io.ktor.features.BadRequestException
|
||||||
|
import io.ktor.request.receive
|
||||||
|
import kotlin.reflect.typeOf
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives content for this request.
|
||||||
|
* @param type instance of `KClass` specifying type to be received.
|
||||||
|
* @return instance of [T] received from this call, or `null` if content cannot be transformed to the requested type..
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
public suspend inline fun <reified T : Any> ApplicationCall.receiveOrBadRequest(message: String = "Bad Request, wrong body request"): T {
|
||||||
|
return try {
|
||||||
|
receive<T>(typeOf<T>())
|
||||||
|
} catch (cause: MissingKotlinParameterException) {
|
||||||
|
application.log.debug("Conversion failed, throw bad exception", cause)
|
||||||
|
throw BadRequestException(message, cause)
|
||||||
|
} catch (cause: UnrecognizedPropertyException) {
|
||||||
|
application.log.debug("Conversion failed, throw bad exception", cause)
|
||||||
|
throw BadRequestException(message, cause)
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/main/kotlin/fr/dcproject/common/utils/Resources.kt
Normal file
15
src/main/kotlin/fr/dcproject/common/utils/Resources.kt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package fr.dcproject.common.utils
|
||||||
|
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
fun String.readResource(callback: (String) -> Unit = {}): String {
|
||||||
|
val content = callback::class.java.getResource(this)?.readText() ?: error("File not found")
|
||||||
|
callback(content)
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.getResource(callback: (URL) -> Unit = {}): URL {
|
||||||
|
val content = callback::class.java.getResource(this) ?: error("File not found")
|
||||||
|
callback(content)
|
||||||
|
return content
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package fr.dcproject.utils
|
package fr.dcproject.common.utils
|
||||||
|
|
||||||
import java.util.*
|
import java.util.UUID
|
||||||
|
|
||||||
fun String.toUUID(): UUID = UUID.fromString(this.trim())
|
fun String.toUUID(): UUID = UUID.fromString(this.trim())
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user