diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..ff65085d --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,68 @@ +#!/usr/bin/env groovy +pipeline { + agent { label 'docker' } + + environment { + MAVEN_IMAGE = 'maven:3.8-openjdk-17-slim' + DOCKER_BUILDKIT = '1' + PROJECT_TITLE = 'TCDI Admin' + REPO = 'registry.developmentgateway.org/' + } + + stages { + + stage('Compile') { + steps { + script { + def args = "-e JAVA_TOOL_OPTIONS=-Duser.home=$WORKSPACE_TMP" + withDockerContainer(image: env.MAVEN_IMAGE, args: args) { + // TODO: checkstyle + sh 'mvn -B clean package -DskipTests -Dcheckstyle.skip && mkdir forms/target/deps' + dir('forms/target/deps') { + sh 'jar -xf ../*.jar' + } + } + } + } + } // Compile + + stage('Package & Publish') { + steps { + script { + def tag = ['main', 'master'].contains(env.BRANCH_NAME) ? + 'latest' : + env.BRANCH_NAME.replaceAll('[^\\p{Alnum}-_]', '_').toLowerCase() + withEnv(["TAG=$tag"]) { + def dc = 'docker-compose' + sh "$dc build admin && $dc push admin" + } + } + } + } // Package & Publish + + stage('Deploy') { + when { branch 'develop' } + agent { label 'ansible' } + steps { + script { + def tag = ['main', 'master'].contains(env.BRANCH_NAME) ? + 'latest' : + env.BRANCH_NAME.replaceAll('[^\\p{Alnum}-_]', '_').toLowerCase() + ansiblePlaybook( + credentialsId: 'Deploy', + become: true, + playbook: 'deploy.yml', + skippedTags: 'provision', + extraVars: [ + project_title: env.PROJECT_TITLE, + repo: env.REPO, + tag: tag, + pull: "true" + ] + ) + } // script + } // steps + } + + } // stages +} diff --git a/README.md b/README.md index d61ed239..0fedd451 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# dg-toolkit +# tcdi-admin based on dg-toolkit [![Build Status](https://travis-ci.org/devgateway/dg-toolkit.svg?branch=master)](https://travis-ci.org/devgateway/dg-toolkit) @@ -113,7 +113,7 @@ frolvlad/alpine-oraclejdk8 slim 00d8610f052e 2 weeks ago The image can be started with ``` -$docker run -p 8090:8090 -t devgateway/toolkit/forms +$docker run -p 8080:8080 -t devgateway/toolkit/forms ``` That's it, congrats! diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml index 86fcf6c4..0a8e36a1 100644 --- a/checkstyle-suppressions.xml +++ b/checkstyle-suppressions.xml @@ -7,6 +7,8 @@ + + \ No newline at end of file diff --git a/checkstyle.xml b/checkstyle.xml index 7416a841..3d334b4b 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -10,12 +10,13 @@ --> + + + - - @@ -43,10 +44,7 @@ - - - - + @@ -58,6 +56,7 @@ + @@ -97,12 +96,12 @@ - + @@ -112,12 +111,11 @@ - + - diff --git a/checkstyle/.gitignore b/checkstyle/.gitignore deleted file mode 100644 index b83d2226..00000000 --- a/checkstyle/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target/ diff --git a/checkstyle/pom.xml b/checkstyle/pom.xml deleted file mode 100644 index fc9c04af..00000000 --- a/checkstyle/pom.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - 4.0.0 - - checkstyle - org.devgateway.toolkit - 1.0 - - - UTF-8 - 8 - 8 - 3.0.0 - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - ${maven-checkstyle-plugin.version} - - - - diff --git a/checkstyle/src/main/java/org/devgateway/toolkit/checks/CachableQueryAnnotationCheck.java b/checkstyle/src/main/java/org/devgateway/toolkit/checks/CachableQueryAnnotationCheck.java deleted file mode 100644 index 1671cdfd..00000000 --- a/checkstyle/src/main/java/org/devgateway/toolkit/checks/CachableQueryAnnotationCheck.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.devgateway.toolkit.checks; - -import com.puppycrawl.tools.checkstyle.api.AbstractCheck; -import com.puppycrawl.tools.checkstyle.api.DetailAST; -import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.utils.AnnotationUtility; - -/** - * Checks that the methods of all classes annotated with @CacheableHibernateQueryResult - * are explicitly annotated to cache or not the query result. - * - * Anytime a new method is defined this will catch a potential missing caching definition. - * - * @author Nadejda Mandrescu - */ -public class CachableQueryAnnotationCheck extends AbstractCheck { - private static final String ERROR_MESSAGE = - "@CacheableHibernateQueryResult must annotate its methods explicitly either with " + - "@CacheHibernateQueryResult or @NoCacheHibernateQueryResult"; - - @Override - public int[] getDefaultTokens() { - return new int[]{TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF}; - } - - @Override - public void visitToken(DetailAST ast) { - if (AnnotationUtility.containsAnnotation(ast, "CacheableHibernateQueryResult")) { - DetailAST objBlock = ast.findFirstToken(TokenTypes.OBJBLOCK); - DetailAST methodDef = objBlock.findFirstToken(TokenTypes.METHOD_DEF); - while (methodDef != null) { - if (methodDef.getType() == TokenTypes.METHOD_DEF) { - if (!(AnnotationUtility.containsAnnotation(methodDef, "CacheHibernateQueryResult") - || AnnotationUtility.containsAnnotation(methodDef, "NoCacheHibernateQueryResult"))) { - log(methodDef.getLineNo(), ERROR_MESSAGE); - } - } - methodDef = methodDef.getNextSibling(); - } - } - } -} diff --git a/checkstyle/src/main/resources/packagenames.xml b/checkstyle/src/main/resources/packagenames.xml deleted file mode 100644 index bb173ad8..00000000 --- a/checkstyle/src/main/resources/packagenames.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - diff --git a/deploy.yml b/deploy.yml new file mode 100644 index 00000000..48de8636 --- /dev/null +++ b/deploy.yml @@ -0,0 +1,84 @@ +--- +- name: Deploy + hosts: + - "{{ project_title | regex_replace('[^\\w_]', '_') | lower }}_{{ tag }}" + vars: + product: "{{ project_title | regex_replace('[^\\w_]', '_') | lower }}" + systemd_service: + Unit.Description: "{{ project_title }}" + Unit.After: docker.socket docker.service + Unit.BindsTo: docker.socket docker.service + Install.WantedBy: multi-user.target + Service.Type: exec + Service.ExecStart: /usr/bin/docker-compose --no-ansi up + Service.WorkingDirectory: "/opt/devgateway/{{ product }}" + Service.Environment: "TAG={{ tag }} REPO={{ repo }}" + + tasks: + + - name: Install packages + ansible.builtin.package: + name: + - firewalld + - docker-compose + tags: + - provision + + - name: Open firewall ports + ansible.posix.firewalld: + service: http + state: enabled + permanent: true + immediate: true + zone: public + tags: + - provision + + - name: Configure Systemd unit + community.general.ini_file: + path: /etc/systemd/system/{{ product }}.service + create: true + no_extra_spaces: true + section: "{{ item.key.split('.')[0] }}" + option: "{{ item.key.split('.')[1] }}" + value: "{{ item.value }}" + loop: "{{ systemd_service | dict2items }}" + loop_control: + label: "{{ item.key }}" + notify: + - Reload Systemd + + - name: Install Compose file + ansible.builtin.copy: + src: docker-compose.yml + dest: "{{ systemd_service['Service.WorkingDirectory'] }}/" + notify: + - Restart stack + + - name: Update images + ansible.builtin.command: + chdir: "{{ systemd_service['Service.WorkingDirectory'] }}" + cmd: /usr/bin/docker-compose pull --quiet + environment: + TAG: "{{ tag }}" + REPO: "{{ repo }}" + notify: + - Restart stack + when: pull | default(false) + + - name: Enable Compose service + ansible.builtin.service: + name: "{{ product }}" + enabled: true + state: started + + handlers: + + - name: Reload Systemd + ansible.builtin.systemd: + daemon_reload: true + + - name: Restart stack + ansible.builtin.service: + name: "{{ product }}" + state: restarted diff --git a/dev_services.bat b/dev_services.bat new file mode 100644 index 00000000..e20c201f --- /dev/null +++ b/dev_services.bat @@ -0,0 +1,3 @@ +set TAG=staging + +docker-compose up postgres admin \ No newline at end of file diff --git a/dev_services.sh b/dev_services.sh new file mode 100644 index 00000000..cee88436 --- /dev/null +++ b/dev_services.sh @@ -0,0 +1,2 @@ +set TAG=staging +docker-compose up postgres admin \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 00000000..58ac7b02 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,35 @@ +#!/bin/sh + + + PROP_FILE="tcdi-admin.properties" + echo "Writing to $PROP_FILE:" + + PROPERTIES="$(cat <<-EOF + server.port + spring.application.name + spring.liquibase.enabled + spring.datasource.jdbc-url + spring.datasource.url + spring.mail.host + spring.jpa.hibernate.ddl-auto + EOF + )" + + env + + echo "$PROPERTIES" | while IFS=read PROPERTY; do + VAR_NAME="$(echo "$PROPERTY" | tr '[:lower:].-' '[:upper:]__')" + eval VALUE="\$$VAR_NAME" + if [ -n "$VALUE" ]; then + echo "$PROPERTY=$VALUE" + fi + done | tee -a "$PROP_FILE" + + JAR="tcdi-admin-forms-0.0.1-SNAPSHOT.jar" + JAVA_OPTS="-Dspring.config.location=file://$PROP_FILE" + #exec /bin/sh -c "java -jar '$JAR' $JAVA_OPTS $@" nobody + exec /bin/bash + ;; +*) + exec $@ + ;; \ No newline at end of file diff --git a/forms/Dockerfile b/forms/Dockerfile new file mode 100644 index 00000000..71b58f2b --- /dev/null +++ b/forms/Dockerfile @@ -0,0 +1,10 @@ +FROM openjdk:17-jdk-slim +WORKDIR /opt/devgateway/tcdi/admin +COPY target/deps/BOOT-INF/lib lib +COPY target/deps/META-INF META-INF +COPY entrypoint.sh ./ +COPY target/deps/BOOT-INF/classes . +#USER nobody +EXPOSE 8080 +ENTRYPOINT ["/opt/devgateway/tcdi/admin/entrypoint.sh"] +CMD ["admin"] diff --git a/forms/entrypoint.sh b/forms/entrypoint.sh new file mode 100755 index 00000000..ce870333 --- /dev/null +++ b/forms/entrypoint.sh @@ -0,0 +1,37 @@ +#!/bin/bash + + PROP_FILE="/etc/$1.properties" + truncate -s 0 $PROP_FILE + echo "..................... Writing to $PROP_FILE: ............... " + + while IFS='=' read -r -d '' n v; do + if [[ $n == SPRING* ]]; then + VAR_NAME="$(echo "$n" | tr '[:upper:]_' '[:lower:].')" + echo "$VAR_NAME=$v" >> $PROP_FILE + fi + done < <(env -0) + + while IFS='=' read -r -d '' n v; do + if [[ $n == TCDI_* ]]; then + VAR_NAME="$(echo "$n" | tr '[:upper:]_' '[:lower:].' | cut -c 6-)" + echo "$VAR_NAME=$v" >> $PROP_FILE + fi + done < <(env -0) + + + echo "................. Properties ................." + cat $PROP_FILE + echo "................. End sou ................." + JAVA_ARGS="$(tr '\n' ' ' <<-EOF + -cp .:lib/* + org.devgateway.toolkit.forms.wicket.FormsWebApplication + EOF + )" + + JAVA_OPTS="-Dspring.config.location=file://$PROP_FILE" + exec java $JAVA_ARGS $JAVA_OPTS $@ nobody + ;; +*) + exec $@ + ;; + diff --git a/forms/pom.xml b/forms/pom.xml index a98d10a9..2f1c3553 100644 --- a/forms/pom.xml +++ b/forms/pom.xml @@ -15,36 +15,40 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - forms + tcdi-admin-forms jar Wicket Forms - DGToolkit Forms + TCDI Admin Forms - org.devgateway.toolkit - toolkit + org.devgateway.tcdi + tcdi-admin 0.0.1-SNAPSHOT UTF-8 - 1.8 - 8.10.0 - 8.10.0 - 2.0.11 - 1.13 - 2.0.19 - v20200406 - 3.1 + 17 + 10.2.0 + 10.0.0 + 5.0.4 + 4.0.4 + 1.17 + 3.0.3 + v20240317 + 3.3.0 2.4.8 - 1.86.0 + 2.2.0 + 6.5.2 + 3.1.9 + 4.1.3 - org.devgateway.toolkit - persistence + org.devgateway.tcdi + tcdi-admin-persistence 0.0.1-SNAPSHOT @@ -55,49 +59,15 @@ - org.springframework.boot - spring-boot-devtools - true - - - - org.devgateway.toolkit - persistence-mongodb - 0.0.1-SNAPSHOT - - - - org.devgateway.toolkit - ui - 0.0.1-SNAPSHOT - - - - - - - - - - - - - - - - - - - - org.devgateway.toolkit - web + org.devgateway.tcdi + tcdi-admin-web 0.0.1-SNAPSHOT com.thoughtworks.xstream xstream - 1.4.18 + 1.4.20 @@ -177,6 +147,12 @@ ${wicket.webjars.version} + + org.webjars + font-awesome + ${font.awesome.version} + + org.apache.wicket wicket-devutils @@ -189,6 +165,12 @@ ${wicketstuff.version} + + org.wicketstuff + wicketstuff-editable-grid + ${wicketstuff.version} + + org.apache.wicket @@ -261,7 +243,7 @@ de.agilecoders.wicket wicket-bootstrap-less - ${wicket.bootstrap.version} + ${wicket.bootstrap.less.version} @@ -278,14 +260,97 @@ org.apache.tika tika-core - 2.0.0 + 3.0.0 org.apache.tika tika-parsers - 2.0.0 + 3.0.0 pom + + + org.glassfish.jersey.core + jersey-client + ${jersey.version} + + + + org.glassfish.jersey.core + jersey-common + ${jersey.version} + + + org.glassfish.jersey.inject + jersey-hk2 + ${jersey.version} + + + org.glassfish.jersey.media + jersey-media-json-jackson + ${jersey.version} + + + org.glassfish.jersey.media + jersey-media-multipart + ${jersey.version} + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + ${netflix.eureka.version} + + + org.glassfish.jersey.core + jersey-client + + + + org.glassfish.jersey.core + jersey-common + + + + org.glassfish.jersey.inject + jersey-hk2 + + + org.glassfish.jersey.media + jersey-media-json-jackson + + + org.glassfish.jersey.media + jersey-media-multipart + + + + + + com.sun.mail + jakarta.mail + 2.0.1 + + + + jakarta.servlet + jakarta.servlet-api + 6.1.0 + provided + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.springframework.boot + spring-boot-starter-jersey + 3.3.4 + @@ -366,10 +431,17 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + 3.11.0 ${java.version} ${java.version} + + + org.hibernate.orm + hibernate-jpamodelgen + ${hibernate.version} + + @@ -378,6 +450,13 @@ + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/EurekaClientConfig.java b/forms/src/main/java/org/devgateway/toolkit/forms/EurekaClientConfig.java new file mode 100644 index 00000000..2256c2b7 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/EurekaClientConfig.java @@ -0,0 +1,31 @@ +package org.devgateway.toolkit.forms; + +import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs; +import com.netflix.discovery.shared.transport.jersey.TransportClientFactories; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.SearchStrategy; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier; +import org.springframework.cloud.netflix.eureka.http.RestTemplateDiscoveryClientOptionalArgs; +import org.springframework.cloud.netflix.eureka.http.RestTemplateTransportClientFactories; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@EnableDiscoveryClient +@Configuration +public class EurekaClientConfig { + @Bean + @ConditionalOnClass(name = { "org.springframework.web.client.RestTemplate", "org.glassfish.jersey.client.JerseyClient" }) + @ConditionalOnMissingBean(value = { AbstractDiscoveryClientOptionalArgs.class }, search = SearchStrategy.CURRENT) + public RestTemplateDiscoveryClientOptionalArgs restTemplateDiscoveryClientOptionalArgs(EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) { + return new RestTemplateDiscoveryClientOptionalArgs(eurekaClientHttpRequestFactorySupplier); + } + + @Bean + @ConditionalOnClass(name = { "org.springframework.web.client.RestTemplate", "org.glassfish.jersey.client.JerseyClient" }) + @ConditionalOnMissingBean(value = { TransportClientFactories.class }, search = SearchStrategy.CURRENT) + public RestTemplateTransportClientFactories restTemplateTransportClientFactories(RestTemplateDiscoveryClientOptionalArgs optionalArgs) { + return new RestTemplateTransportClientFactories(optionalArgs); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/FormsSecurityConfig.java b/forms/src/main/java/org/devgateway/toolkit/forms/FormsSecurityConfig.java index 9b97fa58..6ca51b71 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/FormsSecurityConfig.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/FormsSecurityConfig.java @@ -13,23 +13,29 @@ import org.devgateway.toolkit.persistence.spring.CustomJPAUserDetailsService; import org.devgateway.toolkit.web.spring.WebSecurityConfig; +import org.devgateway.toolkit.web.util.SettingsUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.RememberMeAuthenticationProvider; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices; import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices; -import static org.devgateway.toolkit.web.WebConstants.FORMS_BASE_PATH; +import java.util.Arrays; +import java.util.stream.Collectors; @Configuration @EnableWebSecurity -@Order(1) // this ensures the forms security comes first +@Order(1) public class FormsSecurityConfig extends WebSecurityConfig { /** @@ -37,30 +43,32 @@ public class FormsSecurityConfig extends WebSecurityConfig { */ private static final String UNIQUE_SECRET_REMEMBER_ME_KEY = "secret"; - /** - * We ensure the superclass configuration is being applied Take note the - * {@link FormsSecurityConfig} extends {@link WebSecurityConfig} which has - * configuration for the dg-toolkit/web module. We then apply ant matchers - * and ignore security for css/js/images resources, and wicket mounted - * resources - */ - @Override - public void configure(final WebSecurity web) throws Exception { - super.configure(web); - web.ignoring().antMatchers("/img/**", "/css*/**", "/js*/**", "/assets*/**", "/favicon.ico", "/resources/**", - "/resources/public/**"); - web.ignoring().antMatchers( - FORMS_BASE_PATH + "/wicket/resource/**/*.js", - FORMS_BASE_PATH + "/wicket/resource/**/*.css", - FORMS_BASE_PATH + "/wicket/resource/**/*.png", - FORMS_BASE_PATH + "/wicket/resource/**/*.jpg", - FORMS_BASE_PATH + "/wicket/resource/**/*.woff", - FORMS_BASE_PATH + "/wicket/resource/**/*.woff2", - FORMS_BASE_PATH + "/wicket/resource/**/*.ttf", - FORMS_BASE_PATH + "/wicket/resource/**/*.svg", - FORMS_BASE_PATH + "/wicket/resource/**/*.gif"); + @Autowired + private SettingsUtils settingsUtils; + + @Autowired + protected CustomJPAUserDetailsService customJPAUserDetailsService; + + @Value("${allowedApiEndpoints}") + private String[] allowedApiEndpoints; + + @Value("${roleHierarchy}") + private String roleHierarchyStringRepresentation; + + @Autowired + private PasswordEncoder passwordEncoder; + + private String[] getAllowedAPIEndpointsWithBasePath() { + if (allowedApiEndpoints != null) { + return Arrays.stream(allowedApiEndpoints) + .map(s -> settingsUtils.getFormsBasePath() + s) + .collect(Collectors.toList()).toArray(new String[allowedApiEndpoints.length]); + } + + return new String[]{}; } + /** * This bean defines the same key in the * {@link RememberMeAuthenticationProvider} @@ -86,26 +94,52 @@ public AbstractRememberMeServices rememberMeServices() { return rememberMeServices; } - @Override - protected void configure(final HttpSecurity http) throws Exception { - super.configure(http); - - // we do not allow anyonymous token. When - // enabled this basically means any guest - // user will have an annoymous default role - http.anonymous().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER). - // we let Wicket create and manage sessions, so we disable - // session creation by spring - and().csrf().disable(); // csrf protection interferes with some - // wicket stuff - - // we enable http rememberMe cookie for autologin - // http.rememberMe().key(UNIQUE_SECRET_REMEMBER_ME_KEY); + /** + * We ensure the superclass configuration is being applied Take note the + * {@link FormsSecurityConfig} extends {@link WebSecurityConfig} which has + * configuration for the dg-toolkit/web module. We then apply ant matchers + * and ignore security for css/js/images resources, and wicket mounted + * resources + */ + @Bean + public SecurityFilterChain formsSecurityFilterChain(HttpSecurity http) throws Exception { + String formsBasePath = settingsUtils.getFormsBasePath(); - // resolved the error Refused to display * in a frame because it set - // 'X-Frame-Options' to 'DENY'. - http.headers().contentTypeOptions().and().xssProtection().and().cacheControl().and() - .httpStrictTransportSecurity().and().frameOptions().sameOrigin(); + http.securityContext(securityContext -> + securityContext.securityContextRepository(httpSessionSecurityContextRepository()) + ) + .authorizeHttpRequests(authz -> authz + .requestMatchers(formsBasePath + "/monitoring/**").hasRole("ADMIN") + .requestMatchers(formsBasePath + "/img/**", formsBasePath + "/css*/**", + formsBasePath + "/js*/**", formsBasePath + "/assets*/**", + formsBasePath + "/favicon.ico", formsBasePath + "/resources/**", + formsBasePath + "/resources/public/**", + formsBasePath + "/wicket/resource/**/*.js", formsBasePath + "/wicket/resource/**/*.css", + formsBasePath + "/wicket/resource/**/*.png", formsBasePath + "/wicket/resource/**/*.jpg", + formsBasePath + "/wicket/resource/**/*.woff", formsBasePath + "/wicket/resource/**/*.woff2", + formsBasePath + "/wicket/resource/**/*.ttf", formsBasePath + "/wicket/resource/**/*.svg", + formsBasePath + "/wicket/resource/**/*.gif", formsBasePath + "/forgotPassword/**" + ).permitAll() // Ignore static resources + .requestMatchers(formsBasePath + "/error/**", "/error/**").permitAll() + .requestMatchers(formsBasePath + "/**").authenticated() + ) + .formLogin(form -> + form.loginPage(formsBasePath + "/login").permitAll() + ) + .rememberMe(rememberMe -> + rememberMe.key(UNIQUE_SECRET_REMEMBER_ME_KEY).alwaysRemember(true) + ) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.NEVER)) + .csrf(csrf -> csrf.disable()) + .anonymous(anonymous -> anonymous.disable()) // Disable anonymous users + .headers(headers -> + headers.frameOptions(frameOptions -> frameOptions.sameOrigin()) + .contentTypeOptions(Customizer.withDefaults()) + .xssProtection(Customizer.withDefaults()) + .contentSecurityPolicy(csp -> csp.policyDirectives("script-src 'self'; style-src 'self'")) + .cacheControl(Customizer.withDefaults()) + ); + return http.build(); } } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/JavaMelodyConfiguration.java b/forms/src/main/java/org/devgateway/toolkit/forms/JavaMelodyConfiguration.java index 2d714e31..574aff10 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/JavaMelodyConfiguration.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/JavaMelodyConfiguration.java @@ -29,8 +29,8 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; -import javax.servlet.DispatcherType; -import javax.servlet.ServletContext; +import jakarta.servlet.DispatcherType; +import jakarta.servlet.ServletContext; import java.util.Arrays; import java.util.EventListener; import java.util.HashSet; diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/WarInitializer.java b/forms/src/main/java/org/devgateway/toolkit/forms/WarInitializer.java index ab641f75..a00580a0 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/WarInitializer.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/WarInitializer.java @@ -17,9 +17,8 @@ /** * Allows the app to deployed as Servlet 3.0 WAR - * - * @author mpostelnicu * + * @author mpostelnicu */ public class WarInitializer extends SpringBootServletInitializer { diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/WebConstants.java b/forms/src/main/java/org/devgateway/toolkit/forms/WebConstants.java index e2cae919..81a5eede 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/WebConstants.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/WebConstants.java @@ -26,7 +26,7 @@ private WebConstants() { } - public static final int PAGE_SIZE = 10; + public static final Integer DEFAULT_PAGE_SIZE = 20; public static final int SELECT_PAGE_SIZE = 25; public static final int PAGE_SIZE_NO_LIMIT = 999999; @@ -36,15 +36,25 @@ private WebConstants() { = "if(typeof disableFormLeavingConfirmation === 'function') disableFormLeavingConfirmation();"; public static final String PARAM_PRINT = "print"; + public static final String PARAM_YEAR = "year"; public static final String PARAM_ID = "id"; + + public static final String PARAM_SERVICE = "service"; + + public static final String PARAM_ENTITY = "entity"; public static final String V_POSITION = "vPosition"; public static final String MAX_HEIGHT = "maxPosition"; public static final String PARAM_REVISION_ID = "revisionId"; public static final String PARAM_ENTITY_CLASS = "class"; + public static final String PARAM_AUTO_SAVE = "autosave"; public static final String LANGUAGE_PARAM = "lang"; + public static final String SERVICE_DATA_TYPE = "data"; + + public static final String SERVICE_TETSIM_TYPE = "tetsim"; + public static final class StringValidators { public static final StringValidator MAXIMUM_LENGTH_VALIDATOR_STD_DEFAULT_TEXT = StringValidator.maximumLength(DBConstants.STD_DEFAULT_TEXT_LENGTH); @@ -54,6 +64,8 @@ public static final class StringValidators { StringValidator.maximumLength(DBConstants.MAX_DEFAULT_TEXT_AREA); } + public static final int MAXIMUM_PERCENTAGE = 100; + // add more languages here. It is pointless to make this dynamic because the // wicket i18n is in .properties files so we need // to change the src code anyway. diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/application-dev.properties b/forms/src/main/java/org/devgateway/toolkit/forms/application-dev.properties new file mode 100644 index 00000000..16915911 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/application-dev.properties @@ -0,0 +1,8 @@ +server.port = 8080 +eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/ +eureka.client.registerWithEureka=true +eureka.client.fetchRegistry=true +logging.level.org.springframework=DEBUG +eureka.instance.metadata-map.type=data + +spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/application.properties b/forms/src/main/java/org/devgateway/toolkit/forms/application.properties index 642e6623..2ccb1823 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/application.properties +++ b/forms/src/main/java/org/devgateway/toolkit/forms/application.properties @@ -10,10 +10,22 @@ # Development Gateway - initial API and implementation ############################################################################### spring.profiles.active=reports -server.port = 8090 +spring.application.name=tcdi-admin +server.port = 8080 server.servlet.session.timeout=7d -javamelody.enabled=true +javamelody.enabled=false javamelody.spring-monitoring-enabled=true javamelody.init-parameters.log=true javamelody.advisor-auto-proxy-creator-enabled=false spring.aop.proxy-target-class=true + +# The presence of either of those properties switches on the RemoteIpValve. +# This presence of valve will fix issue with reverse proxy +server.tomcat.remote-ip-header=x-forwarded-for +server.tomcat.protocol-header=x-forwarded-proto + +eureka.client.serviceUrl.defaultZone=http://eureka:8761/eureka/ +eureka.client.registerWithEureka=true +eureka.client.fetchRegistry=true + +spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/client/ClientConstants.java b/forms/src/main/java/org/devgateway/toolkit/forms/client/ClientConstants.java new file mode 100644 index 00000000..0ceccbe5 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/client/ClientConstants.java @@ -0,0 +1,29 @@ +package org.devgateway.toolkit.forms.client; + +public class ClientConstants { + + public static final class JobStatus { + public static final String COMPLETED = "COMPLETED"; + public static final String ERROR = "ERROR"; + } + + public final static String PATH_HEALTH = "/actuator/health"; + public final static String PATH_JOBS = "/admin/jobs"; + public final static String PATH_DATASETS = "/admin/datasets"; + + public final static String PATH_DIMENSIONS = "/admin/dimensions"; + + public final static String PATH_MEASURES = "/admin/measures"; + + public static final String PATH_CATEGORIES = "/admin/categories"; + + public final static String PATH_FILTERS = "/admin/filters"; + + public final static String PATH_TEMPLATE_DOWNLOAD = "/admin/template/download"; + + + public final static String PATH_CODE = "/code"; + + public final static String CODE_PREFIX = "tcdi-"; + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/client/DataSetClientException.java b/forms/src/main/java/org/devgateway/toolkit/forms/client/DataSetClientException.java new file mode 100644 index 00000000..8fb4642d --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/client/DataSetClientException.java @@ -0,0 +1,7 @@ +package org.devgateway.toolkit.forms.client; + +public class DataSetClientException extends Throwable { + public DataSetClientException(final String message) { + super(message); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/client/DatasetClient.java b/forms/src/main/java/org/devgateway/toolkit/forms/client/DatasetClient.java new file mode 100644 index 00000000..66514d9e --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/client/DatasetClient.java @@ -0,0 +1,219 @@ +package org.devgateway.toolkit.forms.client; + +import org.apache.commons.io.FileUtils; +import org.devgateway.toolkit.persistence.dao.data.Dataset; +import org.devgateway.toolkit.persistence.dto.ServiceDimension; +import org.devgateway.toolkit.persistence.dto.ServiceMeasure; +import org.glassfish.jersey.client.JerseyClient; +import org.glassfish.jersey.client.JerseyClientBuilder; +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; +import org.glassfish.jersey.media.multipart.FormDataMultiPart; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.glassfish.jersey.media.multipart.file.FileDataBodyPart; + +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.Response; +import java.io.File; +import java.io.IOException; +import java.util.List; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM; +import static jakarta.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE; +import static jakarta.ws.rs.core.MediaType.MULTIPART_FORM_DATA_TYPE; +import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN_TYPE; +import static jakarta.ws.rs.core.Response.Status.Family.SUCCESSFUL; +import static org.devgateway.toolkit.forms.client.ClientConstants.CODE_PREFIX; +import static org.devgateway.toolkit.forms.client.ClientConstants.PATH_CODE; +import static org.devgateway.toolkit.forms.client.ClientConstants.PATH_DATASETS; +import static org.devgateway.toolkit.forms.client.ClientConstants.PATH_DIMENSIONS; +import static org.devgateway.toolkit.forms.client.ClientConstants.PATH_HEALTH; +import static org.devgateway.toolkit.forms.client.ClientConstants.PATH_JOBS; +import static org.devgateway.toolkit.forms.client.ClientConstants.PATH_MEASURES; +import static org.devgateway.toolkit.forms.client.ClientConstants.PATH_TEMPLATE_DOWNLOAD; + + +public class DatasetClient { + + private final JerseyClient client; + + private final String baseUrl; + + public DatasetClient(final String baseUrl) { + this.baseUrl = baseUrl; + this.client = JerseyClientBuilder.createClient().register(MultiPartFeature.class); + } + + public DatasetJobStatus getDatasetStatus(String jobId) throws DataSetClientException { + if (isUp()) { + Response jobStatusResponse = client.target(baseUrl) + .path(PATH_JOBS) + .path(jobId) + .request(APPLICATION_JSON) + .get(); + + if (jobStatusResponse.getStatusInfo().getFamily() == SUCCESSFUL) { + return jobStatusResponse.readEntity(DatasetJobStatus.class); + } + + throw new DataSetClientException(jobStatusResponse.toString()); + } + + throw new RuntimeException(("Service is not up")); + } + + public DatasetJobStatus unpublishDataset(String code) throws DataSetClientException { + if (isUp()) { + Response jobStatusResponse = client.target(baseUrl) + .path(PATH_DATASETS) + .path(code) + .request() + .delete(); + + if (jobStatusResponse.getStatusInfo().getFamily() == SUCCESSFUL) { + return jobStatusResponse.readEntity(DatasetJobStatus.class); + } + + throw new DataSetClientException(jobStatusResponse.toString()); + } else { + throw new RuntimeException(("Service is not up")); + } + } + + public DatasetJobStatus publishDataset(Dataset dataset, byte[] datasetContent) throws DataSetClientException { + if (isUp()) { + File tempUploadFile; + try { + tempUploadFile = File.createTempFile(dataset.getYear() + "_tetsim", "csv"); + tempUploadFile.deleteOnExit(); + + FileUtils.writeByteArrayToFile(tempUploadFile, datasetContent); + FileDataBodyPart fileDataBodyPart = new FileDataBodyPart("file", tempUploadFile, APPLICATION_OCTET_STREAM_TYPE); + fileDataBodyPart.setContentDisposition(FormDataContentDisposition.name("file").fileName(tempUploadFile.getName()).build()); + + FormDataMultiPart multiPart = new FormDataMultiPart(); + multiPart.field("name", "TETSIM dataset " + dataset.getYear()); + multiPart.field("code", CODE_PREFIX + dataset.getId()); + multiPart.field("file", tempUploadFile.getName(), TEXT_PLAIN_TYPE) + .bodyPart(fileDataBodyPart); + + Response jobStatusResponse = client.target(baseUrl) + .path(PATH_DATASETS) + .request() + .post(Entity.entity(multiPart, MULTIPART_FORM_DATA_TYPE)); + + if (jobStatusResponse.getStatusInfo().getFamily() == SUCCESSFUL) { + return jobStatusResponse.readEntity(DatasetJobStatus.class); + } + + throw new DataSetClientException(jobStatusResponse.toString()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + throw new RuntimeException(("Service is not up")); + } + + public DatasetJobStatus publishDataset(String name, String code, File file) throws DataSetClientException { + if (isUp()) { + FileDataBodyPart fileDataBodyPart = new FileDataBodyPart("file", file, APPLICATION_OCTET_STREAM_TYPE); + fileDataBodyPart.setContentDisposition(FormDataContentDisposition.name("file") + .fileName(file.getName()) + .build()); + + FormDataMultiPart multiPart = new FormDataMultiPart(); + multiPart.field("name", name); + multiPart.field("code", code); + multiPart.field("file", file.getName(), TEXT_PLAIN_TYPE).bodyPart(fileDataBodyPart); + + Response jobStatusResponse = client.target(baseUrl) + .path(PATH_DATASETS) + .request() + .post(Entity.entity(multiPart, MULTIPART_FORM_DATA_TYPE)); + + if (jobStatusResponse.getStatusInfo().getFamily() == SUCCESSFUL) { + return jobStatusResponse.readEntity(DatasetJobStatus.class); + } + + throw new DataSetClientException(jobStatusResponse.toString()); + } + + throw new RuntimeException(("Service is not up")); + } + + public DatasetJobStatus getDatasetJobStatus(String code) { + Response jobStatusResponse = client.target(baseUrl) + .path(PATH_JOBS) + .path(PATH_CODE) + .path(code) + .request(APPLICATION_JSON).get(); + + if (jobStatusResponse.getStatusInfo().getFamily() == SUCCESSFUL) { + return jobStatusResponse.readEntity(DatasetJobStatus.class); + } + + return null; + } + + public boolean isUp() { + Response healthResponse = client.target(baseUrl).path(PATH_HEALTH) + .request(APPLICATION_JSON).get(); + + if (healthResponse.getStatusInfo().getFamily() == SUCCESSFUL) { + return healthResponse.readEntity(ServiceHealthStatus.class).isUp(); + } + + return false; + } + + public List getDimensions() { + if (isUp()) { + Response dimensionsResponse = client.target(baseUrl) + .path(PATH_DIMENSIONS) + .request(APPLICATION_JSON).get(); + + if (dimensionsResponse.getStatusInfo().getFamily() == SUCCESSFUL) { + return dimensionsResponse.readEntity(new GenericType>() {}); + } + + return null; + } + + throw new RuntimeException(("Service is not up")); + } + + public List getMeasures() { + if (isUp()) { + Response measuresResponse = client.target(baseUrl) + .path(PATH_MEASURES) + .request(APPLICATION_JSON).get(); + + if (measuresResponse.getStatusInfo().getFamily() == SUCCESSFUL) { + return measuresResponse.readEntity(new GenericType>() {}); + } + + return null; + } + + throw new RuntimeException(("Service is not up")); + } + + public byte[] getTemplateDownload() { + if (isUp()) { + Response response = client.target(baseUrl) + .path(PATH_TEMPLATE_DOWNLOAD) + .request(APPLICATION_OCTET_STREAM) + .get(); + + if (response.getStatusInfo().getFamily() == SUCCESSFUL) { + return response.readEntity(byte[].class); + } + + return null; + } + + throw new RuntimeException(("Service is not up")); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/client/DatasetJobStatus.java b/forms/src/main/java/org/devgateway/toolkit/forms/client/DatasetJobStatus.java new file mode 100644 index 00000000..6687724a --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/client/DatasetJobStatus.java @@ -0,0 +1,78 @@ +package org.devgateway.toolkit.forms.client; + +import java.time.ZonedDateTime; + +public class DatasetJobStatus { + + private Long id; + + private ZonedDateTime createdDate; + + private ZonedDateTime endDate; + + private String status; + + private String code; + + private String message; + + public Long getId() { + return id; + } + + public void setId(final Long id) { + this.id = id; + } + + public ZonedDateTime getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(final ZonedDateTime createdDate) { + this.createdDate = createdDate; + } + + public ZonedDateTime getEndDate() { + return endDate; + } + + public void setEndDate(final ZonedDateTime endDate) { + this.endDate = endDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(final String status) { + this.status = status; + } + + public String getCode() { + return code; + } + + public void setCode(final String code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(final String message) { + this.message = message; + } + + @Override + public String toString() { + return "DatasetJobStatus{" + + "id=" + id + + ", createdDate=" + createdDate + + ", endDate=" + endDate + + ", status='" + status + '\'' + + ", code='" + code + '\'' + + ", message='" + message + '\'' + + '}'; + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceCategoryClient.java b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceCategoryClient.java new file mode 100644 index 00000000..129e0471 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceCategoryClient.java @@ -0,0 +1,29 @@ +package org.devgateway.toolkit.forms.client; + +import org.devgateway.toolkit.persistence.dto.ServiceCategory; + +import jakarta.ws.rs.core.GenericType; +import java.util.List; + +public class ServiceCategoryClient extends ServiceEntityClient { + + public ServiceCategoryClient(final String baseUrl) { + super(baseUrl); + } + + @Override + public String getEntitiesPath() { + return ClientConstants.PATH_CATEGORIES; + } + + @Override + protected GenericType getGenericType() { + return new GenericType() {}; + } + + @Override + protected GenericType> getGenericListType() { + return new GenericType>() {}; + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceDatasetClient.java b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceDatasetClient.java new file mode 100644 index 00000000..fc02833c --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceDatasetClient.java @@ -0,0 +1,49 @@ +package org.devgateway.toolkit.forms.client; + +import org.devgateway.toolkit.persistence.dto.ServiceDataset; + +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.Response; +import java.util.List; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.Response.Status.Family.SUCCESSFUL; + +public class ServiceDatasetClient extends ServiceEntityClient { + + public ServiceDatasetClient(final String baseUrl) { + super(baseUrl); + } + + @Override + public String getEntitiesPath() { + return ClientConstants.PATH_DATASETS; + } + + @Override + protected GenericType getGenericType() { + return new GenericType() {}; + } + + @Override + protected GenericType> getGenericListType() { + return new GenericType>() {}; + } + + public void delete(final ServiceDataset entity) { + if (isUp()) { + Response response = client.target(baseUrl) + .path(getEntitiesPath()) + .path(entity.getCode().toString()) + .request(APPLICATION_JSON) + .delete(); + + if (response.getStatusInfo().getFamily() != SUCCESSFUL) { + throw new RuntimeException("Error in deleting the dataset"); + } + } else { + throw new RuntimeException(("Service is not up")); + } + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceDimensionClient.java b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceDimensionClient.java new file mode 100644 index 00000000..e5f4e06f --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceDimensionClient.java @@ -0,0 +1,29 @@ +package org.devgateway.toolkit.forms.client; + +import org.devgateway.toolkit.persistence.dto.ServiceDimension; + +import jakarta.ws.rs.core.GenericType; +import java.util.List; + +public class ServiceDimensionClient extends ServiceEntityClient { + + public ServiceDimensionClient(final String baseUrl) { + super(baseUrl); + } + + @Override + public String getEntitiesPath() { + return ClientConstants.PATH_DIMENSIONS; + } + + @Override + protected GenericType getGenericType() { + return new GenericType() {}; + } + + @Override + protected GenericType> getGenericListType() { + return new GenericType>() {}; + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceEntityClient.java b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceEntityClient.java new file mode 100644 index 00000000..7a1a5171 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceEntityClient.java @@ -0,0 +1,136 @@ +package org.devgateway.toolkit.forms.client; + +import jakarta.ws.rs.ProcessingException; +import org.devgateway.toolkit.persistence.dto.ServiceEntity; +import org.glassfish.jersey.client.JerseyClient; +import org.glassfish.jersey.client.JerseyClientBuilder; +import org.glassfish.jersey.media.multipart.MultiPartFeature; + +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.Response; +import java.util.List; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.Response.Status.Family.SUCCESSFUL; +import static org.devgateway.toolkit.forms.client.ClientConstants.PATH_HEALTH; + +public abstract class ServiceEntityClient { + + protected final JerseyClient client; + + protected final String baseUrl; + + public ServiceEntityClient(final String baseUrl) { + this.baseUrl = baseUrl; + this.client = JerseyClientBuilder.createClient(); + this.client.register(MultiPartFeature.class); + } + + public abstract String getEntitiesPath(); + + public List findAll() { + if (isUp()) { + Response response = client.target(baseUrl) + .path(getEntitiesPath()) + .request(APPLICATION_JSON).get(); + + if (response.getStatusInfo().getFamily() == SUCCESSFUL) { + return response.readEntity(getGenericListType()); + } + return null; + } + + throw new RuntimeException(("Service is not up")); + } + + public T findOne(final Long id) { + if (isUp()) { + Response response = client.target(baseUrl) + .path(getEntitiesPath()) + .path(id.toString()) + .request(APPLICATION_JSON).get(); + + if (response.getStatusInfo().getFamily() == SUCCESSFUL) { + return response.readEntity(getGenericType()); + } + + return null; + } + + throw new RuntimeException(("Service is not up")); + } + + public void save(final T entity) { + if (isUp()) { + Response measuresResponse = client.target(baseUrl) + .path(getEntitiesPath()) + .request(APPLICATION_JSON) + .post(Entity.entity(entity, APPLICATION_JSON)); + + if (measuresResponse.getStatusInfo().getFamily() != SUCCESSFUL) { + throw new RuntimeException("Error in updating the entity"); + } + } else { + throw new RuntimeException(("Service is not up")); + } + } + + public void update(final T entity) { + if (isUp()) { + Response measuresResponse = client.target(baseUrl) + .path(getEntitiesPath()) + .path(entity.getId().toString()) + .request(APPLICATION_JSON) + .put(Entity.entity(entity, APPLICATION_JSON)); + + if (measuresResponse.getStatusInfo().getFamily() != SUCCESSFUL) { + throw new RuntimeException("Error in updating the entity"); + } + } else { + throw new RuntimeException(("Service is not up")); + } + } + + public void delete(final T entity) { + if (isUp()) { + Response response = client.target(baseUrl) + .path(getEntitiesPath()) + .path(entity.getId().toString()) + .request(APPLICATION_JSON) + .delete(); + + if (response.getStatusInfo().getFamily() != SUCCESSFUL) { + throw new RuntimeException("Error in deleting the entity"); + } + } else { + throw new RuntimeException(("Service is not up")); + } + } + + public boolean isUp() { + try { + Response healthResponse = client.target(baseUrl).path(PATH_HEALTH) + .request(APPLICATION_JSON).get(); + + if (healthResponse.getStatusInfo().getFamily() == SUCCESSFUL) { + try { + // First try the direct mapping to ServiceHealthStatus + ServiceHealthStatus status = healthResponse.readEntity(ServiceHealthStatus.class); + return status.isUp(); + } catch (ProcessingException e) { + return false; + } + } + return false; + } catch (Exception e) { + System.err.println("Health check failed: " + e.getMessage()); + return false; + } + } + + protected abstract GenericType getGenericType(); + + protected abstract GenericType> getGenericListType(); + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceFilterClient.java b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceFilterClient.java new file mode 100644 index 00000000..6479a138 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceFilterClient.java @@ -0,0 +1,29 @@ +package org.devgateway.toolkit.forms.client; + +import org.devgateway.toolkit.persistence.dto.ServiceFilter; + +import jakarta.ws.rs.core.GenericType; +import java.util.List; + +public class ServiceFilterClient extends ServiceEntityClient { + + public ServiceFilterClient(final String baseUrl) { + super(baseUrl); + } + + @Override + public String getEntitiesPath() { + return ClientConstants.PATH_FILTERS; + } + + @Override + protected GenericType getGenericType() { + return new GenericType() {}; + } + + @Override + protected GenericType> getGenericListType() { + return new GenericType>() {}; + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceHealthStatus.java b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceHealthStatus.java new file mode 100644 index 00000000..f891db05 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceHealthStatus.java @@ -0,0 +1,21 @@ +package org.devgateway.toolkit.forms.client; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class ServiceHealthStatus { + + private String status; + + public String getStatus() { + return status; + } + + public void setStatus(final String status) { + this.status = status; + } + + public boolean isUp() { + return "UP".equalsIgnoreCase(status); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceMeasureClient.java b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceMeasureClient.java new file mode 100644 index 00000000..bc325d27 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/client/ServiceMeasureClient.java @@ -0,0 +1,29 @@ +package org.devgateway.toolkit.forms.client; + +import org.devgateway.toolkit.persistence.dto.ServiceMeasure; + +import jakarta.ws.rs.core.GenericType; +import java.util.List; + +public class ServiceMeasureClient extends ServiceEntityClient { + + public ServiceMeasureClient(final String baseUrl) { + super(baseUrl); + } + + @Override + public String getEntitiesPath() { + return ClientConstants.PATH_MEASURES; + } + + @Override + protected GenericType getGenericType() { + return new GenericType() {}; + } + + @Override + protected GenericType> getGenericListType() { + return new GenericType>() {}; + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/exceptions/NullEditPageClassException.java b/forms/src/main/java/org/devgateway/toolkit/forms/exceptions/NullEditPageClassException.java index 4252babd..ee95d617 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/exceptions/NullEditPageClassException.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/exceptions/NullEditPageClassException.java @@ -1,16 +1,16 @@ -/******************************************************************************* +/** * Copyright (c) 2015 Development Gateway, Inc and others. - * + *

* All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT - * + *

* Contributors: * Development Gateway - initial API and implementation - *******************************************************************************/ + */ /** - * + * */ package org.devgateway.toolkit.forms.exceptions; diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/exceptions/NullListPageClassException.java b/forms/src/main/java/org/devgateway/toolkit/forms/exceptions/NullListPageClassException.java index 496ee949..80281d27 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/exceptions/NullListPageClassException.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/exceptions/NullListPageClassException.java @@ -1,16 +1,16 @@ -/******************************************************************************* +/** * Copyright (c) 2015 Development Gateway, Inc and others. - * + *

* All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT - * + *

* Contributors: * Development Gateway - initial API and implementation - *******************************************************************************/ + */ /** - * + * */ package org.devgateway.toolkit.forms.exceptions; diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/exceptions/NullServiceEntityServiceException.java b/forms/src/main/java/org/devgateway/toolkit/forms/exceptions/NullServiceEntityServiceException.java new file mode 100644 index 00000000..05656e00 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/exceptions/NullServiceEntityServiceException.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015 Development Gateway, Inc and others. + *

+ * All rights reserved. This program and the accompanying materials + * are made available under the terms of the MIT License (MIT) + * which accompanies this distribution, and is available at + * https://opensource.org/licenses/MIT + *

+ * Contributors: + * Development Gateway - initial API and implementation + */ +/** + * + */ +package org.devgateway.toolkit.forms.exceptions; + +/** + * @author vchihai + */ +public class NullServiceEntityServiceException extends RuntimeException { + private static final long serialVersionUID = 7516874812755335131L; + + public NullServiceEntityServiceException() { + super("serviceEntityService is null! Please set the serviceEntityService in your constructor"); + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/models/SubComponentWrapModel.java b/forms/src/main/java/org/devgateway/toolkit/forms/models/SubComponentWrapModel.java index 194fe406..9de6bf91 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/models/SubComponentWrapModel.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/models/SubComponentWrapModel.java @@ -1,16 +1,16 @@ -/******************************************************************************* +/** * Copyright (c) 2015 Development Gateway, Inc and others. - * + *

* All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT - * + *

* Contributors: * Development Gateway - initial API and implementation - *******************************************************************************/ + */ /** - * + * */ package org.devgateway.toolkit.forms.models; diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/security/SecurityConstants.java b/forms/src/main/java/org/devgateway/toolkit/forms/security/SecurityConstants.java index 220de14d..774b518f 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/security/SecurityConstants.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/security/SecurityConstants.java @@ -1,16 +1,16 @@ -/******************************************************************************* +/** * Copyright (c) 2015 Development Gateway, Inc and others. - * + *

* All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT - * + *

* Contributors: * Development Gateway - initial API and implementation - *******************************************************************************/ + */ /** - * + * */ package org.devgateway.toolkit.forms.security; diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/DatasetClientService.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/DatasetClientService.java new file mode 100644 index 00000000..0bbfcd2c --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/DatasetClientService.java @@ -0,0 +1,130 @@ +package org.devgateway.toolkit.forms.service; + +import org.apache.commons.io.FileUtils; +import org.devgateway.toolkit.forms.client.DataSetClientException; +import org.devgateway.toolkit.forms.client.DatasetClient; +import org.devgateway.toolkit.persistence.dao.data.CSVDataset; +import org.devgateway.toolkit.persistence.dao.data.Dataset; +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.dto.ServiceMeasure; +import org.devgateway.toolkit.persistence.dto.ServiceMetadata; +import org.devgateway.toolkit.persistence.service.data.CSVDatasetService; +import org.devgateway.toolkit.persistence.service.data.TetsimDatasetService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static org.devgateway.toolkit.forms.client.ClientConstants.CODE_PREFIX; +import static org.devgateway.toolkit.forms.client.ClientConstants.JobStatus.COMPLETED; +import static org.devgateway.toolkit.forms.client.ClientConstants.JobStatus.ERROR; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.DRAFT; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.ERROR_IN_PUBLISHING; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.ERROR_IN_UNPUBLISHING; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.PUBLISHED; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.PUBLISHING; + +@Service +public class DatasetClientService { + + private static final Logger logger = LoggerFactory.getLogger(DatasetClientService.class); + + @Autowired + private TetsimDatasetService tetsimDatasetService; + + @Autowired + private CSVDatasetService csvDatasetService; + + @Autowired + private EurekaClientService eurekaClientService; + + @Scheduled(cron = "0 * * * * *") + public void triggerCheckDatasetsJob() { + logger.debug("Fired triggerCheckDatasetsJob"); + List datasets = new ArrayList<>(); + datasets.addAll(tetsimDatasetService.findAllInProgress()); + datasets.addAll(csvDatasetService.findAllInProgress()); + + checkDatasetJobs(datasets); + } + + private void checkDatasetJobs(List datasets) { + datasets.forEach(d -> { + ServiceMetadata serviceMetadata = eurekaClientService.findByName(d.getDestinationService()); + DatasetClient client = new DatasetClient(serviceMetadata.getUrl()); + String status = client.getDatasetJobStatus(CODE_PREFIX + d.getId()).getStatus(); + String initialStatus = d.getStatus(); + if (COMPLETED.equals(status)) { + String completedStatus = getCompletedStatus(initialStatus); + d.setStatus(completedStatus); + logger.info(String.format("The dataset with id %s changed the status from %s to %s", + d.getId(), initialStatus, completedStatus)); + } else if (ERROR.equals(status)) { + String errorStatus = getErrorStatus(initialStatus); + d.setStatus(errorStatus); + logger.info(String.format("The dataset with id %s changed the status from %s to %s", + d.getId(), initialStatus, errorStatus)); + } + + if (!initialStatus.equals(d.getStatus())) { + if (d instanceof TetsimDataset) { + tetsimDatasetService.save((TetsimDataset) d); + } else if (d instanceof CSVDataset) { + csvDatasetService.save((CSVDataset) d); + } else { + throw new RuntimeException("Invalid dataset class"); + } + } + }); + } + + private String getCompletedStatus(final String status) { + return PUBLISHING.equals(status) ? PUBLISHED : DRAFT; + } + + private String getErrorStatus(final String status) { + return PUBLISHING.equals(status) ? ERROR_IN_PUBLISHING : ERROR_IN_UNPUBLISHING; + } + + public void publishDataset(Dataset dataset, String fileName, byte[] content) throws DataSetClientException { + String serviceURL = getDestinationService(dataset).getUrl(); + DatasetClient client = new DatasetClient(serviceURL); + + String name = "Dataset " + dataset.getYear(); + String code = CODE_PREFIX + dataset.getId(); + + File tempUploadFile; + try { + tempUploadFile = File.createTempFile(fileName, null); + tempUploadFile.deleteOnExit(); + FileUtils.writeByteArrayToFile(tempUploadFile, content); + } catch (IOException e) { + throw new RuntimeException(e); + } + + client.publishDataset(name, code, tempUploadFile); + } + + public void unpublishDataset(Dataset dataset) throws DataSetClientException { + String code = CODE_PREFIX + dataset.getId(); + String serviceURL = getDestinationService(dataset).getUrl(); + + new DatasetClient(serviceURL).unpublishDataset(code); + } + + private ServiceMetadata getDestinationService(Dataset dataset) { + String destinationService = dataset.getDestinationService(); + return eurekaClientService.findByName(destinationService); + } + + public byte[] getTemplateDownload(final String serviceName) { + ServiceMetadata service = eurekaClientService.findByName(serviceName); + return new DatasetClient(service.getUrl()).getTemplateDownload(); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/DerbyDatabaseBackupService.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/DerbyDatabaseBackupService.java index 68a0026c..cd3065e6 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/service/DerbyDatabaseBackupService.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/DerbyDatabaseBackupService.java @@ -32,17 +32,15 @@ /** * @author mpostelnicu Provides built-in backup services. Defaults to the - * database location derby.system.home. Currently works only for Derby. - * Runs 9PM daily (good backup time for both EST and CET) + * database location derby.system.home. Currently works only for Derby. + * Runs 9PM daily (good backup time for both EST and CET) */ @Service public class DerbyDatabaseBackupService { - private static final Logger logger = LoggerFactory.getLogger(DerbyDatabaseBackupService.class); - public static final String DATABASE_PRODUCT_NAME_APACHE_DERBY = "Apache Derby"; public static final String ARCHIVE_SUFFIX = ".zip"; - + private static final Logger logger = LoggerFactory.getLogger(DerbyDatabaseBackupService.class); @Autowired private DataSource datasource; @@ -55,7 +53,6 @@ public class DerbyDatabaseBackupService { * use a cron format and invoke it every day at 21:00 server time. That * should be a good time for backup for both EST and CET */ - @Scheduled(cron = "0 0 21 * * ?") public void backupDatabase() { String databaseProductName; @@ -89,9 +86,8 @@ public void backupDatabase() { * last leaf of backup's location parent directory + {@link #databaseName} * If the backupPath does not have a parent, it uses the host name from * {@link InetAddress#getLocalHost()} - * - * @param backupPath - * the parent directory for the backup + * + * @param backupPath the parent directory for the backup * @return the backup url to be used by the backup procedure * @throws UnknownHostException */ @@ -121,7 +117,7 @@ private String createBackupURL(final String backupPath) { * Use backup.home system variable, if exists, as homedir for backups If * backup.home does not exist try using derby.system.home If that is also * null, use user.dir - * + * * @return the backupURL */ private String createBackupURL() { @@ -138,11 +134,11 @@ private String createBackupURL() { /** * Backup the On-Line Derby database. This temporarily locks the db in * readonly mode - * + *

* Invokes SYSCS_BACKUP_DATABASE and dumps the database to the temporary * directory Use {@link ZipUtil#pack(File, File)} to zip the directory * Deletes the temporary directory - * + * * @see #createBackupURL(String) */ private void backupDerbyDatabase() { diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/EurekaClientService.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/EurekaClientService.java new file mode 100644 index 00000000..e00b43fe --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/EurekaClientService.java @@ -0,0 +1,54 @@ +package org.devgateway.toolkit.forms.service; + +import com.netflix.appinfo.InstanceInfo; +import org.devgateway.toolkit.persistence.dto.ServiceMetadata; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.netflix.eureka.EurekaServiceInstance; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import static org.devgateway.toolkit.forms.WebConstants.SERVICE_DATA_TYPE; + +@Service +public class EurekaClientService { + + @Autowired + private DiscoveryClient discoveryClient; + + public List findAll() { + List services = new ArrayList<>(); + discoveryClient.getServices().forEach(s -> { + discoveryClient.getInstances(s).stream().forEach(instance -> { + InstanceInfo instanceInfo = ((EurekaServiceInstance) instance).getInstanceInfo(); + ServiceMetadata service = new ServiceMetadata(); + service.setName(instanceInfo.getAppName()); + service.setUrl(instanceInfo.getHomePageUrl()); + service.setId(instanceInfo.getId()); + service.setType(instance.getMetadata().getOrDefault("type", null)); + service.setLabel(instance.getMetadata().getOrDefault("label", instanceInfo.getAppName())); + service.setStatus(instanceInfo.getStatus().toString()); + service.setTetsim(Boolean.valueOf(instanceInfo.getMetadata().getOrDefault("tetsim", "false"))); + services.add(service); + }); + }); + + return services; + } + + public List findAllWithData() { + return findAll().stream() + .filter(s -> SERVICE_DATA_TYPE.equalsIgnoreCase(s.getType())) + .collect(Collectors.toList()); + } + + public ServiceMetadata findByName(String name) { + return findAll().stream() + .filter(s -> s.getName().equals(name)) + .findFirst().get(); + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/SendEmailService.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/SendEmailService.java index 06baf338..c9e24aae 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/service/SendEmailService.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/SendEmailService.java @@ -11,8 +11,13 @@ *******************************************************************************/ package org.devgateway.toolkit.forms.service; +import org.apache.commons.lang3.StringUtils; import org.devgateway.toolkit.persistence.dao.Person; +import org.devgateway.toolkit.persistence.service.AdminSettingsService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.mail.MailException; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; @@ -28,10 +33,20 @@ @Component public class SendEmailService { + private static final Logger logger = LoggerFactory.getLogger(SendEmailService.class); + + private final static String DEFAULT_EMAIL_FROM_ADDRESS = "tcdisupport@developmentgateway.org"; + + @Value("${spring.mail.sender}") + private String from; + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired private JavaMailSender javaMailSender; + @Autowired + private AdminSettingsService adminSettingsService; + private SimpleMailMessage templateMessage; /** @@ -43,19 +58,22 @@ public class SendEmailService { * @param newPassword */ public void sendEmailResetPassword(final Person person, final String newPassword) { + String country = adminSettingsService.get().getCountryName(); final SimpleMailMessage msg = new SimpleMailMessage(); + String fromEmail = StringUtils.isNotBlank(from) ? from : DEFAULT_EMAIL_FROM_ADDRESS; msg.setTo(person.getEmail()); - msg.setFrom("support@developmentgateway.org"); - msg.setSubject("Recover your password"); + msg.setFrom(fromEmail); + msg.setSubject("TCDI " + country + " - Recover your password"); msg.setText("Dear " + person.getFirstName() + " " + person.getLastName() + ",\n\n" - + "These are your new login credentials for DGToolkit.\n\n" + "Username: " + person.getUsername() + "\n" + + "These are your new login credentials for TCDI Admin " + country+ ".\n\n" + + "Username: " + person.getUsername() + "\n" + "Password: " + newPassword + "\n\n" + "At login, you will be prompted to change your password to one of your choice.\n\n" + "Thank you,\n" - + "DG Team"); + + "TCDI Team."); try { javaMailSender.send(msg); } catch (MailException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/SessionFinderService.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/SessionFinderService.java index 909253e0..c9f0ee71 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/service/SessionFinderService.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/SessionFinderService.java @@ -16,13 +16,13 @@ import org.hibernate.Session; import org.springframework.stereotype.Component; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; /** * Spring Service allowing access to hibernate session. This is needed by * {@link DozerModel} - * + * * @author mpostelnicu * @see DozerModel */ @@ -34,7 +34,7 @@ public class SessionFinderService implements SessionFinder { /* * (non-Javadoc) - * + * * @see * nl.dries.wicket.hibernate.dozer.SessionFinder#getHibernateSession(java * .lang.Class) diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/BaseServiceEntityService.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/BaseServiceEntityService.java new file mode 100644 index 00000000..60ff63ad --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/BaseServiceEntityService.java @@ -0,0 +1,28 @@ +package org.devgateway.toolkit.forms.service.admin; + +import org.devgateway.toolkit.persistence.dto.ServiceEntity; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.function.Predicate; + +@Service +public interface BaseServiceEntityService { + + List findAll(String serviceName); + + List findAll(String serviceName, Predicate spec); + + T findOne(String serviceName, Long id); + + void save(String serviceName, T entity); + + void update(String serviceName, T entity); + + void delete(String serviceName, T entity); + + long count(String serviceName); + + T newInstance(); + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/BaseServiceEntityServiceImpl.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/BaseServiceEntityServiceImpl.java new file mode 100644 index 00000000..7e82acf5 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/BaseServiceEntityServiceImpl.java @@ -0,0 +1,55 @@ +package org.devgateway.toolkit.forms.service.admin; + +import org.devgateway.toolkit.forms.client.ServiceEntityClient; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.persistence.dto.ServiceEntity; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public abstract class BaseServiceEntityServiceImpl implements BaseServiceEntityService { + + @Override + public List findAll(final String serviceName) { + return serviceEntityClient(serviceName).findAll(); + } + + @Override + public List findAll(final String serviceName, final Predicate spec) { + return findAll(serviceName).stream() + .filter(spec) + .collect(Collectors.toList()); + } + + @Override + public T findOne(final String serviceName, final Long id) { + return serviceEntityClient(serviceName).findOne(id); + } + + @Override + public void save(final String serviceName, final T entity) { + serviceEntityClient(serviceName).save(entity); + } + + public void update(final String serviceName, final T entity) { + serviceEntityClient(serviceName).update(entity); + } + + public void delete(final String serviceName, final T entity) { + serviceEntityClient(serviceName).delete(entity); + } + + @Override + public long count(String serviceName) { + return 0; + } + + @Override + public T newInstance() { + return null; + } + + protected abstract ServiceEntityClient serviceEntityClient(final String serviceName); +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceCategoryService.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceCategoryService.java new file mode 100644 index 00000000..0035bcdb --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceCategoryService.java @@ -0,0 +1,6 @@ +package org.devgateway.toolkit.forms.service.admin; + +import org.devgateway.toolkit.persistence.dto.ServiceCategory; + +public interface ServiceCategoryService extends BaseServiceEntityService { +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceCategoryServiceImpl.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceCategoryServiceImpl.java new file mode 100644 index 00000000..17999c89 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceCategoryServiceImpl.java @@ -0,0 +1,25 @@ +package org.devgateway.toolkit.forms.service.admin; + +import org.devgateway.toolkit.forms.client.ServiceCategoryClient; +import org.devgateway.toolkit.forms.client.ServiceEntityClient; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.persistence.dto.ServiceCategory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ServiceCategoryServiceImpl extends BaseServiceEntityServiceImpl implements ServiceCategoryService { + + @Autowired + private EurekaClientService eurekaClientService; + + @Override + public ServiceCategory newInstance() { + return new ServiceCategory(); + } + + @Override + protected ServiceEntityClient serviceEntityClient(final String serviceName) { + return new ServiceCategoryClient(eurekaClientService.findByName(serviceName).getUrl()); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceDatasetService.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceDatasetService.java new file mode 100644 index 00000000..e543ab7f --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceDatasetService.java @@ -0,0 +1,6 @@ +package org.devgateway.toolkit.forms.service.admin; + +import org.devgateway.toolkit.persistence.dto.ServiceDataset; + +public interface ServiceDatasetService extends BaseServiceEntityService { +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceDatasetServiceImpl.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceDatasetServiceImpl.java new file mode 100644 index 00000000..5625fb6d --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceDatasetServiceImpl.java @@ -0,0 +1,25 @@ +package org.devgateway.toolkit.forms.service.admin; + +import org.devgateway.toolkit.forms.client.ServiceDatasetClient; +import org.devgateway.toolkit.forms.client.ServiceEntityClient; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.persistence.dto.ServiceDataset; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ServiceDatasetServiceImpl extends BaseServiceEntityServiceImpl implements ServiceDatasetService { + + @Autowired + private EurekaClientService eurekaClientService; + + @Override + public ServiceDataset newInstance() { + return new ServiceDataset(); + } + + @Override + protected ServiceEntityClient serviceEntityClient(final String serviceName) { + return new ServiceDatasetClient(eurekaClientService.findByName(serviceName).getUrl()); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceDimensionService.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceDimensionService.java new file mode 100644 index 00000000..e27c371f --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceDimensionService.java @@ -0,0 +1,6 @@ +package org.devgateway.toolkit.forms.service.admin; + +import org.devgateway.toolkit.persistence.dto.ServiceDimension; + +public interface ServiceDimensionService extends BaseServiceEntityService { +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceDimensionServiceImpl.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceDimensionServiceImpl.java new file mode 100644 index 00000000..eef58eab --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceDimensionServiceImpl.java @@ -0,0 +1,25 @@ +package org.devgateway.toolkit.forms.service.admin; + +import org.devgateway.toolkit.forms.client.ServiceDimensionClient; +import org.devgateway.toolkit.forms.client.ServiceEntityClient; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.persistence.dto.ServiceDimension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ServiceDimensionServiceImpl extends BaseServiceEntityServiceImpl implements ServiceDimensionService { + + @Autowired + private EurekaClientService eurekaClientService; + + @Override + public ServiceDimension newInstance() { + return new ServiceDimension(); + } + + @Override + protected ServiceEntityClient serviceEntityClient(final String serviceName) { + return new ServiceDimensionClient(eurekaClientService.findByName(serviceName).getUrl()); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceFilterService.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceFilterService.java new file mode 100644 index 00000000..24152e9f --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceFilterService.java @@ -0,0 +1,6 @@ +package org.devgateway.toolkit.forms.service.admin; + +import org.devgateway.toolkit.persistence.dto.ServiceFilter; + +public interface ServiceFilterService extends BaseServiceEntityService { +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceFilterServiceImpl.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceFilterServiceImpl.java new file mode 100644 index 00000000..372afac5 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceFilterServiceImpl.java @@ -0,0 +1,25 @@ +package org.devgateway.toolkit.forms.service.admin; + +import org.devgateway.toolkit.forms.client.ServiceEntityClient; +import org.devgateway.toolkit.forms.client.ServiceFilterClient; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.persistence.dto.ServiceFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ServiceFilterServiceImpl extends BaseServiceEntityServiceImpl implements ServiceFilterService { + + @Autowired + private EurekaClientService eurekaClientService; + + @Override + public ServiceFilter newInstance() { + return new ServiceFilter(); + } + + @Override + protected ServiceEntityClient serviceEntityClient(final String serviceName) { + return new ServiceFilterClient(eurekaClientService.findByName(serviceName).getUrl()); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceMeasureService.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceMeasureService.java new file mode 100644 index 00000000..67efddfb --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceMeasureService.java @@ -0,0 +1,6 @@ +package org.devgateway.toolkit.forms.service.admin; + +import org.devgateway.toolkit.persistence.dto.ServiceMeasure; + +public interface ServiceMeasureService extends BaseServiceEntityService { +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceMeasureServiceImpl.java b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceMeasureServiceImpl.java new file mode 100644 index 00000000..1ab90f22 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/service/admin/ServiceMeasureServiceImpl.java @@ -0,0 +1,25 @@ +package org.devgateway.toolkit.forms.service.admin; + +import org.devgateway.toolkit.forms.client.ServiceEntityClient; +import org.devgateway.toolkit.forms.client.ServiceMeasureClient; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.persistence.dto.ServiceMeasure; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ServiceMeasureServiceImpl extends BaseServiceEntityServiceImpl implements ServiceMeasureService { + + @Autowired + private EurekaClientService eurekaClientService; + + @Override + public ServiceMeasure newInstance() { + return new ServiceMeasure(); + } + + @Override + protected ServiceEntityClient serviceEntityClient(final String serviceName) { + return new ServiceMeasureClient(eurekaClientService.findByName(serviceName).getUrl()); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/util/MarkupCacheService.java b/forms/src/main/java/org/devgateway/toolkit/forms/util/MarkupCacheService.java index 0d668aa8..7b55513d 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/util/MarkupCacheService.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/util/MarkupCacheService.java @@ -17,8 +17,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.cache.Cache; -import javax.cache.CacheManager; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; + import java.util.Collection; /** @@ -68,7 +69,7 @@ public void addPentahoReportToCache(final String outputType, final String report final byte[] buffer) { // get the reports cache "reportsCache", declared in ehcache.xml - final Cache cache = cm.getCache("reportsCache", String.class, byte[].class); + final Cache cache = cm.getCache("reportsCache"); cache.put(createCacheKey(outputType, reportName, parameters), buffer); } @@ -84,12 +85,11 @@ public void addPentahoReportToCache(final String outputType, final String report public byte[] getPentahoReportFromCache(final String outputType, final String reportName, final String parameters) { // get the reports cache "reportsCache", declared in ehcache.xml - final Cache cache = cm.getCache("reportsCache", String.class, byte[].class); - - final String key = createCacheKey(outputType, reportName, parameters); + final Cache cache = cm.getCache("reportsCache"); - if (cache.containsKey(key)) { - return cache.get(key); + if (cache != null) { + String key = createCacheKey(outputType, reportName, parameters); + return cache.get(key, byte[].class); } return null; @@ -101,10 +101,10 @@ public byte[] getPentahoReportFromCache(final String outputType, final String re public void clearPentahoReportsCache() { // get the reports cache "reportsCache", declared in ehcache.xml - final Cache cache = cm.getCache("reportsCache"); + final Cache cache = cm.getCache("reportsCache"); if (cache != null) { - cache.removeAll(); + cache.clear(); } } @@ -114,15 +114,15 @@ public void clearPentahoReportsCache() { public void clearAllCaches() { // get the reports cache "reportsApiCache", declared in ehcache.xml - final Cache cache = cm.getCache("reportsApiCache"); + final Cache cache = cm.getCache("reportsApiCache"); if (cache != null) { - cache.removeAll(); + cache.clear(); } // get the reports cache "excelExportCache", declared in ehcache.xml - final Cache excelExportCache = cm.getCache("excelExportCache"); + final Cache excelExportCache = cm.getCache("excelExportCache"); if (excelExportCache != null) { - excelExportCache.removeAll(); + excelExportCache.clear(); } } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/validators/AbstractEarlierThanDateFieldValidator.java b/forms/src/main/java/org/devgateway/toolkit/forms/validators/AbstractEarlierThanDateFieldValidator.java index 031dbfb3..114a5cb0 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/validators/AbstractEarlierThanDateFieldValidator.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/validators/AbstractEarlierThanDateFieldValidator.java @@ -5,12 +5,9 @@ import org.apache.wicket.validation.ValidationError; import org.devgateway.toolkit.forms.wicket.components.form.AbstractDateFieldBootstrapFormComponent; -import java.time.LocalDate; -import java.util.Date; - /** * @author mpostelnicu {@link AbstractDateFieldBootstrapFormComponent} validator for - * dates that have a chronology + * dates that have a chronology */ public abstract class AbstractEarlierThanDateFieldValidator implements IValidator { private static final long serialVersionUID = 5915013097774040799L; diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/validators/AbstractEarlierThanDateValidator.java b/forms/src/main/java/org/devgateway/toolkit/forms/validators/AbstractEarlierThanDateValidator.java index 68c4f428..b2a3ddf1 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/validators/AbstractEarlierThanDateValidator.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/validators/AbstractEarlierThanDateValidator.java @@ -1,13 +1,9 @@ package org.devgateway.toolkit.forms.validators; -import org.apache.poi.ss.formula.functions.T; import org.apache.wicket.validation.IValidatable; import org.apache.wicket.validation.IValidator; import org.apache.wicket.validation.ValidationError; -import java.time.LocalDate; -import java.util.Date; - /** * Validator to test if the date is earlier than provided high date * diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/validators/EarlierThanDateFieldValidator.java b/forms/src/main/java/org/devgateway/toolkit/forms/validators/EarlierThanDateFieldValidator.java index 03f51ce4..0fa38520 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/validators/EarlierThanDateFieldValidator.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/validators/EarlierThanDateFieldValidator.java @@ -1,16 +1,16 @@ -/******************************************************************************* +/** * Copyright (c) 2015 Development Gateway, Inc and others. - * + *

* All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT - * + *

* Contributors: * Development Gateway - initial API and implementation - *******************************************************************************/ + */ /** - * + * */ package org.devgateway.toolkit.forms.validators; diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/validators/EarlierThanDateValidator.java b/forms/src/main/java/org/devgateway/toolkit/forms/validators/EarlierThanDateValidator.java index 68e11b2f..5cb11154 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/validators/EarlierThanDateValidator.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/validators/EarlierThanDateValidator.java @@ -11,15 +11,11 @@ *******************************************************************************/ package org.devgateway.toolkit.forms.validators; -import org.apache.wicket.validation.IValidatable; -import org.apache.wicket.validation.IValidator; -import org.apache.wicket.validation.ValidationError; - import java.util.Date; /** * Validator to test if the date is earlier than provided high date - * + * * @author idobre * @since 5/18/15 */ diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/validators/PhoneNumberValidator.properties b/forms/src/main/java/org/devgateway/toolkit/forms/validators/PhoneNumberValidator.properties index 2806775d..36f13fb4 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/validators/PhoneNumberValidator.properties +++ b/forms/src/main/java/org/devgateway/toolkit/forms/validators/PhoneNumberValidator.properties @@ -10,3 +10,4 @@ # Development Gateway - initial API and implementation ############################################################################### pattern=Invalid telephone number. The maximum length is 50 characters. The telephone number should contain only numbers 0-9, whitespace or the characters ()-+. +must be greater than 1 \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/validators/PositiveBigDecimalValidator.java b/forms/src/main/java/org/devgateway/toolkit/forms/validators/PositiveBigDecimalValidator.java new file mode 100644 index 00000000..2a4b676f --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/validators/PositiveBigDecimalValidator.java @@ -0,0 +1,36 @@ +package org.devgateway.toolkit.forms.validators; + +import org.apache.wicket.validation.IValidatable; +import org.apache.wicket.validation.IValidator; +import org.apache.wicket.validation.ValidationError; + +import java.math.BigDecimal; + +public class PositiveBigDecimalValidator implements IValidator { + + private boolean includeZero; + + public PositiveBigDecimalValidator() { + this(false); + } + + public PositiveBigDecimalValidator(boolean includeZero) { + this.includeZero = includeZero; + } + + @Override + public void validate(final IValidatable validatable) { + BigDecimal value = validatable.getValue(); + if (includeZero) { + if (value.compareTo(BigDecimal.ZERO) < 0) { + ValidationError error = new ValidationError(this); + error.addKey("positive"); + validatable.error(error); + } + } else if (value.compareTo(BigDecimal.ZERO) <= 0) { + ValidationError error = new ValidationError(this); + error.addKey("nonNegative"); + validatable.error(error); + } + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/validators/PositiveBigDecimalValidator.properties b/forms/src/main/java/org/devgateway/toolkit/forms/validators/PositiveBigDecimalValidator.properties new file mode 100644 index 00000000..c6600c97 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/validators/PositiveBigDecimalValidator.properties @@ -0,0 +1,2 @@ +positive=The value must be greater than 0 +nonNegative=The value must be greater than or equal to 0 \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/validators/UniqueLanguageTranslationValidator.java b/forms/src/main/java/org/devgateway/toolkit/forms/validators/UniqueLanguageTranslationValidator.java new file mode 100644 index 00000000..0442b788 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/validators/UniqueLanguageTranslationValidator.java @@ -0,0 +1,30 @@ +package org.devgateway.toolkit.forms.validators; + +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.FormComponent; +import org.apache.wicket.markup.html.form.validation.AbstractFormValidator; +import org.devgateway.toolkit.persistence.dto.ServiceCategory; +import org.devgateway.toolkit.persistence.dto.ServiceTextTranslation; + +import java.util.stream.Collectors; + +public class UniqueLanguageTranslationValidator extends AbstractFormValidator { + + @Override + public FormComponent[] getDependentFormComponents() { + return new FormComponent[0]; + } + + @Override + public void validate(final Form form) { + ServiceCategory serviceCategory = (ServiceCategory) form.getModelObject(); + serviceCategory.getLabels().stream() + .filter(label -> label.getLanguage() != null) + .collect(Collectors.groupingBy(s -> s.getLanguage().toUpperCase())) + .entrySet().stream() + .filter(entry -> entry.getValue().size() > 1) + .forEach(entry -> { + form.error("Language " + entry.getKey() + " is duplicated"); + }); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/validators/YearValidator.java b/forms/src/main/java/org/devgateway/toolkit/forms/validators/YearValidator.java index 8c605edd..32f111c7 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/validators/YearValidator.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/validators/YearValidator.java @@ -1,25 +1,25 @@ -/******************************************************************************* +/** * Copyright (c) 2015 Development Gateway, Inc and others. - * + *

* All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT - * + *

* Contributors: * Development Gateway - initial API and implementation - *******************************************************************************/ + */ /** - * + * */ package org.devgateway.toolkit.forms.validators; -import java.util.Calendar; - import org.apache.wicket.validation.IValidatable; import org.apache.wicket.validation.IValidator; import org.apache.wicket.validation.ValidationError; +import java.util.Calendar; + /** * @author mpostelnicu Validates an Integer input to be a valid year Returns * errors when this is not true diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/FormsWebApplication.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/FormsWebApplication.java index a313cf56..61855469 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/FormsWebApplication.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/FormsWebApplication.java @@ -23,6 +23,7 @@ import de.agilecoders.wicket.extensions.markup.html.bootstrap.editor.SummernoteStoredImageResourceReference; import de.agilecoders.wicket.less.BootstrapLess; import de.agilecoders.wicket.webjars.WicketWebjars; +import de.agilecoders.wicket.webjars.request.resource.WebjarsJavaScriptResourceReference; import nl.dries.wicket.hibernate.dozer.DozerRequestCycleListener; import nl.dries.wicket.hibernate.dozer.SessionFinderHolder; import org.apache.wicket.Application; @@ -32,7 +33,12 @@ import org.apache.wicket.ajax.AjaxNewWindowNotifyingBehavior; import org.apache.wicket.authroles.authentication.AuthenticatedWebApplication; import org.apache.wicket.authroles.authentication.AuthenticatedWebSession; -import org.apache.wicket.devutils.diskstore.DebugDiskDataStore; +//import org.apache.wicket.devutils.diskstore.DebugDiskDataStore; +import org.apache.wicket.csp.CSPDirective; +import org.apache.wicket.csp.CSPDirectiveSrcValue; +import org.apache.wicket.markup.head.IHeaderResponse; +import org.apache.wicket.markup.head.filter.JavaScriptFilteredIntoFooterHeaderResponse; +import org.apache.wicket.markup.html.IHeaderResponseDecorator; import org.apache.wicket.markup.html.IPackageResourceGuard; import org.apache.wicket.markup.html.SecurePackageResourceGuard; import org.apache.wicket.markup.html.WebPage; @@ -40,6 +46,7 @@ import org.apache.wicket.request.resource.ResourceReference; import org.apache.wicket.request.resource.caching.FilenameWithVersionResourceCachingStrategy; import org.apache.wicket.request.resource.caching.version.CachingResourceVersion; +import org.apache.wicket.resource.JQueryResourceReference; import org.apache.wicket.settings.RequestCycleSettings.RenderStrategy; import org.apache.wicket.spring.injection.annot.SpringComponentInjector; import org.apache.wicket.util.file.Folder; @@ -59,6 +66,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.PropertySource; @@ -67,8 +75,10 @@ import org.wicketstuff.select2.ApplicationSettings; import java.math.BigDecimal; +import java.time.Duration; import java.time.LocalDate; import java.time.ZonedDateTime; +import java.util.Iterator; /** * The web application class also serves as spring boot starting point by using @@ -77,6 +87,8 @@ * * @author Stefan Kloe, mpostelnicu */ + +@EnableDiscoveryClient(autoRegister = true) @EnableScheduling @SpringBootApplication(exclude = {org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration.class}) @ComponentScan("org.devgateway.toolkit") @@ -109,8 +121,8 @@ public static void main(final String[] args) { @Override protected IConverterLocator newConverterLocator() { ConverterLocator locator = (ConverterLocator) super.newConverterLocator(); - locator.set(BigDecimal.class, new NonNumericFilteredBigDecimalConverter(defaultDecimalFormatter)); locator.set(Double.class, new FormattedDoubleConverter(defaultDecimalFormatter)); + locator.set(BigDecimal.class, new NonNumericFilteredBigDecimalConverter(defaultDecimalFormatter)); locator.set(LocalDate.class, new LocalDateFormatter()); locator.set(ZonedDateTime.class, new ZonedDateTimeFormatter()); return locator; @@ -152,6 +164,9 @@ private void configureBootstrap() { final IBootstrapSettings settings = new BootstrapSettings(); settings.useCdnResources(false); +// final ThemeProvider themeProvider = new BootswatchThemeProvider(BootswatchTheme.Paper); +// settings.setThemeProvider(themeProvider); + // use the default bootstrap theme Bootstrap.install(this, settings); BootstrapLess.install(this); @@ -163,7 +178,8 @@ private void configureBootstrap() { */ private void optimizeForWebPerformance() { // add javascript files at the bottom of the page - setHeaderResponseDecorator(new RenderJavaScriptToFooterHeaderResponseDecorator("scripts-bucket")); + getHeaderResponseDecorators().add(response -> + new JavaScriptFilteredIntoFooterHeaderResponse(response, "scripts-bucket")); // This is only enabled for deployment configuration // -Dwicket.configuration=deployment @@ -183,6 +199,7 @@ private void optimizeForWebPerformance() { new CachingResourceVersion(new Adler32ResourceVersion()))); getRequestCycleSettings().setRenderStrategy(RenderStrategy.ONE_PASS_RENDER); + // be sure that we have added Dozer Listener getRequestCycleListeners().add(new DozerRequestCycleListener()); @@ -239,12 +256,30 @@ protected void init() { // watch this using the URL // http://.../wicket/internal/debug/diskDataStore if (usesDevelopmentConfig()) { - DebugDiskDataStore.register(this); + getDebugSettings().setDevelopmentUtilitiesEnabled(true); } SessionFinderHolder.setSessionFinder(sessionFinderService); useCustomizedSelect2Version(); + + configureCsp(); + } + + private void configureCsp() { + getCspSettings().blocking().clear() + .add(CSPDirective.SCRIPT_SRC, CSPDirectiveSrcValue.SELF) + .add(CSPDirective.SCRIPT_SRC, CSPDirectiveSrcValue.UNSAFE_INLINE) + .add(CSPDirective.STYLE_SRC, CSPDirectiveSrcValue.SELF) + .add(CSPDirective.STYLE_SRC, CSPDirectiveSrcValue.UNSAFE_INLINE) + .add(CSPDirective.IMG_SRC, CSPDirectiveSrcValue.SELF) + .add(CSPDirective.CONNECT_SRC, CSPDirectiveSrcValue.SELF) + .add(CSPDirective.FONT_SRC, CSPDirectiveSrcValue.SELF) + .add(CSPDirective.MANIFEST_SRC, CSPDirectiveSrcValue.SELF) + .add(CSPDirective.CHILD_SRC, CSPDirectiveSrcValue.SELF) + .add(CSPDirective.BASE_URI, CSPDirectiveSrcValue.SELF) + .add(CSPDirective.FRAME_SRC, CSPDirectiveSrcValue.SELF) + .add(CSPDirective.DEFAULT_SRC, CSPDirectiveSrcValue.NONE); } /** diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/SSAuthenticatedWebSession.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/SSAuthenticatedWebSession.java index ba74b461..f30e1a37 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/SSAuthenticatedWebSession.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/SSAuthenticatedWebSession.java @@ -11,9 +11,8 @@ *******************************************************************************/ package org.devgateway.toolkit.forms.wicket; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.apache.wicket.Session; import org.apache.wicket.authroles.authentication.AuthenticatedWebSession; import org.apache.wicket.authroles.authorization.strategies.role.Roles; @@ -21,6 +20,7 @@ import org.apache.wicket.request.Request; import org.apache.wicket.request.cycle.RequestCycle; import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.wicket.components.util.PageUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.access.hierarchicalroles.RoleHierarchy; @@ -32,11 +32,13 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.RememberMeServices; +import org.springframework.security.web.context.HttpSessionSecurityContextRepository; + import java.util.Collection; /** * AuthenticatedWebSession implementation using Spring Security. - * + *

* Based on: * https://cwiki.apache.org/confluence/display/WICKET/Spring+Security+and+Wicket-auth-roles * @@ -56,15 +58,32 @@ public class SSAuthenticatedWebSession extends AuthenticatedWebSession { @SpringBean private AuthenticationManager authenticationManager; + @SpringBean + private HttpSessionSecurityContextRepository securityContextRepository; + @SpringBean private RoleHierarchy roleHierarchy; // @SpringBean // private SessionRegistry sessionRegistry; + public SSAuthenticatedWebSession(final Request request) { + super(request); + Injector.get().inject(this); + ensureDependenciesNotNull(); + if (authenticationManager == null) { + throw new IllegalStateException("Injection of AuthenticationManager failed."); + } + + } + + public static SSAuthenticatedWebSession getSSAuthenticatedWebSession() { + return (SSAuthenticatedWebSession) Session.get(); + } + /* * (non-Javadoc) - * + * * @see org.apache.wicket.Session#replaceSession() */ @Override @@ -78,20 +97,6 @@ private void ensureDependenciesNotNull() { } } - public SSAuthenticatedWebSession(final Request request) { - super(request); - Injector.get().inject(this); - ensureDependenciesNotNull(); - if (authenticationManager == null) { - throw new IllegalStateException("Injection of AuthenticationManager failed."); - } - - } - - public static SSAuthenticatedWebSession getSSAuthenticatedWebSession() { - return (SSAuthenticatedWebSession) Session.get(); - } - @Override public boolean authenticate(final String username, final String password) { boolean authenticated; @@ -99,6 +104,11 @@ public boolean authenticate(final String username, final String password) { Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password)); SecurityContextHolder.getContext().setAuthentication(authentication); + + // (since Spring Security 5.7) explicitly save context, no longer done by security filter + securityContextRepository.saveContext(SecurityContextHolder.getContext(), PageUtil.getHttpServletRequest(), + PageUtil.getHttpServletResponse()); + // httpSession.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, // SecurityContextHolder.getContext()); authenticated = authentication.isAuthenticated(); @@ -129,10 +139,10 @@ public Roles getRoles() { /** * Gets the Spring roles and dumps them into Wicket's {@link Roles} object, * only if the user is signed in - * + * + * @param roles * @see {@link #isSignedIn()} * @see #addRolesFromAuthentication(Roles, Authentication) - * @param roles */ private void getRolesIfSignedIn(final Roles roles) { if (isSignedIn()) { diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/WebInitializer.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/WebInitializer.java index 02fd99fa..960d2b59 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/WebInitializer.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/WebInitializer.java @@ -13,17 +13,15 @@ import org.apache.wicket.protocol.http.WicketFilter; import org.apache.wicket.spring.SpringWebApplicationFactory; +import org.devgateway.toolkit.web.util.SettingsUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.context.annotation.Configuration; import org.springframework.security.web.session.HttpSessionEventPublisher; -import javax.servlet.FilterRegistration; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.SessionTrackingMode; -import java.util.Collections; - -import static org.devgateway.toolkit.web.WebConstants.FORMS_BASE_PATH; +import jakarta.servlet.FilterRegistration; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; /** * This class is the replacement of the web.xml. It registers the wicket filter @@ -35,8 +33,10 @@ @Configuration public class WebInitializer implements ServletContextInitializer { + @Autowired + private SettingsUtils settingsUtils; + private static final String PARAM_APP_BEAN = "applicationBean"; - public static final String FORMS_PATH_PATTERN = FORMS_BASE_PATH + "/*"; @Override public void onStartup(final ServletContext sc) throws ServletException { @@ -55,8 +55,8 @@ public void onStartup(final ServletContext sc) throws ServletException { filter.setInitParameter(PARAM_APP_BEAN, "formsWebApplication"); // This line is the only surprise when comparing to the equivalent // web.xml. Without some initialization seems to be missing. - filter.setInitParameter(WicketFilter.FILTER_MAPPING_PARAM, FORMS_PATH_PATTERN); - filter.addMappingForUrlPatterns(null, false, FORMS_PATH_PATTERN); + filter.setInitParameter(WicketFilter.FILTER_MAPPING_PARAM, settingsUtils.getFormsBasePath() + "/*"); + filter.addMappingForUrlPatterns(null, false, settingsUtils.getFormsBasePath() + "/*"); // // Request Listener // sc.addListener(new RequestContextListener()); diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/BigLinkDefinition.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/BigLinkDefinition.java new file mode 100644 index 00000000..7e080d64 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/BigLinkDefinition.java @@ -0,0 +1,56 @@ +package org.devgateway.toolkit.forms.wicket.components; + +import de.agilecoders.wicket.core.markup.html.bootstrap.image.IconType; +import org.apache.wicket.Page; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.ResourceModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; + +import java.io.Serializable; + +/** + * @author Octavian Ciubotaru + */ +public class BigLinkDefinition implements Serializable { + + private final String id; + private final Class pageClass; + private final IconType iconType; + + private final PageParameters pageParameters; + + public BigLinkDefinition(String id, Class pageClass, IconType iconType) { + this.id = id; + this.pageClass = pageClass; + this.iconType = iconType; + this.pageParameters = new PageParameters(); + } + + public BigLinkDefinition(String id, Class pageClass, PageParameters pageParameters, + IconType iconType) { + this.id = id; + this.pageClass = pageClass; + this.iconType = iconType; + this.pageParameters = pageParameters; + } + + public IModel getLabelModel() { + return new ResourceModel(id + ".label"); + } + + public IModel getDescModel() { + return new ResourceModel(id + ".desc"); + } + + public Class getPageClass() { + return pageClass; + } + + public IconType getIconType() { + return iconType; + } + + public PageParameters getPageParameters() { + return pageParameters; + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/BigLinksPanel.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/BigLinksPanel.html new file mode 100644 index 00000000..b4a37c42 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/BigLinksPanel.html @@ -0,0 +1,12 @@ + + + + +

+ + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/BigLinksPanel.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/BigLinksPanel.java new file mode 100644 index 00000000..2bf7b463 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/BigLinksPanel.java @@ -0,0 +1,35 @@ +package org.devgateway.toolkit.forms.wicket.components; + +import org.apache.wicket.behavior.AttributeAppender; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.markup.html.panel.GenericPanel; +import org.apache.wicket.model.IModel; +import org.devgateway.toolkit.forms.wicket.components.buttons.HomepageButton; + +import java.util.List; + +/** + * @author Octavian Ciubotaru + */ +public class BigLinksPanel extends GenericPanel> { + + public BigLinksPanel(String id, IModel> model) { + super(id, model); + + int size = model.getObject().size(); + int colSpan = (size == 0 || size > 3) ? 3 : 12 / size; + + add(new ListView("buttons", model) { + + @Override + protected void populateItem(ListItem item) { + BigLinkDefinition def = item.getModelObject(); + item.add(new AttributeAppender("class", "col-md-" + colSpan, " ")); + item.add(new HomepageButton<>("button", + def.getPageClass(), def.getPageParameters(), + def.getLabelModel(), def.getDescModel(), def.getIconType())); + } + }); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/CollapsablePanel.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/CollapsablePanel.java index c7be026e..829800c3 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/CollapsablePanel.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/CollapsablePanel.java @@ -46,5 +46,5 @@ protected void onInitialize() { onInitializeBody(body); } - protected abstract void onInitializeBody(final WebMarkupContainer body); + protected abstract void onInitializeBody(WebMarkupContainer body); } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/LinkTargetBlankPanel.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/LinkTargetBlankPanel.html new file mode 100644 index 00000000..b8fd141d --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/LinkTargetBlankPanel.html @@ -0,0 +1,10 @@ + + + LinkTargetBlankPanel + + + + + + + \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/LinkTargetBlankPanel.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/LinkTargetBlankPanel.java new file mode 100644 index 00000000..db866676 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/LinkTargetBlankPanel.java @@ -0,0 +1,26 @@ +package org.devgateway.toolkit.forms.wicket.components; + +import org.apache.wicket.markup.ComponentTag; +import org.apache.wicket.markup.html.link.ExternalLink; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.model.IModel; + +public class LinkTargetBlankPanel extends Panel { + + public LinkTargetBlankPanel(String id, IModel url) { + this(id, url, url); + } + + public LinkTargetBlankPanel(String id, IModel url, IModel label) { + super(id); + add(new ExternalLink("link", url, label) { + private static final long serialVersionUID = -8010560272317354356L; + + @Override + protected void onComponentTag(ComponentTag tag) { + super.onComponentTag(tag); + tag.put("target", "_blank"); + } + }); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/PageableTablePanel.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/PageableTablePanel.java index a28cadde..7b8831a8 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/PageableTablePanel.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/PageableTablePanel.java @@ -8,9 +8,11 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; import org.devgateway.toolkit.forms.WebConstants; import org.devgateway.toolkit.forms.wicket.components.table.AjaxFallbackBootstrapDataTable; import org.devgateway.toolkit.forms.wicket.providers.ListDataProvider; +import org.devgateway.toolkit.persistence.service.AdminSettingsService; import java.io.Serializable; import java.util.ArrayList; @@ -29,12 +31,13 @@ public class PageableTablePanel parentModel; + @SpringBean + AdminSettingsService adminSettingsService; + protected AjaxFallbackBootstrapDataTable dataTable; protected ISortableDataProvider dataProvider; - protected int rowsPerPage = WebConstants.PAGE_SIZE; - protected List> columns = new ArrayList<>(); public PageableTablePanel(final String id, final IModel parentModel) { @@ -57,10 +60,14 @@ protected void onInitialize() { } protected AjaxFallbackBootstrapDataTable buildDataTable() { - dataTable = new AjaxFallbackBootstrapDataTable("table", columns, dataProvider, rowsPerPage); + dataTable = new AjaxFallbackBootstrapDataTable("table", columns, dataProvider, getPageSize()); return dataTable; } + private Integer getPageSize() { + return adminSettingsService.get().getPageSize(); + } + public AjaxFallbackBootstrapDataTable getDataTable() { return dataTable; } @@ -69,10 +76,6 @@ public void setSort(final Object property, final SortOrder sortOrder) { ((ListDataProvider) dataProvider).setSort(property, SortOrder.ASCENDING); } - public void setPageSize(final int pageSize) { - rowsPerPage = pageSize; - } - protected List getItems() { return getModelObject(); } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/breadcrumbs/BreadCrumbPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/breadcrumbs/BreadCrumbPage.java new file mode 100644 index 00000000..4dc28322 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/breadcrumbs/BreadCrumbPage.java @@ -0,0 +1,28 @@ +package org.devgateway.toolkit.forms.wicket.components.breadcrumbs; + +import org.devgateway.toolkit.forms.wicket.page.BasePage; +import org.devgateway.toolkit.forms.wicket.page.Homepage; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used to declare a breadcrumb on a class. + * + * @author Viorel Chihai + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface BreadCrumbPage { + + /** + * The upper level in breadcrumb hierarchy + */ + Class parent() default Homepage.class; + + boolean isRoot() default false; + + boolean hasServiceParam() default false; +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/breadcrumbs/BreadCrumbPanel.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/breadcrumbs/BreadCrumbPanel.html new file mode 100644 index 00000000..6fbd67f5 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/breadcrumbs/BreadCrumbPanel.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/breadcrumbs/BreadCrumbPanel.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/breadcrumbs/BreadCrumbPanel.java new file mode 100644 index 00000000..fe1690c1 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/breadcrumbs/BreadCrumbPanel.java @@ -0,0 +1,136 @@ +package org.devgateway.toolkit.forms.wicket.components.breadcrumbs; + +import de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapBookmarkablePageLink; +import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.devgateway.toolkit.forms.wicket.page.BasePage; + +import java.util.ArrayList; +import java.util.List; + +import static de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons.Type.Link; +import static org.devgateway.toolkit.forms.WebConstants.PARAM_SERVICE; + +/** + * A component that renders bread crumbs. + * + *
+ * first / second / third
+ * 
+ * + * @author Viorel Chihai + */ +public abstract class BreadCrumbPanel extends Panel { + + private List breadcrumbs; + + public BreadCrumbPanel(final String id) { + super(id); + } + + @Override + protected void onInitialize() { + super.onInitialize(); + getBreadcrumbs().clear(); + createBreadcrumb(); + + IModel> breadcrumbsModel = new IModel>() { + private static final long serialVersionUID = 1L; + + @Override + public List getObject() { + return getBreadcrumbs(); + } + }; + + ListView breadcrumbList = new ListView("breadcrumb", breadcrumbsModel) { + private static final long serialVersionUID = 1L; + + @Override + protected void populateItem(final ListItem item) { + final Breadcrumb dto = item.getModelObject(); + BootstrapBookmarkablePageLink link = new BootstrapBookmarkablePageLink("bcLink", dto.getPage(), dto.getPageParameters(), Link); + link.setLabel(dto.getLabel()); + item.add(link); + link.setEnabled(dto.isUseLink()); + } + }; + add(breadcrumbList); + } + + public List getBreadcrumbs() { + if (breadcrumbs == null) { + breadcrumbs = new ArrayList<>(); + } + + return breadcrumbs; + } + + public void addBreadcrumb(final Breadcrumb breadcrumb) { + getBreadcrumbs().add(breadcrumb); + } + + protected void createBreadcrumb() { + BreadCrumbPage breadCrumbAnnotation = getPageClass().getDeclaredAnnotation(BreadCrumbPage.class); + if (breadCrumbAnnotation != null) { + if (!breadCrumbAnnotation.isRoot()) { + createParentBreadcrumb(breadCrumbAnnotation.parent()); + } + + Breadcrumb bc = new Breadcrumb(new IModel() { + private static final long serialVersionUID = 1L; + + @Override + public String getObject() { + return getLabelModel().getObject(); + } + }, getPageClass()); + bc.setUseLink(false); + addBreadcrumb(bc); + } + } + + protected void createParentBreadcrumb(final Class clazz) { + if (clazz != null && clazz.getDeclaredAnnotation(BreadCrumbPage.class) != null) { + if (!clazz.getDeclaredAnnotation(BreadCrumbPage.class).isRoot()) { + createParentBreadcrumb(clazz.getDeclaredAnnotation(BreadCrumbPage.class).parent()); + } + + Breadcrumb bc = new Breadcrumb(new IModel() { + private static final long serialVersionUID = 1L; + + @Override + public String getObject() { + return getLabelModel(clazz).getObject(); + } + }, clazz, getBreadcrumbPageParameters(clazz)); + addBreadcrumb(bc); + } + } + + private PageParameters getBreadcrumbPageParameters(final Class clazz) { + boolean hasServiceLabel = clazz.getDeclaredAnnotation(BreadCrumbPage.class).hasServiceParam(); + + if (hasServiceLabel) { + PageParameters pageParameters = new PageParameters(); + String service = this.getPage().getPageParameters().get(PARAM_SERVICE).toString(); + pageParameters.set(PARAM_SERVICE, service); + return pageParameters; + } + + return new PageParameters(); + + } + + protected abstract Class getPageClass(); + + protected abstract IModel getLabelModel(); + + protected abstract IModel getLabelModel(Class clazz); + + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/breadcrumbs/Breadcrumb.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/breadcrumbs/Breadcrumb.java new file mode 100644 index 00000000..f354dd80 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/breadcrumbs/Breadcrumb.java @@ -0,0 +1,72 @@ +package org.devgateway.toolkit.forms.wicket.components.breadcrumbs; + +import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.model.IModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; + +import java.io.Serializable; + +/** + * @author Viorel Chihai + */ +public class Breadcrumb implements Serializable { + + private static final long serialVersionUID = 1L; + + private IModel labelModel; + + private boolean useLink = true; + + private boolean visible = true; + + private Class page; + + PageParameters pageParameters; + + public Breadcrumb(final IModel labelModel, final Class page) { + this(labelModel, page, new PageParameters()); + } + + public Breadcrumb(final IModel labelModel, final Class page, final PageParameters pageParameters) { + this.labelModel = labelModel; + this.page = page; + this.pageParameters = pageParameters; + } + + public IModel getLabel() { + return labelModel; + } + + public void setLabel(final IModel labelModel) { + this.labelModel = labelModel; + } + + public boolean isUseLink() { + return useLink; + } + + public void setUseLink(final boolean useLink) { + this.useLink = useLink; + } + + public boolean isVisible() { + return visible; + } + + public void setVisible(final boolean visible) { + this.visible = visible; + } + + public void setPage(final Class page) { + this.page = page; + } + + public Class getPage() { + return page; + } + + public PageParameters getPageParameters() { + return pageParameters; + } + +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/HomepageButton.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/HomepageButton.html new file mode 100644 index 00000000..3e106122 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/HomepageButton.html @@ -0,0 +1,15 @@ + + + HomePageButton + + + + +

+ + +

+ + + + \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/HomepageButton.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/HomepageButton.java new file mode 100644 index 00000000..9c727459 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/HomepageButton.java @@ -0,0 +1,45 @@ +package org.devgateway.toolkit.forms.wicket.components.buttons; + +import de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapBookmarkablePageLink; +import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; +import de.agilecoders.wicket.core.markup.html.bootstrap.image.IconType; +import org.apache.wicket.Component; +import org.apache.wicket.Page; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.ResourceModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; + +public class HomepageButton extends BootstrapBookmarkablePageLink { + + public

HomepageButton(final String componentId, final Class

pageClass, + final IconType iconType) { + this(componentId, pageClass, null, null, iconType); + } + + public

HomepageButton(String componentId, Class

pageClass, IModel labelModel, + IModel descriptionModel, IconType iconType) { + this(componentId, pageClass, new PageParameters(), labelModel, descriptionModel, iconType); + } + + public

HomepageButton(String componentId, Class

pageClass, PageParameters pageParameters, + IModel labelModel, + IModel descriptionModel, IconType iconType) { + super(componentId, pageClass, pageParameters, Buttons.Type.Default); + + setLabel(labelModel == null + ? new ResourceModel(componentId + ".label") + : labelModel); + + add(new Label("description", descriptionModel == null + ? new ResourceModel(componentId + ".desc") + : descriptionModel)); + + setIconType(iconType); + setSize(Buttons.Size.Large); + } + + protected Component newLabel(final String markupId) { + return super.newLabel(markupId).setRenderBodyOnly(false); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaAjaxButton.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaAjaxButton.java new file mode 100644 index 00000000..2ef0cf21 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaAjaxButton.java @@ -0,0 +1,62 @@ +package org.devgateway.toolkit.forms.wicket.components.buttons.ladda; + +import de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapAjaxButton; +import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; +import java.io.Serializable; +import org.apache.wicket.AttributeModifier; +import org.apache.wicket.Component; +import org.apache.wicket.ajax.attributes.AjaxRequestAttributes; +import org.apache.wicket.behavior.Behavior; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.IModel; + +public class LaddaAjaxButton extends BootstrapAjaxButton { + private final LaddaBehavior laddaBehavior = new LaddaBehavior(); + + public LaddaAjaxButton(String id, Buttons.Type type) { + super(id, type); + } + + public LaddaAjaxButton(String id, IModel model, Buttons.Type type) { + super(id, model, type); + } + + public LaddaAjaxButton(String id, Form form, Buttons.Type type) { + super(id, form, type); + } + + public LaddaAjaxButton(String id, IModel model, Form form, Buttons.Type type) { + super(id, model, form, type); + } + + protected void onInitialize() { + super.onInitialize(); + this.add(new Behavior[]{this.laddaBehavior}); + } + + public LaddaAjaxButton setEffect(LaddaBehavior.Effect effect) { + this.laddaBehavior.withEffect(effect); + return this; + } + + public LaddaAjaxButton setSpinnerColor(String color) { + this.laddaBehavior.withSpinnerColor(color); + return this; + } + + public LaddaAjaxButton setSpinnerSize(int size) { + this.laddaBehavior.withSpinnerSize(size); + return this; + } + + protected void updateAjaxAttributes(AjaxRequestAttributes attributes) { + super.updateAjaxAttributes(attributes); + attributes.getAjaxCallListeners().add(new LaddaAjaxCallListener()); + } + + protected Component newLabel(String markupId, IModel model) { + Component label = super.newLabel(markupId, model); + label.add(new Behavior[]{AttributeModifier.append("class", "ladda-label")}); + return label; + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaAjaxCallListener.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaAjaxCallListener.java new file mode 100644 index 00000000..93e2963e --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaAjaxCallListener.java @@ -0,0 +1,10 @@ +package org.devgateway.toolkit.forms.wicket.components.buttons.ladda; + +import org.apache.wicket.ajax.attributes.AjaxCallListener; + +public class LaddaAjaxCallListener extends AjaxCallListener { + public LaddaAjaxCallListener() { + this.onBeforeSend("var $this = jQuery('#'+attrs.c); var l = Ladda.create($this[0]); l.start(); $this.data('ladda', l)"); + this.onComplete("var $this = jQuery('#'+attrs.c); var l = $this.data('ladda'); if (l) {l.stop(); $this.removeData('ladda');}"); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaBehavior.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaBehavior.java new file mode 100644 index 00000000..6a71a7ca --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaBehavior.java @@ -0,0 +1,80 @@ +package org.devgateway.toolkit.forms.wicket.components.buttons.ladda; + +import de.agilecoders.wicket.core.markup.html.bootstrap.behavior.ICssClassNameProvider; +import de.agilecoders.wicket.core.util.Attributes; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.references.SpinJsReference; +import org.apache.wicket.Component; +import org.apache.wicket.behavior.Behavior; +import org.apache.wicket.markup.ComponentTag; +import org.apache.wicket.markup.head.CssHeaderItem; +import org.apache.wicket.markup.head.IHeaderResponse; +import org.apache.wicket.markup.head.JavaScriptHeaderItem; +import org.apache.wicket.util.lang.Args; +import org.apache.wicket.util.string.Strings; + +public class LaddaBehavior extends Behavior { + private Effect effect; + private String spinnerColor; + private int spinnerSize; + + public LaddaBehavior() { + this.effect = LaddaBehavior.Effect.ZOOM_OUT; + } + + public LaddaBehavior withEffect(Effect effect) { + this.effect = (Effect)Args.notNull(effect, "effect"); + return this; + } + + public LaddaBehavior withSpinnerColor(String color) { + this.spinnerColor = color; + return this; + } + + public LaddaBehavior withSpinnerSize(int size) { + this.spinnerSize = size; + return this; + } + + public void onComponentTag(Component component, ComponentTag tag) { + super.onComponentTag(component, tag); + Attributes.addClass(tag, new String[]{"ladda-button"}); + Attributes.set(tag, "data-style", this.effect.cssClassName()); + if (!Strings.isEmpty(this.spinnerColor)) { + Attributes.set(tag, "data-spinner-color", this.spinnerColor); + } + + if (this.spinnerSize > 0) { + Attributes.set(tag, "data-spinner-size", String.valueOf(this.spinnerSize)); + } + + } + + public void renderHead(Component component, IHeaderResponse response) { + super.renderHead(component, response); + response.render(CssHeaderItem.forReference(LaddaCssReference.INSTANCE)); + response.render(JavaScriptHeaderItem.forReference(SpinJsReference.INSTANCE)); + response.render(JavaScriptHeaderItem.forReference(LaddaJsReference.INSTANCE)); + } + + public static enum Effect implements ICssClassNameProvider { + EXPAND_LEFT, + EXPAND_RIGHT, + EXPAND_UP, + EXPAND_DOWN, + ZOOM_IN, + ZOOM_OUT, + SLIDE_LEFT, + SLIDE_RIGHT, + SLIDE_UP, + SLIDE_DOWN, + CONTRACT; + + private Effect() { + } + + public String cssClassName() { + return this.name().toLowerCase().replace('_', '-'); + } + } +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaCssReference.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaCssReference.java new file mode 100644 index 00000000..86d0421c --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaCssReference.java @@ -0,0 +1,11 @@ +package org.devgateway.toolkit.forms.wicket.components.buttons.ladda; + +import org.apache.wicket.request.resource.CssResourceReference; + +public class LaddaCssReference extends CssResourceReference { + public static final LaddaCssReference INSTANCE = new LaddaCssReference(); + + public LaddaCssReference() { + super(LaddaCssReference.class, "css/ladda-themeless.css"); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaJsReference.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaJsReference.java new file mode 100644 index 00000000..96f6c2ca --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/LaddaJsReference.java @@ -0,0 +1,11 @@ +package org.devgateway.toolkit.forms.wicket.components.buttons.ladda; + +import org.apache.wicket.request.resource.JavaScriptResourceReference; + +public class LaddaJsReference extends JavaScriptResourceReference { + public static final LaddaJsReference INSTANCE = new LaddaJsReference(); + + public LaddaJsReference() { + super(LaddaJsReference.class, "js/ladda.js"); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/css/ladda-themeless.css b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/css/ladda-themeless.css new file mode 100644 index 00000000..880c9ff8 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/css/ladda-themeless.css @@ -0,0 +1,314 @@ +.ladda-button { + position: relative; } + +/* Spinner animation */ +.ladda-button .ladda-spinner { + position: absolute; + z-index: 2; + display: inline-block; + width: 32px; + height: 32px; + top: 50%; + margin-top: -16px; + opacity: 0; + pointer-events: none; } + +/* Button label */ +.ladda-button .ladda-label { + position: relative; + z-index: 3; } + +/* Progress bar */ +.ladda-button .ladda-progress { + position: absolute; + width: 0; + height: 100%; + left: 0; + top: 0; + background: rgba(0, 0, 0, 0.2); + visibility: hidden; + opacity: 0; + -webkit-transition: 0.1s linear all !important; + -moz-transition: 0.1s linear all !important; + -ms-transition: 0.1s linear all !important; + -o-transition: 0.1s linear all !important; + transition: 0.1s linear all !important; } + +.ladda-button[data-loading] .ladda-progress { + opacity: 1; + visibility: visible; } + +/************************************* + * EASING + */ +.ladda-button, +.ladda-button .ladda-spinner, +.ladda-button .ladda-label { + -webkit-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important; + -moz-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important; + -ms-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important; + -o-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important; + transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important; } + +.ladda-button[data-style=zoom-in], +.ladda-button[data-style=zoom-in] .ladda-spinner, +.ladda-button[data-style=zoom-in] .ladda-label, +.ladda-button[data-style=zoom-out], +.ladda-button[data-style=zoom-out] .ladda-spinner, +.ladda-button[data-style=zoom-out] .ladda-label { + -webkit-transition: 0.3s ease all !important; + -moz-transition: 0.3s ease all !important; + -ms-transition: 0.3s ease all !important; + -o-transition: 0.3s ease all !important; + transition: 0.3s ease all !important; } + +/************************************* + * EXPAND LEFT + */ +.ladda-button[data-style=expand-right] .ladda-spinner { + right: 14px; } +.ladda-button[data-style=expand-right][data-size="s"] .ladda-spinner, .ladda-button[data-style=expand-right][data-size="xs"] .ladda-spinner { + right: 4px; } +.ladda-button[data-style=expand-right][data-loading] { + padding-right: 56px; } +.ladda-button[data-style=expand-right][data-loading] .ladda-spinner { + opacity: 1; } +.ladda-button[data-style=expand-right][data-loading][data-size="s"], .ladda-button[data-style=expand-right][data-loading][data-size="xs"] { + padding-right: 40px; } + +/************************************* + * EXPAND RIGHT + */ +.ladda-button[data-style=expand-left] .ladda-spinner { + left: 14px; } +.ladda-button[data-style=expand-left][data-size="s"] .ladda-spinner, .ladda-button[data-style=expand-left][data-size="xs"] .ladda-spinner { + left: 4px; } +.ladda-button[data-style=expand-left][data-loading] { + padding-left: 56px; } +.ladda-button[data-style=expand-left][data-loading] .ladda-spinner { + opacity: 1; } +.ladda-button[data-style=expand-left][data-loading][data-size="s"], .ladda-button[data-style=expand-left][data-loading][data-size="xs"] { + padding-left: 40px; } + +/************************************* + * EXPAND UP + */ +.ladda-button[data-style=expand-up] { + overflow: hidden; } +.ladda-button[data-style=expand-up] .ladda-spinner { + top: -32px; + left: 50%; + margin-left: -16px; } +.ladda-button[data-style=expand-up][data-loading] { + padding-top: 54px; } +.ladda-button[data-style=expand-up][data-loading] .ladda-spinner { + opacity: 1; + top: 14px; + margin-top: 0; } +.ladda-button[data-style=expand-up][data-loading][data-size="s"], .ladda-button[data-style=expand-up][data-loading][data-size="xs"] { + padding-top: 32px; } +.ladda-button[data-style=expand-up][data-loading][data-size="s"] .ladda-spinner, .ladda-button[data-style=expand-up][data-loading][data-size="xs"] .ladda-spinner { + top: 4px; } + +/************************************* + * EXPAND DOWN + */ +.ladda-button[data-style=expand-down] { + overflow: hidden; } +.ladda-button[data-style=expand-down] .ladda-spinner { + top: 62px; + left: 50%; + margin-left: -16px; } +.ladda-button[data-style=expand-down][data-size="s"] .ladda-spinner, .ladda-button[data-style=expand-down][data-size="xs"] .ladda-spinner { + top: 40px; } +.ladda-button[data-style=expand-down][data-loading] { + padding-bottom: 54px; } +.ladda-button[data-style=expand-down][data-loading] .ladda-spinner { + opacity: 1; } +.ladda-button[data-style=expand-down][data-loading][data-size="s"], .ladda-button[data-style=expand-down][data-loading][data-size="xs"] { + padding-bottom: 32px; } + +/************************************* + * SLIDE LEFT + */ +.ladda-button[data-style=slide-left] { + overflow: hidden; } +.ladda-button[data-style=slide-left] .ladda-label { + position: relative; } +.ladda-button[data-style=slide-left] .ladda-spinner { + left: 100%; + margin-left: -16px; } +.ladda-button[data-style=slide-left][data-loading] .ladda-label { + opacity: 0; + left: -100%; } +.ladda-button[data-style=slide-left][data-loading] .ladda-spinner { + opacity: 1; + left: 50%; } + +/************************************* + * SLIDE RIGHT + */ +.ladda-button[data-style=slide-right] { + overflow: hidden; } +.ladda-button[data-style=slide-right] .ladda-label { + position: relative; } +.ladda-button[data-style=slide-right] .ladda-spinner { + right: 100%; + margin-left: -16px; } +.ladda-button[data-style=slide-right][data-loading] .ladda-label { + opacity: 0; + left: 100%; } +.ladda-button[data-style=slide-right][data-loading] .ladda-spinner { + opacity: 1; + left: 50%; } + +/************************************* + * SLIDE UP + */ +.ladda-button[data-style=slide-up] { + overflow: hidden; } +.ladda-button[data-style=slide-up] .ladda-label { + position: relative; } +.ladda-button[data-style=slide-up] .ladda-spinner { + left: 50%; + margin-left: -16px; + margin-top: 1em; } +.ladda-button[data-style=slide-up][data-loading] .ladda-label { + opacity: 0; + top: -1em; } +.ladda-button[data-style=slide-up][data-loading] .ladda-spinner { + opacity: 1; + margin-top: -16px; } + +/************************************* + * SLIDE DOWN + */ +.ladda-button[data-style=slide-down] { + overflow: hidden; } +.ladda-button[data-style=slide-down] .ladda-label { + position: relative; } +.ladda-button[data-style=slide-down] .ladda-spinner { + left: 50%; + margin-left: -16px; + margin-top: -2em; } +.ladda-button[data-style=slide-down][data-loading] .ladda-label { + opacity: 0; + top: 1em; } +.ladda-button[data-style=slide-down][data-loading] .ladda-spinner { + opacity: 1; + margin-top: -16px; } + +/************************************* + * ZOOM-OUT + */ +.ladda-button[data-style=zoom-out] { + overflow: hidden; } + +.ladda-button[data-style=zoom-out] .ladda-spinner { + left: 50%; + margin-left: -16px; + -webkit-transform: scale(2.5); + -moz-transform: scale(2.5); + -ms-transform: scale(2.5); + -o-transform: scale(2.5); + transform: scale(2.5); } + +.ladda-button[data-style=zoom-out] .ladda-label { + position: relative; + display: inline-block; } + +.ladda-button[data-style=zoom-out][data-loading] .ladda-label { + opacity: 0; + -webkit-transform: scale(0.5); + -moz-transform: scale(0.5); + -ms-transform: scale(0.5); + -o-transform: scale(0.5); + transform: scale(0.5); } + +.ladda-button[data-style=zoom-out][data-loading] .ladda-spinner { + opacity: 1; + -webkit-transform: none; + -moz-transform: none; + -ms-transform: none; + -o-transform: none; + transform: none; } + +/************************************* + * ZOOM-IN + */ +.ladda-button[data-style=zoom-in] { + overflow: hidden; } + +.ladda-button[data-style=zoom-in] .ladda-spinner { + left: 50%; + margin-left: -16px; + -webkit-transform: scale(0.2); + -moz-transform: scale(0.2); + -ms-transform: scale(0.2); + -o-transform: scale(0.2); + transform: scale(0.2); } + +.ladda-button[data-style=zoom-in] .ladda-label { + position: relative; + display: inline-block; } + +.ladda-button[data-style=zoom-in][data-loading] .ladda-label { + opacity: 0; + -webkit-transform: scale(2.2); + -moz-transform: scale(2.2); + -ms-transform: scale(2.2); + -o-transform: scale(2.2); + transform: scale(2.2); } + +.ladda-button[data-style=zoom-in][data-loading] .ladda-spinner { + opacity: 1; + -webkit-transform: none; + -moz-transform: none; + -ms-transform: none; + -o-transform: none; + transform: none; } + +/************************************* + * CONTRACT + */ +.ladda-button[data-style=contract] { + overflow: hidden; + width: 100px; } + +.ladda-button[data-style=contract] .ladda-spinner { + left: 50%; + margin-left: -16px; } + +.ladda-button[data-style=contract][data-loading] { + border-radius: 50%; + width: 52px; } + +.ladda-button[data-style=contract][data-loading] .ladda-label { + opacity: 0; } + +.ladda-button[data-style=contract][data-loading] .ladda-spinner { + opacity: 1; } + +/************************************* + * OVERLAY + */ +.ladda-button[data-style=contract-overlay] { + overflow: hidden; + width: 100px; + box-shadow: 0px 0px 0px 3000px transparent; } + +.ladda-button[data-style=contract-overlay] .ladda-spinner { + left: 50%; + margin-left: -16px; } + +.ladda-button[data-style=contract-overlay][data-loading] { + border-radius: 50%; + width: 52px; + /*outline: 10000px solid rgba( 0, 0, 0, 0.5 );*/ + box-shadow: 0px 0px 0px 3000px rgba(0, 0, 0, 0.8); } + +.ladda-button[data-style=contract-overlay][data-loading] .ladda-label { + opacity: 0; } + +.ladda-button[data-style=contract-overlay][data-loading] .ladda-spinner { + opacity: 1; } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/css/ladda-themeless.min.css b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/css/ladda-themeless.min.css new file mode 100644 index 00000000..389d208e --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/css/ladda-themeless.min.css @@ -0,0 +1 @@ +.ladda-button{position:relative}.ladda-button .ladda-spinner{position:absolute;z-index:2;display:inline-block;width:32px;height:32px;top:50%;margin-top:0;opacity:0;pointer-events:none}.ladda-button .ladda-label{position:relative;z-index:3}.ladda-button .ladda-progress{position:absolute;width:0;height:100%;left:0;top:0;background:rgba(0,0,0,0.2);visibility:hidden;opacity:0;-webkit-transition:0.1s linear all !important;-moz-transition:0.1s linear all !important;-ms-transition:0.1s linear all !important;-o-transition:0.1s linear all !important;transition:0.1s linear all !important}.ladda-button[data-loading] .ladda-progress{opacity:1;visibility:visible}.ladda-button,.ladda-button .ladda-spinner,.ladda-button .ladda-label{-webkit-transition:0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;-moz-transition:0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;-ms-transition:0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;-o-transition:0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;transition:0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important}.ladda-button[data-style=zoom-in],.ladda-button[data-style=zoom-in] .ladda-spinner,.ladda-button[data-style=zoom-in] .ladda-label,.ladda-button[data-style=zoom-out],.ladda-button[data-style=zoom-out] .ladda-spinner,.ladda-button[data-style=zoom-out] .ladda-label{-webkit-transition:0.3s ease all !important;-moz-transition:0.3s ease all !important;-ms-transition:0.3s ease all !important;-o-transition:0.3s ease all !important;transition:0.3s ease all !important}.ladda-button[data-style=expand-right] .ladda-spinner{right:-6px}.ladda-button[data-style=expand-right][data-size="s"] .ladda-spinner,.ladda-button[data-style=expand-right][data-size="xs"] .ladda-spinner{right:-12px}.ladda-button[data-style=expand-right][data-loading]{padding-right:56px}.ladda-button[data-style=expand-right][data-loading] .ladda-spinner{opacity:1}.ladda-button[data-style=expand-right][data-loading][data-size="s"],.ladda-button[data-style=expand-right][data-loading][data-size="xs"]{padding-right:40px}.ladda-button[data-style=expand-left] .ladda-spinner{left:26px}.ladda-button[data-style=expand-left][data-size="s"] .ladda-spinner,.ladda-button[data-style=expand-left][data-size="xs"] .ladda-spinner{left:4px}.ladda-button[data-style=expand-left][data-loading]{padding-left:56px}.ladda-button[data-style=expand-left][data-loading] .ladda-spinner{opacity:1}.ladda-button[data-style=expand-left][data-loading][data-size="s"],.ladda-button[data-style=expand-left][data-loading][data-size="xs"]{padding-left:40px}.ladda-button[data-style=expand-up]{overflow:hidden}.ladda-button[data-style=expand-up] .ladda-spinner{top:-32px;left:50%;margin-left:0}.ladda-button[data-style=expand-up][data-loading]{padding-top:54px}.ladda-button[data-style=expand-up][data-loading] .ladda-spinner{opacity:1;top:26px;margin-top:0}.ladda-button[data-style=expand-up][data-loading][data-size="s"],.ladda-button[data-style=expand-up][data-loading][data-size="xs"]{padding-top:32px}.ladda-button[data-style=expand-up][data-loading][data-size="s"] .ladda-spinner,.ladda-button[data-style=expand-up][data-loading][data-size="xs"] .ladda-spinner{top:4px}.ladda-button[data-style=expand-down]{overflow:hidden}.ladda-button[data-style=expand-down] .ladda-spinner{top:62px;left:50%;margin-left:0}.ladda-button[data-style=expand-down][data-size="s"] .ladda-spinner,.ladda-button[data-style=expand-down][data-size="xs"] .ladda-spinner{top:40px}.ladda-button[data-style=expand-down][data-loading]{padding-bottom:54px}.ladda-button[data-style=expand-down][data-loading] .ladda-spinner{opacity:1}.ladda-button[data-style=expand-down][data-loading][data-size="s"],.ladda-button[data-style=expand-down][data-loading][data-size="xs"]{padding-bottom:32px}.ladda-button[data-style=slide-left]{overflow:hidden}.ladda-button[data-style=slide-left] .ladda-label{position:relative}.ladda-button[data-style=slide-left] .ladda-spinner{left:100%;margin-left:0}.ladda-button[data-style=slide-left][data-loading] .ladda-label{opacity:0;left:-100%}.ladda-button[data-style=slide-left][data-loading] .ladda-spinner{opacity:1;left:50%}.ladda-button[data-style=slide-right]{overflow:hidden}.ladda-button[data-style=slide-right] .ladda-label{position:relative}.ladda-button[data-style=slide-right] .ladda-spinner{right:100%;margin-left:0;left:16px}.ladda-button[data-style=slide-right][data-loading] .ladda-label{opacity:0;left:100%}.ladda-button[data-style=slide-right][data-loading] .ladda-spinner{opacity:1;left:50%}.ladda-button[data-style=slide-up]{overflow:hidden}.ladda-button[data-style=slide-up] .ladda-label{position:relative}.ladda-button[data-style=slide-up] .ladda-spinner{left:50%;margin-left:0;margin-top:1em}.ladda-button[data-style=slide-up][data-loading] .ladda-label{opacity:0;top:-1em}.ladda-button[data-style=slide-up][data-loading] .ladda-spinner{opacity:1;margin-top:0}.ladda-button[data-style=slide-down]{overflow:hidden}.ladda-button[data-style=slide-down] .ladda-label{position:relative}.ladda-button[data-style=slide-down] .ladda-spinner{left:50%;margin-left:0;margin-top:-2em}.ladda-button[data-style=slide-down][data-loading] .ladda-label{opacity:0;top:1em}.ladda-button[data-style=slide-down][data-loading] .ladda-spinner{opacity:1;margin-top:0}.ladda-button[data-style=zoom-out]{overflow:hidden}.ladda-button[data-style=zoom-out] .ladda-spinner{left:50%;margin-left:32px;-webkit-transform:scale(2.5);-moz-transform:scale(2.5);-ms-transform:scale(2.5);-o-transform:scale(2.5);transform:scale(2.5)}.ladda-button[data-style=zoom-out] .ladda-label{position:relative;display:inline-block}.ladda-button[data-style=zoom-out][data-loading] .ladda-label{opacity:0;-webkit-transform:scale(0.5);-moz-transform:scale(0.5);-ms-transform:scale(0.5);-o-transform:scale(0.5);transform:scale(0.5)}.ladda-button[data-style=zoom-out][data-loading] .ladda-spinner{opacity:1;margin-left:0;-webkit-transform:none;-moz-transform:none;-ms-transform:none;-o-transform:none;transform:none}.ladda-button[data-style=zoom-in]{overflow:hidden}.ladda-button[data-style=zoom-in] .ladda-spinner{left:50%;margin-left:-16px;-webkit-transform:scale(0.2);-moz-transform:scale(0.2);-ms-transform:scale(0.2);-o-transform:scale(0.2);transform:scale(0.2)}.ladda-button[data-style=zoom-in] .ladda-label{position:relative;display:inline-block}.ladda-button[data-style=zoom-in][data-loading] .ladda-label{opacity:0;-webkit-transform:scale(2.2);-moz-transform:scale(2.2);-ms-transform:scale(2.2);-o-transform:scale(2.2);transform:scale(2.2)}.ladda-button[data-style=zoom-in][data-loading] .ladda-spinner{opacity:1;margin-left:0;-webkit-transform:none;-moz-transform:none;-ms-transform:none;-o-transform:none;transform:none}.ladda-button[data-style=contract]{overflow:hidden;width:100px}.ladda-button[data-style=contract] .ladda-spinner{left:50%;margin-left:0}.ladda-button[data-style=contract][data-loading]{border-radius:50%;width:52px}.ladda-button[data-style=contract][data-loading] .ladda-label{opacity:0}.ladda-button[data-style=contract][data-loading] .ladda-spinner{opacity:1}.ladda-button[data-style=contract-overlay]{overflow:hidden;width:100px;box-shadow:0px 0px 0px 2000px transparent}.ladda-button[data-style=contract-overlay] .ladda-spinner{left:50%;margin-left:0}.ladda-button[data-style=contract-overlay][data-loading]{border-radius:50%;width:52px;box-shadow:0px 0px 0px 2000px rgba(0,0,0,0.8)}.ladda-button[data-style=contract-overlay][data-loading] .ladda-label{opacity:0}.ladda-button[data-style=contract-overlay][data-loading] .ladda-spinner{opacity:1} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/js/ladda.js b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/js/ladda.js new file mode 100644 index 00000000..5f4af9c7 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/js/ladda.js @@ -0,0 +1,160 @@ +(function(root, factory) { + if (typeof exports === "object") { + module.exports = factory(); + } else if (typeof define === "function" && define.amd) { + define([ "./spin" ], factory); + } else { + root.Ladda = factory(root.Spinner); + } +})(this, function(Spinner) { + "use strict"; + var ALL_INSTANCES = []; + function create(button) { + if (typeof button === "undefined") { + console.warn("Ladda button target must be defined."); + return; + } + if (!button.querySelector(".ladda-label")) { + button.innerHTML = '' + button.innerHTML + ""; + } + var spinner = createSpinner(button); + var spinnerWrapper = document.createElement("span"); + spinnerWrapper.className = "ladda-spinner"; + button.appendChild(spinnerWrapper); + var timer; + var instance = { + start: function() { + button.setAttribute("disabled", ""); + button.setAttribute("data-loading", ""); + clearTimeout(timer); + spinner.spin(spinnerWrapper); + this.setProgress(0); + return this; + }, + startAfter: function(delay) { + clearTimeout(timer); + timer = setTimeout(function() { + instance.start(); + }, delay); + return this; + }, + stop: function() { + button.removeAttribute("disabled"); + button.removeAttribute("data-loading"); + clearTimeout(timer); + timer = setTimeout(function() { + spinner.stop(); + }, 1e3); + return this; + }, + toggle: function() { + if (this.isLoading()) { + this.stop(); + } else { + this.start(); + } + return this; + }, + setProgress: function(progress) { + progress = Math.max(Math.min(progress, 1), 0); + var progressElement = button.querySelector(".ladda-progress"); + if (progress === 0 && progressElement && progressElement.parentNode) { + progressElement.parentNode.removeChild(progressElement); + } else { + if (!progressElement) { + progressElement = document.createElement("div"); + progressElement.className = "ladda-progress"; + button.appendChild(progressElement); + } + progressElement.style.width = (progress || 0) * button.offsetWidth + "px"; + } + }, + enable: function() { + this.stop(); + return this; + }, + disable: function() { + this.stop(); + button.setAttribute("disabled", ""); + return this; + }, + isLoading: function() { + return button.hasAttribute("data-loading"); + }, + getTarget: function() { + return button; + } + }; + ALL_INSTANCES.push(instance); + return instance; + } + function bind(target, options) { + options = options || {}; + var targets = []; + if (typeof target === "string") { + targets = toArray(document.querySelectorAll(target)); + } else if (typeof target === "object" && typeof target.nodeName === "string") { + targets = [ target ]; + } + for (var i = 0, len = targets.length; i < len; i++) { + (function() { + var element = targets[i]; + if (typeof element.addEventListener === "function") { + var instance = create(element); + var timeout = -1; + element.addEventListener("click", function() { + instance.startAfter(1); + if (typeof options.timeout === "number") { + clearTimeout(timeout); + timeout = setTimeout(instance.stop, options.timeout); + } + if (typeof options.callback === "function") { + options.callback.apply(null, [ instance ]); + } + }, false); + } + })(); + } + } + function stopAll() { + for (var i = 0, len = ALL_INSTANCES.length; i < len; i++) { + ALL_INSTANCES[i].stop(); + } + } + function createSpinner(button) { + var height = button.offsetHeight, spinnerColor; + if (height > 32) { + height *= .8; + } + if (button.hasAttribute("data-spinner-size")) { + height = parseInt(button.getAttribute("data-spinner-size"), 10); + } + if (button.hasAttribute("data-spinner-color")) { + spinnerColor = button.getAttribute("data-spinner-color"); + } + var lines = 12, radius = height * .2, length = radius * .6, width = radius < 7 ? 2 : 3; + return new Spinner({ + color: spinnerColor || "#fff", + lines: lines, + radius: radius, + length: length, + width: width, + zIndex: "auto", + top: "50%", + left: "50%", + className: "" + }); + } + function toArray(nodes) { + var a = []; + for (var i = 0; i < nodes.length; i++) { + a.push(nodes[i]); + } + return a; + } + return { + bind: bind, + create: create, + stopAll: stopAll + }; +}); \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/js/ladda.min.js b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/js/ladda.min.js new file mode 100644 index 00000000..7d8e22a9 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/buttons/ladda/js/ladda.min.js @@ -0,0 +1 @@ +(function(t,e){"object"==typeof exports?module.exports=e(require("spin.js")):"function"==typeof define&&define.amd?define(["spin"],e):t.Ladda=e(t.Spinner)})(this,function(t){"use strict";function e(t){if(t===void 0)return console.warn("Ladda button target must be defined."),void 0;t.querySelector(".ladda-label")||(t.innerHTML=''+t.innerHTML+"");var e,n=document.createElement("span");n.className="ladda-spinner",t.appendChild(n);var r,a={start:function(){return e||(e=o(t)),t.setAttribute("disabled",""),t.setAttribute("data-loading",""),clearTimeout(r),e.spin(n),this.setProgress(0),this},startAfter:function(t){return clearTimeout(r),r=setTimeout(function(){a.start()},t),this},stop:function(){return t.removeAttribute("disabled"),t.removeAttribute("data-loading"),clearTimeout(r),e&&(r=setTimeout(function(){e.stop()},1e3)),this},toggle:function(){return this.isLoading()?this.stop():this.start(),this},setProgress:function(e){e=Math.max(Math.min(e,1),0);var n=t.querySelector(".ladda-progress");0===e&&n&&n.parentNode?n.parentNode.removeChild(n):(n||(n=document.createElement("div"),n.className="ladda-progress",t.appendChild(n)),n.style.width=(e||0)*t.offsetWidth+"px")},enable:function(){return this.stop(),this},disable:function(){return this.stop(),t.setAttribute("disabled",""),this},isLoading:function(){return t.hasAttribute("data-loading")},remove:function(){clearTimeout(r),t.removeAttribute("disabled",""),t.removeAttribute("data-loading",""),e&&(e.stop(),e=null);for(var n=0,i=u.length;i>n;n++)if(a===u[n]){u.splice(n,1);break}}};return u.push(a),a}function n(t,e){for(;t.parentNode&&t.tagName!==e;)t=t.parentNode;return e===t.tagName?t:void 0}function r(t){for(var e=["input","textarea"],n=[],r=0;e.length>r;r++)for(var a=t.getElementsByTagName(e[r]),i=0;a.length>i;i++)a[i].hasAttribute("required")&&n.push(a[i]);return n}function a(t,a){a=a||{};var i=[];"string"==typeof t?i=s(document.querySelectorAll(t)):"object"==typeof t&&"string"==typeof t.nodeName&&(i=[t]);for(var o=0,u=i.length;u>o;o++)(function(){var t=i[o];if("function"==typeof t.addEventListener){var s=e(t),u=-1;t.addEventListener("click",function(){var e=!0,i=n(t,"FORM");if(i!==void 0)for(var o=r(i),d=0;o.length>d;d++)""===o[d].value.replace(/^\s+|\s+$/g,"")&&(e=!1);e&&(s.startAfter(1),"number"==typeof a.timeout&&(clearTimeout(u),u=setTimeout(s.stop,a.timeout)),"function"==typeof a.callback&&a.callback.apply(null,[s]))},!1)}})()}function i(){for(var t=0,e=u.length;e>t;t++)u[t].stop()}function o(e){var n,r=e.offsetHeight;0===r&&(r=parseFloat(window.getComputedStyle(e).height)),r>32&&(r*=.8),e.hasAttribute("data-spinner-size")&&(r=parseInt(e.getAttribute("data-spinner-size"),10)),e.hasAttribute("data-spinner-color")&&(n=e.getAttribute("data-spinner-color"));var a=12,i=.2*r,o=.6*i,s=7>i?2:3;return new t({color:n||"#fff",lines:a,radius:i,length:o,width:s,zIndex:"auto",top:"auto",left:"auto",className:""})}function s(t){for(var e=[],n=0;t.length>n;n++)e.push(t[n]);return e}var u=[];return{bind:a,create:e,stopAll:i}}); \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapAddButton.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapAddButton.java index d0937a10..341bd610 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapAddButton.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapAddButton.java @@ -16,8 +16,8 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons.Size; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconType; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.ladda.LaddaAjaxButton; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; +import org.devgateway.toolkit.forms.wicket.components.buttons.ladda.LaddaAjaxButton; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.event.IEvent; import org.apache.wicket.model.IModel; @@ -37,9 +37,9 @@ public abstract class BootstrapAddButton extends LaddaAjaxButton { */ public BootstrapAddButton(final String id, final IModel model) { super(id, model, Buttons.Type.Info); - setIconType(FontAwesomeIconType.save); + setIconType(FontAwesome5IconType.save_s); setDefaultFormProcessing(false); - setIconType(FontAwesomeIconType.plus).setSize(Size.Medium).setLabel(model); + setIconType(FontAwesome5IconType.plus_s).setSize(Size.Medium).setLabel(model); setOutputMarkupPlaceholderTag(true); } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapCancelButton.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapCancelButton.java index b20acc67..ddbbffdd 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapCancelButton.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapCancelButton.java @@ -1,29 +1,29 @@ -/******************************************************************************* +/** * Copyright (c) 2015 Development Gateway, Inc and others. - * + *

* All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT - * + *

* Contributors: * Development Gateway - initial API and implementation - *******************************************************************************/ + */ /** - * + * */ package org.devgateway.toolkit.forms.wicket.components.form; import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconType; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.ladda.LaddaAjaxButton; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; +import org.devgateway.toolkit.forms.wicket.components.buttons.ladda.LaddaAjaxButton; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.model.IModel; import org.devgateway.toolkit.forms.wicket.components.ComponentUtil; /** * @author mpostelnicu - * + * */ public abstract class BootstrapCancelButton extends LaddaAjaxButton { @@ -36,7 +36,7 @@ public abstract class BootstrapCancelButton extends LaddaAjaxButton { public BootstrapCancelButton(final String id, final IModel model) { super(id, model, Buttons.Type.Default); setDefaultFormProcessing(false); - setIconType(FontAwesomeIconType.ban); + setIconType(FontAwesome5IconType.ban_s); } @Override @@ -44,7 +44,7 @@ public BootstrapCancelButton(final String id, final IModel model) { /* * (non-Javadoc) - * + * * @see de.agilecoders.wicket.extensions.markup.html.bootstrap.ladda. * LaddaAjaxButton#onInitialize() */ diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapDeleteButton.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapDeleteButton.java index fd9611ef..af65c591 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapDeleteButton.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapDeleteButton.java @@ -1,22 +1,22 @@ -/******************************************************************************* +/** * Copyright (c) 2015 Development Gateway, Inc and others. - * + *

* All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT - * + *

* Contributors: * Development Gateway - initial API and implementation - *******************************************************************************/ + */ /** - * + * */ package org.devgateway.toolkit.forms.wicket.components.form; import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconType; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.ladda.LaddaAjaxButton; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; +import org.devgateway.toolkit.forms.wicket.components.buttons.ladda.LaddaAjaxButton; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.attributes.AjaxCallListener; import org.apache.wicket.ajax.attributes.AjaxRequestAttributes; @@ -29,7 +29,7 @@ /** * @author mpostelnicu - * + * */ public abstract class BootstrapDeleteButton extends LaddaAjaxButton { @@ -55,7 +55,7 @@ protected void onInitialize() { super.onInitialize(); add(new AttributeAppender("onclick", new Model("window.onbeforeunload = null;"), " ")); setDefaultFormProcessing(false); - setIconType(FontAwesomeIconType.trash_o); + setIconType(FontAwesome5IconType.trash_s); if (ComponentUtil.isViewMode()) { setVisibilityAllowed(false); diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapSubmitButton.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapSubmitButton.java index 65a9b22f..22e9dd56 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapSubmitButton.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/BootstrapSubmitButton.java @@ -1,23 +1,22 @@ -/******************************************************************************* +/** * Copyright (c) 2015 Development Gateway, Inc and others. - * + *

* All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT - * + *

* Contributors: * Development Gateway - initial API and implementation - *******************************************************************************/ + */ /** - * + * */ package org.devgateway.toolkit.forms.wicket.components.form; import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconType; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.ladda.LaddaAjaxButton; - +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; +import org.devgateway.toolkit.forms.wicket.components.buttons.ladda.LaddaAjaxButton; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.model.IModel; @@ -25,7 +24,7 @@ /** * @author mpostelnicu - * + * */ public abstract class BootstrapSubmitButton extends LaddaAjaxButton { @@ -37,12 +36,12 @@ public abstract class BootstrapSubmitButton extends LaddaAjaxButton { */ public BootstrapSubmitButton(final String id, final IModel model) { super(id, model, Buttons.Type.Primary); - setIconType(FontAwesomeIconType.save); + setIconType(FontAwesome5IconType.save_s); } public BootstrapSubmitButton(final String id, final Form form, final IModel model) { super(id, model, form, Buttons.Type.Primary); - setIconType(FontAwesomeIconType.save); + setIconType(FontAwesome5IconType.save_s); } @Override diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/CheckBoxBootstrapFormComponent.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/CheckBoxBootstrapFormComponent.java index 7fe82e93..2c425b2f 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/CheckBoxBootstrapFormComponent.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/CheckBoxBootstrapFormComponent.java @@ -19,7 +19,6 @@ /** * @author mpostelnicu - * */ public class CheckBoxBootstrapFormComponent extends GenericEnablingBootstrapFormComponent { private static final long serialVersionUID = -4032850928243673675L; @@ -27,7 +26,7 @@ public class CheckBoxBootstrapFormComponent extends GenericEnablingBootstrapForm private CheckBox wrappedCheckbox; public CheckBoxBootstrapFormComponent(final String id, final IModel labelModel, - final IModel model) { + final IModel model) { super(id, labelModel, model); } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/CheckBoxPickerBootstrapFormComponent.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/CheckBoxPickerBootstrapFormComponent.java index 4f609a29..a47eb312 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/CheckBoxPickerBootstrapFormComponent.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/CheckBoxPickerBootstrapFormComponent.java @@ -14,14 +14,13 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.button.ButtonGroup; import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.checkbox.bootstrapcheckbox.BootstrapCheckBoxPicker; import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.checkbox.bootstrapcheckbox.BootstrapCheckBoxPickerConfig; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconType; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.model.IModel; /** * @author mpostelnicu - * */ public class CheckBoxPickerBootstrapFormComponent extends GenericEnablingBootstrapFormComponent { @@ -30,7 +29,7 @@ public class CheckBoxPickerBootstrapFormComponent private BootstrapCheckBoxPickerConfig config; public CheckBoxPickerBootstrapFormComponent(final String id, final IModel labelModel, - final IModel model) { + final IModel model) { super(id, labelModel, model); } @@ -50,7 +49,7 @@ public CheckBoxPickerBootstrapFormComponent(final String id) { protected BootstrapCheckBoxPicker inputField(final String id, final IModel model) { config = new BootstrapCheckBoxPickerConfig().withOnClass("btn-info").withOffClass("btn-warning") - .withOnIcon(FontAwesomeIconType.thumbs_up).withOffIcon(FontAwesomeIconType.thumbs_down) + .withOnIcon(FontAwesome5IconType.thumbs_up_s).withOffIcon(FontAwesome5IconType.thumbs_down_s) .withReverse(true).withStyle(ButtonGroup.Size.Small); final BootstrapCheckBoxPicker checkBoxPicker = new BootstrapCheckBoxPicker("field", initFieldModel(), config); diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/ColorPickerBootstrapFormComponent.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/ColorPickerBootstrapFormComponent.java index 950291f4..5ecc96e7 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/ColorPickerBootstrapFormComponent.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/ColorPickerBootstrapFormComponent.java @@ -1,16 +1,16 @@ -/******************************************************************************* +/** * Copyright (c) 2015 Development Gateway, Inc and others. - * + *

* All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT - * + *

* Contributors: * Development Gateway - initial API and implementation - *******************************************************************************/ + */ /** - * + * */ package org.devgateway.toolkit.forms.wicket.components.form; @@ -19,7 +19,7 @@ /** * @author mpostelnicu - * + * */ public class ColorPickerBootstrapFormComponent extends GenericBootstrapFormComponent { diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/EditableTablePanel.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/EditableTablePanel.java index 3f822c34..bf4e5f82 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/EditableTablePanel.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/EditableTablePanel.java @@ -35,11 +35,11 @@ /** * This panel can be used to edit small data grid tables. - * + *

*

For many columns you need to use {@link org.devgateway.toolkit.forms.wicket.components.ListViewSectionPanel}. * For too many rows you should check * {@link org.devgateway.toolkit.forms.wicket.components.form.EditableGridFormComponent}. - * + *

*

This class also tracks and updates computed columns (computed formula must be defined in the column model). * *

(Optional) You can use bottom toolbar for computed totals. @@ -52,23 +52,20 @@ public class EditableTablePanel property that can be used as unique id among entries */ protected String rowIdProperty; - + protected boolean usePagingWithErrors = true; + protected CustomUpdatableToolbar customUpdatableToolbar; private List computedColumnsProperties = new ArrayList<>(); private Map rowId2RowIndex = new HashMap<>(); private Map> rowId2ComputedColumnsComponentIds = new HashMap<>(); - - protected boolean usePagingWithErrors = true; private LoopItem currentPaginatorLoopItem; - protected CustomUpdatableToolbar customUpdatableToolbar; - public EditableTablePanel(final String id, final IModel parentModel) { super(id, parentModel); } protected AjaxFallbackBootstrapDataTable buildDataTable() { AjaxFallbackBootstrapDataTable dataTable = super.buildDataTable(); - if (this.rowsPerPage != WebConstants.PAGE_SIZE_NO_LIMIT && usePagingWithErrors) { + if (usePagingWithErrors) { AjaxBootstrapNavigationToolbar navToolbar = dataTable.getNavigationToolbar(); navToolbar.withPagingNavFactory(new PagingNavigationFactory(EditableTablePagination.class, this)); } @@ -98,7 +95,7 @@ public void addComputedColumn(final String resourceKey, final String property) { } public void addComputedColumn(final String resourceKey, final String sortProperty, final String property, - final String css) { + final String css) { if (rowIdProperty == null) { throw new RuntimeException("No row id property configured."); } @@ -106,9 +103,10 @@ public void addComputedColumn(final String resourceKey, final String sortPropert IColumn computedColumn = new PropertyColumn( new StringResourceModel(resourceKey), sortProperty, property) { private static final long serialVersionUID = -3578903469355827616L; + @Override public void populateItem(final Item> item, final String componentId, - final IModel rowModel) { + final IModel rowModel) { super.populateItem(item, componentId, rowModel); item.setOutputMarkupId(true); @@ -146,7 +144,7 @@ protected void onUpdate(final AjaxRequestTarget target) { protected boolean hasErrors(final long pageIndex) { // customize with your page validation logic - return false; + return false; } private void onRowEdit(final AjaxRequestTarget target, final IModel rowModel) { @@ -195,7 +193,7 @@ public class EditableTablePagination extends AbstractBootstrapPagingNavigationWi private static final long serialVersionUID = -5015086509864523000L; public EditableTablePagination(final String id, final IPageable pageable, - final IPagingLabelProvider labelProvider) { + final IPagingLabelProvider labelProvider) { super(id, pageable, labelProvider); } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/FileInputBootstrapFormComponent.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/FileInputBootstrapFormComponent.java index 954dc58d..bbd62cd0 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/FileInputBootstrapFormComponent.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/FileInputBootstrapFormComponent.java @@ -19,7 +19,7 @@ import org.devgateway.toolkit.persistence.dao.FileMetadata; import org.devgateway.toolkit.persistence.dao.GenericPersistable; -import javax.persistence.EntityManager; +import jakarta.persistence.EntityManager; import java.util.Arrays; import java.util.Collection; diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/FileInputBootstrapFormComponentWrapper.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/FileInputBootstrapFormComponentWrapper.html index 352e0ba5..eeadd923 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/FileInputBootstrapFormComponentWrapper.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/FileInputBootstrapFormComponentWrapper.html @@ -13,7 +13,7 @@ - + @@ -45,6 +45,10 @@ +

diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/FileInputBootstrapFormComponentWrapper.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/FileInputBootstrapFormComponentWrapper.java index b611b9ca..c61add4d 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/FileInputBootstrapFormComponentWrapper.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/FileInputBootstrapFormComponentWrapper.java @@ -19,7 +19,7 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.image.IconBehavior; import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.fileinput.BootstrapFileInput; import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.fileinput.FileInputConfig; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconType; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; import de.agilecoders.wicket.jquery.Key; import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; @@ -96,6 +96,8 @@ public class FileInputBootstrapFormComponentWrapper extends FormComponentPane private Boolean disableDeleteButton = false; + private boolean allowDownloadWhenReadonly = true; + private boolean requireAtLeastOneItem = false; /** @@ -133,7 +135,7 @@ protected void onInitialize() { addFileUploadFeedbackComponent(); addBootstrapFileInputComponent(); - bootstrapFileInput.withShowUpload(true).withShowRemove(false).withShowPreview(true).withShowCaption(true); + bootstrapFileInput.withShowUpload(true).withShowRemove(false).withShowPreview(false).withShowCaption(true); } public boolean isVisibleAlreadyUploadedFiles() { @@ -209,11 +211,17 @@ public String getContentType() { } }; + ResourceStreamRequestHandler handler = new ResourceStreamRequestHandler(rstream, modelObject.getName()); handler.setContentDisposition(ContentDisposition.ATTACHMENT); getRequestCycle().scheduleRequestHandlerAfterCurrent(handler); } + + @Override + public boolean isEnabledInHierarchy() { + return isLinkEnabledInHierarchy(this, super.isEnabledInHierarchy()); + } }; downloadLink.add(new Label("downloadText", item.getModelObject().getName())); downloadLink.add(new TooltipBehavior(new StringResourceModel("downloadUploadedFileTooltip", @@ -235,7 +243,7 @@ public void onClick(final AjaxRequestTarget target) { target.add(alreadyUploadedFiles); } }; - delete.add(new IconBehavior(FontAwesomeIconType.trash)); + delete.add(new IconBehavior(FontAwesome5IconType.trash_s)); delete.add(new TooltipBehavior(new StringResourceModel("removeUploadedFileTooltip", FileInputBootstrapFormComponentWrapper.this, null), TOOLTIP_CONFIG)); @@ -345,7 +353,7 @@ public void onClick(final AjaxRequestTarget target) { FileInputBootstrapFormComponentWrapper.this.onUpdate(target); } }; - delete.add(new IconBehavior(FontAwesomeIconType.trash)); + delete.add(new IconBehavior(FontAwesome5IconType.trash_s)); delete.add(new TooltipBehavior(new StringResourceModel("removeUploadedFileTooltip", FileInputBootstrapFormComponentWrapper.this, null), TOOLTIP_CONFIG)); @@ -457,6 +465,7 @@ protected void onSubmit(final AjaxRequestTarget target) { target.add(fileUploadFeedback); target.add(pendingFiles); + target.appendJavaScript("$('.cover-buttons-div').css(\"z-index\", -1);"); FileInputBootstrapFormComponentWrapper.this.onUpdate(target); } }; @@ -564,6 +573,21 @@ public void requireAtLeastOneItem() { requireAtLeastOneItem = true; } + public boolean isAllowDownloadWhenReadonly() { + return allowDownloadWhenReadonly; + } + + public void setAllowDownloadWhenReadonly(final boolean allowDownloadWhenReadonly) { + this.allowDownloadWhenReadonly = allowDownloadWhenReadonly; + } + + private boolean isLinkEnabledInHierarchy(final Component component, final boolean defaultState) { + if (allowDownloadWhenReadonly) { + return component.isEnableAllowed() && component.isEnabled(); + } + return defaultState; + } + @Override public boolean checkRequired() { return !requireAtLeastOneItem || !ObjectUtils.isEmpty(getModelObject()); diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/GenericBootstrapFormComponent.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/GenericBootstrapFormComponent.java index d925fcb7..b2b84fd1 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/GenericBootstrapFormComponent.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/GenericBootstrapFormComponent.java @@ -16,14 +16,12 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.form.InputBehavior; import de.agilecoders.wicket.core.markup.html.bootstrap.form.InputBehavior.Size; import de.agilecoders.wicket.core.util.Attributes; -import org.apache.wicket.AttributeModifier; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.event.IEvent; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.html.TransparentWebMarkupContainer; -import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.CheckGroup; import org.apache.wicket.markup.html.form.FormComponent; @@ -42,10 +40,8 @@ import org.hibernate.envers.AuditReaderFactory; import org.hibernate.envers.query.AuditEntity; import org.hibernate.envers.query.AuditQuery; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import javax.persistence.EntityManager; +import jakarta.persistence.EntityManager; import java.util.ArrayList; import java.util.List; @@ -54,20 +50,14 @@ */ public abstract class GenericBootstrapFormComponent> extends FieldPanel { private static final long serialVersionUID = -7051128382707812456L; - + private final IModel labelModel; protected FormGroup border; - protected FIELD field; - private InputBehavior sizeBehavior; - private TooltipConfig.OpenTrigger configWithTrigger = TooltipConfig.OpenTrigger.hover; - // use a flag if we need to display a Tooltip since StringResourceModel it's expensive private Boolean showTooltip = false; - private final IModel labelModel; - public GenericBootstrapFormComponent(final String id) { this(id, null); } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/GenericEnablingBootstrapFormComponent.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/GenericEnablingBootstrapFormComponent.java index 2edc5cad..23b6f891 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/GenericEnablingBootstrapFormComponent.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/GenericEnablingBootstrapFormComponent.java @@ -1,16 +1,16 @@ -/******************************************************************************* +/** * Copyright (c) 2015 Development Gateway, Inc and others. - * + *

* All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT - * + *

* Contributors: * Development Gateway - initial API and implementation - *******************************************************************************/ + */ /** - * + * */ package org.devgateway.toolkit.forms.wicket.components.form; @@ -54,14 +54,14 @@ public GenericEnablingBootstrapFormComponent(final String id, final IModel * @param model */ public GenericEnablingBootstrapFormComponent(final String id, final IModel labelModel, - final IModel model) { + final IModel model) { super(id, labelModel, model); } /** * Returns true if the bound components should have * {@link #setVisibilityAllowed(boolean)} to true otherwise returns false. - * + * * @param selectedValue * the selected value of the current component, that may be taken * into consideration when evaluating the visibility of the bound @@ -73,7 +73,7 @@ public GenericEnablingBootstrapFormComponent(final String id, final IModel addBoundComponent(fina /** * This is the negated version of * {@link GenericEnablingBootstrapFormComponent#addBoundComponent(Component)} - * + * * @param c * @return */ diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/PercentageFieldBootstrapFormComponent.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/PercentageFieldBootstrapFormComponent.java index 000654eb..93b1c519 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/PercentageFieldBootstrapFormComponent.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/PercentageFieldBootstrapFormComponent.java @@ -1,16 +1,16 @@ -/******************************************************************************* +/** * Copyright (c) 2015 Development Gateway, Inc and others. - * + *

* All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT - * + *

* Contributors: * Development Gateway - initial API and implementation - *******************************************************************************/ + */ /** - * + * */ package org.devgateway.toolkit.forms.wicket.components.form; @@ -38,7 +38,7 @@ public class PercentageFieldBootstrapFormComponent extends TextFieldBootstrapFor private Label label; public PercentageFieldBootstrapFormComponent(final String id, final IModel labelModel, - final IModel model) { + final IModel model) { super(id, labelModel, model); } @@ -60,7 +60,7 @@ protected TextField inputField(final String id, final IModel auditorClass, final EntityManager entityManager, diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/Select2MultiChoiceBootstrapFormComponent.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/Select2MultiChoiceBootstrapFormComponent.java index 2f1fa64a..ac62bc69 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/Select2MultiChoiceBootstrapFormComponent.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/Select2MultiChoiceBootstrapFormComponent.java @@ -21,7 +21,7 @@ import org.wicketstuff.select2.Select2BootstrapTheme; import org.wicketstuff.select2.Select2MultiChoice; -import javax.persistence.EntityManager; +import jakarta.persistence.EntityManager; import java.util.Collection; /** diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/ToolkitSummernoteEditor.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/ToolkitSummernoteEditor.java index e2e72f71..4216477c 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/ToolkitSummernoteEditor.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/form/ToolkitSummernoteEditor.java @@ -9,11 +9,11 @@ import de.agilecoders.wicket.extensions.markup.html.bootstrap.editor.SummernoteEditorOverlayCssReference; import de.agilecoders.wicket.extensions.markup.html.bootstrap.editor.SummernoteStorage; import de.agilecoders.wicket.extensions.markup.html.bootstrap.editor.SummernoteStoredImageResourceReference; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeCssReference; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5CssReference; import de.agilecoders.wicket.extensions.markup.html.bootstrap.references.SpinJsReference; import de.agilecoders.wicket.jquery.IKey; -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload2.core.FileItem; +import org.apache.commons.fileupload2.core.FileUploadException; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior; import org.apache.wicket.ajax.AjaxRequestTarget; @@ -159,7 +159,7 @@ public void renderHead(final IHeaderResponse response) { return; } response.render(CssHeaderItem.forReference(SummernoteEditorCssReference.instance())); - response.render(CssHeaderItem.forReference(FontAwesomeCssReference.instance())); + response.render(CssHeaderItem.forReference(FontAwesome5CssReference.instance())); response.render(CssHeaderItem.forReference(SummernoteEditorOverlayCssReference.instance())); response.render(JavaScriptHeaderItem.forReference(SummernoteEditorJavaScriptReference.instance())); response.render(JavaScriptHeaderItem.forReference(SummernoteEditorFormDataReference.instance())); diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/modal/ConfirmationModal.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/modal/ConfirmationModal.java index 9b8a9632..b880a994 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/modal/ConfirmationModal.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/modal/ConfirmationModal.java @@ -2,7 +2,7 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconType; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Form; @@ -33,7 +33,7 @@ public ConfirmationModal(String markupId, IModel model) { setFadeIn(false); form = new Form("confirmationForm"); - description = new Label("description", new StringResourceModel("description")); + description = new Label("description", new StringResourceModel("description", this).getString()); form.add(description); form.add(getSubmitButton()); form.add(getCancelButton()); @@ -55,7 +55,7 @@ protected void onError(final AjaxRequestTarget target) { } }; submitButton.setType(Buttons.Type.Success); - submitButton.setIconType(FontAwesomeIconType.check); + submitButton.setIconType(FontAwesome5IconType.check_s); return submitButton; } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/AbstractBootstrapPagingNavigationWithError.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/AbstractBootstrapPagingNavigationWithError.java index 69db1e93..ca15a79b 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/AbstractBootstrapPagingNavigationWithError.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/AbstractBootstrapPagingNavigationWithError.java @@ -23,5 +23,5 @@ protected String getCssClass(final long pageIndex) { .filter(s -> !s.isEmpty()).collect(Collectors.joining(" ")); } - protected abstract boolean hasErrors(final long pageIndex); + protected abstract boolean hasErrors(long pageIndex); } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/AjaxBootstrapNavigator.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/AjaxBootstrapNavigator.java index 736c8d0d..43b0aac2 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/AjaxBootstrapNavigator.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/AjaxBootstrapNavigator.java @@ -12,13 +12,11 @@ package org.devgateway.toolkit.forms.wicket.components.table; import org.apache.wicket.Component; -import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigator; import org.apache.wicket.markup.html.link.AbstractLink; import org.apache.wicket.markup.html.navigation.paging.IPageable; import org.apache.wicket.markup.html.navigation.paging.IPagingLabelProvider; import org.apache.wicket.markup.html.navigation.paging.PagingNavigation; -import org.devgateway.toolkit.forms.WebConstants; /** * @author idobre diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/PagingNavigationFactory.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/PagingNavigationFactory.java index a3ca7811..880fb97a 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/PagingNavigationFactory.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/PagingNavigationFactory.java @@ -5,7 +5,6 @@ import org.apache.wicket.markup.html.navigation.paging.PagingNavigation; import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; /** * @author Nadejda Mandrescu diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/CSVDatasetFilterState.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/CSVDatasetFilterState.java new file mode 100644 index 00000000..2ddd08c3 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/CSVDatasetFilterState.java @@ -0,0 +1,76 @@ +package org.devgateway.toolkit.forms.wicket.components.table.filter; + +import org.apache.commons.lang3.StringUtils; +import org.devgateway.toolkit.persistence.dao.AbstractStatusAuditableEntity_; +import org.devgateway.toolkit.persistence.dao.data.CSVDataset; +import org.devgateway.toolkit.persistence.dao.data.CSVDataset_; +import org.devgateway.toolkit.persistence.repository.SpecificationContext; +import org.springframework.data.jpa.domain.Specification; + +import jakarta.persistence.criteria.Predicate; +import java.util.ArrayList; +import java.util.List; + +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.DELETED; + +/** + * Created by Viorel Chihai + */ +public class CSVDatasetFilterState extends JpaFilterState { + + private static final long serialVersionUID = -3419455862012018431L; + + private Integer year; + + private String status; + + private String service; + + @Override + public Specification getSpecification() { + return (root, query, cb) -> { + List predicates = new ArrayList<>(); + SpecificationContext sc = new SpecificationContext<>(root, query, cb); + + predicates.add(sc.cb().notLike(sc.root().get(AbstractStatusAuditableEntity_.status), DELETED)); + + if (StringUtils.isNotBlank(service)) { + predicates.add(sc.cb().equal(sc.cb().lower(sc.root().get(CSVDataset_.destinationService)), service.toLowerCase())); + } + + if (year != null) { + predicates.add(sc.cb().equal(sc.root().get(CSVDataset_.year), year)); + } + + if (StringUtils.isNotBlank(status)) { + predicates.add(sc.cb().like(sc.root().get(CSVDataset_.status), status)); + } + + return cb.and(predicates.toArray(new Predicate[predicates.size()])); + }; + } + + public Integer getYear() { + return year; + } + + public void setYear(final Integer year) { + this.year = year; + } + + public String getStatus() { + return status; + } + + public void setStatus(final String status) { + this.status = status; + } + + public String getService() { + return service; + } + + public void setService(final String service) { + this.service = service; + } +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/JpaFilterState.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/JpaFilterState.java index b9739a76..8ae6207d 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/JpaFilterState.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/JpaFilterState.java @@ -7,7 +7,7 @@ import org.devgateway.toolkit.persistence.repository.SpecificationContext; import org.springframework.data.jpa.domain.Specification; -import javax.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Predicate; import java.io.Serializable; import java.util.List; diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceCategoryFilterState.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceCategoryFilterState.java new file mode 100644 index 00000000..3f471e47 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceCategoryFilterState.java @@ -0,0 +1,57 @@ +package org.devgateway.toolkit.forms.wicket.components.table.filter; + +import org.apache.commons.lang3.StringUtils; +import org.devgateway.toolkit.persistence.dto.ServiceCategory; + +import java.util.function.Predicate; + +public class ServiceCategoryFilterState extends ServiceEntityFilterState { + + private String code; + + private String value; + + private String type; + + @Override + public Predicate spec() { + Predicate filter = super.spec(); + if (StringUtils.isNotBlank(code)) { + filter = filter.and((ServiceCategory) -> StringUtils.containsIgnoreCase(ServiceCategory.getCode(), code)); + } + + if (StringUtils.isNotBlank(value)) { + filter = filter.and((ServiceCategory) -> StringUtils.containsIgnoreCase(ServiceCategory.getValue(), value)); + } + + if (StringUtils.isNotBlank(type)) { + filter = filter.and((ServiceCategory) -> StringUtils.containsIgnoreCase(ServiceCategory.getType(), type)); + } + + return filter; + } + + public String getCode() { + return code; + } + + public void setCode(final String code) { + this.code = code; + } + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } + + public String getType() { + return type; + } + + public void setType(final String type) { + this.type = type; + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceDatasetFilterState.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceDatasetFilterState.java new file mode 100644 index 00000000..8c0095a8 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceDatasetFilterState.java @@ -0,0 +1,43 @@ +package org.devgateway.toolkit.forms.wicket.components.table.filter; + +import org.apache.commons.lang3.StringUtils; +import org.devgateway.toolkit.persistence.dto.ServiceDataset; + +import java.util.function.Predicate; + +public class ServiceDatasetFilterState extends ServiceEntityFilterState { + + private String code; + + private String value; + + @Override + public Predicate spec() { + Predicate filter = super.spec(); + if (StringUtils.isNotBlank(code)) { + filter = filter.and((ServiceDataset) -> StringUtils.containsIgnoreCase(ServiceDataset.getCode(), code)); + } + + if (StringUtils.isNotBlank(value)) { + filter = filter.and((ServiceDataset) -> StringUtils.containsIgnoreCase(ServiceDataset.getValue(), value)); + } + + return filter; + } + + public String getCode() { + return code; + } + + public void setCode(final String code) { + this.code = code; + } + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceDimensionFilterState.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceDimensionFilterState.java new file mode 100644 index 00000000..dace0c96 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceDimensionFilterState.java @@ -0,0 +1,43 @@ +package org.devgateway.toolkit.forms.wicket.components.table.filter; + +import org.apache.commons.lang3.StringUtils; +import org.devgateway.toolkit.persistence.dto.ServiceDimension; + +import java.util.function.Predicate; + +public class ServiceDimensionFilterState extends ServiceEntityFilterState { + + private String code; + + private String value; + + @Override + public Predicate spec() { + Predicate filter = super.spec(); + if (StringUtils.isNotBlank(code)) { + filter = filter.and((ServiceDimension) -> StringUtils.containsIgnoreCase(ServiceDimension.getCode(), code)); + } + + if (StringUtils.isNotBlank(value)) { + filter = filter.and((ServiceDimension) -> StringUtils.containsIgnoreCase(ServiceDimension.getValue(), value)); + } + + return filter; + } + + public String getCode() { + return code; + } + + public void setCode(final String code) { + this.code = code; + } + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceEntityFilterState.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceEntityFilterState.java new file mode 100644 index 00000000..0dd19673 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceEntityFilterState.java @@ -0,0 +1,14 @@ +package org.devgateway.toolkit.forms.wicket.components.table.filter; + +import org.devgateway.toolkit.persistence.dto.ServiceEntity; + +import java.io.Serializable; +import java.util.function.Predicate; + +public class ServiceEntityFilterState implements Serializable { + + public Predicate spec() { + return (T) -> true; + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceFilterFilterState.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceFilterFilterState.java new file mode 100644 index 00000000..8b9d4896 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceFilterFilterState.java @@ -0,0 +1,57 @@ +package org.devgateway.toolkit.forms.wicket.components.table.filter; + +import org.apache.commons.lang3.StringUtils; +import org.devgateway.toolkit.persistence.dto.ServiceFilter; + +import java.util.function.Predicate; + +public class ServiceFilterFilterState extends ServiceEntityFilterState { + + private String code; + + private String value; + + private String fieldType; + + @Override + public Predicate spec() { + Predicate filter = super.spec(); + if (StringUtils.isNotBlank(code)) { + filter = filter.and((ServiceFilter) -> StringUtils.containsIgnoreCase(ServiceFilter.getCode(), code)); + } + + if (StringUtils.isNotBlank(value)) { + filter = filter.and((ServiceFilter) -> StringUtils.containsIgnoreCase(ServiceFilter.getValue(), value)); + } + + if (StringUtils.isNotBlank(fieldType)) { + filter = filter.and((ServiceFilter) -> StringUtils.containsIgnoreCase(ServiceFilter.getFieldType(), fieldType)); + } + + return filter; + } + + public String getCode() { + return code; + } + + public void setCode(final String code) { + this.code = code; + } + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } + + public String getFieldType() { + return fieldType; + } + + public void setFieldType(final String fieldType) { + this.fieldType = fieldType; + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceMeasureFilterState.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceMeasureFilterState.java new file mode 100644 index 00000000..deb19d4d --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/ServiceMeasureFilterState.java @@ -0,0 +1,57 @@ +package org.devgateway.toolkit.forms.wicket.components.table.filter; + +import org.apache.commons.lang3.StringUtils; +import org.devgateway.toolkit.persistence.dto.ServiceMeasure; + +import java.util.function.Predicate; + +public class ServiceMeasureFilterState extends ServiceEntityFilterState { + + private String code; + + private String value; + + private String parent; + + @Override + public Predicate spec() { + Predicate filter = super.spec(); + if (StringUtils.isNotBlank(code)) { + filter = filter.and((ServiceMeasure) -> StringUtils.containsIgnoreCase(ServiceMeasure.getCode(), code)); + } + + if (StringUtils.isNotBlank(value)) { + filter = filter.and((ServiceMeasure) -> StringUtils.containsIgnoreCase(ServiceMeasure.getValue(), value)); + } + + if (StringUtils.isNotBlank(parent)) { + filter = filter.and((ServiceCategory) -> StringUtils.containsIgnoreCase(ServiceCategory.getParent(), parent)); + } + + return filter; + } + + public String getCode() { + return code; + } + + public void setCode(final String code) { + this.code = code; + } + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } + + public String getParent() { + return parent; + } + + public void setParent(final String parent) { + this.parent = parent; + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/TestFormFilterState.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/TestFormFilterState.java index 36596736..18889902 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/TestFormFilterState.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/TestFormFilterState.java @@ -6,7 +6,7 @@ import org.devgateway.toolkit.persistence.repository.SpecificationContext; import org.springframework.data.jpa.domain.Specification; -import javax.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Predicate; import java.util.ArrayList; import java.util.List; diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/TetsimDatasetFilterState.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/TetsimDatasetFilterState.java new file mode 100644 index 00000000..77f2be4a --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/table/filter/TetsimDatasetFilterState.java @@ -0,0 +1,78 @@ +package org.devgateway.toolkit.forms.wicket.components.table.filter; + +import org.apache.commons.lang3.StringUtils; +import org.devgateway.toolkit.persistence.dao.AbstractStatusAuditableEntity_; +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset_; +import org.devgateway.toolkit.persistence.repository.SpecificationContext; +import org.springframework.data.jpa.domain.Specification; + +import jakarta.persistence.criteria.Predicate; +import java.util.ArrayList; +import java.util.List; + +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.DELETED; + +/** + * Created by Viorel Chihai + */ +public class TetsimDatasetFilterState extends JpaFilterState { + + private static final long serialVersionUID = 6655165533257383853L; + + private Integer year; + + private String status; + + private String service; + + @Override + public Specification getSpecification() { + return (root, query, cb) -> { + List predicates = new ArrayList<>(); + SpecificationContext sc = new SpecificationContext<>(root, query, cb); + + predicates.add(sc.cb().notLike(sc.root().get(AbstractStatusAuditableEntity_.status), DELETED)); + + if (StringUtils.isNotBlank(service)) { + predicates.add(sc.cb().equal(sc.cb().lower(sc.root().get(TetsimDataset_.destinationService)), service.toLowerCase())); + } + + if (year != null) { + predicates.add(sc.cb().equal(sc.root().get(TetsimDataset_.year), year)); + } + + if (StringUtils.isNotBlank(status)) { + predicates.add(sc.cb().like(sc.root().get(TetsimDataset_.status), status)); + } + + return cb.and(predicates.toArray(new Predicate[predicates.size()])); + }; + } + + public String getService() { + return service; + } + + public void setService(final String service) { + this.service = service; + } + + public Integer getYear() { + return year; + } + + public void setYear(final Integer year) { + this.year = year; + } + + @Override + public String getStatus() { + return status; + } + + @Override + public void setStatus(final String status) { + this.status = status; + } +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/util/CustomDownloadLink.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/util/CustomDownloadLink.java index 1caabf6c..6f85c07d 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/util/CustomDownloadLink.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/util/CustomDownloadLink.java @@ -14,7 +14,7 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipBehavior; import de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipConfig; import de.agilecoders.wicket.core.markup.html.bootstrap.image.IconBehavior; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconType; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; import org.apache.wicket.markup.html.link.Link; import org.apache.wicket.model.IModel; import org.apache.wicket.model.StringResourceModel; @@ -36,7 +36,7 @@ public class CustomDownloadLink extends Link { public CustomDownloadLink(final String id, final IModel model) { super(id, model); - add(new IconBehavior(FontAwesomeIconType.download)); + add(new IconBehavior(FontAwesome5IconType.download_s)); add(new TooltipBehavior(new StringResourceModel("downloadUploadedFileTooltip", this, null), TOOLTIP_CONFIG)); } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/util/PageUtil.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/util/PageUtil.java new file mode 100644 index 00000000..48591001 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/components/util/PageUtil.java @@ -0,0 +1,23 @@ +package org.devgateway.toolkit.forms.wicket.components.util; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.wicket.request.cycle.RequestCycle; + + +/** + * @author Nadejda Mandrescu + */ +public final class PageUtil { + private PageUtil() { + } + + public static HttpServletRequest getHttpServletRequest() { + return (HttpServletRequest) RequestCycle.get().getRequest().getContainerRequest(); + } + + public static HttpServletResponse getHttpServletResponse() { + return (HttpServletResponse) RequestCycle.get().getResponse().getContainerResponse(); + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/converters/NonNumericFilteredBigDecimalConverter.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/converters/NonNumericFilteredBigDecimalConverter.java index b20eece7..8f2c60da 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/converters/NonNumericFilteredBigDecimalConverter.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/converters/NonNumericFilteredBigDecimalConverter.java @@ -39,6 +39,8 @@ public class NonNumericFilteredBigDecimalConverter extends BigDecimalConverter { private static final long serialVersionUID = 1L; + private static final int MAX_SCALE_BIG_DECIMAL = 16; + private final INumberFormatter numberFormatter; public NonNumericFilteredBigDecimalConverter(final INumberFormatter numberFormatter) { @@ -53,10 +55,11 @@ protected NumberFormat newNumberFormat(final Locale locale) { @Override public BigDecimal convertToObject(final String value, final Locale locale) { - String newValue = value; - if (newValue != null) { - newValue = newValue.replaceAll("[^\\d\\.]", ""); - } - return super.convertToObject(newValue, locale); +// String newValue = value; +// if (newValue != null) { +// newValue = newValue.replaceAll("[^\\d\\.]", ""); +// } + + return parse(value, null, BigDecimal.TEN.scaleByPowerOfTen(MAX_SCALE_BIG_DECIMAL), locale); } } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/events/EditingDisabledEvent.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/events/EditingDisabledEvent.java index 09f1f5e8..fedbfa2f 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/events/EditingDisabledEvent.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/events/EditingDisabledEvent.java @@ -13,9 +13,8 @@ /** * Event that triggers all editing fields/buttons to enabled=false - * - * @author mpostelnicu * + * @author mpostelnicu */ public class EditingDisabledEvent { } \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/events/EditingEnabledEvent.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/events/EditingEnabledEvent.java index b91f05ae..b6412831 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/events/EditingEnabledEvent.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/events/EditingEnabledEvent.java @@ -13,9 +13,8 @@ /** * Event that triggers all editing fields/buttons to enabled=true - * - * @author mpostelnicu * + * @author mpostelnicu */ public class EditingEnabledEvent { } \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/BasePage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/BasePage.html index 00d13c0c..343eed39 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/BasePage.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/BasePage.html @@ -2,7 +2,7 @@ - DGToolkit + TCDI Admin @@ -10,6 +10,7 @@

+
[BREADCRUMB]

[PAGE-TITLE]

diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/BasePage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/BasePage.java index 2da7ea12..4a89bdbe 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/BasePage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/BasePage.java @@ -12,7 +12,6 @@ package org.devgateway.toolkit.forms.wicket.page; import de.agilecoders.wicket.core.markup.html.bootstrap.behavior.CssClassNameAppender; -import de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapBookmarkablePageLink; import de.agilecoders.wicket.core.markup.html.bootstrap.button.dropdown.MenuBookmarkablePageLink; import de.agilecoders.wicket.core.markup.html.bootstrap.button.dropdown.MenuDivider; import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel; @@ -21,25 +20,23 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.navbar.NavbarButton; import de.agilecoders.wicket.core.markup.html.bootstrap.navbar.NavbarComponents; import de.agilecoders.wicket.core.markup.html.bootstrap.navbar.NavbarDropDownButton; -import de.agilecoders.wicket.core.markup.html.references.RespondJavaScriptReference; +//import de.agilecoders.wicket.core.markup.html.references.RespondJavaScriptReference; import de.agilecoders.wicket.core.markup.html.themes.bootstrap.BootstrapCssReference; import de.agilecoders.wicket.core.util.CssClassNames; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeCssReference; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconType; -import org.apache.wicket.Component; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5CssReference; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; +import org.apache.wicket.Application; import org.apache.wicket.Page; import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; -import org.apache.wicket.markup.ComponentTag; -import org.apache.wicket.markup.head.CssHeaderItem; -import org.apache.wicket.markup.head.IHeaderResponse; -import org.apache.wicket.markup.head.JavaScriptHeaderItem; -import org.apache.wicket.markup.head.MetaDataHeaderItem; +import org.apache.wicket.markup.head.*; import org.apache.wicket.markup.head.filter.HeaderResponseContainer; import org.apache.wicket.markup.html.GenericWebPage; import org.apache.wicket.markup.html.TransparentWebMarkupContainer; +import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.link.AbstractLink; import org.apache.wicket.markup.html.pages.RedirectPage; +import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.StringResourceModel; @@ -49,11 +46,13 @@ import org.apache.wicket.request.resource.JavaScriptResourceReference; import org.apache.wicket.request.resource.PackageResourceReference; import org.apache.wicket.resource.JQueryResourceReference; +import org.apache.wicket.spring.injection.annot.SpringBean; import org.apache.wicket.util.string.StringValue; import org.devgateway.toolkit.forms.WebConstants; -import org.devgateway.toolkit.forms.security.SecurityConstants; import org.devgateway.toolkit.forms.security.SecurityUtil; -import org.devgateway.toolkit.forms.wicket.page.lists.ListGroupPage; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPanel; import org.devgateway.toolkit.forms.wicket.page.lists.ListTestFormPage; import org.devgateway.toolkit.forms.wicket.page.lists.ListUserPage; import org.devgateway.toolkit.forms.wicket.page.user.EditUserPage; @@ -63,10 +62,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import static org.devgateway.toolkit.forms.WebConstants.PARAM_SERVICE; +import static org.devgateway.toolkit.forms.security.SecurityConstants.Roles.ROLE_USER; + /** * Base wicket-bootstrap {@link org.apache.wicket.Page} * @@ -77,6 +80,9 @@ public abstract class BasePage extends GenericWebPage { protected static final Logger logger = LoggerFactory.getLogger(BasePage.class); + @SpringBean + private EurekaClientService eurekaClientService; + private TransparentWebMarkupContainer mainContainer; private Header mainHeader; @@ -87,6 +93,8 @@ public abstract class BasePage extends GenericWebPage { private Navbar navbar; + protected BreadCrumbPanel breadcrumbPanel; + protected NotificationPanel feedbackPanel; /** @@ -152,6 +160,9 @@ public BasePage(final PageParameters parameters) { navbar = newNavbar("navbar"); mainHeader.add(navbar); + breadcrumbPanel = createBreadcrumbPanel("breadcrumb"); + mainContainer.add(breadcrumbPanel); + // Add information about navbar position on mainHeader element. if (navbar.getPosition().equals(Navbar.Position.DEFAULT)) { mainHeader.add(new CssClassNameAppender("with-navbar-default")); @@ -162,11 +173,15 @@ public BasePage(final PageParameters parameters) { mainFooter = new Footer("mainFooter"); add(mainFooter); - pageTitle = new Label("pageTitle", new ResourceModel("page.title")); + pageTitle = getPageTitle(); add(pageTitle); } + protected Label getPageTitle() { + return new Label("pageTitle", new ResourceModel("page.title")); + } + protected NotificationPanel createFeedbackPanel() { final NotificationPanel notificationPanel = new NotificationPanel("feedback"); notificationPanel.setOutputMarkupId(true); @@ -193,13 +208,13 @@ protected List newSubMenuButtons(final String buttonMarkupId) { return list; } }; - languageDropDown.setIconType(FontAwesomeIconType.flag); + languageDropDown.setIconType(FontAwesome5IconType.flag_s); return languageDropDown; } protected MetaDataHeaderItem getFavicon() { PackageResourceReference faviconRef = - new PackageResourceReference(BaseStyles.class, "assets/img/icons/toolkit-favicon.svg"); + new PackageResourceReference(BaseStyles.class, "assets/img/icons/tcdi-favicon.svg"); MetaDataHeaderItem icon = MetaDataHeaderItem.forLinkTag("icon", urlFor(faviconRef, null).toString()); icon.addTagAttribute("type", "image/svg+xml"); @@ -211,8 +226,8 @@ protected NavbarButton newLogoutMenu() { // logout menu final NavbarButton logoutMenu = new NavbarButton(LogoutPage.class, new StringResourceModel("navbar.logout", this, null)); - logoutMenu.setIconType(FontAwesomeIconType.sign_out); - MetaDataRoleAuthorizationStrategy.authorize(logoutMenu, Component.RENDER, SecurityConstants.Roles.ROLE_USER); + logoutMenu.setIconType(FontAwesome5IconType.sign_out_alt_s); + MetaDataRoleAuthorizationStrategy.authorize(logoutMenu, RENDER, ROLE_USER); return logoutMenu; } @@ -229,8 +244,8 @@ protected NavbarButton newAccountMenu() { final NavbarButton accountMenu = new NavbarButton<>(EditUserPage.class, pageParametersForAccountPage, account); - accountMenu.setIconType(FontAwesomeIconType.user); - MetaDataRoleAuthorizationStrategy.authorize(accountMenu, Component.RENDER, SecurityConstants.Roles.ROLE_USER); + accountMenu.setIconType(FontAwesome5IconType.user_s); + MetaDataRoleAuthorizationStrategy.authorize(accountMenu, RENDER, ROLE_USER); return accountMenu; } @@ -238,15 +253,14 @@ protected NavbarButton newHomeMenu() { // home NavbarButton homeMenu = new NavbarButton<>(Homepage.class, new StringResourceModel("navbar.home", this, null)); - homeMenu.setIconType(FontAwesomeIconType.home); - MetaDataRoleAuthorizationStrategy.authorize(homeMenu, Component.RENDER, SecurityConstants.Roles.ROLE_USER); + homeMenu.setIconType(FontAwesome5IconType.home_s); + MetaDataRoleAuthorizationStrategy.authorize(homeMenu, RENDER, ROLE_USER); return homeMenu; } - protected NavbarDropDownButton newAdminMenu() { - + protected NavbarDropDownButton newConfigurationsMenu() { // admin menu - NavbarDropDownButton adminMenu = new NavbarDropDownButton(new StringResourceModel("navbar.admin", this, null)) { + NavbarDropDownButton configurationsMenu = new NavbarDropDownButton(new StringResourceModel("navbar.configurations", this, null)) { private static final long serialVersionUID = 1L; @Override @@ -254,63 +268,33 @@ protected List newSubMenuButtons(final String arg0) { final List list = new ArrayList<>(); list.add(new MenuBookmarkablePageLink(ListUserPage.class, null, new StringResourceModel("navbar.users", this, null)) - .setIconType(FontAwesomeIconType.users)); - - list.add(new MenuBookmarkablePageLink(ListGroupPage.class, null, - new StringResourceModel("navbar.groups", this, null)).setIconType(FontAwesomeIconType.tags)); - - list.add(new MenuBookmarkablePageLink(ListTestFormPage.class, null, - new StringResourceModel("navbar.testcomponents", this, null)) - .setIconType(FontAwesomeIconType.android)); - - list.add(new MenuDivider()); - - final BootstrapBookmarkablePageLink swagger = new MenuBookmarkablePageLink(SwaggerPage.class, - new StringResourceModel("navbar.swagger", BasePage.this, null)) - .setIconType(FontAwesomeIconType.code); - MetaDataRoleAuthorizationStrategy.authorize(swagger, Component.RENDER, - SecurityConstants.Roles.ROLE_ADMIN); - list.add(swagger); - - final BootstrapBookmarkablePageLink javamelody = new MenuBookmarkablePageLink( - JavamelodyPage.class, new StringResourceModel("navbar.javamelody", - BasePage.this, null)).setIconType(FontAwesomeIconType.eye); - MetaDataRoleAuthorizationStrategy.authorize(javamelody, Component.RENDER, - SecurityConstants.Roles.ROLE_ADMIN); - list.add(javamelody); - - list.add(new MenuBookmarkablePageLink(SpringEndpointsPage.class, null, - new StringResourceModel("navbar.springendpoints", this, null)) - .setIconType(FontAwesomeIconType.anchor)); - - final MenuBookmarkablePageLink uiBrowserLink = - new MenuBookmarkablePageLink( - UIRedirectPage.class, null, new StringResourceModel("navbar.ui", this, null)) { - private static final long serialVersionUID = 1L; - - @Override - protected void onComponentTag(final ComponentTag tag) { - super.onComponentTag(tag); - tag.put("target", "_blank"); - } - }; - uiBrowserLink.setIconType(FontAwesomeIconType.rocket).setEnabled(true); - list.add(uiBrowserLink); + .setIconType(FontAwesome5IconType.users_s)); list.add(new MenuDivider()); list.add(new MenuBookmarkablePageLink(EditAdminSettingsPage.class, new StringResourceModel("navbar.adminSettings", BasePage.this, null)) - .setIconType(FontAwesomeIconType.briefcase)); + .setIconType(FontAwesome5IconType.cogs_s)); return list; } }; - adminMenu.setIconType(FontAwesomeIconType.cog); - MetaDataRoleAuthorizationStrategy.authorize(adminMenu, Component.RENDER, SecurityConstants.Roles.ROLE_USER); + configurationsMenu.setIconType(FontAwesome5IconType.tools_s); + MetaDataRoleAuthorizationStrategy.authorize(configurationsMenu, RENDER, ROLE_USER); - return adminMenu; + return configurationsMenu; + } + + protected NavbarButton newDataMenu() { + NavbarButton dataSetsMenu = new NavbarButton(DataPage.class, + new StringResourceModel("navbar.data", this, null)) + .setIconType(FontAwesome5IconType.table_s); + + dataSetsMenu.setIconType(FontAwesome5IconType.table_s); + MetaDataRoleAuthorizationStrategy.authorize(dataSetsMenu, RENDER, ROLE_USER); + + return dataSetsMenu; } /** @@ -329,14 +313,14 @@ protected Navbar newNavbar(final String markupId) { * @see org.devgateway.toolkit.forms.wicket.styles.BaseStyles */ navbar.setPosition(Navbar.Position.TOP); - navbar.setBrandImage(new PackageResourceReference(BaseStyles.class, "assets/img/toolkit-logo-0048.png"), + navbar.add(new CssClassNameAppender( "navbar-default", "navbar-border")); + navbar.setBrandImage(new PackageResourceReference(BaseStyles.class, "assets/img/tcdi-horizontal-logo.svg"), new StringResourceModel("brandImageAltText", this, null)); - navbar.setInverted(true); - navbar.addComponents(NavbarComponents.transform(Navbar.ComponentPosition.RIGHT, newHomeMenu(), newAdminMenu(), - newAccountMenu(), newLogoutMenu())); + navbar.addComponents(NavbarComponents.transform(Navbar.ComponentPosition.RIGHT, newHomeMenu(), newConfigurationsMenu(), + newDataMenu(), newAccountMenu(), newLogoutMenu())); - navbar.addComponents(NavbarComponents.transform(Navbar.ComponentPosition.LEFT, newLanguageMenu())); +// navbar.addComponents(NavbarComponents.transform(Navbar.ComponentPosition.RIGHT, newLanguageMenu())); return navbar; } @@ -350,14 +334,56 @@ public void renderHead(final IHeaderResponse response) { // Load Styles. response.render(CssHeaderItem.forReference(BootstrapCssReference.instance())); - response.render(CssHeaderItem.forReference(FontAwesomeCssReference.instance())); + response.render(CssHeaderItem.forReference(FontAwesome5CssReference.instance())); response.render(CssHeaderItem.forReference(BaseStyles.INSTANCE)); // Load Scripts. - response.render(RespondJavaScriptReference.headerItem()); - response.render(JavaScriptHeaderItem.forReference(JQueryResourceReference.getV2())); + response.render(JavaScriptHeaderItem.forReference(JQueryResourceReference.getV3())); response.render(JavaScriptHeaderItem.forReference(new JavaScriptResourceReference(BaseStyles.class, "assets/js/fileupload.js"))); } + + protected BreadCrumbPanel createBreadcrumbPanel(final String markupId) { + return new BreadCrumbPanel(markupId) { + @Override + protected IModel getLabelModel() { + return getBreadcrumbTitleModel(); + } + + @Override + protected IModel getLabelModel(final Class clazz) { + return getBreadcrumbTitleModel(clazz); + } + + @Override + protected Class getPageClass() { + return BasePage.this.getClass(); + } + }; + } + + protected IModel getBreadcrumbTitleModel() { + return new StringResourceModel("page.title", this, null); + } + + protected IModel getBreadcrumbTitleModel(final Class clazz) { + boolean hasServiceLabel = clazz.getDeclaredAnnotation(BreadCrumbPage.class).hasServiceParam(); + + if (hasServiceLabel) { + return Model.of(MessageFormat.format(getString("breadcrumb." + clazz.getSimpleName()), getServiceLabel())); + } + + return new StringResourceModel("breadcrumb." + clazz.getSimpleName(), this, null) + .setDefaultValue(getBreadcrumbTitleModel()); + } + + private boolean hasBreadcrumbPanel() { + return this.getClass().getDeclaredAnnotation(BreadCrumbPage.class) != null; + } + + protected String getServiceLabel() { + String service = getPageParameters().get(PARAM_SERVICE).toString(); + return eurekaClientService.findByName(service).getLabel(); + } } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/BasePage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/BasePage.properties index a7520833..9a47fb19 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/BasePage.properties +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/BasePage.properties @@ -13,7 +13,14 @@ navbar.home=Home navbar.logout=Logout navbar.users=Users navbar.groups=Groups -navbar.admin=Admin +navbar.services=Services +navbar.configurations=Configurations +navbar.data=Data +navbar.tetsim=TETSIM +navbar.prevalence=Prevalence +navbar.policy=Policy +navbar.ecigarettes=E-cigarette +navbar.tobaccoproducts=Tobacco Products navbar.testcomponents=Test Components navbar.swagger=Swagger navbar.halbrowser=HAL Browser @@ -29,3 +36,16 @@ fileUnit.KB=KB fileUnit.MB=MB fileUnit.GB=GB fileUnit.TB=TB + +breadcrumb.Homepage=Home +breadcrumb.ConfigurationsHomepage=Configurations +breadcrumb.ListUserPage=Users +breadcrumb.EditAdminSettingsPage=Settings +breadcrumb.DataPage=Data +breadcrumb.DataServicePage={0} +breadcrumb.ListServiceMeasuresPage=Measures +breadcrumb.ListServiceDimensionsPage=Dimensions +breadcrumb.ListServiceCategoriesPage=Categories +breadcrumb.ListServiceFiltersPage=Filters +breadcrumb.ListCSVDatasetPage=Datasets +breadcrumb.ListTetsimDatasetPage=Datasets diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/ConfigurationsHomepage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/ConfigurationsHomepage.html new file mode 100644 index 00000000..2455643c --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/ConfigurationsHomepage.html @@ -0,0 +1,12 @@ + + + + + Configurations + + + +
+
+ + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/ConfigurationsHomepage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/ConfigurationsHomepage.java new file mode 100644 index 00000000..9290477b --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/ConfigurationsHomepage.java @@ -0,0 +1,49 @@ +package org.devgateway.toolkit.forms.wicket.page; + +import com.google.common.collect.ImmutableList; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; +import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.security.SecurityConstants; +import org.devgateway.toolkit.forms.wicket.components.BigLinkDefinition; +import org.devgateway.toolkit.forms.wicket.components.BigLinksPanel; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.page.lists.ListUserPage; +import org.devgateway.toolkit.web.util.SettingsUtils; + +import java.util.List; + +/** + * @author mpostelnicu + * + */ +@AuthorizeInstantiation(SecurityConstants.Roles.ROLE_USER) +@BreadCrumbPage +public class ConfigurationsHomepage extends BasePage { + + @SpringBean + protected SettingsUtils settingsUtils; + + private static final List LINKS = new ImmutableList.Builder() + .add(new BigLinkDefinition("users", ListUserPage.class, FontAwesome5IconType.users_s)) + .add(new BigLinkDefinition("settings", EditAdminSettingsPage.class, FontAwesome5IconType.cogs_s)) + .build(); + + /** + * @param parameters + */ + public ConfigurationsHomepage(final PageParameters parameters) { + super(parameters); + + add(new BigLinksPanel("links", Model.ofList(LINKS))); + } + + protected Label getPageTitle() { + return new Label("pageTitle", new StringResourceModel("page.title", this, + Model.of(settingsUtils.getSetting()))); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/ConfigurationsHomepage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/ConfigurationsHomepage.properties new file mode 100644 index 00000000..a23e62ad --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/ConfigurationsHomepage.properties @@ -0,0 +1,7 @@ +page.title=Configurations + +users.label=Users +users.desc=Manage the Users + +settings.label=Settings +settings.desc=Manage the general settings of the system \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataPage.html new file mode 100644 index 00000000..b7b222d9 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataPage.html @@ -0,0 +1,13 @@ + + + + + Datasets + + + +
+
+ + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataPage.java new file mode 100644 index 00000000..5c474fc3 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataPage.java @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2015 Development Gateway, Inc and others. + *

+ * All rights reserved. This program and the accompanying materials + * are made available under the terms of the MIT License (MIT) + * which accompanies this distribution, and is available at + * https://opensource.org/licenses/MIT + *

+ * Contributors: + * Development Gateway - initial API and implementation + */ +/** + * + */ +package org.devgateway.toolkit.forms.wicket.page; + +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; +import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.security.SecurityConstants; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.forms.wicket.components.BigLinkDefinition; +import org.devgateway.toolkit.forms.wicket.components.BigLinksPanel; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.persistence.dao.AdminSettings; +import org.devgateway.toolkit.persistence.dto.ServiceMetadata; +import org.devgateway.toolkit.web.util.SettingsUtils; +import org.wicketstuff.annotation.mount.MountPath; + +import java.util.ArrayList; +import java.util.List; + +import static org.devgateway.toolkit.forms.WebConstants.PARAM_SERVICE; +import static org.devgateway.toolkit.forms.WebConstants.SERVICE_DATA_TYPE; +import static org.devgateway.toolkit.forms.WebConstants.SERVICE_TETSIM_TYPE; + +/** + * @author Viorel Chihai + */ +@AuthorizeInstantiation(SecurityConstants.Roles.ROLE_USER) +@MountPath(value = "/dataPage") +@BreadCrumbPage +public class DataPage extends BasePage { + + @SpringBean + protected SettingsUtils settingsUtils; + + @SpringBean + private EurekaClientService eurekaClientService; + + public DataPage(final PageParameters parameters) { + super(parameters); + + List services = eurekaClientService.findAllWithData(); + + List links = new ArrayList<>(); + for (ServiceMetadata service : services) { + PageParameters pageParameters = new PageParameters(); + pageParameters.add(PARAM_SERVICE, service.getName()); + + FontAwesome5IconType serviceIcon = getServiceIcon(service); + + links.add(new BigLinkDefinition(service.getId(), DataServicePage.class, pageParameters, serviceIcon) { + + @Override + public IModel getLabelModel() { + return Model.of(service.getLabel()); + } + + @Override + public IModel getDescModel() { + return Model.of(service.getDescription()); + } + }); + } + + add(new BigLinksPanel("links", Model.ofList(links))); + Label noServiceError = new Label("noServiceError", new StringResourceModel("noServiceError", this, null)); + noServiceError.setVisible(links.isEmpty()); + add(noServiceError); + } + + private FontAwesome5IconType getServiceIcon(final ServiceMetadata serviceMetadata) { + if (serviceMetadata.isTetsim()) { + return FontAwesome5IconType.list_alt_r; + } + + return FontAwesome5IconType.file_csv_s; + } + + protected Label getPageTitle() { + return new Label("pageTitle", getPageTitleResourceModel()); + } + + private StringResourceModel getPageTitleResourceModel() { + return new StringResourceModel("page.title", this, (Model.of(settingsUtils.getSetting()))); + } + + @Override + protected IModel getBreadcrumbTitleModel() { + return new StringResourceModel("breadcrumb.title", this); + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataPage.properties new file mode 100644 index 00000000..201e02ad --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataPage.properties @@ -0,0 +1,5 @@ +page.title=${countryName} Data + +noServiceError=No data service available. + +breadcrumb.title=Data \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataServicePage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataServicePage.html new file mode 100644 index 00000000..b0e96a79 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataServicePage.html @@ -0,0 +1,12 @@ + + + + + Datasets + + + +

+ + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataServicePage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataServicePage.java new file mode 100644 index 00000000..71f9102c --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataServicePage.java @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2015 Development Gateway, Inc and others. + *

+ * All rights reserved. This program and the accompanying materials + * are made available under the terms of the MIT License (MIT) + * which accompanies this distribution, and is available at + * https://opensource.org/licenses/MIT + *

+ * Contributors: + * Development Gateway - initial API and implementation + */ +/** + * + */ +package org.devgateway.toolkit.forms.wicket.page; + +import de.agilecoders.wicket.core.markup.html.bootstrap.image.IconType; +import org.apache.wicket.Page; +import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.model.Model; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.security.SecurityConstants; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.forms.wicket.components.BigLinkDefinition; +import org.devgateway.toolkit.forms.wicket.components.BigLinksPanel; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.page.lists.admin.ListServiceCategoriesPage; +import org.devgateway.toolkit.forms.wicket.page.lists.admin.ListServiceDimensionsPage; +import org.devgateway.toolkit.forms.wicket.page.lists.admin.ListServiceFiltersPage; +import org.devgateway.toolkit.forms.wicket.page.lists.admin.ListServiceMeasuresPage; +import org.devgateway.toolkit.forms.wicket.page.lists.dataset.ListCSVDatasetPage; +import org.devgateway.toolkit.forms.wicket.page.lists.dataset.ListTetsimDatasetPage; +import org.devgateway.toolkit.persistence.dto.ServiceMetadata; +import org.devgateway.toolkit.web.util.SettingsUtils; +import org.wicketstuff.annotation.mount.MountPath; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import static de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType.chart_bar_s; +import static de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType.database_s; +import static de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType.filter_s; +import static de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType.layer_group_s; +import static de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType.ruler_s; +import static org.devgateway.toolkit.forms.WebConstants.PARAM_SERVICE; +import static org.devgateway.toolkit.forms.WebConstants.SERVICE_DATA_TYPE; +import static org.devgateway.toolkit.forms.WebConstants.SERVICE_TETSIM_TYPE; + +/** + * @author Viorel Chihai + */ +@AuthorizeInstantiation(SecurityConstants.Roles.ROLE_USER) +@MountPath +@BreadCrumbPage(parent = DataPage.class, hasServiceParam = true) +public class DataServicePage extends BasePage { + + @SpringBean + protected SettingsUtils settingsUtils; + + @SpringBean + private EurekaClientService eurekaClientService; + + public DataServicePage(final PageParameters parameters) { + super(parameters); + + ServiceMetadata serviceMetadata = eurekaClientService.findByName(parameters.get(PARAM_SERVICE).toString()); + + List links = new ArrayList<>(); + links.add(getEntityLink("datasets", getServicePageClass(serviceMetadata), database_s)); + links.add(getEntityLink("measures", ListServiceMeasuresPage.class, ruler_s)); + links.add(getEntityLink("dimensions", ListServiceDimensionsPage.class, chart_bar_s)); + links.add(getEntityLink("categories", ListServiceCategoriesPage.class, layer_group_s)); + links.add(getEntityLink("filters", ListServiceFiltersPage.class, filter_s)); + + add(new BigLinksPanel("links", Model.ofList(links))); + } + + private BigLinkDefinition getEntityLink(final String entity, Class pageClass, IconType iconType) { + PageParameters pageParams = new PageParameters(); + pageParams.set(PARAM_SERVICE, getPageParameters().get(PARAM_SERVICE).toString()); + + return new BigLinkDefinition(entity, pageClass, pageParams, iconType); + } + + private Class getServicePageClass(final ServiceMetadata serviceMetadata) { + if (serviceMetadata.isTetsim()) { + return ListTetsimDatasetPage.class; + } + + return ListCSVDatasetPage.class; + } + + protected Label getPageTitle() { + String countryName = settingsUtils.getSetting().getCountryName(); + + return new Label("pageTitle", + Model.of(MessageFormat.format(getString("page.title"), countryName, getServiceLabel()))); + + } + + protected Model getBreadcrumbTitleModel() { + return Model.of(MessageFormat.format(getString("breadcrumb.title"), getServiceLabel())); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataServicePage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataServicePage.properties new file mode 100644 index 00000000..5874d729 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DataServicePage.properties @@ -0,0 +1,18 @@ +page.title={0} {1} + +datasets.label=Data entry or upload +datasets.desc=Manage datasets + +measures.label=Measures +measures.desc=Manage measures + +dimensions.label=Dimensions +dimensions.desc=Manage dimensions + +categories.label=Categories +categories.desc=Manage categories + +filters.label=Filters +filters.desc=Manage filters + +breadcrumb.title={0} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DatasetsHomepage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DatasetsHomepage.html new file mode 100644 index 00000000..b0e96a79 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DatasetsHomepage.html @@ -0,0 +1,12 @@ + + + + + Datasets + + + +

+ + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DatasetsHomepage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DatasetsHomepage.java new file mode 100644 index 00000000..a9f5ac8d --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DatasetsHomepage.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2015 Development Gateway, Inc and others. + *

+ * All rights reserved. This program and the accompanying materials + * are made available under the terms of the MIT License (MIT) + * which accompanies this distribution, and is available at + * https://opensource.org/licenses/MIT + *

+ * Contributors: + * Development Gateway - initial API and implementation + */ +/** + * + */ +package org.devgateway.toolkit.forms.wicket.page; + +import com.google.common.collect.ImmutableList; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; +import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.security.SecurityConstants; +import org.devgateway.toolkit.forms.wicket.components.BigLinkDefinition; +import org.devgateway.toolkit.forms.wicket.components.BigLinksPanel; +import org.devgateway.toolkit.forms.wicket.page.lists.dataset.ListCSVDatasetPage; +import org.devgateway.toolkit.forms.wicket.page.lists.dataset.ListTetsimDatasetPage; +import org.devgateway.toolkit.web.util.SettingsUtils; +import org.wicketstuff.annotation.mount.MountPath; + +import java.util.List; + +/** + * @author Viorel Chihai + */ +@AuthorizeInstantiation(SecurityConstants.Roles.ROLE_USER) +@MountPath +public class DatasetsHomepage extends BasePage { + + @SpringBean + protected SettingsUtils settingsUtils; + + private static final List LINKS = new ImmutableList.Builder() + .add(new BigLinkDefinition("tetsimDataset", ListTetsimDatasetPage.class, + FontAwesome5IconType.percentage_s)) + .add(new BigLinkDefinition("csvDataset", ListCSVDatasetPage.class, + FontAwesome5IconType.file_csv_s)) + .build(); + + public DatasetsHomepage(final PageParameters parameters) { + super(parameters); + + add(new BigLinksPanel("links", Model.ofList(LINKS))); + } + + protected Label getPageTitle() { + return new Label("pageTitle", new StringResourceModel("page.title", this, + Model.of(settingsUtils.getSetting()))); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DatasetsHomepage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DatasetsHomepage.properties new file mode 100644 index 00000000..279ab4cb --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/DatasetsHomepage.properties @@ -0,0 +1,7 @@ +page.title=${countryName} Datasets + +tetsimDataset.label=TETSIM +tetsimDataset.desc=Manage the TETSIM Dataset + +csvDataset.label=CSV +csvDataset.desc=Manage the CSV Dataset \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/EditAdminSettingsPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/EditAdminSettingsPage.html index bd60a80b..b1fced20 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/EditAdminSettingsPage.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/EditAdminSettingsPage.html @@ -6,17 +6,43 @@ -

-
+
+
[[System Settings]]
-
-
-
+
+
+
+
+
+
+
+
- +
+
+ + [[Application Settings]] +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/EditAdminSettingsPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/EditAdminSettingsPage.java index 88822a8d..7673b003 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/EditAdminSettingsPage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/EditAdminSettingsPage.java @@ -1,5 +1,6 @@ package org.devgateway.toolkit.forms.wicket.page; +import org.apache.wicket.AttributeModifier; import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.model.StringResourceModel; @@ -7,13 +8,17 @@ import org.apache.wicket.spring.injection.annot.SpringBean; import org.apache.wicket.validation.validator.RangeValidator; import org.devgateway.toolkit.forms.security.SecurityConstants; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; import org.devgateway.toolkit.forms.wicket.components.form.CheckBoxToggleBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.components.form.Select2ChoiceBootstrapFormComponent; import org.devgateway.toolkit.forms.wicket.components.form.TextFieldBootstrapFormComponent; import org.devgateway.toolkit.forms.wicket.page.edit.AbstractEditPage; +import org.devgateway.toolkit.forms.wicket.providers.GenericChoiceProvider; import org.devgateway.toolkit.persistence.dao.AdminSettings; import org.devgateway.toolkit.persistence.service.AdminSettingsService; import org.wicketstuff.annotation.mount.MountPath; +import java.util.Arrays; import java.util.List; /** @@ -22,6 +27,7 @@ */ @AuthorizeInstantiation(SecurityConstants.Roles.ROLE_ADMIN) @MountPath(value = "/adminsettings") +@BreadCrumbPage(parent = ConfigurationsHomepage.class) public class EditAdminSettingsPage extends AbstractEditPage { private static final long serialVersionUID = 5742724046825803877L; @@ -30,6 +36,8 @@ public class EditAdminSettingsPage extends AbstractEditPage { private TextFieldBootstrapFormComponent autosaveTime; + private Select2ChoiceBootstrapFormComponent pageSize; + @SpringBean private AdminSettingsService adminSettingsService; @@ -37,7 +45,7 @@ public EditAdminSettingsPage(final PageParameters parameters) { super(parameters); this.jpaService = adminSettingsService; - this.listPageClass = Homepage.class; + this.listPageClass = ConfigurationsHomepage.class; if (entityId == null) { final List listSettings = adminSettingsService.findAll(); @@ -57,10 +65,31 @@ protected void onInitialize() { rebootServer = new CheckBoxToggleBootstrapFormComponent("rebootServer"); editForm.add(rebootServer); + editForm.add(new Label("appSettingsTitle", new StringResourceModel("appSettingsTitle", this, null))); + + TextFieldBootstrapFormComponent tetsimCurrency = new TextFieldBootstrapFormComponent<>("tetsimCurrency"); + tetsimCurrency.required(); + tetsimCurrency.getBorder().add(AttributeModifier.append("class", "required-field")); + editForm.add(tetsimCurrency); + + editForm.add(new TextFieldBootstrapFormComponent<>("countryName")); + autosaveTime = new TextFieldBootstrapFormComponent<>("autosaveTime"); autosaveTime.integer().required(); + autosaveTime.getBorder().add(AttributeModifier.append("class", "required-field")); autosaveTime.getField().add(RangeValidator.range(0, 60)); autosaveTime.setShowTooltip(true); editForm.add(autosaveTime); + + pageSize = new Select2ChoiceBootstrapFormComponent<>("pageSize", + new GenericChoiceProvider<>(getPageSizeRange())); + pageSize.required(); + pageSize.getBorder().add(AttributeModifier.append("class", "required-field")); + editForm.add(pageSize); + + } + + public List getPageSizeRange() { + return Arrays.asList(5, 10, 15, 20, 25, 50, 100); } } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/EditAdminSettingsPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/EditAdminSettingsPage.properties index e17132db..1ea13fb2 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/EditAdminSettingsPage.properties +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/EditAdminSettingsPage.properties @@ -1,5 +1,11 @@ -page.title=Admin settings +page.title=Settings +page.title.add=Settings systemTitle=System Settings +appSettingsTitle=Application Settings rebootServer.label=Enable server reboot warning autosaveTime.label=Autosave Time (minutes) autosaveTime.help=Set to 0 to disable +tetsimCurrency.label=Currency for TETSIM +countryName.label=Country Name +pageSize.label=Default items in list +pageSize.help=The default number of items that will appear in lists \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Footer.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Footer.html index 2b7601b0..9c1c9b36 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Footer.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Footer.html @@ -7,9 +7,9 @@
-
+
- DG-Toolkit   + TCDI Admin    -  © Copyright diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Header.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Header.java index 13870ee4..cf356de2 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Header.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Header.java @@ -97,7 +97,7 @@ protected void onConfigure() { add(rebootAlert); MetaDataRoleAuthorizationStrategy.authorize(rebootAlert, Component.RENDER, SecurityConstants.Roles.ROLE_USER); - add(new AbstractAjaxTimerBehavior(org.apache.wicket.util.time.Duration.seconds(ALERT_UPDATE_INTERVAL_SECONDS)) { + add(new AbstractAjaxTimerBehavior(Duration.ofSeconds(ALERT_UPDATE_INTERVAL_SECONDS)) { private static final long serialVersionUID = -1168209018766325709L; @Override diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Homepage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Homepage.html index 8bce0124..e4bc8b81 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Homepage.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Homepage.html @@ -6,9 +6,11 @@ -
-
-

+
+
+
+
+
diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Homepage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Homepage.java index 10eebf3e..291d49cf 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Homepage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Homepage.java @@ -1,33 +1,54 @@ -/** - * Copyright (c) 2015 Development Gateway, Inc and others. - *

- * All rights reserved. This program and the accompanying materials - * are made available under the terms of the MIT License (MIT) - * which accompanies this distribution, and is available at - * https://opensource.org/licenses/MIT - *

- * Contributors: - * Development Gateway - initial API and implementation - */ -/** - * - */ package org.devgateway.toolkit.forms.wicket.page; +import com.google.common.collect.ImmutableList; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.StringResourceModel; import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; import org.devgateway.toolkit.forms.security.SecurityConstants; +import org.devgateway.toolkit.forms.wicket.components.BigLinkDefinition; +import org.devgateway.toolkit.forms.wicket.components.BigLinksPanel; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.page.lists.admin.ListServicePage; +import org.devgateway.toolkit.web.util.SettingsUtils; + +import java.util.List; /** * @author mpostelnicu * */ @AuthorizeInstantiation(SecurityConstants.Roles.ROLE_USER) +@BreadCrumbPage(isRoot = true) public class Homepage extends BasePage { + + @SpringBean + protected SettingsUtils settingsUtils; + private static final List LINKS = new ImmutableList.Builder() + .add(new BigLinkDefinition("data", DataPage.class, FontAwesome5IconType.table_s)) + .add(new BigLinkDefinition("configurations", ConfigurationsHomepage.class, FontAwesome5IconType.tools_s)) + .build(); + /** * @param parameters */ public Homepage(final PageParameters parameters) { super(parameters); + + add(new BigLinksPanel("links", Model.ofList(LINKS))); + } + + protected Label getPageTitle() { + return new Label("pageTitle", new StringResourceModel("page.title", this, + Model.of(settingsUtils.getSetting()))); + } + + @Override + protected IModel getBreadcrumbTitleModel() { + return new StringResourceModel("breadcrumb.title", this, null); } } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Homepage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Homepage.properties index bb3cec81..a091d0ee 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Homepage.properties +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/Homepage.properties @@ -1,13 +1,9 @@ -############################################################################### -# Copyright (c) 2015 Development Gateway, Inc and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the MIT License (MIT) -# which accompanies this distribution, and is available at -# https://opensource.org/licenses/MIT -# -# Contributors: -# Development Gateway - initial API and implementation -############################################################################### -page.title=Home Page -welcome=Welcome to DG-Toolkit! +page.title=${countryName} TCDI Admin Module + +data.label=Data +data.desc=Upload and edit data, manage the measures, dimensions and categories for each dataset + +configurations.label=Configurations +configurations.desc=Manage the general configurations of the system + +breadcrumb.title=Home \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/JavamelodyPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/JavamelodyPage.java index a0493d19..c2ca0124 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/JavamelodyPage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/JavamelodyPage.java @@ -1,9 +1,7 @@ package org.devgateway.toolkit.forms.wicket.page; import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation; -import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.markup.html.pages.RedirectPage; -import org.apache.wicket.request.flow.RedirectToUrlException; import org.devgateway.toolkit.forms.security.SecurityConstants; /** diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/RevisionsPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/RevisionsPage.html index e82c2eeb..75c75a53 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/RevisionsPage.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/RevisionsPage.html @@ -2,7 +2,7 @@ -

+
diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/RevisionsPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/RevisionsPage.java index 3cdf80a3..1bb66b56 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/RevisionsPage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/RevisionsPage.java @@ -28,9 +28,8 @@ import org.wicketstuff.annotation.mount.MountPath; import org.wicketstuff.datetime.markup.html.basic.DateLabel; -import javax.persistence.EntityManager; +import jakarta.persistence.EntityManager; import java.util.ArrayList; -import java.util.Date; import java.util.List; import static org.devgateway.toolkit.persistence.PersistenceConstants.ZONED_DATE_TIME_PATTER; diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/SpringEndpointsPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/SpringEndpointsPage.java index 528979dc..c40b7d75 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/SpringEndpointsPage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/SpringEndpointsPage.java @@ -1,16 +1,16 @@ -/******************************************************************************* +/** * Copyright (c) 2015 Development Gateway, Inc and others. - * + *

* All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT - * + *

* Contributors: * Development Gateway - initial API and implementation - *******************************************************************************/ + */ /** - * + * */ package org.devgateway.toolkit.forms.wicket.page; diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditPage.html index ce5c4283..3137982a 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditPage.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditPage.html @@ -2,12 +2,12 @@ -

-
+
+
-
+
@@ -15,9 +15,13 @@
-
-
-
+
+
+
+
+
+
+
diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditPage.java index 5556976c..6f267704 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditPage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditPage.java @@ -15,7 +15,7 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.TextContentModal; import de.agilecoders.wicket.core.markup.html.bootstrap.form.BootstrapForm; import de.agilecoders.wicket.core.util.Attributes; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.ladda.LaddaAjaxButton; +import org.devgateway.toolkit.forms.wicket.components.buttons.ladda.LaddaAjaxButton; import nl.dries.wicket.hibernate.dozer.DozerModel; import org.apache.wicket.Page; import org.apache.wicket.ajax.AjaxEventBehavior; @@ -50,7 +50,7 @@ import org.springframework.dao.DataIntegrityViolationException; import org.springframework.orm.ObjectOptimisticLockingFailureException; -import javax.persistence.EntityManager; +import jakarta.persistence.EntityManager; import java.io.Serializable; /** @@ -115,12 +115,16 @@ private T newInstance() { protected TextContentModal deleteModal; + protected TextContentModal cancelModal; + protected TextContentModal deleteFailedModal; protected TextContentModal saveFailedModal; + protected TextContentModal failedModal; + @SpringBean - private EntityManager entityManager; + protected EntityManager entityManager; @SpringBean(required = false) private MarkupCacheService markupCacheService; @@ -152,8 +156,7 @@ public GenericBootstrapValidationVisitor getBootstrapValidationVisitor(final Aja protected TextContentModal createDeleteModal() { final TextContentModal modal = new TextContentModal("deleteModal", - Model.of("DELETE is an irreversible operation. Are you sure?")); - modal.addCloseButton(); + Model.of("Are you sure you want to delete? You will no longer be able to access this data.")); final LaddaAjaxButton deleteButton = new LaddaAjaxButton("button", Buttons.Type.Danger) { @Override @@ -166,12 +169,34 @@ protected void onSubmit(final AjaxRequestTarget target) { } }; deleteButton.setDefaultFormProcessing(false); - deleteButton.setLabel(Model.of("DELETE")); + deleteButton.setLabel(Model.of("Yes")); + modal.addCloseButton(Model.of("No")); modal.addButton(deleteButton); return modal; } + protected TextContentModal createCancelModal() { + final TextContentModal cancelModal = new TextContentModal("cancelModal", + Model.of("Are you sure you want to cancel? Any changes made will be lost.")); + + final LaddaAjaxButton cancelButton = new BootstrapCancelButton("button", Model.of("Yes")) { + private static final long serialVersionUID = -9144254663723097155L; + + @Override + protected void onSubmit(final AjaxRequestTarget target) { + cancelModal.appendCloseDialogJavaScript(target); + setResponsePage(listPageClass, getCancelPageParameters()); + } + }; + + cancelButton.setType(Buttons.Type.Success); + cancelModal.addButton(cancelButton); + cancelModal.addCloseButton(Model.of("No")); + + return cancelModal; + } + protected TextContentModal createDeleteFailedModal() { final TextContentModal modal = new TextContentModal("deleteFailedModal", new ResourceModel("delete_error_message")); @@ -179,7 +204,7 @@ protected TextContentModal createDeleteFailedModal() { final LaddaAjaxButton deleteButton = new LaddaAjaxButton("button", Buttons.Type.Info) { @Override protected void onSubmit(final AjaxRequestTarget target) { - setResponsePage(listPageClass); + setResponsePage(listPageClass, getCancelPageParameters()); } }; deleteButton.setDefaultFormProcessing(false); @@ -189,7 +214,7 @@ protected void onSubmit(final AjaxRequestTarget target) { modal.add(new AjaxEventBehavior("hidden.bs.modal") { @Override protected void onEvent(final AjaxRequestTarget target) { - setResponsePage(listPageClass); + setResponsePage(listPageClass, getCancelPageParameters()); } }); @@ -213,7 +238,31 @@ protected void onSubmit(final AjaxRequestTarget target) { modal.add(new AjaxEventBehavior("hidden.bs.modal") { @Override protected void onEvent(final AjaxRequestTarget target) { - setResponsePage(listPageClass); + setResponsePage(listPageClass, getPageParameters()); + } + }); + + return modal; + } + + protected TextContentModal createFailedModal() { + final TextContentModal modal = new TextContentModal("failedModal", + new ResourceModel("failedMessage")); + modal.header(new ResourceModel("error")); + final LaddaAjaxButton okButton = new LaddaAjaxButton("button", Buttons.Type.Info) { + @Override + protected void onSubmit(final AjaxRequestTarget target) { + setResponsePage(listPageClass, getPageParameters()); + } + }; + okButton.setDefaultFormProcessing(false); + okButton.setLabel(Model.of("OK")); + modal.addButton(okButton); + + modal.add(new AjaxEventBehavior("hidden.bs.modal") { + @Override + protected void onEvent(final AjaxRequestTarget target) { + setResponsePage(listPageClass, getPageParameters()); } }); @@ -256,12 +305,18 @@ public EditForm(final String id) { deleteModal = createDeleteModal(); add(deleteModal); + cancelModal = createCancelModal(); + add(cancelModal); + deleteFailedModal = createDeleteFailedModal(); add(deleteFailedModal); saveFailedModal = createSaveFailedModal(); add(saveFailedModal); + failedModal = createFailedModal(); + add(failedModal); + // don't display the delete button if we just create a new entity if (entityId == null) { deleteButton.setVisibilityAllowed(false); @@ -277,7 +332,7 @@ protected BootstrapCancelButton getCancelButton(final String id) { @Override protected void onSubmit(final AjaxRequestTarget target) { - setResponsePage(listPageClass); + setResponsePage(listPageClass, getPageParameters()); } }; } @@ -352,7 +407,7 @@ protected Class getResponsePage() { * @return */ protected PageParameters getParameterPage() { - return null; + return getSaveEditParameters(); } @Override @@ -400,6 +455,14 @@ public boolean isRedirectToSelf() { } } + protected PageParameters getSaveEditParameters() { + return null; + } + + protected PageParameters getCancelPageParameters() { + return null; + } + protected void beforeSaveEntity(final T saveable) { } @@ -483,6 +546,8 @@ protected void onComponentTag(final ComponentTag tag) { Fragment fragment = new Fragment("extraButtons", "noButtons", this); editForm.add(fragment); + pageTitle.setDefaultModel(getTitleModel()); + } protected void onDelete(final AjaxRequestTarget target) { @@ -518,6 +583,16 @@ protected void onInitialize() { IModel model = null; +// if (entityId != null) { +// T entity = jpaService.findById(entityId).orElse(null); +// model = new CompoundPropertyModel<>(entity); +// } else { +// T instance = newInstance(); +// if (instance != null) { +// model = new CompoundPropertyModel<>(instance); +// } +// } + if (entityId != null) { model = new DozerModel<>(jpaService.findById(entityId).orElse(null)); } else { @@ -536,4 +611,12 @@ protected void onInitialize() { protected void afterLoad(final IModel model) { } + + protected StringResourceModel getTitleModel() { + if (entityId == null) { + return new StringResourceModel("page.title.add", this, null); + } else { + return new StringResourceModel("page.title.edit", this, null); + } + } } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditPage.properties index 313d965e..72f13965 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditPage.properties +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditPage.properties @@ -10,6 +10,8 @@ # Development Gateway - initial API and implementation ############################################################################### page.title=Edit Item +page.title.add=Add Item +page.title.edit=Edit Item WorkstreamSectionEditPage.page.title=Workstream Section Edit CountryEditPage.page.title=Countries Edit CoordinationGoalsEditPage.page.title=Coordination Goals Edit @@ -27,3 +29,4 @@ formHasErrors=The form has errors or is missing information and cannot be submit error=Error delete_error_message=Cannot delete entity, it is in use by the system optimistic_lock_error_message=Changes were not saved. This object was modified by someone else. +failedMessage=The request failed. Please try again later. diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditStatusEntityPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditStatusEntityPage.html index efa99fb7..c67c0470 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditStatusEntityPage.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditStatusEntityPage.html @@ -3,13 +3,19 @@ +
+
+ ErrorInPublishing +
+
+


-
+
@@ -21,7 +27,7 @@
-
+
@@ -61,29 +67,32 @@ -
+
AutoSaveLabel CheckedOutTo
-
+
- - + + +
+
+ diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditStatusEntityPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditStatusEntityPage.java index 0855f117..c0ced96e 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditStatusEntityPage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditStatusEntityPage.java @@ -14,8 +14,8 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.TextContentModal; import de.agilecoders.wicket.core.markup.html.bootstrap.form.BootstrapCheckbox; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconType; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.ladda.LaddaAjaxButton; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; +import org.devgateway.toolkit.forms.wicket.components.buttons.ladda.LaddaAjaxButton; import org.apache.wicket.AttributeModifier; import org.apache.wicket.Component; import org.apache.wicket.ajax.AbstractAjaxTimerBehavior; @@ -40,7 +40,6 @@ import org.apache.wicket.model.StringResourceModel; import org.apache.wicket.request.mapper.parameter.PageParameters; import org.apache.wicket.util.string.Strings; -import org.apache.wicket.util.time.Duration; import org.apache.wicket.util.visit.IVisit; import org.apache.wicket.util.visit.IVisitor; import org.devgateway.toolkit.forms.WebConstants; @@ -52,17 +51,27 @@ import org.devgateway.toolkit.forms.wicket.components.form.OptionallyRequiredTextAreaFieldComponent; import org.devgateway.toolkit.forms.wicket.components.form.TextAreaFieldBootstrapFormComponent; import org.devgateway.toolkit.forms.wicket.components.util.ComponentUtil; -import org.devgateway.toolkit.forms.wicket.components.util.FormSecurityUtil; import org.devgateway.toolkit.forms.wicket.events.EditingDisabledEvent; import org.devgateway.toolkit.forms.wicket.page.BasePage; import org.devgateway.toolkit.forms.wicket.styles.BlockUiJavaScript; import org.devgateway.toolkit.persistence.dao.AbstractStatusAuditableEntity; -import org.devgateway.toolkit.persistence.dao.DBConstants; import org.devgateway.toolkit.persistence.dao.StatusChangedComment; import org.springframework.util.ObjectUtils; import org.wicketstuff.datetime.markup.html.basic.DateLabel; import org.wicketstuff.select2.Select2Choice; +import java.text.MessageFormat; +import java.time.Duration; + +import static org.devgateway.toolkit.forms.WebConstants.PARAM_AUTO_SAVE; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.DRAFT; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.ERROR_IN_PUBLISHING; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.ERROR_IN_UNPUBLISHING; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.PUBLISHED; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.PUBLISHING; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.SAVED; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.UNPUBLISHING; + /** * @author mpostelnicu * Page used to make editing easy, extend to get easy access to one entity for editing @@ -72,16 +81,22 @@ public abstract class AbstractEditStatusEntityPage getErrorInPublishingMessage() { + String status = ERROR_IN_PUBLISHING.equals(editForm.getModelObject().getStatus()) ? "publishing" : "unpublishing"; + return Model.of(MessageFormat.format(getString("errorInPublishingTitle"), status)); + } + + private boolean isErrorInPublishingVisible() { + String status = editForm.getModelObject().getStatus(); + return ERROR_IN_PUBLISHING.equals(status) || ERROR_IN_UNPUBLISHING.equals(status); + } + @Override protected void afterSaveEntity(final T saveable) { super.afterSaveEntity(saveable); @@ -284,14 +379,12 @@ protected void checkAndSendEventForDisableEditing() { } public boolean isDisableEditingEvent() { - return !Strings.isEqual(editForm.getModelObject().getStatus(), DBConstants.Status.DRAFT) || isViewMode(); + return !Strings.isEqual(editForm.getModelObject().getStatus(), DRAFT) || isViewMode(); } protected boolean isViewMode() { return false; -// return SecurityConstants.Action.VIEW -// .equals(permissionEntityRenderableService.getAllowedAccess(this, editForm.getModelObject())); } private void addCheckedOutTo() { @@ -309,7 +402,8 @@ private void addCheckedOutTo() { private void addRemoveLock() { removeLock = new CheckBoxBootstrapFormComponent("removeLock"); - removeLock.setVisibilityAllowed(getLockableResource().getCheckedOutUser() != null); +// removeLock.setVisibilityAllowed(getLockableResource().getCheckedOutUser() != null); + removeLock.setVisibilityAllowed(false); editForm.add(removeLock); MetaDataRoleAuthorizationStrategy.authorize(removeLock, Component.RENDER, SecurityConstants.Roles.ROLE_ADMIN); } @@ -350,9 +444,11 @@ protected void enableDisableAutosaveFields(final AjaxRequestTarget target) { private void addAutosaveBehavior(final AjaxRequestTarget target) { // enable autosave if (!ComponentUtil.isPrintMode() && adminSettingsService.getAutosaveTime() > 0 - && Strings.isEqual(editForm.getModelObject().getStatus(), DBConstants.Status.DRAFT)) { + && Strings.isEqual(editForm.getModelObject().getStatus(), DRAFT) + && !editForm.getModelObject().isNew()) { saveDraftContinueButton.add(getAutosaveBehavior()); - autoSaveLabel.setVisibilityAllowed(true); + boolean isAutoSaveVisible = getPageParameters().get(PARAM_AUTO_SAVE).toBoolean(false); + autoSaveLabel.setVisibilityAllowed(isAutoSaveVisible); if (target != null) { target.add(autoSaveLabel); } @@ -361,7 +457,7 @@ private void addAutosaveBehavior(final AjaxRequestTarget target) { private AbstractAjaxTimerBehavior getAutosaveBehavior() { final AbstractAjaxTimerBehavior ajaxTimerBehavior = new AbstractAjaxTimerBehavior( - Duration.minutes(adminSettingsService.getAutosaveTime())) { + Duration.ofMinutes(adminSettingsService.getAutosaveTime())) { @Override protected void onTimer(final AjaxRequestTarget target) { // display block UI message until the page is reloaded @@ -375,8 +471,11 @@ protected void onTimer(final AjaxRequestTarget target) { + "$('#" + verticalPosition.getMarkupId() + "').val($(window).scrollTop()); " + "$('#" + saveDraftContinueButton.getMarkupId() + "').click();"); + target.prependJavaScript(getShowBlockUICode()); + // disable all buttons from js target.prependJavaScript("$('#" + editForm.getMarkupId() + " button').prop('disabled', true);"); + target.prependJavaScript("$('#modals button').prop('disabled', false);"); } }; @@ -396,11 +495,16 @@ private String getStatusLabelClass() { } switch (editForm.getModelObject().getStatus()) { - case DBConstants.Status.APPROVED: + case PUBLISHED: return "label-success"; - case DBConstants.Status.DRAFT: + case DRAFT: + case ERROR_IN_PUBLISHING: + case ERROR_IN_UNPUBLISHING: return "label-danger"; - case DBConstants.Status.SUBMITTED: + case SAVED: + return "label-primary"; + case PUBLISHING: + case UNPUBLISHING: return "label-warning"; default: return ""; @@ -423,6 +527,7 @@ public void onEvent(final IEvent event) { } }; checkBoxBootstrapFormComponent.setVisibilityAllowed(!isViewMode()); + checkBoxBootstrapFormComponent.setVisibilityAllowed(false); return checkBoxBootstrapFormComponent; } @@ -436,6 +541,7 @@ public void onEvent(final IEvent event) { } }; comment.setShowTooltip(true); + comment.setVisibilityAllowed(false); return comment; } @@ -491,7 +597,7 @@ protected String getOnClickScript() { protected void onSubmit(final AjaxRequestTarget target) { editForm.visitChildren(GenericBootstrapFormComponent.class, new AllowNullForCertainInvalidFieldsVisitor()); - setStatusAppendComment(DBConstants.Status.DRAFT); + setStatusAppendComment(DRAFT); super.onSubmit(target); } }; @@ -509,12 +615,12 @@ protected String getOnClickScript() { @Override protected void onSubmit(final AjaxRequestTarget target) { - setStatusAppendComment(DBConstants.Status.SUBMITTED); + setStatusAppendComment(SAVED); super.onSubmit(target); } }; - button.setIconType(FontAwesomeIconType.send); + button.setIconType(FontAwesome5IconType.envelope_s); return button; } @@ -528,7 +634,7 @@ protected String getOnClickScript() { @Override protected void onSubmit(final AjaxRequestTarget target) { - setStatusAppendComment(DBConstants.Status.SUBMITTED); + setStatusAppendComment(SAVED); super.onSubmit(target); } @@ -543,7 +649,7 @@ protected PageParameters getParameterPage() { } }; - button.setIconType(FontAwesomeIconType.tasks); + button.setIconType(FontAwesome5IconType.tasks_s); return button; } @@ -575,7 +681,7 @@ protected String getOnClickScript() { protected void onSubmit(final AjaxRequestTarget target) { editForm.visitChildren(GenericBootstrapFormComponent.class, new AllowNullForCertainInvalidFieldsVisitor()); - setStatusAppendComment(DBConstants.Status.DRAFT); + setStatusAppendComment(DRAFT); super.onSubmit(target); } @@ -586,17 +692,17 @@ protected Class getResponsePage() { @Override protected PageParameters getParameterPage() { - return getPageParameters(); + return getPageParameters().set(PARAM_AUTO_SAVE, true); } }; - button.setIconType(FontAwesomeIconType.tasks); + button.setIconType(FontAwesome5IconType.tasks_s); return button; } private SaveEditPageButton getSaveApprovePageButton() { - final SaveEditPageButton saveEditPageButton = new SaveEditPageButton("approve", - new StringResourceModel("approve", this, null)) { + final SaveEditPageButton saveEditPageButton = new SaveEditPageButton("saveApprove", + new StringResourceModel("saveApprove", this, null)) { @Override protected String getOnClickScript() { @@ -605,33 +711,58 @@ protected String getOnClickScript() { @Override protected void onSubmit(final AjaxRequestTarget target) { - setStatusAppendComment(DBConstants.Status.APPROVED); - super.onSubmit(target); + approveModal.show(true); + target.add(approveModal); + } + + @Override + protected void onError(final AjaxRequestTarget target) { + super.onError(target); + target.add(feedbackPanel); + } + }; + saveEditPageButton.setIconType(FontAwesome5IconType.thumbs_up_s); + return saveEditPageButton; + } + + private SaveEditPageButton getApprovePageButton() { + final SaveEditPageButton saveEditPageButton = new SaveEditPageButton("approve", + new StringResourceModel("approve", this, null)) { + + @Override + protected void onSubmit(final AjaxRequestTarget target) { + approveModal.show(true); + target.add(approveModal); + } + + @Override + protected void onError(final AjaxRequestTarget target) { + super.onError(target); + target.add(feedbackPanel); } }; - saveEditPageButton.setIconType(FontAwesomeIconType.thumbs_up); + saveEditPageButton.setIconType(FontAwesome5IconType.thumbs_up_s); return saveEditPageButton; } protected SaveEditPageButton getRevertToDraftPageButton() { final SaveEditPageButton saveEditPageButton = new SaveEditPageButton("revertToDraft", new StringResourceModel("revertToDraft", this, null)) { + @Override - protected String getOnClickScript() { - return WebConstants.DISABLE_FORM_LEAVING_JS; + protected void onSubmit(final AjaxRequestTarget target) { + unpublishModal.show(true); + target.add(unpublishModal); } @Override - protected void onSubmit(final AjaxRequestTarget target) { - setStatusAppendComment(DBConstants.Status.DRAFT); - editForm.getModelObject().setRemoveLock(true); - super.onSubmit(target); - target.add(editForm); - setButtonsPermissions(); - onAfterRevertToDraft(target); + protected void onError(final AjaxRequestTarget target) { + super.onError(target); + target.add(feedbackPanel); } + }; - saveEditPageButton.setIconType(FontAwesomeIconType.thumbs_down); + saveEditPageButton.setIconType(FontAwesome5IconType.thumbs_down_s); return saveEditPageButton; } @@ -639,6 +770,10 @@ protected void onAfterRevertToDraft(AjaxRequestTarget target) { } + protected void onApprove(AjaxRequestTarget target) { + + } + protected void setStatusAppendComment(final String status) { final T saveable = editForm.getModelObject(); @@ -659,8 +794,9 @@ protected void setButtonsPermissions() { addSaveButtonsPermissions(saveButton); addSaveButtonsPermissions(saveDraftContinueButton); addSaveButtonsPermissions(submitAndNext); - addSaveButtonsPermissions(saveSubmitButton); - addApproveButtonPermissions(saveApproveButton); + addSaveSubmitButtonPermissions(saveSubmitButton); + addSaveApproveButtonPermissions(saveApproveButton); + addApproveButtonPermissions(approveButton); addSaveRevertButtonPermissions(revertToDraftPageButton); addDeleteButtonPermissions(deleteButton); @@ -670,35 +806,30 @@ protected void setButtonsPermissions() { submitAndNext.setVisibilityAllowed(false); saveSubmitButton.setVisibilityAllowed(false); saveApproveButton.setVisibilityAllowed(false); + approveButton.setVisibilityAllowed(false); revertToDraftPageButton.setVisibilityAllowed(false); } } protected void addDeleteButtonPermissions(final Component button) { - MetaDataRoleAuthorizationStrategy.authorize(button, Component.RENDER, SecurityConstants.Roles.ROLE_ADMIN); - button.setVisibilityAllowed(entityId != null && !isViewMode()); - MetaDataRoleAuthorizationStrategy.authorize( - button, Component.RENDER, getCommaCombinedRoles()); + button.setVisibilityAllowed(entityId != null && !isViewMode() + && !(PUBLISHING.equals(editForm.getModelObject().getStatus()) + || PUBLISHED.equals(editForm.getModelObject().getStatus()))); } protected void addSaveRevertButtonPermissions(final Component button) { addDefaultAllButtonsPermissions(button); - MetaDataRoleAuthorizationStrategy.authorize(button, Component.RENDER, getValidatorRole()); - MetaDataRoleAuthorizationStrategy.authorize(button, Component.RENDER, getCommaCombinedRoles()); button.setVisibilityAllowed(button.isVisibilityAllowed() - && !DBConstants.Status.DRAFT.equals(editForm.getModelObject().getStatus())); - - // additionally normal users should not revert anything that was already validated - if (FormSecurityUtil.isCurrentRoleOnlyUser(getUserRole(), getValidatorRole()) - && DBConstants.Status.APPROVED.equals(editForm.getModelObject().getStatus())) { - button.setVisibilityAllowed(false); - } else - - //admins can revert anything - if (FormSecurityUtil.isCurrentUserAdmin() - && DBConstants.Status.APPROVED.equals(editForm.getModelObject().getStatus())) { - button.setVisibilityAllowed(true); - } + && (PUBLISHED.equals(editForm.getModelObject().getStatus()) + || ERROR_IN_UNPUBLISHING.equals(editForm.getModelObject().getStatus()))); + } + + protected void addSaveApproveButtonPermissions(final Component button) { + addDefaultAllButtonsPermissions(button); + MetaDataRoleAuthorizationStrategy.authorize( + button, Component.RENDER, getValidatorRole()); + button.setVisibilityAllowed(button.isVisibilityAllowed() + && DRAFT.equals(editForm.getModelObject().getStatus())); } protected void addApproveButtonPermissions(final Component button) { @@ -706,19 +837,30 @@ protected void addApproveButtonPermissions(final Component button) { MetaDataRoleAuthorizationStrategy.authorize( button, Component.RENDER, getValidatorRole()); button.setVisibilityAllowed(button.isVisibilityAllowed() - && DBConstants.Status.SUBMITTED.equals(editForm.getModelObject().getStatus())); + && (SAVED.equals(editForm.getModelObject().getStatus()) + || ERROR_IN_PUBLISHING.equals(editForm.getModelObject().getStatus()))); + } + + protected void addSaveSubmitButtonPermissions(final Component button) { + addDefaultAllButtonsPermissions(button); + MetaDataRoleAuthorizationStrategy.authorize(button, Component.RENDER, getCommaCombinedRoles()); + button.setVisibilityAllowed(button.isVisibilityAllowed() + && DRAFT.equals(editForm.getModelObject().getStatus())); } protected void addSaveButtonsPermissions(final Component button) { addDefaultAllButtonsPermissions(button); MetaDataRoleAuthorizationStrategy.authorize(button, Component.RENDER, getCommaCombinedRoles()); button.setVisibilityAllowed(button.isVisibilityAllowed() - && DBConstants.Status.DRAFT.equals(editForm.getModelObject().getStatus())); + && (DRAFT.equals(editForm.getModelObject().getStatus()) + || SAVED.equals(editForm.getModelObject().getStatus()) + || ERROR_IN_PUBLISHING.equals(editForm.getModelObject().getStatus()) + || ERROR_IN_UNPUBLISHING.equals(editForm.getModelObject().getStatus()))); } protected void addDefaultAllButtonsPermissions(final Component button) { - MetaDataRoleAuthorizationStrategy.authorize(button, Component.RENDER, SecurityConstants.Roles.ROLE_ADMIN); + MetaDataRoleAuthorizationStrategy.authorize(button, Component.RENDER, SecurityConstants.Roles.ROLE_USER); } @@ -731,6 +873,10 @@ private void scrollToPreviousPosition(final IHeaderResponse response) { ))); } + protected PageParameters getParamsWithServiceInformation() { + return null; + } + @Override public void renderHead(final IHeaderResponse response) { super.renderHead(response); diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditStatusEntityPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditStatusEntityPage.properties index 97f5162f..14e2e466 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditStatusEntityPage.properties +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/AbstractEditStatusEntityPage.properties @@ -9,19 +9,14 @@ # Contributors: # Development Gateway - initial API and implementation ############################################################################### -approve=Approve -revertToDraft=Reject to draft -saveButton=Save Draft -saveSubmit=Save & Submit +approve=Publish +revertToDraft=Unpublish +saveButton=Save as Draft +saveSubmit=Save +saveApprove=Save and Publish submitAndNext=Save and Next saveContinue=Save Draft & Continue -newStatusComment.label=Update Comment -newStatusComment.help=Add a comment to describe this update during validation or data entry. This comment can be useful for other people editing or validating this form. \ - PLEASE NOTE, text entered here will be viewable by anyone with access to this page. -visibleStatusComments.label=View comments and form history autosave_message=Form is saving -autoSaveLabelMessage=Form auto-saved less than {0,number} minutes ago +autoSaveLabelMessage=Form auto-saved less than {0,number} minutes ago. checkedOutToMessage=Checked out to user {0}. -removeLock.label=Force form check in -removeLock.help=This will check back in a form that has been checked out by another user. Use this only if you know \ - the user is no longer editing the form and you want to allow other users access to the form. +errorInPublishingTitle=There was an error during {0}. Please check the data and try to republish it. If it doesn't work please contact the admin. diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/EditTestFormPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/EditTestFormPage.html index 7b3bbfae..38b11ca2 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/EditTestFormPage.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/EditTestFormPage.html @@ -22,24 +22,24 @@
-
+
-
+
-
+
-
+
diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/AbstractEditServiceEntityPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/AbstractEditServiceEntityPage.html new file mode 100644 index 00000000..70f9dbc2 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/AbstractEditServiceEntityPage.html @@ -0,0 +1,25 @@ + + + + +
+
+
+ +
+
+ + +
+
+
+
+
+
+ +
+
+
+ + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/AbstractEditServiceEntityPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/AbstractEditServiceEntityPage.java new file mode 100644 index 00000000..194159cc --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/AbstractEditServiceEntityPage.java @@ -0,0 +1,385 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.admin; + +import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; +import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.TextContentModal; +import de.agilecoders.wicket.core.markup.html.bootstrap.form.BootstrapForm; +import org.devgateway.toolkit.forms.wicket.components.buttons.ladda.LaddaAjaxButton; +import org.apache.wicket.Page; +import org.apache.wicket.ajax.AjaxEventBehavior; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.model.CompoundPropertyModel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.ResourceModel; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.apache.wicket.validation.ValidationError; +import org.devgateway.toolkit.forms.WebConstants; +import org.devgateway.toolkit.forms.exceptions.NullListPageClassException; +import org.devgateway.toolkit.forms.service.DatasetClientService; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.forms.service.admin.BaseServiceEntityService; +import org.devgateway.toolkit.forms.wicket.components.form.BootstrapCancelButton; +import org.devgateway.toolkit.forms.wicket.components.form.BootstrapSubmitButton; +import org.devgateway.toolkit.forms.wicket.components.form.GenericBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.components.form.visitors.GenericBootstrapValidationVisitor; +import org.devgateway.toolkit.forms.wicket.page.BasePage; +import org.devgateway.toolkit.persistence.dto.ServiceEntity; +import org.devgateway.toolkit.persistence.service.BaseJpaService; +import org.springframework.orm.ObjectOptimisticLockingFailureException; + +import java.text.MessageFormat; + +import static org.devgateway.toolkit.forms.WebConstants.PARAM_SERVICE; + +public abstract class AbstractEditServiceEntityPage extends BasePage { + private static final long serialVersionUID = -2184956023986944919L; + + /** + * Factory method for the new instance of the entity being editing. This + * will be invoked only when the parameter PARAM_ID is null + * + * @return + */ + /** + * The repository used to fetch and save the entity, this is initialized in + * subclasses + */ + protected Class listPageClass; + + /** + * The form used by all subclasses + */ + protected EditForm editForm; + + protected BaseServiceEntityService entityService; + + private CompoundPropertyModel compoundModel; + + /** + * the entity id, or null if a new entity is requested + */ + protected Long entityId; + + protected String serviceName; + + /** + * This is a wrapper model that ensures we can easily edit the properties of + * the entity + */ + /** + * generic submit button for the form + */ + protected BootstrapSubmitButton saveButton; + + /** + * generic delete button for the form + */ + protected TextContentModal cancelModal; + + protected TextContentModal saveFailedModal; + + @SpringBean + protected EurekaClientService eurekaClientService; + + public EditForm getEditForm() { + return editForm; + } + + public GenericBootstrapValidationVisitor getBootstrapValidationVisitor(final AjaxRequestTarget target) { + return new GenericBootstrapValidationVisitor(target); + } + + protected TextContentModal createCancelModal() { + final TextContentModal cancelModal = new TextContentModal("cancelModal", + Model.of("Are you sure you want to cancel? Any changes made will be lost.")); + + final LaddaAjaxButton cancelButton = new BootstrapCancelButton("button", Model.of("Yes")) { + private static final long serialVersionUID = -9144254663723097155L; + + @Override + protected void onSubmit(final AjaxRequestTarget target) { + cancelModal.appendCloseDialogJavaScript(target); + setResponsePage(listPageClass, getCancelPageParameters()); + } + }; + + cancelButton.setType(Buttons.Type.Success); + cancelModal.addButton(cancelButton); + cancelModal.addCloseButton(Model.of("No")); + + return cancelModal; + } + + protected TextContentModal createSaveFailedModal() { + final TextContentModal modal = new TextContentModal("saveFailedModal", Model.of("Save failed!")); + modal.header(new ResourceModel("error")); + final LaddaAjaxButton okButton = new LaddaAjaxButton("button", Buttons.Type.Info) { + @Override + protected void onSubmit(final AjaxRequestTarget target) { + setResponsePage(listPageClass); + } + }; + okButton.setDefaultFormProcessing(false); + okButton.setLabel(Model.of("OK")); + modal.addButton(okButton); + + modal.add(new AjaxEventBehavior("hidden.bs.modal") { + @Override + protected void onEvent(final AjaxRequestTarget target) { + setResponsePage(listPageClass); + } + }); + + return modal; + } + + public class EditForm extends BootstrapForm { + private static final long serialVersionUID = -9127043819229346784L; + + /** + * wrap the model with a {@link CompoundPropertyModel} to ease editing + * of fields + * + * @param model + */ + public void setCompoundPropertyModel(final IModel model) { + compoundModel = new CompoundPropertyModel(model); + setModel(compoundModel); + } + + public EditForm(final String id, final IModel model) { + this(id); + setCompoundPropertyModel(model); + } + + public EditForm(final String id) { + super(id); + + setOutputMarkupId(true); + + saveButton = getSaveEditPageButton(); + add(saveButton); + + cancelModal = createCancelModal(); + add(cancelModal); + + saveFailedModal = createSaveFailedModal(); + add(saveFailedModal); + + add(getCancelButton("cancel")); + } + } + + protected BootstrapCancelButton getCancelButton(final String id) { + return new BootstrapCancelButton(id, new StringResourceModel("cancelButton", this, null)) { + private static final long serialVersionUID = -249084359200507749L; + + @Override + protected void onSubmit(final AjaxRequestTarget target) { + setResponsePage(listPageClass, getCancelPageParameters()); + } + }; + } + + /** + * Generic functionality for the save page button, this can be extended + * further by subclasses + * + */ + public class SaveEditPageButton extends BootstrapSubmitButton { + private static final long serialVersionUID = 9075809391795974349L; + + private boolean redirect = true; + + private boolean redirectToSelf = false; + + public SaveEditPageButton(final String id, final IModel model) { + super(id, model); + } + + @Override + protected void onSubmit(final AjaxRequestTarget target) { + try { + // save the object and go back to the list page + T entity = editForm.getModelObject(); + + if (editForm.getModelObject().getId() != null) { + entityService.update(serviceName, entity); + } else { + entityService.save(serviceName, entity); + } + + // only redirect if redirect is true + if (redirectToSelf) { + // we need to close the blockUI if it's opened and enable all + // the buttons + target.appendJavaScript("$.unblockUI();"); + target.appendJavaScript("$('#" + editForm.getMarkupId() + " button').prop('disabled', false);"); + } else if (redirect) { + setResponsePage(getResponsePage(), getParameterPage()); + } + + // redirect is set back to true, which is the default behavior + redirect = true; + redirectToSelf = false; + } catch (ObjectOptimisticLockingFailureException e) { + saveFailedModal.show(target); + } + } + + /** + * by default, submit button returns back to listPage + * + * @return + */ + protected Class getResponsePage() { + return listPageClass; + } + + /** + * no params by default + * + * @return + */ + protected PageParameters getParameterPage() { + return getSaveEditParameters(); + } + + @Override + protected void onError(final AjaxRequestTarget target) { + // make all errors visible + GenericBootstrapValidationVisitor genericBootstrapValidationVisitor = getBootstrapValidationVisitor(target); + editForm.visitChildren(GenericBootstrapFormComponent.class, genericBootstrapValidationVisitor); + + ValidationError error = new ValidationError(); + error.addKey("formHasErrors"); + error(error); + + target.add(feedbackPanel); + + // autoscroll down to the feedback panel + target.appendJavaScript("$('html, body').animate({scrollTop: $(\".feedbackPanel\").offset().top}, 500);"); + } + + /** + * @return the redirect + */ + public boolean isRedirect() { + return redirect; + } + + /** + * @param redirect the redirect to set + */ + public void setRedirect(final boolean redirect) { + this.redirect = redirect; + } + + /** + * @param redirectToSelf the redirectToSelf to set + */ + public void setRedirectToSelf(final boolean redirectToSelf) { + this.redirectToSelf = redirectToSelf; + } + + /** + * @return the redirectToSelf + */ + public boolean isRedirectToSelf() { + return redirectToSelf; + } + } + + protected PageParameters getSaveEditParameters() { + return getParamsWithServiceInformation(); + } + + protected PageParameters getCancelPageParameters() { + return getParamsWithServiceInformation(); + } + + /** + * Override this to create new save buttons with additional behaviors + * + * @return + */ + protected SaveEditPageButton getSaveEditPageButton() { + return new SaveEditPageButton("save", new StringResourceModel("saveButton", this, null)); + } + + public AbstractEditServiceEntityPage(final PageParameters parameters) { + super(parameters); + + if (!parameters.get(WebConstants.PARAM_ID).isNull()) { + entityId = parameters.get(WebConstants.PARAM_ID).toLongObject(); + } + + editForm = new EditForm("editForm"); + editForm.setMultiPart(true); + + add(editForm); + + // section in child + pageTitle.setDefaultModel(getTitleModel()); + + serviceName = getPageParameters().get(PARAM_SERVICE).toString(); + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + // we dont like receiving null list pages + if (listPageClass == null) { + throw new NullListPageClassException(); + } + + IModel model = null; + + if (entityId != null) { + T entity = entityService.findOne(serviceName, entityId); + model = Model.of(entity); + } else { + T entity = entityService.newInstance(); + if (entity != null) { + model = Model.of(entity); + } + } + + if (model != null) { + editForm.setCompoundPropertyModel(model); + } + + } + + protected Model getTitleModel() { + String serviceLabel = getServiceLabel(); + if (entityId == null) { + return Model.of(MessageFormat.format(getString("page.title.add"), serviceLabel)); + } else { + return Model.of(MessageFormat.format(getString("page.title.edit"), serviceLabel)); + } + } + + protected PageParameters getParamsWithServiceInformation() { + String service = getPageParameters().get(PARAM_SERVICE).toString(); + + PageParameters pageParams = new PageParameters(); + pageParams.add(PARAM_SERVICE, service); + + return pageParams; + } + + protected IModel getBreadcrumbTitleModel() { + String serviceLabel = getServiceLabel(); + if (entityId == null) { + return Model.of(MessageFormat.format(getString("breadcrumb.title.add"), serviceLabel)); + } else { + return Model.of(MessageFormat.format(getString("breadcrumb.title.edit"), serviceLabel)); + } + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/AbstractEditServiceEntityPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/AbstractEditServiceEntityPage.properties new file mode 100644 index 00000000..9eaa6963 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/AbstractEditServiceEntityPage.properties @@ -0,0 +1,22 @@ +############################################################################### +# Copyright (c) 2015 Development Gateway, Inc and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the MIT License (MIT) +# which accompanies this distribution, and is available at +# https://opensource.org/licenses/MIT +# +# Contributors: +# Development Gateway - initial API and implementation +############################################################################### +page.title=Edit {0} Entity +page.title.add=Add {0} Entity +page.title.edit=Edit {0} Entity +cancelButton=Cancel +saveButton=Save +formHasErrors=The form has errors or is missing information and cannot be submitted. Please scroll up, fix all the errors (highlighted in red) and re-submit! +error=Error + +breadcrumb.title=Edit Entity +breadcrumb.title.add=Add Entity +breadcrumb.title.edit=Edit Entity \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceCategoryPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceCategoryPage.html new file mode 100644 index 00000000..34128e18 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceCategoryPage.html @@ -0,0 +1,30 @@ + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ + + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceCategoryPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceCategoryPage.java new file mode 100644 index 00000000..bbff0164 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceCategoryPage.java @@ -0,0 +1,58 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.admin; + +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.service.admin.ServiceCategoryService; +import org.devgateway.toolkit.forms.validators.UniqueLanguageTranslationValidator; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.components.form.ColorPickerBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.components.form.TextFieldBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.page.edit.admin.panel.ListViewTextTranslationSectionPanel; +import org.devgateway.toolkit.forms.wicket.page.lists.admin.ListServiceCategoriesPage; +import org.devgateway.toolkit.persistence.dto.ServiceCategory; +import org.wicketstuff.annotation.mount.MountPath; + +@MountPath(value = "/editServiceCategory") +@BreadCrumbPage(parent = ListServiceCategoriesPage.class, hasServiceParam = true) +public class EditServiceCategoryPage extends AbstractEditServiceEntityPage { + private static final long serialVersionUID = -9013029067860834250L; + + @SpringBean + private ServiceCategoryService serviceCategoryService; + + public EditServiceCategoryPage(final PageParameters parameters) { + super(parameters); + this.listPageClass = ListServiceCategoriesPage.class; + this.entityService = serviceCategoryService; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + final TextFieldBootstrapFormComponent value = new TextFieldBootstrapFormComponent<>("code"); + value.setEnabled(false); + editForm.add(value); + + final TextFieldBootstrapFormComponent label = new TextFieldBootstrapFormComponent<>("value"); + label.getField().setRequired(true); + editForm.add(label); + + final TextFieldBootstrapFormComponent type = new TextFieldBootstrapFormComponent<>("type"); + type.setEnabled(false); + editForm.add(type); + + final TextFieldBootstrapFormComponent position = new TextFieldBootstrapFormComponent<>("position"); + position.getField().setRequired(true); + editForm.add(position); + + ColorPickerBootstrapFormComponent colorPicker = new ColorPickerBootstrapFormComponent("color", + new PropertyModel<>(editForm.getModelObject(), "categoryStyle.color")); + editForm.add(colorPicker); + + editForm.add(new ListViewTextTranslationSectionPanel("labels")); + editForm.add(new UniqueLanguageTranslationValidator()); + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceCategoryPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceCategoryPage.properties new file mode 100644 index 00000000..1a62ad81 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceCategoryPage.properties @@ -0,0 +1,24 @@ +############################################################################### +# Copyright (c) 2022 Development Gateway, Inc and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the MIT License (MIT) +# which accompanies this distribution, and is available at +# https://opensource.org/licenses/MIT +# +# Contributors: +# Development Gateway - initial API and implementation +############################################################################### +page.title=Edit {0} Category +page.title.add=Add {0} Category +page.title.edit=Edit {0} Category +code.label=Value +value.label=System Label +position.label=Position +type.label=Type +color.label=Color in graphic +labels.label=Label Translations + +breadcrumb.title=Edit Category +breadcrumb.title.add=Add Category +breadcrumb.title.edit=Edit Category \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceDimensionPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceDimensionPage.html new file mode 100644 index 00000000..f88ef4b5 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceDimensionPage.html @@ -0,0 +1,25 @@ + + + + +
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+
+ + + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceDimensionPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceDimensionPage.java new file mode 100644 index 00000000..4eede891 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceDimensionPage.java @@ -0,0 +1,48 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.admin; + +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.service.admin.ServiceDimensionService; +import org.devgateway.toolkit.forms.validators.UniqueLanguageTranslationValidator; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.components.form.TextFieldBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.page.edit.admin.panel.ListViewTextTranslationSectionPanel; +import org.devgateway.toolkit.forms.wicket.page.lists.admin.ListServiceDimensionsPage; +import org.devgateway.toolkit.persistence.dto.ServiceDimension; +import org.wicketstuff.annotation.mount.MountPath; + +@MountPath(value = "/editServiceDimension") +@BreadCrumbPage(parent = ListServiceDimensionsPage.class, hasServiceParam = true) +public class EditServiceDimensionPage extends AbstractEditServiceEntityPage { + private static final long serialVersionUID = -1594571319284288551L; + + @SpringBean + private ServiceDimensionService serviceDimensionService; + + public EditServiceDimensionPage(final PageParameters parameters) { + super(parameters); + this.listPageClass = ListServiceDimensionsPage.class; + this.entityService = serviceDimensionService; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + final TextFieldBootstrapFormComponent code = new TextFieldBootstrapFormComponent<>("code"); + code.setEnabled(false); + editForm.add(code); + + final TextFieldBootstrapFormComponent value = new TextFieldBootstrapFormComponent<>("value"); + value.getField().setRequired(true); + editForm.add(value); + + final TextFieldBootstrapFormComponent position = new TextFieldBootstrapFormComponent<>("position"); + position.getField().setRequired(true); + editForm.add(position); + + editForm.add(new ListViewTextTranslationSectionPanel("labels")); + editForm.add(new UniqueLanguageTranslationValidator()); + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceDimensionPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceDimensionPage.properties new file mode 100644 index 00000000..a2807f26 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceDimensionPage.properties @@ -0,0 +1,22 @@ +############################################################################### +# Copyright (c) 2015 Development Gateway, Inc and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the MIT License (MIT) +# which accompanies this distribution, and is available at +# https://opensource.org/licenses/MIT +# +# Contributors: +# Development Gateway - initial API and implementation +############################################################################### +page.title=Edit {0} Dimension +page.title.add=Add {0} Dimension +page.title.edit=Edit {0} Dimension +code.label=Value +value.label=System Label +position.label=Position +labels.label=Labels + +breadcrumb.title=Edit Dimension +breadcrumb.title.add=Add Dimension +breadcrumb.title.edit=Edit Dimension \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceFilterPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceFilterPage.html new file mode 100644 index 00000000..f259b5b8 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceFilterPage.html @@ -0,0 +1,25 @@ + + + + +
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+
+ + + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceFilterPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceFilterPage.java new file mode 100644 index 00000000..9a71ee5f --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceFilterPage.java @@ -0,0 +1,48 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.admin; + +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.service.admin.ServiceFilterService; +import org.devgateway.toolkit.forms.validators.UniqueLanguageTranslationValidator; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.components.form.TextFieldBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.page.edit.admin.panel.ListViewTextTranslationSectionPanel; +import org.devgateway.toolkit.forms.wicket.page.lists.admin.ListServiceFiltersPage; +import org.devgateway.toolkit.persistence.dto.ServiceFilter; +import org.wicketstuff.annotation.mount.MountPath; + +@MountPath(value = "/editServiceFilter") +@BreadCrumbPage(parent = ListServiceFiltersPage.class, hasServiceParam = true) +public class EditServiceFilterPage extends AbstractEditServiceEntityPage { + private static final long serialVersionUID = -8409084805556720923L; + + @SpringBean + private ServiceFilterService serviceFilterService; + + public EditServiceFilterPage(final PageParameters parameters) { + super(parameters); + this.listPageClass = ListServiceFiltersPage.class; + this.entityService = serviceFilterService; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + final TextFieldBootstrapFormComponent code = new TextFieldBootstrapFormComponent<>("code"); + code.setEnabled(false); + editForm.add(code); + + final TextFieldBootstrapFormComponent value = new TextFieldBootstrapFormComponent<>("value"); + value.getField().setRequired(true); + editForm.add(value); + + final TextFieldBootstrapFormComponent fieldType = new TextFieldBootstrapFormComponent<>("fieldType"); + fieldType.setEnabled(false); + editForm.add(fieldType); + + editForm.add(new ListViewTextTranslationSectionPanel("labels")); + editForm.add(new UniqueLanguageTranslationValidator()); + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceFilterPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceFilterPage.properties new file mode 100644 index 00000000..a965ce9b --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceFilterPage.properties @@ -0,0 +1,22 @@ +############################################################################### +# Copyright (c) 2015 Development Gateway, Inc and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the MIT License (MIT) +# which accompanies this distribution, and is available at +# https://opensource.org/licenses/MIT +# +# Contributors: +# Development Gateway - initial API and implementation +############################################################################### +page.title=Edit {0} Filter +page.title.add=Add {0} Filter +page.title.edit=Edit {0} Filter +code.label=Value +value.label=System Label +fieldType.label=Type +labels.label=Labels + +breadcrumb.title=Edit Filter +breadcrumb.title.add=Add Filter +breadcrumb.title.edit=Edit Filter \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceMeasurePage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceMeasurePage.html new file mode 100644 index 00000000..ccc8559d --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceMeasurePage.html @@ -0,0 +1,33 @@ + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ + + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceMeasurePage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceMeasurePage.java new file mode 100644 index 00000000..5c70b3ae --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceMeasurePage.java @@ -0,0 +1,62 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.admin; + +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.service.admin.ServiceMeasureService; +import org.devgateway.toolkit.forms.validators.UniqueLanguageTranslationValidator; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.components.form.ColorPickerBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.components.form.TextFieldBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.page.edit.admin.panel.ListViewTextTranslationSectionPanel; +import org.devgateway.toolkit.forms.wicket.page.lists.admin.ListServiceMeasuresPage; +import org.devgateway.toolkit.persistence.dto.ServiceMeasure; +import org.wicketstuff.annotation.mount.MountPath; + +@MountPath(value = "/editServiceMeasure") +@BreadCrumbPage(parent = ListServiceMeasuresPage.class, hasServiceParam = true) +public class EditServiceMeasurePage extends AbstractEditServiceEntityPage { + private static final long serialVersionUID = -9013029067860834250L; + + @SpringBean + private ServiceMeasureService serviceMeasureService; + + public EditServiceMeasurePage(final PageParameters parameters) { + super(parameters); + this.listPageClass = ListServiceMeasuresPage.class; + this.entityService = serviceMeasureService; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + final TextFieldBootstrapFormComponent value = new TextFieldBootstrapFormComponent<>("code"); + value.setEnabled(false); + editForm.add(value); + + final TextFieldBootstrapFormComponent label = new TextFieldBootstrapFormComponent<>("value"); + label.getField().setRequired(true); + editForm.add(label); + + final TextFieldBootstrapFormComponent parent = new TextFieldBootstrapFormComponent<>("parent"); + parent.setEnabled(false); + editForm.add(parent); + + final TextFieldBootstrapFormComponent expression = new TextFieldBootstrapFormComponent<>("expression"); + expression.setEnabled(false); + editForm.add(expression); + + final TextFieldBootstrapFormComponent position = new TextFieldBootstrapFormComponent<>("position"); + position.getField().setRequired(true); + editForm.add(position); + + ColorPickerBootstrapFormComponent colorPicker = new ColorPickerBootstrapFormComponent("color", + new PropertyModel<>(editForm.getModelObject(), "categoryStyle.color")); + editForm.add(colorPicker); + + editForm.add(new ListViewTextTranslationSectionPanel("labels")); + editForm.add(new UniqueLanguageTranslationValidator()); + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceMeasurePage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceMeasurePage.properties new file mode 100644 index 00000000..4ce271b3 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/EditServiceMeasurePage.properties @@ -0,0 +1,25 @@ +############################################################################### +# Copyright (c) 2022 Development Gateway, Inc and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the MIT License (MIT) +# which accompanies this distribution, and is available at +# https://opensource.org/licenses/MIT +# +# Contributors: +# Development Gateway - initial API and implementation +############################################################################### +page.title=Edit {0} Measure +page.title.add=Add {0} Measure +page.title.edit=Edit {0} Measure +code.label=Value +value.label=System Label +position.label=Position +color.label=Color in graphic +labels.label=Label Translations +parent.label=Group +expression.label=Expression + +breadcrumb.title=Edit Measure +breadcrumb.title.add=Add Measure +breadcrumb.title.edit=Edit Measure \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/panel/ListViewTextTranslationSectionPanel.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/panel/ListViewTextTranslationSectionPanel.html new file mode 100644 index 00000000..a8163c55 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/panel/ListViewTextTranslationSectionPanel.html @@ -0,0 +1,34 @@ + + + ListSectionPanel + + + +
+
+
+

[[title]]

+
(Please use the Wordpress Language Local Code - for example FR for French.)
+
+
+ +
+
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+ + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/panel/ListViewTextTranslationSectionPanel.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/panel/ListViewTextTranslationSectionPanel.java new file mode 100644 index 00000000..747dc838 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/panel/ListViewTextTranslationSectionPanel.java @@ -0,0 +1,138 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.admin.panel; + +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.markup.html.TransparentWebMarkupContainer; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.model.CompoundPropertyModel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.ResourceModel; +import org.devgateway.toolkit.forms.wicket.components.CompoundSectionPanel; +import org.devgateway.toolkit.forms.wicket.components.form.BootstrapAddButton; +import org.devgateway.toolkit.forms.wicket.components.form.BootstrapDeleteButton; +import org.devgateway.toolkit.forms.wicket.components.form.TextFieldBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.components.util.ComponentUtil; +import org.devgateway.toolkit.persistence.dto.ServiceCategory; +import org.devgateway.toolkit.persistence.dto.ServiceTextTranslation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class ListViewTextTranslationSectionPanel extends CompoundSectionPanel> { + private static final Logger logger = LoggerFactory.getLogger(ListViewTextTranslationSectionPanel.class); + + protected WebMarkupContainer listWrapper; + + protected ListView listView; + + public ListViewTextTranslationSectionPanel(final String id) { + super(id); + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + setOutputMarkupId(true); + setOutputMarkupPlaceholderTag(true); + + listWrapper = new TransparentWebMarkupContainer("listWrapper"); + listWrapper.setOutputMarkupId(true); + add(listWrapper); + + listWrapper.add(new Label("panelTitle", title)); + + listView = new ListView("list", getModel()) { + @Override + protected void populateItem(final ListItem item) { + item.setOutputMarkupId(true); + item.setOutputMarkupPlaceholderTag(true); + + // we wrap the item model on a compound model so we can use the field ids as property models + final CompoundPropertyModel compoundPropertyModel = new CompoundPropertyModel<>(item.getModel()); + + // we set back the model as the compound model, thus ensures the rest of the items added will benefit + item.setModel(compoundPropertyModel); + + // we add the rest of the items in the listItem + populateCompoundListItem(item); + + addItemContainer(item); + } + }; + + listView.setReuseItems(true); + listView.setOutputMarkupId(true); + listWrapper.add(listView); + + final BootstrapAddButton addButton = getAddNewChildButton(); + add(addButton); + } + + private void addItemContainer(final ListItem item) { + // we add the remove button + final BootstrapDeleteButton removeButton = getRemoveChildButton(item.getModelObject()); + item.add(removeButton); + } + + /** + * Removes a child based on its index + * + * @param item + * @return + */ + private BootstrapDeleteButton getRemoveChildButton(final ServiceTextTranslation item) { + final BootstrapDeleteButton removeButton = new BootstrapDeleteButton("remove", + new ResourceModel("removeButton")) { + @Override + protected void onSubmit(final AjaxRequestTarget target) { + ListViewTextTranslationSectionPanel.this.getModelObject().remove(item); + listView.removeAll(); + target.add(listWrapper); + } + }; + + removeButton.setOutputMarkupPlaceholderTag(true); + return removeButton; + } + + /** + * Returns the new child button. + */ + final BootstrapAddButton getAddNewChildButton() { + final BootstrapAddButton newButton = new BootstrapAddButton("newButton", new ResourceModel("newButton")) { + @Override + protected void onSubmit(final AjaxRequestTarget target) { + final ServiceTextTranslation newChild = createNewChild( + (IModel) ListViewTextTranslationSectionPanel.this.getParent().getDefaultModel()); + ListViewTextTranslationSectionPanel.this.getModel().getObject().add(newChild); + + listView.removeAll(); + target.add(listWrapper); + } + + }; + + newButton.setOutputMarkupPlaceholderTag(true); + return newButton; + } + + public ServiceTextTranslation createNewChild(IModel parentModel) { + ServiceTextTranslation textTranslation = new ServiceTextTranslation(); + textTranslation.setParent(parentModel.getObject()); + + return textTranslation; + } + + public void populateCompoundListItem(ListItem item) { + final TextFieldBootstrapFormComponent language = ComponentUtil.addTextField(item, "language"); + language.setShowTooltip(true); + language.required(); + + final TextFieldBootstrapFormComponent value = ComponentUtil.addTextField(item, "text"); + value.required(); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/panel/ListViewTextTranslationSectionPanel.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/panel/ListViewTextTranslationSectionPanel.properties new file mode 100644 index 00000000..3fa6ed59 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/admin/panel/ListViewTextTranslationSectionPanel.properties @@ -0,0 +1,5 @@ +newButton=New Translation +removeButton=Remove Translation +language.label=Language +language.help=Please use the Wordpress Language Local Code - for example FR for French. +text.label=Text diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/category/AbstractCategoryEditPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/category/AbstractCategoryEditPage.properties index a8303a9b..ed39bbbb 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/category/AbstractCategoryEditPage.properties +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/category/AbstractCategoryEditPage.properties @@ -10,4 +10,4 @@ # Development Gateway - initial API and implementation ############################################################################### page.title=Edit Category -label.label=Label \ No newline at end of file +label.label=System Label \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditCSVDatasetPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditCSVDatasetPage.html new file mode 100644 index 00000000..3e7e4478 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditCSVDatasetPage.html @@ -0,0 +1,37 @@ + + + + + Edit CSV Dataset + + + +
+ +
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+ +
+
+
+ +
+ + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditCSVDatasetPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditCSVDatasetPage.java new file mode 100644 index 00000000..08bebd9f --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditCSVDatasetPage.java @@ -0,0 +1,278 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.dataset; + +import de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapAjaxButton; +import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; +import org.devgateway.toolkit.forms.wicket.components.buttons.ladda.LaddaAjaxButton; +import org.apache.commons.lang3.StringUtils; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.request.IRequestCycle; +import org.apache.wicket.request.IRequestHandler; +import org.apache.wicket.request.cycle.RequestCycle; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.WebConstants; +import org.devgateway.toolkit.forms.client.DataSetClientException; +import org.devgateway.toolkit.forms.service.DatasetClientService; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.components.form.AJAXDownload; +import org.devgateway.toolkit.forms.wicket.components.form.BootstrapCancelButton; +import org.devgateway.toolkit.forms.wicket.components.form.FileInputBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.components.form.Select2ChoiceBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.components.form.TextFieldBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.page.edit.AbstractEditStatusEntityPage; +import org.devgateway.toolkit.forms.wicket.page.lists.dataset.ListCSVDatasetPage; +import org.devgateway.toolkit.forms.wicket.providers.GenericChoiceProvider; +import org.devgateway.toolkit.persistence.dao.FileMetadata; +import org.devgateway.toolkit.persistence.dao.data.CSVDataset; +import org.devgateway.toolkit.persistence.service.data.CSVDatasetService; +import org.devgateway.toolkit.web.util.SettingsUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.orm.ObjectOptimisticLockingFailureException; +import org.wicketstuff.annotation.mount.MountPath; + +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; + +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.DELETED; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.PUBLISHING; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.UNPUBLISHING; + +/** + * @author vchihai + */ +@MountPath(value = "/editCSVDataset") +@BreadCrumbPage(parent = ListCSVDatasetPage.class, hasServiceParam = true) +public class EditCSVDatasetPage extends AbstractEditStatusEntityPage { + + private static final long serialVersionUID = -5231470856974604314L; + + private static final Logger logger = LoggerFactory.getLogger(EditCSVDatasetPage.class); + + protected Select2ChoiceBootstrapFormComponent year; + + protected TextFieldBootstrapFormComponent destinationService; + + @SpringBean + protected CSVDatasetService csvDatasetService; + + @SpringBean + protected EurekaClientService eurekaClientService; + + @SpringBean + protected DatasetClientService datasetClientService; + + @SpringBean + protected SettingsUtils settingsUtils; + + public EditCSVDatasetPage(final PageParameters parameters) { + super(parameters); + this.jpaService = csvDatasetService; + this.listPageClass = ListCSVDatasetPage.class; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + if (entityId == null) { + String service = getPageParameters().get(WebConstants.PARAM_SERVICE).toString(); + editForm.getModelObject().setDestinationService(service); + } + + editForm.add(getYear()); + + final TextFieldBootstrapFormComponent description = + new TextFieldBootstrapFormComponent<>("description"); + description.getField().add(WebConstants.StringValidators.MAXIMUM_LENGTH_VALIDATOR_ONE_LINE_TEXT); + editForm.add(description); + + final FileInputBootstrapFormComponent files = new FileInputBootstrapFormComponent("files"); + files.allowedFileExtensions("csv"); + files.required(); + files.maxFiles(1); + files.getFileInputBootstrapFormComponentWrapper().setAllowDownloadWhenReadonly(true); + editForm.add(files); + editForm.add(getService()); + + AJAXDownload downloadTemplateBehaviour = getDownloadTemplateBehaviour(); + editForm.add(downloadTemplateBehaviour); + editForm.add(getDownloadTemplateButton(downloadTemplateBehaviour)); + + } + + private AJAXDownload getDownloadTemplateBehaviour() { + final AJAXDownload download = new AJAXDownload() { + @Override + protected IRequestHandler getHandler() { + return new IRequestHandler() { + @Override + public void respond(final IRequestCycle requestCycle) { + final HttpServletResponse response = (HttpServletResponse) requestCycle.getResponse().getContainerResponse(); + try { + String serviceName = editForm.getModelObject().getDestinationService(); + + final byte[] bytes = datasetClientService.getTemplateDownload(serviceName); + + response.setContentType("text/csv"); + response.setHeader("Content-Disposition", "attachment; filename=" + serviceName + "-template.csv"); + response.getOutputStream().write(bytes); + } catch (IOException e) { + logger.error("Download Template error", e); + } + + RequestCycle.get().scheduleRequestHandlerAfterCurrent(null); + } + + @Override + public void detach(final IRequestCycle requestCycle) { + // do nothing; + } + }; + } + }; + + return download; + } + + private BootstrapAjaxButton getDownloadTemplateButton(final AJAXDownload downloadTemplateBehaviour) { + final LaddaAjaxButton templateDownloadButton = new LaddaAjaxButton("templateDownloadButton", + new Model<>("Template Download"), + Buttons.Type.Warning) { + @Override + protected void onSubmit(final AjaxRequestTarget target) { + super.onSubmit(target); + + // initiate the file download + downloadTemplateBehaviour.initiate(target); + } + }; + templateDownloadButton.setDefaultFormProcessing(false); + templateDownloadButton.setIconType(FontAwesome5IconType.file_csv_s); + return templateDownloadButton; + } + + private Select2ChoiceBootstrapFormComponent getYear() { + year = new Select2ChoiceBootstrapFormComponent<>("year", + new GenericChoiceProvider<>(settingsUtils.getYearsRange())); + editForm.add(year); + year.required(); + + return year; + } + + private TextFieldBootstrapFormComponent getService() { + destinationService = new TextFieldBootstrapFormComponent("destinationService"); + destinationService.setEnabled(false); + + return destinationService; + } + + @Override + protected void onDelete(final AjaxRequestTarget target) { + try { + // save the object and go back to the list page + CSVDataset saveable = editForm.getModelObject(); + saveable.setStatus(DELETED); + + beforeSaveEntity(saveable); + // saves the entity and flushes the changes + jpaService.saveAndFlush(saveable); + + // clears session and detaches all entities that are currently attached + entityManager.clear(); + + // we flush the mondrian/wicket/reports cache to ensure it gets rebuilt + flushReportingCaches(); + afterSaveEntity(saveable); + } catch (ObjectOptimisticLockingFailureException e) { + deleteFailedModal.show(target); + target.add(deleteFailedModal); + } + setResponsePage(listPageClass, getSaveEditParameters()); + } + + protected void onAfterRevertToDraft(final AjaxRequestTarget target) { + try { + CSVDataset dataset = editForm.getModelObject(); + datasetClientService.unpublishDataset(editForm.getModelObject()); + dataset.setStatus(UNPUBLISHING); + } catch (DataSetClientException | Exception e) { + logger.error(e.getMessage(), e); + failedModal.show(target); + } + setResponsePage(listPageClass); + } + + protected void onApprove(final AjaxRequestTarget target) { + try { + CSVDataset dataset = editForm.getModelObject(); + + FileMetadata fileMetadata = dataset.getFiles().stream().findFirst().get(); + String fileName = fileMetadata.getName(); + byte[] content = fileMetadata.getContent().getBytes(); + + datasetClientService.publishDataset(dataset, fileName, content); + dataset.setStatus(PUBLISHING); + } catch (DataSetClientException | Exception e) { + logger.error(e.getMessage(), e); + failedModal.show(target); + } + setResponsePage(listPageClass); + } + + protected BootstrapCancelButton getCancelButton(final String id) { + return new CancelEditPageButton(id, new StringResourceModel("cancelButton", this, null)); + } + + public class CancelEditPageButton extends BootstrapCancelButton { + private static final long serialVersionUID = -1474498211555760931L; + + public CancelEditPageButton(final String id, final IModel model) { + super(id, model); + } + + @Override + protected void onSubmit(final AjaxRequestTarget target) { + cancelModal.show(true); + target.add(cancelModal); + } + } + + @Override + protected void enableDisableAutosaveFields(final AjaxRequestTarget target) { + super.enableDisableAutosaveFields(target); + + if (StringUtils.isBlank(editForm.getModelObject().getDestinationService())) { + saveApproveButton.setEnabled(false); + approveButton.setEnabled(false); + } + } + + @Override + protected PageParameters getSaveEditParameters() { + return getParamsWithServiceInformation(); + } + + @Override + protected PageParameters getCancelPageParameters() { + return getParamsWithServiceInformation(); + } + + protected PageParameters getParamsWithServiceInformation() { + PageParameters pageParams = new PageParameters(); + // add service to the page parameters + pageParams.add(WebConstants.PARAM_SERVICE, editForm.getModelObject().getDestinationService()); + + return pageParams; + } + + protected IModel getBreadcrumbTitleModel() { + return getTitleModel(); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditCSVDatasetPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditCSVDatasetPage.properties new file mode 100644 index 00000000..65eafd6a --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditCSVDatasetPage.properties @@ -0,0 +1,9 @@ +page.title.add=Add CSV Dataset +page.title.edit=Edit CSV Dataset +year.label=Year +destinationService.label=Destination Service + +description.label=Description +files.label=Upload Dataset File +uploadedFilesTitle=Uploaded File +note=* The uploaded document can be accessed by admin, neiti, and auditor users. \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditTetsimDatasetPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditTetsimDatasetPage.html new file mode 100644 index 00000000..fa3ac413 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditTetsimDatasetPage.html @@ -0,0 +1,37 @@ + + + + + Edit TETSIM Dataset + + + +
+ +
+
+
+ +
+

Base-line Numbers:

+
+
+ +
+

Price Analysis:

+
+
+ +
+

Industry responses to the change in taxation:

+
+
+ +
+
+
+ +
+ + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditTetsimDatasetPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditTetsimDatasetPage.java new file mode 100644 index 00000000..7c9ee99c --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditTetsimDatasetPage.java @@ -0,0 +1,251 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.dataset; + +import org.apache.wicket.Component; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.FormComponent; +import org.apache.wicket.markup.html.form.validation.AbstractFormValidator; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.client.DataSetClientException; +import org.devgateway.toolkit.forms.service.DatasetClientService; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.components.form.BootstrapCancelButton; +import org.devgateway.toolkit.forms.wicket.components.form.Select2ChoiceBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.components.form.TextFieldBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.page.edit.AbstractEditStatusEntityPage; +import org.devgateway.toolkit.forms.wicket.page.lists.dataset.ListTetsimDatasetPage; +import org.devgateway.toolkit.forms.wicket.providers.GenericChoiceProvider; +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.dao.data.TetsimPriceVariable; +import org.devgateway.toolkit.persistence.dao.data.TetsimTobaccoProductValue; +import org.devgateway.toolkit.persistence.service.data.TetsimDatasetService; +import org.devgateway.toolkit.persistence.service.tetsim.TetsimOutputService; +import org.devgateway.toolkit.web.util.SettingsUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.orm.ObjectOptimisticLockingFailureException; +import org.wicketstuff.annotation.mount.MountPath; + +import java.math.BigDecimal; + +import static org.devgateway.toolkit.forms.WebConstants.MAXIMUM_PERCENTAGE; +import static org.devgateway.toolkit.forms.WebConstants.PARAM_SERVICE; +import static org.devgateway.toolkit.forms.WebConstants.PARAM_YEAR; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.DELETED; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.PUBLISHING; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.UNPUBLISHING; + +/** + * @author vchihai + */ +@MountPath(value = "/editTetsimDataset") +@BreadCrumbPage(parent = ListTetsimDatasetPage.class, hasServiceParam = true) +public class EditTetsimDatasetPage extends AbstractEditStatusEntityPage { + + private static final long serialVersionUID = -8460878260874111506L; + + private static final Logger logger = LoggerFactory.getLogger(EditTetsimDatasetPage.class); + + protected Select2ChoiceBootstrapFormComponent year; + + protected TextFieldBootstrapFormComponent destinationService; + + @SpringBean + protected TetsimDatasetService tetsimDatasetService; + + @SpringBean + protected TetsimOutputService tetsimOutputService; + + @SpringBean + protected EurekaClientService eurekaClientService; + + @SpringBean + protected DatasetClientService datasetClientService; + + @SpringBean + protected SettingsUtils settingsUtils; + + public EditTetsimDatasetPage(final PageParameters parameters) { + super(parameters); + this.jpaService = tetsimDatasetService; + this.listPageClass = ListTetsimDatasetPage.class; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + editForm.add(getYear()); + editForm.add(getBaseLineNumbers()); + editForm.add(getPriceAnalysisNumbers()); + editForm.add(getIndustryResponsesNumbers()); + editForm.add(getService()); + + editForm.add(new TetsimMarketSharePercentageValidator()); + + if (editForm.getModelObject().getDestinationService() == null) { + String service = getPageParameters().get(PARAM_SERVICE).toString(); + editForm.getModelObject().setDestinationService(service); + } + + if (editForm.getModelObject().isNew() && getYearParam() != null) { + editForm.getModelObject().setYear(getYearParam()); + } + } + + private Select2ChoiceBootstrapFormComponent getYear() { + year = new Select2ChoiceBootstrapFormComponent<>("year", + new GenericChoiceProvider<>(settingsUtils.getYearsRange())); + editForm.add(year); + year.required(); + year.setEnabled(false); + + return year; + } + + private TextFieldBootstrapFormComponent getService() { + destinationService = new TextFieldBootstrapFormComponent<>("destinationService"); + destinationService.setEnabled(false); + return destinationService; + } + + @Override + protected void onDelete(final AjaxRequestTarget target) { + try { + // save the object and go back to the list page + TetsimDataset saveable = editForm.getModelObject(); + saveable.setStatus(DELETED); + + beforeSaveEntity(saveable); + // saves the entity and flushes the changes + jpaService.saveAndFlush(saveable); + + // clears session and detaches all entities that are currently attached + entityManager.clear(); + + // we flush the mondrian/wicket/reports cache to ensure it gets rebuilt + flushReportingCaches(); + afterSaveEntity(saveable); + } catch (ObjectOptimisticLockingFailureException e) { + deleteFailedModal.show(target); + target.add(deleteFailedModal); + } + setResponsePage(listPageClass, getParamsWithServiceInformation()); + } + + @Override + protected void onAfterRevertToDraft(final AjaxRequestTarget target) { + try { + datasetClientService.unpublishDataset(editForm.getModelObject()); + editForm.getModelObject().setStatus(UNPUBLISHING); + } catch (DataSetClientException | Exception e) { + logger.error(e.getMessage(), e); + } + setResponsePage(listPageClass); + } + + protected void onApprove(final AjaxRequestTarget target) { + try { + TetsimDataset dataset = editForm.getModelObject(); + String fileName = dataset.getYear() + "_tetsim.csv"; + byte[] content = tetsimOutputService.getTetsimCSVDatasetOutputs(dataset.getId()); + + datasetClientService.publishDataset(dataset, fileName, content); + + dataset.setStatus(PUBLISHING); + } catch (DataSetClientException | Exception e) { + logger.error(e.getMessage(), e); + failedModal.show(target); + } + setResponsePage(listPageClass); + } + + protected BootstrapCancelButton getCancelButton(final String id) { + return new CancelEditPageButton(id, new StringResourceModel("cancelButton", this, null)); + } + + public class CancelEditPageButton extends BootstrapCancelButton { + private static final long serialVersionUID = -1474498211555760931L; + + public CancelEditPageButton(final String id, final IModel model) { + super(id, model); + } + + @Override + protected void onSubmit(final AjaxRequestTarget target) { + cancelModal.show(true); + target.add(cancelModal); + } + } + + private TetsimBaselineNumbersPanel getBaseLineNumbers() { + return new TetsimBaselineNumbersPanel("baseLineNumbers", editForm.getModel()); + } + + private Component getPriceAnalysisNumbers() { + return new TetsimPriceAnalysisPanel("priceAnalysisNumbers", editForm.getModel()); + } + + private Component getIndustryResponsesNumbers() { + return new TetsimIndustryResponsesPanel("industryResponsesNumbers", editForm.getModel()); + } + + private class TetsimMarketSharePercentageValidator extends AbstractFormValidator { + + @Override + public FormComponent[] getDependentFormComponents() { + return new FormComponent[0]; + } + + @Override + public void validate(final Form form) { + TetsimPriceVariable marketShare = editForm.getModelObject().getMarketShare(); + BigDecimal sum = marketShare.getValues().stream() + .map(TetsimTobaccoProductValue::getValue) + .filter(v -> v != null) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + if (sum.intValue() > MAXIMUM_PERCENTAGE) { + editForm.error(getString("error.form.validation.marketShare.percentage")); + } + } + } + + @Override + protected void enableDisableAutosaveFields(final AjaxRequestTarget target) { + super.enableDisableAutosaveFields(target); + } + + + protected Integer getYearParam() { + return getPageParameters().get(PARAM_YEAR).toOptionalInteger(); + } + + @Override + protected PageParameters getSaveEditParameters() { + return getParamsWithServiceInformation(); + } + + @Override + protected PageParameters getCancelPageParameters() { + return getParamsWithServiceInformation(); + } + + + protected PageParameters getParamsWithServiceInformation() { + PageParameters pageParams = new PageParameters(); + // add service to the page parameters + pageParams.add(PARAM_SERVICE, editForm.getModelObject().getDestinationService()); + + return pageParams; + } + + protected IModel getBreadcrumbTitleModel() { + return getTitleModel(); + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditTetsimDatasetPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditTetsimDatasetPage.properties new file mode 100644 index 00000000..9b5bf214 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/EditTetsimDatasetPage.properties @@ -0,0 +1,6 @@ +page.title.add=Add TETSIM Dataset +page.title.edit=Edit TETSIM Dataset +year.label=Year +destinationService.label=Destination Service + +error.form.validation.marketShare.percentage=The total of all the market share values should add up to 100 \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineDecimalVariable.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineDecimalVariable.java new file mode 100644 index 00000000..c83436e0 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineDecimalVariable.java @@ -0,0 +1,22 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.dataset; + +import org.apache.wicket.model.IModel; +import org.devgateway.toolkit.forms.wicket.components.form.GenericBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.components.form.TextFieldBootstrapFormComponent; + +public class TetsimBaselineDecimalVariable extends TetsimBaselineVariable { + + public TetsimBaselineDecimalVariable(final String id, final IModel labelModel, + final IModel unitModel, final IModel variableModel) { + super(id, labelModel, unitModel, variableModel); + } + + @Override + protected GenericBootstrapFormComponent createInputField() { + TextFieldBootstrapFormComponent field = new TextFieldBootstrapFormComponent<>("input", variableModel); + field.decimal(); + field.required(); + field.hideLabel(); + return field; + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineNumbersPanel.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineNumbersPanel.html new file mode 100644 index 00000000..16481935 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineNumbersPanel.html @@ -0,0 +1,20 @@ + + + + +
+ + + + + + + + + + + +
Base-line NumbersUnitValues
+ + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineNumbersPanel.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineNumbersPanel.java new file mode 100644 index 00000000..0d4ef33d --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineNumbersPanel.java @@ -0,0 +1,104 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.dataset; + +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.markup.repeater.RepeatingView; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.validators.PositiveBigDecimalValidator; +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.service.AdminSettingsService; + +/** + * @author Viorel Chihai + */ +public class TetsimBaselineNumbersPanel extends Panel { + + @SpringBean + private AdminSettingsService adminSettingsService; + + protected final IModel tetsimDatasetIModel; + + public TetsimBaselineNumbersPanel(final String id, final IModel tetsimDatasetIModel) { + super(id); + this.tetsimDatasetIModel = tetsimDatasetIModel; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + add(getBaseLineNumbers()); + } + + private RepeatingView getBaseLineNumbers() { + RepeatingView baseLineNumbers = new RepeatingView("numbers"); + baseLineNumbers.add(getCigaretteConsumptionVariable(baseLineNumbers.newChildId())); + baseLineNumbers.add(getVatRateVariable(baseLineNumbers.newChildId())); + baseLineNumbers.add(getCigaretteDeclaredCustomValueVariable(baseLineNumbers.newChildId())); + baseLineNumbers.add(getAdultPopulationVariable(baseLineNumbers.newChildId())); + baseLineNumbers.add(getSmokingPrevalenceVariable(baseLineNumbers.newChildId())); + + return baseLineNumbers; + } + + private TetsimBaselineDecimalVariable getCigaretteConsumptionVariable(final String id) { + TetsimBaselineDecimalVariable variable = new TetsimBaselineDecimalVariable(id, + new StringResourceModel("cigaretteConsumption.label"), + new StringResourceModel("cigaretteConsumption.unit"), + new PropertyModel<>(tetsimDatasetIModel, "cigaretteConsumption")); + + variable.getInputField().getField().add(new PositiveBigDecimalValidator()); + + return variable; + } + + private TetsimBaselineDecimalVariable getVatRateVariable(final String id) { + TetsimBaselineDecimalVariable variable = new TetsimBaselineDecimalVariable(id, + new StringResourceModel("vatRate.label"), + new StringResourceModel("vatRate.unit"), + new PropertyModel<>(tetsimDatasetIModel, "vatRate")); + + variable.getInputField().getField().add(new PositiveBigDecimalValidator()); + + return variable; + } + + private TetsimBaselineDecimalVariable getCigaretteDeclaredCustomValueVariable(final String id) { + TetsimBaselineDecimalVariable variable = new TetsimBaselineDecimalVariable(id, + new StringResourceModel("cigaretteDeclaredCustomValue.label"), + new StringResourceModel("cigaretteDeclaredCustomValue.unit").setParameters(getDefaultCurrency()), + new PropertyModel<>(tetsimDatasetIModel, "cigaretteDeclaredCustomValue")); + variable.getInputField().getField().add(new PositiveBigDecimalValidator(true)); + + return variable; + } + + private TetsimBaselineDecimalVariable getAdultPopulationVariable(final String id) { + TetsimBaselineDecimalVariable variable = new TetsimBaselineDecimalVariable(id, + new StringResourceModel("adultPopulation.label"), + new StringResourceModel("adultPopulation.unit"), + new PropertyModel<>(tetsimDatasetIModel, "adultPopulation")); + + variable.getInputField().getField().add(new PositiveBigDecimalValidator()); + + return variable; + } + + private TetsimBaselineDecimalVariable getSmokingPrevalenceVariable(final String id) { + TetsimBaselineDecimalVariable variable = new TetsimBaselineDecimalVariable(id, + new StringResourceModel("smokingPrevalence.label"), + new StringResourceModel("smokingPrevalence.unit"), + new PropertyModel<>(tetsimDatasetIModel, "smokingPrevalence")); + + variable.getInputField().getField().add(new PositiveBigDecimalValidator()); + + return variable; + } + + private String getDefaultCurrency() { + return adminSettingsService.get().getTetsimCurrency(); + } +} + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineNumbersPanel.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineNumbersPanel.properties new file mode 100644 index 00000000..29b2524f --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineNumbersPanel.properties @@ -0,0 +1,14 @@ +cigaretteConsumption.label=Total cigarette consumption (including illicit cigarettes) +cigaretteConsumption.unit=Full number of packs + +vatRate.label=VAT rate +vatRate.unit=Percentage + +cigaretteDeclaredCustomValue.label=Declared customs value of imported cigarettes (FOB amount) +cigaretteDeclaredCustomValue.unit={0} per pack + +adultPopulation.label=Adult Population (15+) +adultPopulation.unit=Full number + +smokingPrevalence.label=Smoking prevalence +smokingPrevalence.unit=Percentage \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineVariable.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineVariable.html new file mode 100644 index 00000000..5fa933eb --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineVariable.html @@ -0,0 +1,16 @@ + + + + + + + + + + + +
+ + + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineVariable.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineVariable.java new file mode 100644 index 00000000..d14b1132 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineVariable.java @@ -0,0 +1,47 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.dataset; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.model.IModel; +import org.devgateway.toolkit.forms.wicket.components.form.GenericBootstrapFormComponent; + +/** + * @author Viorel Chihai + */ +public abstract class TetsimBaselineVariable extends Panel { + + private final IModel labelModel; + + private final IModel unitModel; + + protected final IModel variableModel; + + protected GenericBootstrapFormComponent inputField; + + public TetsimBaselineVariable(final String id, final IModel labelModel, + final IModel unitModel, + final IModel variableModel) { + super(id); + this.labelModel = labelModel; + this.unitModel = unitModel; + this.variableModel = variableModel; + inputField = createInputField(); + } + + @Override + protected void onInitialize() { + super.onInitialize(); + add(new Label("label", labelModel)); + add(new Label("unit", unitModel)); + add(inputField); + } + + protected abstract GenericBootstrapFormComponent createInputField(); + + public GenericBootstrapFormComponent getInputField() { + return inputField; + } + +} + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineVariable.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineVariable.properties new file mode 100644 index 00000000..ef09e41b --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimBaselineVariable.properties @@ -0,0 +1 @@ +input.label=input \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimIndustryResponsesPanel.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimIndustryResponsesPanel.html new file mode 100644 index 00000000..aeef6abe --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimIndustryResponsesPanel.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + + +
+
+
+ + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimIndustryResponsesPanel.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimIndustryResponsesPanel.java new file mode 100644 index 00000000..ea940b12 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimIndustryResponsesPanel.java @@ -0,0 +1,92 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.dataset; + +import org.apache.wicket.Component; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.markup.repeater.RepeatingView; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.model.StringResourceModel; +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Viorel Chihai + */ +public class TetsimIndustryResponsesPanel extends Panel { + + protected final IModel tetsimDatasetIModel; + + public TetsimIndustryResponsesPanel(final String id, final IModel tetsimDatasetIModel) { + super(id); + this.tetsimDatasetIModel = tetsimDatasetIModel; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + add(getIndustryResponsesHeaders()); + add(getIndustryResponsesVariables()); + } + + private Component getIndustryResponsesHeaders() { + RepeatingView analysisHeaders = new RepeatingView("industryResponsesHeaders"); + analysisHeaders.add(new Label(analysisHeaders.newChildId(), + Model.of("Industry responses to the change in taxation"))); + analysisHeaders.add(new Label(analysisHeaders.newChildId(), Model.of("Unit"))); + + List tobaccoProducts = TobaccoProduct.ALL.stream().collect(Collectors.toList()); + for (TobaccoProduct tobaccoProduct : tobaccoProducts) { + analysisHeaders.add(new Label(analysisHeaders.newChildId(), + new PropertyModel<>(tobaccoProduct, "label"))); + } + + return analysisHeaders; + } + + private Component getIndustryResponsesVariables() { + RepeatingView variables = new RepeatingView("industryResponsesVariables"); + + variables.add(getOverShifting(variables.newChildId())); + variables.add(getUnderShifting(variables.newChildId())); + + return variables; + } + + /** + * Get overshifting variable panel with tobacco product inputs. + * Mandatory. Numerical fields with decimals. + * + * @param id + * @return TetsimTobaccoProductsVariable + */ + private TetsimTobaccoProductsVariable getOverShifting(final String id) { + return new TetsimTobaccoProductsVariable(id, + new StringResourceModel("overshifting.label"), + new StringResourceModel("overshifting.unit"), + new PropertyModel<>(tetsimDatasetIModel, "overshifting"), true) { + }; + } + + /** + * Get undershifting variable panel with tobacco product inputs. + * Mandatory. Numerical fields with decimals. + * + * @param id + * @return TetsimTobaccoProductsVariable + */ + private TetsimTobaccoProductsVariable getUnderShifting(final String id) { + return new TetsimTobaccoProductsVariable(id, + new StringResourceModel("undershifting.label"), + new StringResourceModel("undershifting.unit"), + new PropertyModel<>(tetsimDatasetIModel, "undershifting"), true) { + }; + } + +} + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimIndustryResponsesPanel.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimIndustryResponsesPanel.properties new file mode 100644 index 00000000..d2fde381 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimIndustryResponsesPanel.properties @@ -0,0 +1,6 @@ +overshifting.label=Overshifting (% change above excise tax increase) +overshifting.unit=Percentage change above excise tax increase + +undershifting.label=Change in illicit NOT (proportion of change in discount price): sensitivity factor +undershifting.unit=Undershifting (% change below excise tax increase) + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimPriceAnalysisPanel.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimPriceAnalysisPanel.html new file mode 100644 index 00000000..db3ade0e --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimPriceAnalysisPanel.html @@ -0,0 +1,17 @@ + + + + + + + + + + + + +
+
+
+ + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimPriceAnalysisPanel.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimPriceAnalysisPanel.java new file mode 100644 index 00000000..3849cd08 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimPriceAnalysisPanel.java @@ -0,0 +1,270 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.dataset; + +import org.apache.wicket.Component; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.markup.repeater.RepeatingView; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.apache.wicket.validation.validator.RangeValidator; +import org.devgateway.toolkit.forms.validators.PositiveBigDecimalValidator; +import org.devgateway.toolkit.forms.wicket.components.form.TextFieldBootstrapFormComponent; +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; +import org.devgateway.toolkit.persistence.service.AdminSettingsService; + +import java.math.BigDecimal; +import java.util.List; +import java.util.stream.Collectors; + +import static org.devgateway.toolkit.forms.WebConstants.MAXIMUM_PERCENTAGE; + +/** + * @author Viorel Chihai + */ +public class TetsimPriceAnalysisPanel extends Panel { + + protected final IModel tetsimDatasetIModel; + + @SpringBean + protected AdminSettingsService adminSettingsService; + + public TetsimPriceAnalysisPanel(final String id, final IModel tetsimDatasetIModel) { + super(id); + this.tetsimDatasetIModel = tetsimDatasetIModel; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + add(getPriceAnalysisHeaders()); + add(getPriceAnalysisVariables()); + } + + private Component getPriceAnalysisHeaders() { + RepeatingView analysisHeaders = new RepeatingView("analysisHeaders"); + analysisHeaders.add(new Label(analysisHeaders.newChildId(), Model.of("Price Variable"))); + analysisHeaders.add(new Label(analysisHeaders.newChildId(), Model.of("Unit"))); + + List tobaccoProducts = TobaccoProduct.ALL.stream().collect(Collectors.toList()); + for (TobaccoProduct tobaccoProduct : tobaccoProducts) { + analysisHeaders.add(new Label(analysisHeaders.newChildId(), + new PropertyModel<>(tobaccoProduct, "label"))); + } + + return analysisHeaders; + } + + private RepeatingView getPriceAnalysisVariables() { + RepeatingView variables = new RepeatingView("analysisVariables"); + + variables.add(getRetailPriceVariable(variables.newChildId())); + variables.add(getMarketShareVariable(variables.newChildId())); + variables.add(getCifVariable(variables.newChildId())); + variables.add(getTobaccoLevy(variables.newChildId())); + variables.add(getExciseTax(variables.newChildId())); + variables.add(getCustomsDuty(variables.newChildId())); + variables.add(getElasticityOfDemandPrice(variables.newChildId())); + variables.add(getElasticityOfDemandCrossPrice(variables.newChildId())); + variables.add(getChangeInIllicitNot(variables.newChildId())); + + return variables; + } + + /** + * Get retail price variable panel with tobacco product inputs. + * Mandatory. Numerical fields with decimals. No negative or 0 values accepted. + * + * @param id + * @return TetsimTobaccoProductsVariable + */ + private TetsimTobaccoProductsVariable getRetailPriceVariable(final String id) { + return new TetsimTobaccoProductsVariable(id, + new StringResourceModel("retailPrice.label"), + new StringResourceModel("retailPrice.unit").setParameters(getDefaultCurrency()), + new PropertyModel<>(tetsimDatasetIModel, "retailPrice")) { + + @Override + protected void addBehavioursToTobaccoProductVariable(final TextFieldBootstrapFormComponent variable1) { + super.addBehavioursToTobaccoProductVariable(variable1); + variable1.getField().add(new PositiveBigDecimalValidator()); + } + }; + } + + /** + * Get market share variable panel with tobacco product inputs. + * Mandatory. Numerical fields with decimals. No negative values accepted. + * The total of all inputs should add up to 100. + * + * @param id + * @return TetsimTobaccoProductsVariable + */ + private TetsimTobaccoProductsVariable getMarketShareVariable(final String id) { + return new TetsimTobaccoProductsVariable(id, + new StringResourceModel("marketShare.label"), + new StringResourceModel("marketShare.unit"), + new PropertyModel<>(tetsimDatasetIModel, "marketShare")) { + + @Override + protected void addBehavioursToTobaccoProductVariable(final TextFieldBootstrapFormComponent variable1) { + super.addBehavioursToTobaccoProductVariable(variable1); + variable1.getField().add(new PositiveBigDecimalValidator(true)); + variable1.getField().add(RangeValidator.maximum(BigDecimal.valueOf(MAXIMUM_PERCENTAGE))); + } + }; + } + + /** + * Get CIF variable panel with tobacco product inputs. + * Mandatory. Numerical fields with decimals. No negative values accepted. + * + * @param id + * @return TetsimTobaccoProductsVariable + */ + private TetsimTobaccoProductsVariable getCifVariable(final String id) { + return new TetsimTobaccoProductsVariable(id, + new StringResourceModel("cif.label"), + new StringResourceModel("cif.unit").setParameters(getDefaultCurrency()), + new PropertyModel<>(tetsimDatasetIModel, "cif")) { + + @Override + protected void addBehavioursToTobaccoProductVariable(final TextFieldBootstrapFormComponent variable1) { + super.addBehavioursToTobaccoProductVariable(variable1); + variable1.getField().add(new PositiveBigDecimalValidator(true)); + } + }; + } + + /** + * Get tobacco levy variable panel with tobacco product inputs. + * Mandatory. Numerical fields with decimals. No negative values accepted. + * + * @param id + * @return TetsimTobaccoProductsVariable + */ + private TetsimTobaccoProductsVariable getTobaccoLevy(final String id) { + return new TetsimTobaccoProductsVariable(id, + new StringResourceModel("tobaccoLevy.label"), + new StringResourceModel("tobaccoLevy.unit"), + new PropertyModel<>(tetsimDatasetIModel, "tobaccoLevy")) { + + @Override + protected void addBehavioursToTobaccoProductVariable(final TextFieldBootstrapFormComponent variable1) { + super.addBehavioursToTobaccoProductVariable(variable1); + variable1.getField().add(new PositiveBigDecimalValidator(true)); + variable1.getField().add(RangeValidator.maximum(BigDecimal.valueOf(MAXIMUM_PERCENTAGE))); + } + }; + } + + /** + * Get excise tax variable panel with tobacco product inputs. + * Mandatory. Numerical fields with decimals. No negative values accepted. + * + * @param id + * @return TetsimTobaccoProductsVariable + */ + private TetsimTobaccoProductsVariable getExciseTax(final String id) { + return new TetsimTobaccoProductsVariable(id, + new StringResourceModel("exciseTax.label"), + new StringResourceModel("exciseTax.unit").setParameters(getDefaultCurrency()), + new PropertyModel<>(tetsimDatasetIModel, "exciseTax")) { + + @Override + protected void addBehavioursToTobaccoProductVariable(final TextFieldBootstrapFormComponent variable1) { + super.addBehavioursToTobaccoProductVariable(variable1); + variable1.getField().add(new PositiveBigDecimalValidator(true)); + } + }; + } + + /** + * Get customs duty variable panel with tobacco product inputs. + * Not Mandatory. Numerical fields with decimals. No negative values accepted. + * + * @param id + * @return TetsimTobaccoProductsVariable + */ + private TetsimTobaccoProductsVariable getCustomsDuty(final String id) { + return new TetsimTobaccoProductsVariable(id, + new StringResourceModel("customsDuty.label"), + new StringResourceModel("customsDuty.unit"), + new PropertyModel<>(tetsimDatasetIModel, "customsDuty"), false) { + + @Override + protected void addBehavioursToTobaccoProductVariable(final TextFieldBootstrapFormComponent variable1) { + super.addBehavioursToTobaccoProductVariable(variable1); + variable1.getField().add(new PositiveBigDecimalValidator(true)); + } + }; + } + + /** + * Get price elasticity of demand variable panel with tobacco product inputs. + * Mandatory. Numerical fields with decimals between -1 and 1. + * + * @param id + * @return TetsimTobaccoProductsVariable + */ + private TetsimTobaccoProductsVariable getElasticityOfDemandPrice(final String id) { + return new TetsimTobaccoProductsVariable(id, + new StringResourceModel("elasticityOfDemandPrice.label"), + new StringResourceModel("elasticityOfDemandPrice.unit"), + new PropertyModel<>(tetsimDatasetIModel, "elasticityOfDemandPrice")) { + + @Override + protected void addBehavioursToTobaccoProductVariable(final TextFieldBootstrapFormComponent variable1) { + super.addBehavioursToTobaccoProductVariable(variable1); + variable1.getField().add(RangeValidator.range(BigDecimal.valueOf(-1), BigDecimal.ONE)); + } + }; + } + + /** + * Get cross-price elasticity of demand variable panel with tobacco product inputs. + * Mandatory. Numerical fields with decimals between -1 and 1. + * + * @param id + * @return TetsimTobaccoProductsVariable + */ + private TetsimTobaccoProductsVariable getElasticityOfDemandCrossPrice(final String id) { + return new TetsimTobaccoProductsVariable(id, + new StringResourceModel("elasticityOfDemandCrossPrice.label"), + new StringResourceModel("elasticityOfDemandCrossPrice.unit"), + new PropertyModel<>(tetsimDatasetIModel, "elasticityOfDemandCrossPrice")) { + + @Override + protected void addBehavioursToTobaccoProductVariable(final TextFieldBootstrapFormComponent variable1) { + super.addBehavioursToTobaccoProductVariable(variable1); + variable1.getField().add(RangeValidator.range(BigDecimal.valueOf(-1), BigDecimal.ONE)); + } + }; + } + + /** + * Get change in illicit not variable panel with tobacco product inputs. + * Only allowed for product marked as illicit in the system category. + * Numerical field with decimals. + * + * @param id + * @return TetsimTobaccoProductsVariable + */ + private TetsimTobaccoProductsVariable getChangeInIllicitNot(final String id) { + return new TetsimTobaccoProductsVariable(id, + new StringResourceModel("changeInIllicitNot.label"), + new StringResourceModel("changeInIllicitNot.unit"), + new PropertyModel<>(tetsimDatasetIModel, "changeInIllicitNot"), false, true) { + }; + } + + private String getDefaultCurrency() { + return adminSettingsService.get().getTetsimCurrency(); + } + +} + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimPriceAnalysisPanel.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimPriceAnalysisPanel.properties new file mode 100644 index 00000000..6ce36c81 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimPriceAnalysisPanel.properties @@ -0,0 +1,27 @@ +retailPrice.label=Retail Price +retailPrice.unit={0} per pack + +marketShare.label=Market Share +marketShare.unit=Percentage + +cif.label=CIF +cif.unit={0} per pack + +tobaccoLevy.label=Tobacco Levy +tobaccoLevy.unit=Percentage of CIF + +exciseTax.label=Excise tax +exciseTax.unit={0} per pack + +customsDuty.label=Customs duty on imported cigarettes +customsDuty.unit=Percentage of FOB value + +elasticityOfDemandPrice.label=Price elasticity of demand +elasticityOfDemandPrice.unit=Number (between -1 and 1) + +elasticityOfDemandCrossPrice.label=Cross-price elasticity of demand (from higher price category) +elasticityOfDemandCrossPrice.unit=Number (between -1 and 1) + +changeInIllicitNot.label=Change in illicit NOT (proportion of change in discount price): sensitivity factor +changeInIllicitNot.unit=Proportion + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimTobaccoProductsVariable.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimTobaccoProductsVariable.html new file mode 100644 index 00000000..989fcf25 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimTobaccoProductsVariable.html @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimTobaccoProductsVariable.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimTobaccoProductsVariable.java new file mode 100644 index 00000000..a3bae716 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimTobaccoProductsVariable.java @@ -0,0 +1,121 @@ +package org.devgateway.toolkit.forms.wicket.page.edit.dataset; + +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.markup.repeater.RepeatingView; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; +import org.devgateway.toolkit.forms.wicket.components.form.TextFieldBootstrapFormComponent; +import org.devgateway.toolkit.persistence.dao.data.TetsimPriceVariable; +import org.devgateway.toolkit.persistence.dao.data.TetsimTobaccoProductValue; +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Viorel Chihai + */ +public class TetsimTobaccoProductsVariable extends Panel { + + private final IModel labelModel; + + private final IModel unitModel; + + private final boolean required; + + private final boolean illicitOnly; + + protected final IModel variableModel; + + protected RepeatingView inputFields; + + public TetsimTobaccoProductsVariable(final String id, final IModel labelModel, + final IModel unitModel, + final IModel variableModel) { + this(id, labelModel, unitModel, variableModel, true); + } + + public TetsimTobaccoProductsVariable(final String id, final IModel labelModel, + final IModel unitModel, + final IModel variableModel, + final boolean required) { + this(id, labelModel, unitModel, variableModel, required, false); + } + + public TetsimTobaccoProductsVariable(final String id, final IModel labelModel, + final IModel unitModel, + final IModel variableModel, + final boolean required, final boolean illicitOnly) { + super(id); + this.labelModel = labelModel; + this.unitModel = unitModel; + this.variableModel = variableModel; + this.required = required; + this.illicitOnly = illicitOnly; + + inputFields = createInputFields(); + } + + @Override + protected void onInitialize() { + super.onInitialize(); + add(new Label("label", labelModel)); + add(new Label("unit", unitModel)); + add(inputFields); + } + + protected RepeatingView createInputFields() { + RepeatingView fields = new RepeatingView("tobaccoProducts"); + List tobaccoProducts = TobaccoProduct.ALL.stream().collect(Collectors.toList()); + TetsimPriceVariable priceVariable = variableModel.getObject(); + + for (TobaccoProduct tobaccoProduct: tobaccoProducts) { + if (!illicitOnly || tobaccoProduct.isIllicit()) { + TetsimTobaccoProductValue tobaccoProductValue = getTobaccoProductValue(priceVariable, tobaccoProduct); + TextFieldBootstrapFormComponent field = new TextFieldBootstrapFormComponent<>(fields.newChildId(), + new PropertyModel<>(Model.of(tobaccoProductValue), "value")); + field.decimal(); + field.hideLabel(); + field.getField().setRequired(required); + + addBehavioursToTobaccoProductVariable(field); + + fields.add(field); + } else { + fields.add(new WebMarkupContainer(fields.newChildId())); + } + } + + return fields; + } + + public TetsimTobaccoProductValue getTobaccoProductValue(final TetsimPriceVariable priceVariable, + final TobaccoProduct product) { + Set tobaccoProductValues = priceVariable == null ? new HashSet<>() + : priceVariable.getValues(); + + TetsimTobaccoProductValue productValue = tobaccoProductValues.stream() + .filter(t -> t.getProduct().getLabel().equals(product.getLabel())).findAny() + .orElse(null); + + if (productValue == null) { + productValue = new TetsimTobaccoProductValue(); + productValue.setProduct(product); + productValue.setPriceVariable(priceVariable); + tobaccoProductValues.add(productValue); + } + + return productValue; + } + + protected void addBehavioursToTobaccoProductVariable(final TextFieldBootstrapFormComponent variable) { + } + +} + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimTobaccoProductsVariable.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimTobaccoProductsVariable.properties new file mode 100644 index 00000000..ef09e41b --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/dataset/TetsimTobaccoProductsVariable.properties @@ -0,0 +1 @@ +input.label=input \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/panel/TestFormChildPanel.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/panel/TestFormChildPanel.html index 0986ce51..bbf1fdf8 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/panel/TestFormChildPanel.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/edit/panel/TestFormChildPanel.html @@ -2,7 +2,7 @@ -
+
diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/AbstractListPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/AbstractListPage.html index 07e2b2dd..c9a5f960 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/AbstractListPage.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/AbstractListPage.html @@ -2,10 +2,19 @@ + + +
+
+ +
+
+ +
- @@ -13,17 +22,31 @@
-
-
+
+
+
+
+ +
+
+ +
+
+ + + + + + \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/AbstractListPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/AbstractListPage.java index 092ac219..9a8502f3 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/AbstractListPage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/AbstractListPage.java @@ -14,8 +14,8 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapBookmarkablePageLink; import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons.Size; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconType; -import de.agilecoders.wicket.extensions.markup.html.bootstrap.ladda.LaddaAjaxButton; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; +import org.devgateway.toolkit.forms.wicket.components.buttons.ladda.LaddaAjaxButton; import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; @@ -27,6 +27,7 @@ import org.apache.wicket.extensions.markup.html.repeater.data.table.filter.IFilteredColumn; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.panel.Fragment; import org.apache.wicket.markup.html.panel.GenericPanel; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.model.IModel; @@ -51,11 +52,12 @@ import org.devgateway.toolkit.forms.wicket.providers.SortableJpaServiceDataProvider; import org.devgateway.toolkit.persistence.dao.GenericPersistable; import org.devgateway.toolkit.persistence.excel.service.ExcelGeneratorService; +import org.devgateway.toolkit.persistence.service.AdminSettingsService; import org.devgateway.toolkit.persistence.service.BaseJpaService; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.Serializable; @@ -73,6 +75,9 @@ public abstract class AbstractListPage extends BasePage { private static final long serialVersionUID = 1958350868666244087L; + @SpringBean + AdminSettingsService adminSettingsService; + protected Class> editPageClass; protected AjaxFallbackBootstrapDataTable dataTable; @@ -81,9 +86,9 @@ public abstract class AbstractListPage jpaService; - private SortableJpaServiceDataProvider dataProvider; + protected SortableJpaServiceDataProvider dataProvider; - private BootstrapBookmarkablePageLink editPageLink; + protected BootstrapBookmarkablePageLink editPageLink; protected Boolean filterGoReset = false; @@ -107,6 +112,13 @@ public ActionPanel getActionPanel(final String id, final IModel model) { protected void onInitialize() { super.onInitialize(); + add(new Fragment("topPage", "topPageTitleFragment", this)); + + Fragment fragment = new Fragment("bottomPageFragment", "noBottomPageFragment", this); + add(fragment); + + add(new Fragment("bottomPage", "bottomPageTitleFragment", this)); + if (jpaService == null) { throw new NullJpaServiceException(); } @@ -114,7 +126,7 @@ protected void onInitialize() { throw new NullEditPageClassException(); } - dataProvider = new SortableJpaServiceDataProvider<>(jpaService); + dataProvider = new SortableJpaServiceDataProvider<>(jpaService, getPageSize()); dataProvider.setFilterState(newFilterState()); // create the excel download form; by default this form is hidden and we should make it visible only to pages @@ -133,7 +145,7 @@ public void populateItem(final Item> cellItem, final String co cellItem.add(getActionPanel(componentId, model)); } }); - dataTable = new AjaxFallbackBootstrapDataTable<>("table", columns, dataProvider, WebConstants.PAGE_SIZE); + dataTable = new AjaxFallbackBootstrapDataTable<>("table", columns, dataProvider, getPageSize()); ResettingFilterForm> filterForm = new ResettingFilterForm<>("filterForm", dataProvider, dataTable); @@ -152,16 +164,26 @@ public void populateItem(final Item> cellItem, final String co setDataTableForFilteredColumns(); } - PageParameters pageParameters = new PageParameters(); - pageParameters.set(WebConstants.PARAM_ID, null); + PageParameters pageParameters = getEditPageParameters(); editPageLink = new BootstrapBookmarkablePageLink("new", editPageClass, pageParameters, Buttons.Type.Success); - editPageLink.setIconType(FontAwesomeIconType.plus_circle).setSize(Size.Large) + editPageLink.setIconType(FontAwesome5IconType.plus_circle_s).setSize(Size.Large) .setLabel(new StringResourceModel("new", AbstractListPage.this, null)); + editPageLink.setOutputMarkupId(true); add(editPageLink); } + private Integer getPageSize() { + return adminSettingsService.get().getPageSize(); + } + + protected PageParameters getEditPageParameters() { + PageParameters pageParameters = new PageParameters(); + pageParameters.set(WebConstants.PARAM_ID, null); + return pageParameters; + } + public class ActionPanel extends GenericPanel { private static final long serialVersionUID = 5821419128121941939L; protected PageParameters pageParameters; @@ -181,27 +203,35 @@ public ActionPanel(final String id, final IModel model) { if (entity != null) { pageParameters.set(WebConstants.PARAM_ID, entity.getId()); } + addEditLinkPageParameters(pageParameters); editItemPageLink = new BootstrapBookmarkablePageLink<>("edit", editPageClass, pageParameters, Buttons.Type.Info); - editItemPageLink.setIconType(FontAwesomeIconType.edit).setSize(Size.Small) + editItemPageLink.setIconType(FontAwesome5IconType.edit_s).setSize(Size.Small) .setLabel(new StringResourceModel("edit", AbstractListPage.this, null)); add(editItemPageLink); add(getPrintButton(pageParameters)); + add(getRevisionsLink(entity)); + } + } - PageParameters revisionsPageParameters = new PageParameters(); - revisionsPageParameters.set(WebConstants.PARAM_ID, entity.getId()); - revisionsPageParameters.set(WebConstants.PARAM_ENTITY_CLASS, entity.getClass().getName()); + protected void addEditLinkPageParameters(final PageParameters pageParameters) { - BootstrapBookmarkablePageLink revisionsPageLink = new BootstrapBookmarkablePageLink<>("revisions", - RevisionsPage.class, revisionsPageParameters, Buttons.Type.Info); - revisionsPageLink.setIconType(FontAwesomeIconType.clock_o).setSize(Size.Small) - .setLabel(new StringResourceModel("revisions", AbstractListPage.this, null)); - add(revisionsPageLink); + } - } + protected Component getRevisionsLink(final T entity) { + PageParameters revisionsPageParameters = new PageParameters(); + revisionsPageParameters.set(WebConstants.PARAM_ID, entity.getId()); + revisionsPageParameters.set(WebConstants.PARAM_ENTITY_CLASS, entity.getClass().getName()); + + BootstrapBookmarkablePageLink revisionsPageLink = new BootstrapBookmarkablePageLink<>("revisions", + RevisionsPage.class, revisionsPageParameters, Buttons.Type.Info); + revisionsPageLink.setIconType(FontAwesome5IconType.clock_s).setSize(Size.Small) + .setLabel(new StringResourceModel("revisions", AbstractListPage.this, null)); + + return revisionsPageLink; } /** @@ -332,7 +362,7 @@ protected void onSubmit(final AjaxRequestTarget target) { download.initiate(target); } }; - excelButton.setIconType(FontAwesomeIconType.file_excel_o); + excelButton.setIconType(FontAwesome5IconType.file_excel_s); add(excelButton); } } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/ListUserPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/ListUserPage.java index 3514a40e..c7385734 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/ListUserPage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/ListUserPage.java @@ -17,6 +17,8 @@ import org.apache.wicket.request.mapper.parameter.PageParameters; import org.apache.wicket.spring.injection.annot.SpringBean; import org.devgateway.toolkit.forms.security.SecurityConstants; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.page.ConfigurationsHomepage; import org.devgateway.toolkit.forms.wicket.page.user.EditUserPageElevated; import org.devgateway.toolkit.persistence.dao.Person; import org.devgateway.toolkit.persistence.service.PersonService; @@ -24,6 +26,7 @@ @AuthorizeInstantiation(SecurityConstants.Roles.ROLE_ADMIN) @MountPath(value = "/listusers") +@BreadCrumbPage(parent = ConfigurationsHomepage.class) public class ListUserPage extends AbstractListPage { private static final long serialVersionUID = 3529738250403399032L; @@ -38,7 +41,6 @@ public ListUserPage(final PageParameters pageParameters) { this.editPageClass = EditUserPageElevated.class; columns.add(new PropertyColumn<>(new Model<>("Name"), "username", "username")); - columns.add(new PropertyColumn<>(new Model<>("Group"), "group", "group")); columns.add(new PropertyColumn<>(new Model<>("Roles"), "roles", "roles")); } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/ListUserPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/ListUserPage.properties index e3160c8f..335b2d54 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/ListUserPage.properties +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/ListUserPage.properties @@ -9,4 +9,4 @@ # Contributors: # Development Gateway - initial API and implementation ############################################################################### -page.title=User List \ No newline at end of file +page.title=Users \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/AbstractListServiceEntityPage$ActionPanel.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/AbstractListServiceEntityPage$ActionPanel.html new file mode 100644 index 00000000..ad387fd1 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/AbstractListServiceEntityPage$ActionPanel.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/AbstractListServiceEntityPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/AbstractListServiceEntityPage.html new file mode 100644 index 00000000..a83ccfcd --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/AbstractListServiceEntityPage.html @@ -0,0 +1,15 @@ + + + + +
+
+
+ +
+
+
+
+
+ + \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/AbstractListServiceEntityPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/AbstractListServiceEntityPage.java new file mode 100644 index 00000000..8f6c48e6 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/AbstractListServiceEntityPage.java @@ -0,0 +1,188 @@ +package org.devgateway.toolkit.forms.wicket.page.lists.admin; + +import de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapBookmarkablePageLink; +import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; +import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; +import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; +import org.apache.wicket.extensions.markup.html.repeater.data.table.filter.FilterToolbar; +import org.apache.wicket.extensions.markup.html.repeater.data.table.filter.IFilteredColumn; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.panel.GenericPanel; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.markup.repeater.RepeatingView; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.WebConstants; +import org.devgateway.toolkit.forms.exceptions.NullServiceEntityServiceException; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.forms.service.admin.BaseServiceEntityService; +import org.devgateway.toolkit.forms.wicket.components.table.AjaxFallbackBootstrapDataTable; +import org.devgateway.toolkit.forms.wicket.components.table.DataTableAware; +import org.devgateway.toolkit.forms.wicket.components.table.ResettingFilterForm; +import org.devgateway.toolkit.forms.wicket.components.table.filter.ServiceEntityFilterState; +import org.devgateway.toolkit.forms.wicket.page.BasePage; +import org.devgateway.toolkit.forms.wicket.page.edit.admin.AbstractEditServiceEntityPage; +import org.devgateway.toolkit.persistence.dto.ServiceCategory; +import org.devgateway.toolkit.persistence.dto.ServiceTextTranslation; +import org.devgateway.toolkit.persistence.service.AdminSettingsService; + +import java.text.MessageFormat; +import java.util.List; + +import static java.util.Comparator.comparing; +import static org.devgateway.toolkit.forms.WebConstants.PARAM_SERVICE; + +public abstract class AbstractListServiceEntityPage extends BasePage { + + private static final long serialVersionUID = 652587400391540726L; + + protected Class> editPageClass; + + @SpringBean + protected AdminSettingsService adminSettingsService; + + @SpringBean + EurekaClientService eurekaClientService; + + protected AjaxFallbackBootstrapDataTable dataTable; + + protected SortableServiceEntityProvider dataProvider; + + protected List> columns; + + protected BaseServiceEntityService serviceEntityService; + + protected int pageRowNo = 0; + + public AbstractListServiceEntityPage(final PageParameters pageParameters) { + super(pageParameters); + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + if (serviceEntityService == null) { + throw new NullServiceEntityServiceException(); + } + + String serviceName = getPageParameters().get(PARAM_SERVICE).toString(); + dataProvider = new SortableServiceEntityProvider<>(serviceEntityService, serviceName); + dataProvider.setFilterState(newFilterState()); + + dataTable = new AjaxFallbackBootstrapDataTable( + "table", columns, dataProvider, getPageSize()) { + private static final long serialVersionUID = 632539691822305263L; + + @Override + protected void onPageChanged() { + pageRowNo = 0; + } + }; + + ResettingFilterForm> filterForm = + new ResettingFilterForm<>("filterForm", dataProvider, dataTable); + filterForm.add(dataTable); + add(filterForm); + + if (hasFilteredColumns()) { + FilterToolbar filterToolbar = new FilterToolbar(dataTable, filterForm); + dataTable.addTopToolbar(filterToolbar); + setDataTableForFilteredColumns(); + } + + columns.add(new AbstractColumn(new StringResourceModel("actionsColumn", this, null)) { + private static final long serialVersionUID = -7447601118569862123L; + + @Override + public void populateItem(final Item> cellItem, final String componentId, + final IModel model) { + cellItem.add(getActionPanel(componentId, model)); + } + }); + } + + protected ServiceEntityFilterState newFilterState() { + return new ServiceEntityFilterState<>(); + } + + protected int getPageSize() { + return adminSettingsService.get().getPageSize(); + } + + public ActionPanel getActionPanel(final String id, final IModel model) { + return new ActionPanel(id, model); + } + + public class ActionPanel extends GenericPanel { + private static final long serialVersionUID = 5821419128121941939L; + + protected BootstrapBookmarkablePageLink editItemPageLink; + + /** + * @param id + * @param model + */ + public ActionPanel(final String id, final IModel model) { + super(id, model); + + final PageParameters pageParameters = new PageParameters(); + + @SuppressWarnings("unchecked") + T entity = (T) ActionPanel.this.getDefaultModelObject(); + if (entity != null) { + pageParameters.set(WebConstants.PARAM_ID, entity.getId()); + } + pageParameters.set(PARAM_SERVICE, getPageParameters().get(PARAM_SERVICE)); + + editItemPageLink = + new BootstrapBookmarkablePageLink<>("edit", editPageClass, pageParameters, Buttons.Type.Info); + editItemPageLink.setIconType(FontAwesome5IconType.edit_s).setSize(Buttons.Size.Small) + .setLabel(new StringResourceModel("edit", this, null)); + add(editItemPageLink); + } + } + + protected Label getPageTitle() { + return new Label("pageTitle", Model.of(MessageFormat.format(getString("page.title"), getServiceLabel()))); + } + + private boolean hasFilteredColumns() { + for (IColumn column : columns) { + if (column instanceof IFilteredColumn) { + return true; + } + } + return false; + } + + private void setDataTableForFilteredColumns() { + for (IColumn column : columns) { + if (column instanceof IFilteredColumn && column instanceof DataTableAware) { + if (((DataTableAware) column).getDataTable() == null) { + ((DataTableAware) column).setDataTable(dataTable); + } + } + } + } + + protected RepeatingView getLableTranslations(final String componentId, final IModel rowModel) { + RepeatingView labelsList = new RepeatingView(componentId); + rowModel.getObject().getLabels().stream().sorted(comparing(ServiceTextTranslation::getLanguage)) + .forEach(label -> { + Label labelItem = new Label(labelsList.newChildId(), label.getLanguage() + ": " + label.getText()); + labelsList.add(labelItem); + }); + return labelsList; + } + + @Override + protected IModel getBreadcrumbTitleModel() { + return new StringResourceModel("breadcrumb.title", this); + } +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/AbstractListServiceEntityPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/AbstractListServiceEntityPage.properties new file mode 100644 index 00000000..e25ddcf7 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/AbstractListServiceEntityPage.properties @@ -0,0 +1,3 @@ +page.title={0} Entities +actionsColumn=Edit +edit=Edit \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceCategoriesPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceCategoriesPage.java new file mode 100644 index 00000000..87514b14 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceCategoriesPage.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2023 Development Gateway, Inc and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the MIT License (MIT) + * which accompanies this distribution, and is available at + * https://opensource.org/licenses/MIT + * + * Contributors: + * Development Gateway - initial API and implementation + *******************************************************************************/ +package org.devgateway.toolkit.forms.wicket.page.lists.admin; + +import de.agilecoders.wicket.core.markup.html.bootstrap.behavior.CssClassNameAppender; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.table.filter.BootstrapTextFilteredPropertyColumn; +import org.apache.wicket.AttributeModifier; +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; +import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.WebConstants; +import org.devgateway.toolkit.forms.service.admin.ServiceCategoryService; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.components.table.filter.ServiceCategoryFilterState; +import org.devgateway.toolkit.forms.wicket.components.table.filter.ServiceEntityFilterState; +import org.devgateway.toolkit.forms.wicket.page.DataServicePage; +import org.devgateway.toolkit.forms.wicket.page.edit.admin.EditServiceCategoryPage; +import org.devgateway.toolkit.persistence.dto.ServiceCategory; +import org.wicketstuff.annotation.mount.MountPath; + +import java.util.ArrayList; + +@MountPath(value = "/categories") +@BreadCrumbPage(parent = DataServicePage.class, hasServiceParam = true) +public class ListServiceCategoriesPage extends AbstractListServiceEntityPage { + + private static final long serialVersionUID = -6132847935476573446L; + + @SpringBean + private ServiceCategoryService serviceCategoryService; + + public ListServiceCategoriesPage(final PageParameters pageParameters) { + super(pageParameters); + + this.serviceEntityService = serviceCategoryService; + this.editPageClass = EditServiceCategoryPage.class; + + String service = pageParameters.get(WebConstants.PARAM_SERVICE).toString(); + dataProvider = new ServiceCategoryProvider(serviceCategoryService, service); + + columns = new ArrayList<>(); + columns.add(new BootstrapTextFilteredPropertyColumn<>(new Model<>("Value"), "code", "code", "code")); + columns.add(new BootstrapTextFilteredPropertyColumn<>(new Model<>("System Label"), "value", "value", "value")); + + columns.add(new PropertyColumn(new Model<>("Label Translations"), null, "labels") { + @Override + public void populateItem(final Item> item, final String componentId, final IModel rowModel) { + item.add(getLableTranslations(componentId, rowModel)); + } + }); + + columns.add(new BootstrapTextFilteredPropertyColumn<>(new Model<>("Type"), "type", "type", "type")); + columns.add(new PropertyColumn<>(new Model<>("Position"), "position", "position")); + + columns.add(new PropertyColumn(new Model<>("Color"), null, + "categoryStyle.color") { + @Override + public void populateItem(final Item> item, final String componentId, final IModel rowModel) { + String color = rowModel.getObject().getCategoryStyle() == null ? "" : rowModel.getObject().getCategoryStyle().getColor(); + item.add(new Label(componentId, "") + .add(new AttributeModifier("style", "background-color: " + color)) + .add(new CssClassNameAppender("color-box")) + ); + } + }); + } + + @Override + public ServiceEntityFilterState newFilterState() { + return new ServiceCategoryFilterState(); + } + +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceCategoriesPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceCategoriesPage.properties new file mode 100644 index 00000000..bce2fc76 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceCategoriesPage.properties @@ -0,0 +1,2 @@ +page.title={0} Categories +breadcrumb.title=Categories \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceDimensionsPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceDimensionsPage.java new file mode 100644 index 00000000..e0623cb9 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceDimensionsPage.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2023 Development Gateway, Inc and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the MIT License (MIT) + * which accompanies this distribution, and is available at + * https://opensource.org/licenses/MIT + * + * Contributors: + * Development Gateway - initial API and implementation + *******************************************************************************/ +package org.devgateway.toolkit.forms.wicket.page.lists.admin; + +import de.agilecoders.wicket.extensions.markup.html.bootstrap.table.filter.BootstrapTextFilteredPropertyColumn; +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; +import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.WebConstants; +import org.devgateway.toolkit.forms.service.admin.ServiceDimensionService; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.components.table.filter.ServiceDimensionFilterState; +import org.devgateway.toolkit.forms.wicket.components.table.filter.ServiceEntityFilterState; +import org.devgateway.toolkit.forms.wicket.page.DataServicePage; +import org.devgateway.toolkit.forms.wicket.page.edit.admin.EditServiceDimensionPage; +import org.devgateway.toolkit.persistence.dto.ServiceDimension; +import org.wicketstuff.annotation.mount.MountPath; + +import java.util.ArrayList; + +@MountPath(value = "/dimensions") +@BreadCrumbPage(parent = DataServicePage.class, hasServiceParam = true) +public class ListServiceDimensionsPage extends AbstractListServiceEntityPage { + + private static final long serialVersionUID = -6132847935476573446L; + + @SpringBean + private ServiceDimensionService serviceDimensionService; + + public ListServiceDimensionsPage(final PageParameters pageParameters) { + super(pageParameters); + + this.serviceEntityService = serviceDimensionService; + this.editPageClass = EditServiceDimensionPage.class; + + String service = pageParameters.get(WebConstants.PARAM_SERVICE).toString(); + dataProvider = new ServiceDimensionProvider(serviceDimensionService, service); + + columns = new ArrayList<>(); + columns.add(new BootstrapTextFilteredPropertyColumn<>(new Model<>("Value"), "code", "code", "code")); + columns.add(new BootstrapTextFilteredPropertyColumn<>(new Model<>("System Label"), "value", "value", "value")); + columns.add(new PropertyColumn(new Model<>("Label Translations"), null, "labels") { + @Override + public void populateItem(final Item> item, final String componentId, final IModel rowModel) { + item.add(getLableTranslations(componentId, rowModel)); + } + }); + columns.add(new PropertyColumn<>(new Model<>("Position"), "position", "position")); + } + + @Override + public ServiceEntityFilterState newFilterState() { + return new ServiceDimensionFilterState(); + } +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceDimensionsPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceDimensionsPage.properties new file mode 100644 index 00000000..fd533006 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceDimensionsPage.properties @@ -0,0 +1,2 @@ +page.title={0} Dimensions +breadcrumb.title=Dimensions \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceFiltersPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceFiltersPage.java new file mode 100644 index 00000000..742fc4c6 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceFiltersPage.java @@ -0,0 +1,58 @@ +package org.devgateway.toolkit.forms.wicket.page.lists.admin; + +import de.agilecoders.wicket.extensions.markup.html.bootstrap.table.filter.BootstrapTextFilteredPropertyColumn; +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; +import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.WebConstants; +import org.devgateway.toolkit.forms.service.admin.ServiceFilterService; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.components.table.filter.ServiceEntityFilterState; +import org.devgateway.toolkit.forms.wicket.components.table.filter.ServiceFilterFilterState; +import org.devgateway.toolkit.forms.wicket.page.DataServicePage; +import org.devgateway.toolkit.forms.wicket.page.edit.admin.EditServiceFilterPage; +import org.devgateway.toolkit.persistence.dto.ServiceFilter; +import org.wicketstuff.annotation.mount.MountPath; + +import java.util.ArrayList; + +@MountPath(value = "/filters") +@BreadCrumbPage(parent = DataServicePage.class, hasServiceParam = true) +public class ListServiceFiltersPage extends AbstractListServiceEntityPage { + + private static final long serialVersionUID = -6619848875255960857L; + + @SpringBean + private ServiceFilterService serviceFilterService; + + public ListServiceFiltersPage(final PageParameters pageParameters) { + super(pageParameters); + + this.serviceEntityService = serviceFilterService; + this.editPageClass = EditServiceFilterPage.class; + + String service = pageParameters.get(WebConstants.PARAM_SERVICE).toString(); + dataProvider = new ServiceFilterProvider(serviceFilterService, service); + + columns = new ArrayList<>(); + columns.add(new BootstrapTextFilteredPropertyColumn<>(new Model<>("Value"), "code", "code", "code")); + columns.add(new BootstrapTextFilteredPropertyColumn<>(new Model<>("System Label"), "value", "value", "value")); + columns.add(new PropertyColumn(new Model<>("Label Translations"), null, "labels") { + @Override + public void populateItem(final Item> item, final String componentId, final IModel rowModel) { + item.add(getLableTranslations(componentId, rowModel)); + } + }); + columns.add(new BootstrapTextFilteredPropertyColumn<>(new Model<>("Type"), "fieldType", "fieldType", "fieldType")); + } + + @Override + public ServiceEntityFilterState newFilterState() { + return new ServiceFilterFilterState(); + } + +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceFiltersPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceFiltersPage.properties new file mode 100644 index 00000000..82c32ecd --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceFiltersPage.properties @@ -0,0 +1,2 @@ +page.title={0} Filters +breadcrumb.title=Filters \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceMeasuresPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceMeasuresPage.java new file mode 100644 index 00000000..d19d7a0a --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceMeasuresPage.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2023 Development Gateway, Inc and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the MIT License (MIT) + * which accompanies this distribution, and is available at + * https://opensource.org/licenses/MIT + * + * Contributors: + * Development Gateway - initial API and implementation + *******************************************************************************/ +package org.devgateway.toolkit.forms.wicket.page.lists.admin; + +import de.agilecoders.wicket.core.markup.html.bootstrap.behavior.CssClassNameAppender; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.table.filter.BootstrapTextFilteredPropertyColumn; +import org.apache.wicket.AttributeModifier; +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; +import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.service.admin.ServiceMeasureService; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.components.table.filter.ServiceEntityFilterState; +import org.devgateway.toolkit.forms.wicket.components.table.filter.ServiceMeasureFilterState; +import org.devgateway.toolkit.forms.wicket.page.DataServicePage; +import org.devgateway.toolkit.forms.wicket.page.edit.admin.EditServiceMeasurePage; +import org.devgateway.toolkit.persistence.dto.ServiceMeasure; +import org.wicketstuff.annotation.mount.MountPath; + +import java.util.ArrayList; + +@MountPath(value = "/measures") +@BreadCrumbPage(parent = DataServicePage.class, hasServiceParam = true) +public class ListServiceMeasuresPage extends AbstractListServiceEntityPage { + + private static final long serialVersionUID = -6132847935476573446L; + + @SpringBean + private ServiceMeasureService serviceMeasureService; + + public ListServiceMeasuresPage(final PageParameters pageParameters) { + super(pageParameters); + + this.serviceEntityService = serviceMeasureService; + this.editPageClass = EditServiceMeasurePage.class; + + columns = new ArrayList<>(); + columns.add(new BootstrapTextFilteredPropertyColumn<>(new Model<>("Value"), "code", "code", "code")); + columns.add(new BootstrapTextFilteredPropertyColumn<>(new Model<>("System Label"), "value", "value", "value")); + columns.add(new PropertyColumn(new Model<>("Label Translations"), null, "labels") { + @Override + public void populateItem(final Item> item, final String componentId, final IModel rowModel) { + item.add(getLableTranslations(componentId, rowModel)); + } + }); + + columns.add(new BootstrapTextFilteredPropertyColumn<>(new Model<>("Group"), "parent", "parent", "parent")); + columns.add(new PropertyColumn<>(new Model<>("Position"), "position", "position")); + columns.add(new PropertyColumn(new Model<>("Color"), null, + "categoryStyle.color") { + @Override + public void populateItem(final Item> item, final String componentId, final IModel rowModel) { + item.add(new Label(componentId, "") + .add(new AttributeModifier("style", "background-color: " + rowModel.getObject().getCategoryStyle().getColor())) + .add(new CssClassNameAppender("color-box")) + ); + } + }); + } + + @Override + public ServiceEntityFilterState newFilterState() { + return new ServiceMeasureFilterState(); + } +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceMeasuresPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceMeasuresPage.properties new file mode 100644 index 00000000..7ec1e8a8 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServiceMeasuresPage.properties @@ -0,0 +1,2 @@ +page.title={0} Measures +breadcrumb.title=Measures \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServicePage$ActionPanel.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServicePage$ActionPanel.html new file mode 100644 index 00000000..cf2e29d7 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServicePage$ActionPanel.html @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServicePage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServicePage.html new file mode 100644 index 00000000..3eaf2050 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServicePage.html @@ -0,0 +1,15 @@ + + + + + + +
+
+
+
+
+ +
+ + \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServicePage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServicePage.java new file mode 100644 index 00000000..e35b58d1 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServicePage.java @@ -0,0 +1,157 @@ +/******************************************************************************* + * Copyright (c) 2015 Development Gateway, Inc and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the MIT License (MIT) + * which accompanies this distribution, and is available at + * https://opensource.org/licenses/MIT + * + * Contributors: + * Development Gateway - initial API and implementation + *******************************************************************************/ +package org.devgateway.toolkit.forms.wicket.page.lists.admin; + +import de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapBookmarkablePageLink; +import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType; +import org.apache.wicket.Component; +import org.apache.wicket.behavior.AttributeAppender; +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; +import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; +import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; +import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.panel.GenericPanel; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.WebConstants; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.forms.wicket.components.LinkTargetBlankPanel; +import org.devgateway.toolkit.forms.wicket.components.table.AjaxFallbackBootstrapDataTable; +import org.devgateway.toolkit.forms.wicket.page.BasePage; +import org.devgateway.toolkit.persistence.dto.ServiceMetadata; +import org.devgateway.toolkit.persistence.service.AdminSettingsService; +import org.wicketstuff.annotation.mount.MountPath; + +import java.util.ArrayList; +import java.util.List; + +@MountPath(value = "/listservices") +public class ListServicePage extends BasePage { + + private static final long serialVersionUID = -6132847935476573446L; + + @SpringBean + AdminSettingsService adminSettingsService; + + protected AjaxFallbackBootstrapDataTable dataTable; + + protected ServiceMetadataProvider dataProvider; + + protected List> columns; + + @SpringBean + private EurekaClientService eurekaClientService; + + protected int pageRowNo = 0; + + public ListServicePage(final PageParameters pageParameters) { + super(pageParameters); + + dataProvider = new ServiceMetadataProvider(eurekaClientService); + + columns = new ArrayList<>(); + columns.add(new PropertyColumn<>(new Model<>("Name"), "name", "name")); + columns.add(new PropertyColumn<>(new Model<>("ID"), "id", "id")); + columns.add(new PropertyColumn(new Model<>("URL"), "url", "url") { + @Override + public void populateItem(final Item> item, final String componentId, + final IModel rowModel) { + item.add(new LinkTargetBlankPanel(componentId, new PropertyModel<>(rowModel, "url"))); + } + }); + columns.add(new PropertyColumn<>(new Model<>("Type"), "type", "type")); + columns.add(new PropertyColumn(new Model<>("Status"), "status", "status") { + @Override + public void populateItem(final Item> item, final String componentId, + final IModel rowModel) { + String cssClass = rowModel.getObject().getStatus().equals("UP") ? "label-success" : "label-danger"; + Label label = new Label(componentId, this.getDataModel(rowModel)); + label.add(AttributeAppender.append("class", "label " + cssClass)); + item.add(label); + } + }); + + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + dataTable = new AjaxFallbackBootstrapDataTable( + "table", columns, dataProvider, getPageSize()) { + private static final long serialVersionUID = -7263599298497560059L; + + @Override + protected void onPageChanged() { + pageRowNo = 0; + } + }; + + columns.add(new AbstractColumn(new StringResourceModel("actionsColumn", this, null)) { + private static final long serialVersionUID = -7447601118569862123L; + + @Override + public void populateItem(final Item> cellItem, final String componentId, + final IModel model) { + cellItem.add(getActionPanel(componentId, model)); + } + }); + + add(dataTable); + } + + protected int getPageSize() { + return adminSettingsService.get().getPageSize(); + } + + public ActionPanel getActionPanel(final String id, final IModel model) { + return new ActionPanel(id, model); + } + + public class ActionPanel extends GenericPanel { + private static final long serialVersionUID = 5821419128121941939L; + + /** + * @param id + * @param model + */ + public ActionPanel(final String id, final IModel model) { + super(id, model); + + String serviceName = model.getObject().getName(); + add(getLink("dimensions", serviceName)); + add(getLink("measures", serviceName)); + add(getLink("filters", serviceName)); + add(getLink("categories", serviceName)); + } + + protected Component getLink(final String entity, final String serviceName) { + PageParameters serviceEntityPageParameters = new PageParameters(); + serviceEntityPageParameters.set(WebConstants.PARAM_SERVICE, serviceName); + serviceEntityPageParameters.set(WebConstants.PARAM_ENTITY, entity); + + BootstrapBookmarkablePageLink entityLink = new BootstrapBookmarkablePageLink<>(entity, + ListServiceDimensionsPage.class, serviceEntityPageParameters, Buttons.Type.Info); + entityLink.setIconType(FontAwesome5IconType.clock_s).setSize(Buttons.Size.Small) + .setLabel(new StringResourceModel(entity, ListServicePage.this, null)); + + return entityLink; + } + } +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServicePage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServicePage.properties new file mode 100644 index 00000000..8f019001 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ListServicePage.properties @@ -0,0 +1,6 @@ +page.title=Service List +actionsColumn=Actions +dimensions=Dimensions +measures=Measures +filters=Filters +categories=Categories \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceCategoryProvider.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceCategoryProvider.java new file mode 100644 index 00000000..6e73c0fd --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceCategoryProvider.java @@ -0,0 +1,21 @@ +package org.devgateway.toolkit.forms.wicket.page.lists.admin; + +import org.devgateway.toolkit.forms.service.admin.BaseServiceEntityService; +import org.devgateway.toolkit.persistence.dto.ServiceCategory; + +import java.util.Comparator; + +/** + * Data provider used to provide information about the services + * + * @author Viorel Chihai + */ +public class ServiceCategoryProvider extends SortableServiceEntityProvider { + private static final long serialVersionUID = 3067952110482080616L; + + public ServiceCategoryProvider(final BaseServiceEntityService serviceEntityService, + final String serviceName) { + super(serviceEntityService, serviceName); + } + +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceDatasetProvider.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceDatasetProvider.java new file mode 100644 index 00000000..0ce93b6e --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceDatasetProvider.java @@ -0,0 +1,18 @@ +package org.devgateway.toolkit.forms.wicket.page.lists.admin; + +import org.devgateway.toolkit.forms.service.admin.BaseServiceEntityService; +import org.devgateway.toolkit.persistence.dto.ServiceDataset; + +/** + * Data provider used to provide information about the services + * + * @author Viorel Chihai + */ +public class ServiceDatasetProvider extends SortableServiceEntityProvider { + private static final long serialVersionUID = 5486671831226922079L; + + public ServiceDatasetProvider(final BaseServiceEntityService serviceEntityService, + final String serviceName) { + super(serviceEntityService, serviceName); + } +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceDimensionProvider.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceDimensionProvider.java new file mode 100644 index 00000000..8b7541e8 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceDimensionProvider.java @@ -0,0 +1,28 @@ +package org.devgateway.toolkit.forms.wicket.page.lists.admin; + +import org.apache.wicket.extensions.markup.html.repeater.util.SortParam; +import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.devgateway.toolkit.forms.service.DatasetClientService; +import org.devgateway.toolkit.forms.service.admin.BaseServiceEntityService; +import org.devgateway.toolkit.persistence.dto.ServiceDimension; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +/** + * Data provider used to provide information about the services + * + * @author Viorel Chihai + */ +public class ServiceDimensionProvider extends SortableServiceEntityProvider { + private static final long serialVersionUID = 3067952110482080616L; + + public ServiceDimensionProvider(final BaseServiceEntityService serviceEntityService, + final String serviceName) { + super(serviceEntityService, serviceName); + } +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceFilterProvider.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceFilterProvider.java new file mode 100644 index 00000000..b89d93c4 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceFilterProvider.java @@ -0,0 +1,21 @@ +package org.devgateway.toolkit.forms.wicket.page.lists.admin; + +import org.devgateway.toolkit.forms.service.admin.BaseServiceEntityService; +import org.devgateway.toolkit.persistence.dto.ServiceDimension; +import org.devgateway.toolkit.persistence.dto.ServiceFilter; + +import java.util.Comparator; + +/** + * Data provider used to provide information about the services + * + * @author Viorel Chihai + */ +public class ServiceFilterProvider extends SortableServiceEntityProvider { + private static final long serialVersionUID = 3067952110482080616L; + + public ServiceFilterProvider(final BaseServiceEntityService serviceEntityService, + final String serviceName) { + super(serviceEntityService, serviceName); + } +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceMeasureProvider.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceMeasureProvider.java new file mode 100644 index 00000000..72648992 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceMeasureProvider.java @@ -0,0 +1,18 @@ +package org.devgateway.toolkit.forms.wicket.page.lists.admin; + +import org.devgateway.toolkit.forms.service.admin.BaseServiceEntityService; +import org.devgateway.toolkit.persistence.dto.ServiceMeasure; + +/** + * Data provider used to provide information about the services + * + * @author Viorel Chihai + */ +public class ServiceMeasureProvider extends SortableServiceEntityProvider { + private static final long serialVersionUID = 1858130875067823547L; + + public ServiceMeasureProvider(BaseServiceEntityService serviceEntityService, final String serviceName) { + super(serviceEntityService, serviceName); + } + +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceMetadataProvider.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceMetadataProvider.java new file mode 100644 index 00000000..6f2a5eb9 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/ServiceMetadataProvider.java @@ -0,0 +1,72 @@ +package org.devgateway.toolkit.forms.wicket.page.lists.admin; + +import org.apache.wicket.extensions.markup.html.repeater.util.SortParam; +import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.devgateway.toolkit.forms.service.EurekaClientService; +import org.devgateway.toolkit.persistence.dto.ServiceMetadata; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +/** + * Data provider used to provide information about the services + * + * @author Viorel Chihai + */ +public class ServiceMetadataProvider extends SortableDataProvider { + private static final long serialVersionUID = 1858130875067823547L; + + protected EurekaClientService eurekaClientService; + + public ServiceMetadataProvider(final EurekaClientService eurekaClientService) { + this.eurekaClientService = eurekaClientService; + } + + @Override + public Iterator iterator(final long first, final long count) { + List services = eurekaClientService.findAllWithData(); + + if (first > services.size()) { + return Collections.emptyIterator(); + } + + if (getSort() == null || getSort().getProperty().equals("label")) { + Comparator comparator = new ServiceMetadataComparator(); + + if (getSort() != null && getSort().isAscending()) { + comparator = comparator.reversed(); + } + + Collections.sort(services, comparator); + } + + return services.subList((int) first, (int) Math.min(first + count, services.size())).iterator(); + } + + @Override + public SortParam getSort() { + return super.getSort(); + } + + @Override + public long size() { + return eurekaClientService.findAllWithData().size(); + } + + @Override + public IModel model(final ServiceMetadata serviceMetadata) { + return Model.of(serviceMetadata); + } + + protected class ServiceMetadataComparator implements Comparator { + @Override + public int compare(final ServiceMetadata s1, final ServiceMetadata s2) { + return String.CASE_INSENSITIVE_ORDER.compare(s1.getName(), s2.getName()); + } + } + +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/SortableServiceEntityProvider.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/SortableServiceEntityProvider.java new file mode 100644 index 00000000..bfcb1ab6 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/admin/SortableServiceEntityProvider.java @@ -0,0 +1,76 @@ +package org.devgateway.toolkit.forms.wicket.page.lists.admin; + +import org.apache.commons.beanutils.BeanComparator; +import org.apache.commons.collections4.comparators.NullComparator; +import org.apache.wicket.extensions.markup.html.repeater.data.table.filter.IFilterStateLocator; +import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.devgateway.toolkit.forms.service.admin.BaseServiceEntityService; +import org.devgateway.toolkit.forms.wicket.components.table.filter.ServiceEntityFilterState; +import org.devgateway.toolkit.persistence.dto.ServiceEntity; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * Data provider used to provide information about the services + * + * @author Viorel Chihai + */ +public class SortableServiceEntityProvider extends SortableDataProvider + implements IFilterStateLocator> { + private static final long serialVersionUID = 1858130875067823547L; + + protected final String serviceName; + + private final BaseServiceEntityService serviceEntityService; + + private ServiceEntityFilterState filterState; + + public SortableServiceEntityProvider(final BaseServiceEntityService serviceEntityService, final String serviceName) { + this.serviceEntityService = serviceEntityService; + this.serviceName = serviceName; + } + + @Override + public Iterator iterator(final long first, final long count) { + List entities = serviceEntityService.findAll(serviceName, filterState.spec()); + + if (first > entities.size()) { + return Collections.emptyIterator(); + } + + if (getSort() != null) { + BeanComparator comparator = new BeanComparator(getSort().getProperty(), new NullComparator(false)); + if (getSort().isAscending()) { + Collections.sort(entities, comparator); + } else { + Collections.sort(entities, comparator.reversed()); + } + } + + return entities.subList((int) first, (int) Math.min(first + count, entities.size())).iterator(); + } + + @Override + public long size() { + return serviceEntityService.findAll(serviceName, filterState.spec()).size(); + } + + @Override + public IModel model(final T object) { + return Model.of(object); + } + + @Override + public ServiceEntityFilterState getFilterState() { + return filterState; + } + + @Override + public void setFilterState(final ServiceEntityFilterState filterState) { + this.filterState = filterState; + } +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/AbstractListDatasetPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/AbstractListDatasetPage.html new file mode 100644 index 00000000..47866312 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/AbstractListDatasetPage.html @@ -0,0 +1,29 @@ + + + + + + + +
+
+

Local Datasets

+
+
+
+ + +
+
+

Remote Datasets

+
+
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/AbstractListDatasetPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/AbstractListDatasetPage.java new file mode 100644 index 00000000..1761cda3 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/AbstractListDatasetPage.java @@ -0,0 +1,46 @@ +package org.devgateway.toolkit.forms.wicket.page.lists.dataset; + +import org.apache.wicket.Component; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.panel.Fragment; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.devgateway.toolkit.forms.wicket.page.lists.AbstractListPage; +import org.devgateway.toolkit.persistence.dao.GenericPersistable; +import org.devgateway.toolkit.persistence.dao.data.Dataset; + +import static org.devgateway.toolkit.forms.WebConstants.PARAM_SERVICE; + +public abstract class AbstractListDatasetPage extends AbstractListPage { + private static final long serialVersionUID = -7637952537702961987L; + + protected Fragment titleFragment; + + public AbstractListDatasetPage(final PageParameters pageParameters) { + super(pageParameters); + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + addTitleFragment(); + } + + protected void addTitleFragment() { + String serviceName = getPageParameters().get(PARAM_SERVICE).toString(); + + titleFragment = new Fragment("topPage", "localDatasetsTitleFragment", + AbstractListDatasetPage.this); + replace(titleFragment); + + titleFragment = new Fragment("bottomPage", "remoteDatasetsTitleFragment", + AbstractListDatasetPage.this); + titleFragment.add(new ListRemoteDatasetsPanel("remoteDatasetsPanel", serviceName)); + replace(titleFragment); + } + + @Override + protected Component getRevisionsLink(final GenericPersistable entity) { + return new WebMarkupContainer("revisions").setVisibilityAllowed(false); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/AbstractListDatasetPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/AbstractListDatasetPage.properties new file mode 100644 index 00000000..7a2d6c90 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/AbstractListDatasetPage.properties @@ -0,0 +1,2 @@ +local.datasets=Local Datasets +remote.datasets=Remote Datasets \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListCSVDatasetPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListCSVDatasetPage.java new file mode 100644 index 00000000..25055b39 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListCSVDatasetPage.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright (c) 2015 Development Gateway, Inc and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the MIT License (MIT) + * which accompanies this distribution, and is available at + * https://opensource.org/licenses/MIT + * + * Contributors: + * Development Gateway - initial API and implementation + *******************************************************************************/ +package org.devgateway.toolkit.forms.wicket.page.lists.dataset; + +import de.agilecoders.wicket.extensions.markup.html.bootstrap.table.filter.BootstrapChoiceFilteredPropertyColumn; +import nl.dries.wicket.hibernate.dozer.DozerListModel; +import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation; +import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; +import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.security.SecurityConstants; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.components.table.filter.CSVDatasetFilterState; +import org.devgateway.toolkit.forms.wicket.components.table.filter.JpaFilterState; +import org.devgateway.toolkit.forms.wicket.page.DataServicePage; +import org.devgateway.toolkit.forms.wicket.page.edit.dataset.EditCSVDatasetPage; +import org.devgateway.toolkit.persistence.dao.data.CSVDataset; +import org.devgateway.toolkit.persistence.service.data.CSVDatasetService; +import org.wicketstuff.annotation.mount.MountPath; + +import java.text.MessageFormat; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.stream.Collectors; + +import static org.devgateway.toolkit.forms.WebConstants.PARAM_SERVICE; + +@AuthorizeInstantiation(SecurityConstants.Roles.ROLE_USER) +@MountPath(value = "/listCSVDataset") +@BreadCrumbPage(parent = DataServicePage.class, hasServiceParam = true) +public class ListCSVDatasetPage extends AbstractListDatasetPage { + private static final long serialVersionUID = -7425220174797515101L; + + @SpringBean + private CSVDatasetService datasetService; + + CSVDatasetFilterState filterState; + + public ListCSVDatasetPage(final PageParameters pageParameters) { + super(pageParameters); + + String service = pageParameters.get(PARAM_SERVICE).toString(); + + this.jpaService = datasetService; + this.editPageClass = EditCSVDatasetPage.class; + + columns.clear(); + + List datasets = datasetService.findAllNotDeletedForService(service); + List years = datasets.stream() + .map(CSVDataset::getYear).distinct().sorted() + .collect(Collectors.toList()); + columns.add(new BootstrapChoiceFilteredPropertyColumn<>(new StringResourceModel("year"), "year", "year", + new DozerListModel<>(years), "year")); + + List statuses = datasets.stream() + .map(CSVDataset::getStatus).distinct().sorted() + .collect(Collectors.toList()); + columns.add(new BootstrapChoiceFilteredPropertyColumn<>(new StringResourceModel("status"), "status", "status", + new DozerListModel<>(statuses), "status")); + + columns.add(new PropertyColumn<>(new StringResourceModel("description"), "description")); + columns.add(new PropertyColumn<>(new StringResourceModel("lastModifiedBy"), "lastModifiedBy", + "lastModifiedBy.get")); + columns.add(new PropertyColumn(new StringResourceModel("lastModifiedDate"), + "lastModifiedDate", + "lastModifiedDate.get") { + + @Override + public IModel getDataModel(final IModel rowModel) { + IModel model = super.getDataModel(rowModel); + ZonedDateTime modifiedDate = (ZonedDateTime) model.getObject(); + return Model.of(modifiedDate.format(DateTimeFormatter.ofPattern("MM/dd/yyyy"))); + } + }); + + + filterState = new CSVDatasetFilterState(); + filterState.setService(service); + + } + + @Override + protected PageParameters getEditPageParameters() { + PageParameters pageParams = super.getEditPageParameters(); + pageParams.set(PARAM_SERVICE, getPageParameters().get(PARAM_SERVICE).toString()); + return pageParams; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + dataProvider.setSort("year", SortOrder.DESCENDING); + + excelForm.setVisibilityAllowed(false); + } + + @Override + public JpaFilterState newFilterState() { + return filterState; + } + + protected Label getPageTitle() { + return new Label("pageTitle", getPageTitleModel()); + } + + @Override + protected IModel getBreadcrumbTitleModel() { + return Model.of(MessageFormat.format(getString("breadcrumb.title"), getServiceLabel())); + } + + private Model getPageTitleModel() { + return Model.of(MessageFormat.format(getString("page.title"), getServiceLabel())); + } + + @Override + protected void addEditLinkPageParameters(final PageParameters pageParameters) { + pageParameters.set(PARAM_SERVICE, getPageParameters().get(PARAM_SERVICE)); + } + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListCSVDatasetPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListCSVDatasetPage.properties new file mode 100644 index 00000000..ebca1222 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListCSVDatasetPage.properties @@ -0,0 +1,10 @@ +page.title={0} Datasets +year=Year +lastModifiedBy=Editor +lastModifiedDate=Latest Modification +status=Status +description=Dataset Description +actionsColumn=Action + +new=Add new dataset +breadcrumb.title=Datasets \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListRemoteDatasetsPanel.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListRemoteDatasetsPanel.html new file mode 100644 index 00000000..59346424 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListRemoteDatasetsPanel.html @@ -0,0 +1,13 @@ + + + + +
+ +
+
+ +
+ + + \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListRemoteDatasetsPanel.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListRemoteDatasetsPanel.java new file mode 100644 index 00000000..f8e29625 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListRemoteDatasetsPanel.java @@ -0,0 +1,138 @@ +package org.devgateway.toolkit.forms.wicket.page.lists.dataset; + +import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.table.filter.BootstrapTextFilteredPropertyColumn; +import org.apache.commons.lang3.StringUtils; +import org.apache.wicket.Component; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; +import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; +import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; +import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.service.admin.ServiceDatasetService; +import org.devgateway.toolkit.forms.wicket.components.table.AjaxFallbackBootstrapDataTable; +import org.devgateway.toolkit.forms.wicket.components.table.ResettingFilterForm; +import org.devgateway.toolkit.forms.wicket.components.table.filter.ServiceDatasetFilterState; +import org.devgateway.toolkit.forms.wicket.components.table.filter.ServiceEntityFilterState; +import org.devgateway.toolkit.forms.wicket.page.lists.admin.ServiceDatasetProvider; +import org.devgateway.toolkit.persistence.dao.data.CSVDataset; +import org.devgateway.toolkit.persistence.dto.ServiceDataset; +import org.devgateway.toolkit.persistence.service.AdminSettingsService; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; + +public class ListRemoteDatasetsPanel extends Panel { + + private String serviceName; + + @SpringBean + protected AdminSettingsService adminSettingsService; + + protected AjaxFallbackBootstrapDataTable dataTable; + + protected ServiceDatasetProvider dataProvider; + + protected List> columns; + + @SpringBean + private ServiceDatasetService serviceDatasetService; + + protected int pageRowNo = 0; + + private Component dialogModalComponent; + + public ListRemoteDatasetsPanel(final String id) { + super(id); + } + + public ListRemoteDatasetsPanel(final String id, final String serviceName) { + super(id); + this.serviceName = serviceName; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + columns = new ArrayList<>(); + columns.add(new BootstrapTextFilteredPropertyColumn<>(new Model<>("Name"), "value", "value", "value")); + columns.add(new PropertyColumn(new Model<>("Date created"), "createdDate", "createdDate") { + @Override + public IModel getDataModel(final IModel rowModel) { + IModel model = super.getDataModel(rowModel); + ZonedDateTime createdDate = (ZonedDateTime) model.getObject(); + return Model.of(createdDate.format(DateTimeFormatter.ofPattern("MM/dd/yyyy"))); + } + }); + columns.add(new AbstractColumn(new StringResourceModel("actionsColumn", this, null)) { + private static final long serialVersionUID = -6185373434402515868L; + + @Override + public void populateItem(final Item> cellItem, final String componentId, + final IModel model) { + cellItem.add(new RemoteDatasetActionPanel(componentId, model) { + @Override + protected void onConfirmationSubmit(final AjaxRequestTarget target) { + serviceDatasetService.delete(serviceName, model.getObject()); + target.add(dataTable); + } + + @Override + protected void onOpenModal(final AjaxRequestTarget target, final Modal modal) { + dialogModalComponent = dialogModalComponent.replaceWith(modal); + target.add(dialogModalComponent); + } + }); + } + + @Override + public String getCssClass() { + return (StringUtils.isNotBlank(super.getCssClass()) ? super.getCssClass() : "") + " col-md-1"; + } + }); + + dataProvider = new ServiceDatasetProvider(serviceDatasetService, serviceName); + dataProvider.setFilterState(new ServiceDatasetFilterState()); + + dataTable = new AjaxFallbackBootstrapDataTable( + "table", columns, dataProvider, getPageSize()) { + private static final long serialVersionUID = 632539691822305263L; + + @Override + protected void onPageChanged() { + pageRowNo = 0; + } + }; + + ResettingFilterForm> filterForm = + new ResettingFilterForm<>("filterForm", dataProvider, dataTable); + filterForm.add(dataTable); + add(filterForm); + + addDialogModal(); + } + + protected void addDialogModal() { + dialogModalComponent = new WebMarkupContainer("dialogModal"); + dialogModalComponent.setOutputMarkupPlaceholderTag(true); + add(this.dialogModalComponent); + } + + protected int getPageSize() { + return adminSettingsService.get().getPageSize(); + } + + public ServiceEntityFilterState newFilterServiceDatasetState() { + return new ServiceDatasetFilterState(); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListRemoteDatasetsPanel.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListRemoteDatasetsPanel.properties new file mode 100644 index 00000000..c9088b90 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListRemoteDatasetsPanel.properties @@ -0,0 +1,4 @@ +name=Name +code=Date Created +remove=Remove +actionsColumn=Action \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListTetsimDatasetPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListTetsimDatasetPage.html new file mode 100644 index 00000000..88f7fdab --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListTetsimDatasetPage.html @@ -0,0 +1,25 @@ + + + + + + +
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+ + \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListTetsimDatasetPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListTetsimDatasetPage.java new file mode 100644 index 00000000..fdac234c --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListTetsimDatasetPage.java @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright (c) 2015 Development Gateway, Inc and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the MIT License (MIT) + * which accompanies this distribution, and is available at + * https://opensource.org/licenses/MIT + * + * Contributors: + * Development Gateway - initial API and implementation + *******************************************************************************/ +package org.devgateway.toolkit.forms.wicket.page.lists.dataset; + +import de.agilecoders.wicket.extensions.markup.html.bootstrap.table.filter.BootstrapChoiceFilteredPropertyColumn; +import nl.dries.wicket.hibernate.dozer.DozerListModel; +import org.apache.wicket.Component; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation; +import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; +import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.panel.Fragment; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.devgateway.toolkit.forms.WebConstants; +import org.devgateway.toolkit.forms.security.SecurityConstants; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.components.form.Select2ChoiceBootstrapFormComponent; +import org.devgateway.toolkit.forms.wicket.components.table.filter.JpaFilterState; +import org.devgateway.toolkit.forms.wicket.components.table.filter.TetsimDatasetFilterState; +import org.devgateway.toolkit.forms.wicket.page.DataServicePage; +import org.devgateway.toolkit.forms.wicket.page.edit.dataset.EditTetsimDatasetPage; +import org.devgateway.toolkit.forms.wicket.page.lists.AbstractListPage; +import org.devgateway.toolkit.forms.wicket.providers.GenericChoiceProvider; +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.service.data.TetsimDatasetService; +import org.devgateway.toolkit.web.util.SettingsUtils; +import org.springframework.util.ObjectUtils; +import org.wicketstuff.annotation.mount.MountPath; + +import java.text.MessageFormat; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static org.devgateway.toolkit.forms.WebConstants.PARAM_SERVICE; +import static org.devgateway.toolkit.forms.WebConstants.PARAM_YEAR; + +@AuthorizeInstantiation(SecurityConstants.Roles.ROLE_USER) +@MountPath(value = "/listTetsimDataset") +@BreadCrumbPage(parent = DataServicePage.class, hasServiceParam = true) +public class ListTetsimDatasetPage extends AbstractListDatasetPage { + private static final long serialVersionUID = -324298525712620234L; + + @SpringBean + protected SettingsUtils settingsUtils; + + TetsimDatasetFilterState filterState; + + protected Select2ChoiceBootstrapFormComponent year; + protected Fragment yearSelectorFragment; + private Integer selectedYear; + @SpringBean + private TetsimDatasetService tetsimDatasetService; + private Label addButtonError; + + public ListTetsimDatasetPage(final PageParameters pageParameters) { + super(pageParameters); + this.jpaService = tetsimDatasetService; + this.editPageClass = EditTetsimDatasetPage.class; + + String service = pageParameters.get(PARAM_SERVICE).toString(); + + columns.clear(); + + List datasets = tetsimDatasetService.findAllNotDeletedForService(service); + List years = datasets.stream() + .map(TetsimDataset::getYear).distinct().sorted() + .collect(Collectors.toList()); + columns.add(new BootstrapChoiceFilteredPropertyColumn<>(new StringResourceModel("year"), "year", "year", + new DozerListModel<>(years), "year")); + + List statuses = datasets.stream() + .map(TetsimDataset::getStatus).distinct().sorted() + .collect(Collectors.toList()); + columns.add(new BootstrapChoiceFilteredPropertyColumn<>(new StringResourceModel("status"), "status", "status", + new DozerListModel<>(statuses), "status")); + + columns.add(new PropertyColumn<>(new StringResourceModel("lastModifiedBy"), "lastModifiedBy", + "lastModifiedBy.get")); + columns.add(new PropertyColumn(new StringResourceModel("lastModifiedDate"), + "lastModifiedDate", + "lastModifiedDate.get") { + + @Override + public IModel getDataModel(final IModel rowModel) { + IModel model = super.getDataModel(rowModel); + ZonedDateTime modifiedDate = (ZonedDateTime) model.getObject(); + return Model.of(modifiedDate.format(DateTimeFormatter.ofPattern("MM/dd/yyyy"))); + } + }); + + + filterState = new TetsimDatasetFilterState(); + filterState.setService(service); + + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + dataProvider.setSort("year", SortOrder.DESCENDING); + + addNewYearSelector(); + + editPageLink.setEnabled(false); + + excelForm.setVisibilityAllowed(false); + } + + private void addNewYearSelector() { + yearSelectorFragment = new Fragment("bottomPageFragment", "yearSelectorFragment", + ListTetsimDatasetPage.this); + replace(yearSelectorFragment); + + Form form = new Form<>("form"); + yearSelectorFragment.add(form); + + year = new Select2ChoiceBootstrapFormComponent("year", + new GenericChoiceProvider<>(getYearsNewData()), Model.of(selectedYear)) { + @Override + public String getPlaceholder() { + return "Select new year to add"; + } + + @Override + protected void onUpdate(final AjaxRequestTarget target) { + preparePageLinkButton(target); + } + }; + + year.setVisibilityAllowed(true); + year.hideLabel(); + form.add(year); + + Label helperTextYear = new Label("helperTextYear"); + form.add(helperTextYear); + + addButtonError = new Label("addButtonError"); + addButtonError.setOutputMarkupId(true); + addButtonError.setOutputMarkupPlaceholderTag(true); + addButtonError.setVisibilityAllowed(false); + form.add(addButtonError); + } + + protected List getYearsNewData() { + return settingsUtils.getYearsRange(); + } + + protected void preparePageLinkButton(final AjaxRequestTarget target) { + if (year.getModelObject() == null) { + addButtonError.setVisibilityAllowed(false); + editPageLink.setEnabled(false); + target.add(addButtonError, editPageLink); + return; + } + + List errors = getAddButtonErrors(); + + addButtonError.setVisibilityAllowed(!errors.isEmpty()); + addButtonError.setDefaultModel(Model.of(String.join("\n", errors))); + target.add(addButtonError); + + if (!errors.isEmpty()) { + editPageLink.setEnabled(false); + target.add(editPageLink); + return; + } + + if (!ObjectUtils.isEmpty(year.getModelObject())) { + editPageLink.setEnabled(true); + attachYearParameters(editPageLink.getPageParameters(), year.getModelObject()); + } else { + editPageLink.setEnabled(false); + } + + target.add(editPageLink); + } + + @Override + protected PageParameters getEditPageParameters() { + PageParameters pageParams = super.getEditPageParameters(); + pageParams.set(PARAM_SERVICE, getPageParameters().get(PARAM_SERVICE).toString()); + return pageParams; + } + + protected List getAddButtonErrors() { + long c = countByNonPublished(); + if (c > 0) { + return Collections.singletonList(getString("existingData")); + } else { + return Collections.emptyList(); + } + } + + protected long countByNonPublished() { + return tetsimDatasetService.countByNonPublished(year.getModelObject()); + } + + void attachYearParameters(PageParameters pageParameters, Integer year) { + if (year != null) { + pageParameters.set(PARAM_YEAR, year); + } + } + + @Override + public JpaFilterState newFilterState() { + return new TetsimDatasetFilterState(); + } + + protected Label getPageTitle() { + return new Label("pageTitle", getPageTitleModel()); + } + + @Override + protected IModel getBreadcrumbTitleModel() { + return Model.of(MessageFormat.format(getString("breadcrumb.title"), getServiceLabel())); + } + + private Model getPageTitleModel() { + return Model.of(MessageFormat.format(getString("page.title"), getServiceLabel())); + } + + @Override + protected void addEditLinkPageParameters(final PageParameters pageParameters) { + pageParameters.set(WebConstants.PARAM_SERVICE, getPageParameters().get(WebConstants.PARAM_SERVICE)); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListTetsimDatasetPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListTetsimDatasetPage.properties new file mode 100644 index 00000000..ef3cce4c --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/ListTetsimDatasetPage.properties @@ -0,0 +1,13 @@ +page.title={0} Datasets +year=Year +lastModifiedBy=Editor +lastModifiedDate=Latest Modification +status=Status +actionsColumn=Action + +year.label=Select Year +new=Add new dataset +helperTextYear=Select the year and then click on Add new dataset +existingData=There is already a dataset for the selected period. + +breadcrumb.title=Datasets \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoteDatasetActionPanel.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoteDatasetActionPanel.html new file mode 100644 index 00000000..cfe64654 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoteDatasetActionPanel.html @@ -0,0 +1,10 @@ + + + + +
+ +
+
+ + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoteDatasetActionPanel.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoteDatasetActionPanel.java new file mode 100644 index 00000000..66a4295f --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoteDatasetActionPanel.java @@ -0,0 +1,53 @@ +package org.devgateway.toolkit.forms.wicket.page.lists.dataset; + +import de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapAjaxButton; +import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; +import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.StringResourceModel; +import org.devgateway.toolkit.persistence.dto.ServiceDataset; + +public abstract class RemoteDatasetActionPanel extends Panel { + + public RemoteDatasetActionPanel(final String id, final IModel model) { + super(id, model); + + Form form = new Form("actionForm"); + add(form); + + BootstrapAjaxButton reject = new BootstrapAjaxButton("remove", + new StringResourceModel("remove"), Buttons.Type.Danger) { + @Override + public void onSubmit(final AjaxRequestTarget target) { + openRemoveModal(target, model); + } + + @Override + protected void onConfigure() { + super.onConfigure(); + } + }; + form.add(reject); + } + + private void openRemoveModal(final AjaxRequestTarget target, final IModel model) { + Modal removeModal = new RemoveRemoteDatasetModal("dialogModal", model) { + @Override + protected void onSubmit(final AjaxRequestTarget target) { + super.onSubmit(target); + onConfirmationSubmit(target); + } + }; + removeModal.show(true); + + onOpenModal(target, removeModal); + } + + protected abstract void onConfirmationSubmit(AjaxRequestTarget target); + + protected abstract void onOpenModal(AjaxRequestTarget target, Modal modal); + +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoteDatasetActionPanel.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoteDatasetActionPanel.properties new file mode 100644 index 00000000..c856d125 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoteDatasetActionPanel.properties @@ -0,0 +1,2 @@ +createdDate=Created Date +remove=Remove \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoveRemoteDatasetModal.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoveRemoteDatasetModal.java new file mode 100644 index 00000000..f47ac6ff --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoveRemoteDatasetModal.java @@ -0,0 +1,11 @@ +package org.devgateway.toolkit.forms.wicket.page.lists.dataset; + +import org.apache.wicket.model.IModel; +import org.devgateway.toolkit.forms.wicket.components.modal.ConfirmationModal; +import org.devgateway.toolkit.persistence.dto.ServiceDataset; + +public class RemoveRemoteDatasetModal extends ConfirmationModal { + public RemoveRemoteDatasetModal(final String markupId, final IModel model) { + super(markupId, model); + } +} diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoveRemoteDatasetModal.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoveRemoteDatasetModal.properties new file mode 100644 index 00000000..4f8a9374 --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/lists/dataset/RemoveRemoteDatasetModal.properties @@ -0,0 +1,4 @@ +header=Remove Dataset +description=Are you sure you want to remove it? The dataset will no longer be visible in wordpress. +submit=Yes +cancel=No diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/ChangePasswordPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/ChangePasswordPage.java index 8780844e..d7449bfe 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/ChangePasswordPage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/ChangePasswordPage.java @@ -25,7 +25,6 @@ protected void onInitialize() { lastName.setVisibilityAllowed(false); email.setVisibilityAllowed(false); title.setVisibilityAllowed(false); - group.setVisibilityAllowed(false); roles.setVisibilityAllowed(false); enabled.setVisibilityAllowed(false); changePasswordNextSignIn.setVisibilityAllowed(false); diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPage.html index 1dd64a9f..f1bdcd97 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPage.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPage.html @@ -2,7 +2,7 @@ -
+
@@ -16,7 +16,6 @@
-
diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPage.java index f27fcd87..19e4ac0e 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPage.java @@ -31,10 +31,10 @@ import org.devgateway.toolkit.forms.security.SecurityConstants; import org.devgateway.toolkit.forms.security.SecurityUtil; import org.devgateway.toolkit.forms.service.SendEmailService; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; import org.devgateway.toolkit.forms.wicket.components.form.BootstrapCancelButton; import org.devgateway.toolkit.forms.wicket.components.form.CheckBoxToggleBootstrapFormComponent; import org.devgateway.toolkit.forms.wicket.components.form.PasswordFieldBootstrapFormComponent; -import org.devgateway.toolkit.forms.wicket.components.form.Select2ChoiceBootstrapFormComponent; import org.devgateway.toolkit.forms.wicket.components.form.Select2MultiChoiceBootstrapFormComponent; import org.devgateway.toolkit.forms.wicket.components.form.TextFieldBootstrapFormComponent; import org.devgateway.toolkit.forms.wicket.components.util.ComponentUtil; @@ -43,10 +43,8 @@ import org.devgateway.toolkit.forms.wicket.page.lists.ListUserPage; import org.devgateway.toolkit.persistence.dao.Person; import org.devgateway.toolkit.persistence.dao.Role; -import org.devgateway.toolkit.persistence.dao.categories.Group; import org.devgateway.toolkit.persistence.service.PersonService; import org.devgateway.toolkit.persistence.service.RoleService; -import org.devgateway.toolkit.persistence.service.category.GroupService; import org.springframework.security.crypto.password.PasswordEncoder; import org.wicketstuff.annotation.mount.MountPath; @@ -54,15 +52,13 @@ @AuthorizeInstantiation(SecurityConstants.Roles.ROLE_USER) @MountPath(value = "/account") +@BreadCrumbPage public class EditUserPage extends AbstractEditPage { private static final long serialVersionUID = 5208480049061989277L; @SpringBean private PersonService personService; - @SpringBean - private GroupService groupService; - @SpringBean private RoleService roleService; @@ -82,8 +78,6 @@ public class EditUserPage extends AbstractEditPage { protected TextFieldBootstrapFormComponent title; - protected Select2ChoiceBootstrapFormComponent group; - protected Select2MultiChoiceBootstrapFormComponent roles; protected CheckBoxToggleBootstrapFormComponent enabled; @@ -150,10 +144,6 @@ protected void onInitialize() { title = ComponentUtil.addTextField(editForm, "title"); title.getField().add(MAXIMUM_LENGTH_VALIDATOR_STD_DEFAULT_TEXT); - group = ComponentUtil.addSelect2ChoiceField(editForm, "group", groupService); - group.required(); - MetaDataRoleAuthorizationStrategy.authorize(group, Component.RENDER, SecurityConstants.Roles.ROLE_ADMIN); - roles = ComponentUtil.addSelect2MultiChoiceField(editForm, "roles", roleService); roles.required(); MetaDataRoleAuthorizationStrategy.authorize(roles, Component.RENDER, SecurityConstants.Roles.ROLE_ADMIN); diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPage.properties b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPage.properties index dc97e47c..744aa813 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPage.properties +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPage.properties @@ -19,7 +19,6 @@ firstName.label=First name lastName.label=Last name email.label=Email address title.label=Title -group.label=Group roles.label=Roles plainPassword.label=Password plainPasswordCheck.label=Repeat password diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPageElevated.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPageElevated.java index b7271fa0..08b3cbbf 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPageElevated.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/EditUserPageElevated.java @@ -14,10 +14,13 @@ import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation; import org.apache.wicket.request.mapper.parameter.PageParameters; import org.devgateway.toolkit.forms.security.SecurityConstants; +import org.devgateway.toolkit.forms.wicket.components.breadcrumbs.BreadCrumbPage; +import org.devgateway.toolkit.forms.wicket.page.lists.ListUserPage; import org.wicketstuff.annotation.mount.MountPath; @AuthorizeInstantiation(SecurityConstants.Roles.ROLE_ADMIN) @MountPath(value = "/user") +@BreadCrumbPage(parent = ListUserPage.class) public class EditUserPageElevated extends EditUserPage { private static final long serialVersionUID = -5372177614898411737L; @@ -25,4 +28,8 @@ public EditUserPageElevated(final PageParameters parameters) { super(parameters); } + private boolean hasBreadcrumbPanel() { + return this.getClass().getDeclaredAnnotation(BreadCrumbPage.class) != null; + } + } diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/ForgotYourPasswordPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/ForgotYourPasswordPage.html index 69ce6903..1a7798c1 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/ForgotYourPasswordPage.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/ForgotYourPasswordPage.html @@ -6,7 +6,7 @@ -
+
diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/LoginPage.html b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/LoginPage.html index d8c63bce..887e892a 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/LoginPage.html +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/LoginPage.html @@ -6,7 +6,7 @@ -
+
diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/LoginPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/LoginPage.java index 28d37ec8..3420f589 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/LoginPage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/LoginPage.java @@ -17,6 +17,7 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel; import de.agilecoders.wicket.core.markup.html.bootstrap.form.BootstrapForm; import org.apache.commons.lang3.BooleanUtils; +import org.apache.wicket.AttributeModifier; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.authroles.authentication.AbstractAuthenticatedWebSession; import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton; @@ -28,7 +29,6 @@ import org.apache.wicket.request.mapper.parameter.PageParameters; import org.apache.wicket.spring.injection.annot.SpringBean; import org.apache.wicket.util.string.StringValue; -import org.apache.wicket.util.time.Duration; import org.devgateway.toolkit.forms.WebConstants; import org.devgateway.toolkit.forms.security.SecurityUtil; import org.devgateway.toolkit.forms.wicket.SSAuthenticatedWebSession; @@ -42,8 +42,9 @@ import org.springframework.security.web.savedrequest.SavedRequest; import org.wicketstuff.annotation.mount.MountPath; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.io.Serializable; +import java.time.Duration; /** * @author mpostelnicu @@ -124,14 +125,16 @@ protected void onInitialize() { retrieveReferrerFromSavedRequestIfPresent(); final NotificationPanel notificationPanel = new NotificationPanel("loginFeedback"); - notificationPanel.hideAfter(Duration.seconds(HIDE_NOTIFICATION_SECONDS)); + notificationPanel.hideAfter(Duration.ofSeconds(HIDE_NOTIFICATION_SECONDS)); notificationPanel.setOutputMarkupId(true); add(notificationPanel); username = ComponentUtil.addTextLoginField(this, "username"); + username.getBorder().add(AttributeModifier.append("class", "required-field")); username.required(); password = ComponentUtil.addTextPasswordField(this, "password"); + password.getBorder().add(AttributeModifier.append("class", "required-field")); password.required(); password.getField().setResetPassword(false); diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/LogoutPage.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/LogoutPage.java index 5bd2b52f..d96496b8 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/LogoutPage.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/page/user/LogoutPage.java @@ -17,14 +17,12 @@ import org.apache.wicket.authroles.authentication.AbstractAuthenticatedWebSession; import org.apache.wicket.markup.html.pages.RedirectPage; import org.apache.wicket.request.cycle.RequestCycle; -import org.apache.wicket.spring.injection.annot.SpringBean; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.web.authentication.RememberMeServices; import org.wicketstuff.annotation.mount.MountPath; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import static org.devgateway.toolkit.web.WebConstants.FORMS_BASE_PATH; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; /** * @author mpostelnicu @@ -34,11 +32,12 @@ public class LogoutPage extends RedirectPage { private static final long serialVersionUID = 1L; - @SpringBean(required = false) + @Autowired(required = false) private RememberMeServices rememberMeServices; public LogoutPage() { - super(RequestCycle.get().getRequest().getContextPath() + FORMS_BASE_PATH + "/login"); + super(RequestCycle.get().getRequest().getContextPath() + + RequestCycle.get().getRequest().getFilterPath() + "/login"); AbstractAuthenticatedWebSession.get().invalidate(); if (rememberMeServices != null) { diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/providers/GenericPersistableJpaTextChoiceProvider.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/providers/GenericPersistableJpaTextChoiceProvider.java index 3f5a0dc4..5376d549 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/providers/GenericPersistableJpaTextChoiceProvider.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/providers/GenericPersistableJpaTextChoiceProvider.java @@ -84,6 +84,16 @@ public void setExcludedIds(final Set excludedIds) { this.excludedIds = excludedIds; } + public GenericPersistableJpaTextChoiceProvider setSort(final Sort sort) { + this.sort = sort; + return this; + } + + public GenericPersistableJpaTextChoiceProvider setSort(final Sort.Direction direction, + final String... properties) { + return this.setSort(Sort.by(direction, properties)); + } + @Override public String getIdValue(final T choice) { // if the object is not null but it hasn't an ID return 0 diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/providers/SortableJpaServiceDataProvider.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/providers/SortableJpaServiceDataProvider.java index 578845a1..6677537c 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/providers/SortableJpaServiceDataProvider.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/providers/SortableJpaServiceDataProvider.java @@ -20,6 +20,7 @@ import org.devgateway.toolkit.forms.models.PersistableJpaRepositoryModel; import org.devgateway.toolkit.forms.wicket.components.table.filter.JpaFilterState; import org.devgateway.toolkit.persistence.dao.GenericPersistable; +import org.devgateway.toolkit.persistence.service.AdminSettingsService; import org.devgateway.toolkit.persistence.service.BaseJpaService; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -38,17 +39,24 @@ public class SortableJpaServiceDataProvider implements IFilterStateLocator> { private static final long serialVersionUID = 6507887810859971417L; + private final Integer pageSize; + private final BaseJpaService jpaService; private JpaFilterState filterState; + public SortableJpaServiceDataProvider(final BaseJpaService jpaService) { + this(jpaService, WebConstants.DEFAULT_PAGE_SIZE); + } + /** * Always provide a proxy jpaService here! For example one coming from a {@link SpringBean} * * @param jpaService */ - public SortableJpaServiceDataProvider(final BaseJpaService jpaService) { + public SortableJpaServiceDataProvider(final BaseJpaService jpaService, final Integer pageSize) { this.jpaService = jpaService; + this.pageSize = pageSize; } /** @@ -68,14 +76,18 @@ protected Sort translateSort() { */ @Override public Iterator iterator(final long first, final long count) { - int page = (int) ((double) first / WebConstants.PAGE_SIZE); + int page = (int) ((double) first / getPageSize()); final Page findAll = jpaService.findAll(filterState.getSpecification(), translateSort() == null - ? PageRequest.of(page, WebConstants.PAGE_SIZE) - : PageRequest.of(page, WebConstants.PAGE_SIZE, translateSort())); + ? PageRequest.of(page, getPageSize()) + : PageRequest.of(page, getPageSize(), translateSort())); return findAll.iterator(); } + private Integer getPageSize() { + return pageSize; + } + @Override public long size() { return jpaService.count(filterState.getSpecification()); diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/BaseStyles.css b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/BaseStyles.css index d569e2e7..f4827eda 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/BaseStyles.css +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/BaseStyles.css @@ -29,7 +29,30 @@ body { border-radius: 0; } -.mainHeader.with-navbar-fixed-top { +.navbar-default { + height: 80px; + padding-top: 15px; + padding-left: 1em; + padding-right: 1em; + align-items: normal !important; +} + +.navbar-border{ + border: 1px solid #d4d2d2; +} + +.well{ + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.mainHeader.with-fixed-top { /* * The mainHeader doesn't have any height when the navbar is fixed, and other elements are behind it. * @@ -39,7 +62,7 @@ body { * @see: Navbar.Position.TOP * @see: bootstrap::navbar.less */ - min-height: 50px; + min-height: 80px; margin-bottom: 32px; } @@ -58,26 +81,51 @@ body { padding: 0px; } +.navbar-brand > img { + height: 100%; +} + +.navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus { + color: #555; + background-color: #e7e7e7; +} .mainContainer { /* * The main page content should have some height. */ min-height: 20em; + padding-bottom: 40px; } .mainFooter { /* * Add some spacing around the footer. */ - margin-top: 2em; + margin-top: -20px; + padding: 20px 0; + min-height: 80px; position: absolute; bottom: 0; width: 100%; /* Set the fixed height of the footer here */ height: 50px; - background-color: #222; + background-color: #175372; +} + +.mainFooter .text-muted { + color: #acdef7; } +.required-field::before { + content: "*"; + color: red; + margin-right: 4px; + font-weight: 700; +} + +label{ + font-weight: 600 !important; +} /* file upload -------------------------------------------------- */ .file-preview.loading { @@ -222,3 +270,131 @@ hr.edit-separator { /* -------------------------------------------------- */ + +.bigLinkContainer .bigLinkItem { + padding: 15px; +} + +button .btn-home-desc { + padding-top: 0; + width: 140px; + font-size: 12px; + text-transform: none; + white-space: normal; +} + +button .btn-home-label { + white-space: normal; + line-height: 20px; +} + +.btn-homepage { + width: 250px; + height: 250px; + margin: 0 auto; + padding: 10px; + display: inline-block; + line-height: 15px; + text-align: center; +} + +.homepage-btn{ + color: #333 !important; + background-color: #fff !important; + border-color: #ccc !important; +} + + +div.parentElement{text-align: center;} + +button .btn-home-desc { + padding-top: 0; + width: 140px; + font-size: 12px; + text-transform: none; + white-space: normal; +} + +button .btn-home-label { + white-space: normal; + line-height: 20px; +} + +.feedbackPanel, .form-wrapper { + margin: 10px 5px 10px 0px; +} + +.error-row { + color: red; +} + +.color-box { + width: 40px; + height: 30px; + display: inline-block; + margin-right: 5px; +} + +.required .control-label:before { + content: "*"; + color: #a94442; + display: inline; + margin-right: 5px; +} + +.row-list-item-button { + min-height: 58px; +} + +.pull-down { + position: absolute; + bottom: 0; +} + +.label-translation-margin { + margin-right: 5px; +} + +.label-translation-description { + margin-top: 10px; + margin-bottom: 10px; + font-style: italic; +} + +.breadcrumb { + background-color: #ffffff; + padding-top: 20px; + padding-bottom: 0px; + padding-left: 12px; + margin-bottom: 0px; +} + +.breadcrumb .btn-link { + padding-left: 0px; + padding-right: 0px; + font-size: 12px; + font-weight: 700; + margin-left: -7px; + color: #aaaaaa; +} + +.breadcrumb a[disabled=disabled] { + color: #000000; + font-weight: 800; + margin-bottom: 1px; +} + +.breadcrumb > li + li:before { + padding: 0 2px; + color: #aaaaaa; + content: "/\00a0"; + font-weight: 700; +} + +/*Media Queries*/ +@media (min-width: 768px) { + .navbar-default{ + padding-left: 15em; + padding-right: 15em; + } +} \ No newline at end of file diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/BlockUiJavaScript.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/BlockUiJavaScript.java index ef16b8a6..62612529 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/BlockUiJavaScript.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/BlockUiJavaScript.java @@ -39,7 +39,7 @@ public BlockUiJavaScript() { public List getDependencies() { final List dependencies = Lists.newArrayList(super.getDependencies()); - dependencies.add(JavaScriptHeaderItem.forReference(JQueryResourceReference.getV2())); + dependencies.add(JavaScriptHeaderItem.forReference(JQueryResourceReference.getV3())); dependencies.add(JavaScriptHeaderItem .forReference(new JavaScriptResourceReference(EmptyCss.class, "/assets/js/jquery.blockUI.js"))); diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/BlockUiReportsJavaScript.java b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/BlockUiReportsJavaScript.java index e9cfe8ea..55e20ea8 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/BlockUiReportsJavaScript.java +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/BlockUiReportsJavaScript.java @@ -39,7 +39,7 @@ public BlockUiReportsJavaScript() { public List getDependencies() { final List dependencies = Lists.newArrayList(super.getDependencies()); - dependencies.add(JavaScriptHeaderItem.forReference(JQueryResourceReference.getV2())); + dependencies.add(JavaScriptHeaderItem.forReference(JQueryResourceReference.getV3())); dependencies.add(JavaScriptHeaderItem .forReference(new JavaScriptResourceReference(EmptyCss.class, "/assets/js/jquery.blockUI.js"))); diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/assets/img/icons/tcdi-favicon.svg b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/assets/img/icons/tcdi-favicon.svg new file mode 100644 index 00000000..0b45c2de --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/assets/img/icons/tcdi-favicon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/assets/img/tcdi-horizontal-logo.svg b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/assets/img/tcdi-horizontal-logo.svg new file mode 100644 index 00000000..f601aadc --- /dev/null +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/assets/img/tcdi-horizontal-logo.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/assets/js/fileupload.js b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/assets/js/fileupload.js index 7030a553..e7f2b067 100644 --- a/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/assets/js/fileupload.js +++ b/forms/src/main/java/org/devgateway/toolkit/forms/wicket/styles/assets/js/fileupload.js @@ -31,8 +31,12 @@ // disable the upload button $(this).closest('.file-input').find('.fileinput-upload-button').show(); $(this).closest('.file-input').find('.fileinput-upload-button').prop("disabled", true); + + // Cover form buttons with a div (will be hidden again in FileInputBootstrapFormComponentWrapper.html) + $('.cover-buttons-div').css("z-index", 100); } else { $(this).closest('.file-input').find('.fileinput-upload-button').hide(); + $('.cover-buttons-div').css("z-index", -1); } }); })(); diff --git a/forms/src/main/resources/logback.xml b/forms/src/main/resources/logback.xml index c6cb063e..de0096fe 100644 --- a/forms/src/main/resources/logback.xml +++ b/forms/src/main/resources/logback.xml @@ -1,30 +1,17 @@ - + + + - - ${LOG_DIR}/logger.log - - %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36} - %msg%n - - - - ${LOG_DIR}/logger.%d{yyyy-MM-dd}.%i.log - - - 64MB - - - 30 - - - + + @@ -36,6 +23,6 @@ - + diff --git a/forms/src/test/java/org/devgateway/toolkit/forms/client/DatasetClientTest.java b/forms/src/test/java/org/devgateway/toolkit/forms/client/DatasetClientTest.java new file mode 100644 index 00000000..412dfc37 --- /dev/null +++ b/forms/src/test/java/org/devgateway/toolkit/forms/client/DatasetClientTest.java @@ -0,0 +1,52 @@ +package org.devgateway.toolkit.forms.client; + + +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class DatasetClientTest { + + private DatasetClient client; + + private String baseUrl = "http://localhost:8084/"; + + @BeforeEach + public void initClient() { + this.client = new DatasetClient(baseUrl); + } + + @Test + public void testJobStatus() throws DataSetClientException { + System.out.println(client.getDatasetStatus("1142").toString()); + } + + @Test + public void testTetsimDataset() { + TetsimDataset dataset = new TetsimDataset(); + dataset.setYear(2020); + try { + client.publishDataset(dataset, Files.readAllBytes(Paths.get("./src/test/resources/2020_tetsim.csv"))); + } catch (DataSetClientException e) { + throw new RuntimeException(e); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Test + public void testClient() { + DatasetClient client = new DatasetClient(baseUrl); + assertTrue(client.isUp()); + } + +} \ No newline at end of file diff --git a/persistence-mongodb/pom.xml b/persistence-mongodb/pom.xml index a0e37796..0ccd3e25 100644 --- a/persistence-mongodb/pom.xml +++ b/persistence-mongodb/pom.xml @@ -23,15 +23,15 @@ UTF-8 - org.devgateway.toolkit.persistence.spring.PersistenceApplication + org.devgateway.tcdi.persistence.spring.PersistenceApplication 1.8 2.2.6 1.9 - org.devgateway.toolkit - toolkit + org.devgateway.tcdi + admin 0.0.1-SNAPSHOT diff --git a/persistence-mongodb/src/main/java/org/devgateway/toolkit/persistence/mongo/application.properties b/persistence-mongodb/src/main/java/org/devgateway/toolkit/persistence/mongo/application.properties index 2a925ce5..e25cc0be 100644 --- a/persistence-mongodb/src/main/java/org/devgateway/toolkit/persistence/mongo/application.properties +++ b/persistence-mongodb/src/main/java/org/devgateway/toolkit/persistence/mongo/application.properties @@ -9,4 +9,4 @@ # Contributors: # Development Gateway - initial API and implementation ############################################################################### -server.port = 8090 +server.port = 8080 diff --git a/persistence/pom.xml b/persistence/pom.xml index 2bc0406e..5fc5c559 100644 --- a/persistence/pom.xml +++ b/persistence/pom.xml @@ -9,26 +9,26 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - persistence + tcdi-admin-persistence jar JPA Persistence - DGToolkit Persistence + TCDI Admin Persistence UTF-8 org.devgateway.toolkit.persistence.spring.PersistenceApplication - 1.8 - 3.8.1 + 17 + 3.10.8 0.3.8 - 3.2.1 + 3.17.0 30.0-jre 1.9.4 - org.devgateway.toolkit - toolkit + org.devgateway.tcdi + tcdi-admin 0.0.1-SNAPSHOT @@ -75,6 +75,7 @@ org.ehcache ehcache ${ehcache.version} + jakarta @@ -82,6 +83,11 @@ spring-boot-starter-cache + + org.springframework.boot + spring-boot-starter-web + + org.springframework spring-context-support @@ -111,21 +117,24 @@ org.hibernate hibernate-jcache + ${hibernate.version} - - javax.cache - cache-api - + + + + org.hibernate - hibernate-entitymanager + hibernate-core + ${hibernate.version} org.hibernate hibernate-envers + ${hibernate.version} hibernate-entitymanager @@ -137,6 +146,7 @@ org.hibernate hibernate-jpamodelgen + ${hibernate.version} @@ -147,29 +157,16 @@ org.apache.derby - derbyclient + derby ${derby.version} + test - org.apache.derby - derbynet - ${derby.version} + org.postgresql + postgresql - - - - - - - - - - - - - org.liquibase liquibase-core @@ -205,6 +202,23 @@ poi-ooxml ${poi.version} + + + com.opencsv + opencsv + 5.9 + + + + jakarta.xml.bind + jakarta.xml.bind-api + 4.0.2 + + + org.glassfish.jaxb + jaxb-runtime + 4.0.5 + @@ -239,18 +253,25 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + 3.11.0 ${java.version} ${java.version} -proc:none + + + org.hibernate + hibernate-jpamodelgen + ${hibernate.version} + + org.bsc.maven maven-processor-plugin - 3.3.3 + 5.1 process @@ -268,7 +289,7 @@ org.codehaus.mojo build-helper-maven-plugin - 1.3 + 3.6.0 add-source diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/application-dev.properties b/persistence/src/main/java/org/devgateway/toolkit/persistence/application-dev.properties new file mode 100644 index 00000000..1dd40424 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/application-dev.properties @@ -0,0 +1,20 @@ +############################################################################### +# Copyright (c) 2015 Development Gateway, Inc and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the MIT License (MIT) +# which accompanies this distribution, and is available at +# https://opensource.org/licenses/MIT +# +# Contributors: +# Development Gateway - initial API and implementation +############################################################################### +spring.config.activate.on-profile=dev +spring.datasource.username=postgres +spring.datasource.password=admin +spring.datasource.jdbc-url=jdbc:postgresql://localhost:5432/tcdi_admin +management.health.mail.enabled=false + +dg-toolkit.forms.base-path=/admin +eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/ +spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/application.properties b/persistence/src/main/java/org/devgateway/toolkit/persistence/application.properties index f17fcb76..7ad93112 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/application.properties +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/application.properties @@ -9,14 +9,14 @@ # Contributors: # Development Gateway - initial API and implementation ############################################################################### -server.port = 8090 +server.port = 8080 # liquibase properties spring.liquibase.enabled=true spring.liquibase.change-log=classpath:liquibase-changelog.xml #spring.jpa.show-sql=true -spring.jpa.database-platform=org.devgateway.toolkit.persistence.derby.DerbyDialect +spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect #performance tunning for hibernate spring.jpa.hibernate.max_fetch_depth=0 @@ -33,17 +33,19 @@ spring.servlet.multipart.enabled = false #enable modified flag for envers, to track field-level modifications spring.jpa.properties.org.hibernate.envers.global_with_modified_flag=true +# tell hibernate to not detect jdbc features as it would cause unhelpful LOG stack trace in logs +spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false + spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.cache.region.factory_class=org.hibernate.cache.jcache.JCacheRegionFactory -spring.jpa.properties.hibernate.javax.cache.missing_cache_strategy=create spring.datasource.max-active=3000 spring.datasource.max-idle=8 spring.datasource.min-idle=8 spring.datasource.initial-size=20 -spring.datasource.driver-class-name=org.apache.derby.jdbc.ClientDriver40 -spring.datasource.username=app -spring.datasource.password=app -spring.datasource.jdbc-url=jdbc:derby://localhost//derby/toolkit;create=true +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.username=postgres +spring.datasource.password=admin +spring.datasource.jdbc-url=jdbc:postgresql://localhost:5432/tcdi_admin spring.datasource.transaction-isolation=2 dg-toolkit.datasource.jndi-name=toolkitDS dg-toolkit.derby.port=1527 @@ -52,3 +54,8 @@ spring.cache.jcache.config=classpath:ehcache.xml spring.data.rest.base-path=/rest spring.profiles.active=integration + +eureka.client.serviceUrl.defaultZone=http://eureka:8761/eureka/ + +dg-toolkit.forms.base-path=/admin +spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/checks/ValidateCacheableHibernateQueryResult.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/checks/ValidateCacheableHibernateQueryResult.java index c4a7e619..b471153d 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/checks/ValidateCacheableHibernateQueryResult.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/checks/ValidateCacheableHibernateQueryResult.java @@ -4,7 +4,7 @@ import org.reflections.Reflections; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.HashSet; import java.util.Set; diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/converter/DefaultDecimalFormatter.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/converter/DefaultDecimalFormatter.java index 007d022f..e5a6d926 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/converter/DefaultDecimalFormatter.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/converter/DefaultDecimalFormatter.java @@ -1,5 +1,6 @@ package org.devgateway.toolkit.persistence.converter; +import java.io.Serializable; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; @@ -9,7 +10,7 @@ /** * @author Nadejda Mandrescu */ -public class DefaultDecimalFormatter implements INumberFormatter { +public class DefaultDecimalFormatter implements INumberFormatter, Serializable { private final ConcurrentHashMap decimalFormats = new ConcurrentHashMap<>(); @@ -19,8 +20,6 @@ public NumberFormat get(final Locale locale) { public DecimalFormat init(final Locale locale) { DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(locale); - decimalFormat.setMaximumFractionDigits(2); - decimalFormat.setMinimumFractionDigits(2); DecimalFormatSymbols decimalFormatSymbols = DecimalFormatSymbols.getInstance(locale); decimalFormatSymbols.setDecimalSeparator('.'); diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/converter/INumberFormatter.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/converter/INumberFormatter.java index d1c960aa..2ddf68b7 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/converter/INumberFormatter.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/converter/INumberFormatter.java @@ -8,5 +8,5 @@ */ public interface INumberFormatter { - NumberFormat get(final Locale locale); + NumberFormat get(Locale locale); } diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/AbstractAuditableEntity.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/AbstractAuditableEntity.java index edb52902..349391db 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/AbstractAuditableEntity.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/AbstractAuditableEntity.java @@ -16,9 +16,9 @@ import org.springframework.data.domain.Auditable; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import javax.persistence.EntityListeners; -import javax.persistence.MappedSuperclass; -import javax.persistence.PreUpdate; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.PreUpdate; import java.time.ZonedDateTime; import java.util.Optional; diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/AbstractStatusAuditableEntity.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/AbstractStatusAuditableEntity.java index 534b4100..7b08428d 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/AbstractStatusAuditableEntity.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/AbstractStatusAuditableEntity.java @@ -6,22 +6,26 @@ import org.hibernate.annotations.OptimisticLock; import org.hibernate.envers.Audited; -import javax.persistence.CascadeType; -import javax.persistence.FetchType; -import javax.persistence.ManyToOne; -import javax.persistence.MappedSuperclass; -import javax.persistence.OneToMany; -import javax.persistence.OrderColumn; -import javax.persistence.Transient; -import javax.validation.constraints.NotNull; +import jakarta.persistence.CascadeType; +import jakarta.persistence.FetchType; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OrderColumn; +import jakarta.persistence.Transient; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.DELETED; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.DRAFT; + @MappedSuperclass public abstract class AbstractStatusAuditableEntity extends AbstractAuditableEntity implements Statusable { + @NotNull @Audited - private String status = DBConstants.Status.DRAFT; + private String status = DRAFT; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @@ -51,6 +55,11 @@ public abstract class AbstractStatusAuditableEntity extends AbstractAuditableEnt @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) private Person checkedOutUser; + @JsonIgnore + public boolean isDeleted() { + return DELETED.equals(getStatus()); + } + @Override public String getStatus() { return status; diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/AdminSettings.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/AdminSettings.java index 48a5c594..8f671f1f 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/AdminSettings.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/AdminSettings.java @@ -4,10 +4,12 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.envers.Audited; -import javax.persistence.Entity; +import jakarta.persistence.Entity; import java.time.Duration; import java.time.LocalDateTime; +import static org.springframework.beans.support.PagedListHolder.DEFAULT_PAGE_SIZE; + /** * @author idobre * @since 6/22/16 @@ -27,6 +29,12 @@ public class AdminSettings extends AbstractAuditableEntity { private Integer autosaveTime = AUTOSAVE_TIME_DEFAULT; + private Integer pageSize = DEFAULT_PAGE_SIZE; + + private String tetsimCurrency; + + private String countryName; + @Override public AbstractAuditableEntity getParent() { return null; @@ -59,4 +67,28 @@ public Integer getAutosaveTime() { public void setAutosaveTime(Integer autosaveTime) { this.autosaveTime = autosaveTime; } + + public String getTetsimCurrency() { + return tetsimCurrency; + } + + public void setTetsimCurrency(String tetsimCurrency) { + this.tetsimCurrency = tetsimCurrency; + } + + public String getCountryName() { + return countryName; + } + + public void setCountryName(final String countryName) { + this.countryName = countryName; + } + + public Integer getPageSize() { + return pageSize; + } + + public void setPageSize(final Integer pageSize) { + this.pageSize = pageSize; + } } diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/DBConstants.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/DBConstants.java index 47a40fd9..90ffa1b8 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/DBConstants.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/DBConstants.java @@ -23,10 +23,19 @@ private DBConstants() { public static final class Status { public static final String DRAFT = "DRAFT"; - public static final String SUBMITTED = "SUBMITTED"; - public static final String APPROVED = "APPROVED"; + public static final String SAVED = "SAVED"; + public static final String PUBLISHING = "PUBLISHING"; + public static final String PUBLISHED = "PUBLISHED"; + public static final String ERROR_IN_PUBLISHING = "ERROR_IN_PUBLISHING"; + public static final String DELETED = "DELETED"; - public static final String[] ALL = {DRAFT, SUBMITTED, APPROVED}; + public static final String UNPUBLISHING = "UNPUBLISHING"; + + public static final String ERROR_IN_UNPUBLISHING = "ERROR_IN_UNPUBLISHING"; + + + public static final String[] ALL = {DRAFT, SAVED, PUBLISHING, PUBLISHED, ERROR_IN_PUBLISHING, UNPUBLISHING, + ERROR_IN_UNPUBLISHING, DELETED}; public static final List ALL_LIST = Collections.unmodifiableList(Arrays.asList(ALL)); } @@ -34,4 +43,5 @@ public static final class Status { public static final int STD_DEFAULT_TEXT_LENGTH = 255; public static final int MAX_DEFAULT_TEXT_LENGTH_ONE_LINE = 3000; public static final int MAX_DEFAULT_TEXT_AREA = 10000; + } diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/FileContent.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/FileContent.java index c76c2760..08c6533f 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/FileContent.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/FileContent.java @@ -11,12 +11,14 @@ *******************************************************************************/ package org.devgateway.toolkit.persistence.dao; -import org.hibernate.annotations.Type; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Lob; -import java.io.Serializable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Lob; + +import java.sql.Types; /** * @author idobre @@ -31,7 +33,7 @@ public class FileContent extends AbstractAuditableEntity { @Lob @Column(length = LOB_LENGTH) - @Type(type = "org.hibernate.type.BinaryType") + @JdbcTypeCode(Types.VARBINARY) private byte[] bytes; public byte[] getBytes() { diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/FileMetadata.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/FileMetadata.java index 890d6a6c..9ff43c2c 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/FileMetadata.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/FileMetadata.java @@ -14,13 +14,12 @@ import org.hibernate.envers.Audited; import org.hibernate.envers.RelationTargetAuditMode; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Index; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import java.io.Serializable; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Index; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; /** * @author idobre diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/GenericPersistable.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/GenericPersistable.java index d5eee8f0..bbed2822 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/GenericPersistable.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/GenericPersistable.java @@ -24,9 +24,9 @@ import nl.dries.wicket.hibernate.dozer.proxy.Proxied; import org.springframework.data.jpa.domain.AbstractPersistable; -import javax.persistence.Column; -import javax.persistence.MappedSuperclass; -import javax.persistence.Version; +import jakarta.persistence.Column; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.Version; /** * @author mpostelnicu diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/JsonViews.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/JsonViews.java index 66c34a98..2161f325 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/JsonViews.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/JsonViews.java @@ -1,7 +1,5 @@ package org.devgateway.toolkit.persistence.dao; -import org.apache.xmlbeans.impl.xb.xsdschema.Public; - /** * These is a set of possible views to be used with com.fasterxml.jackson.annotation.JsonView, * that allows multiple serializations options for the same class based on the view. diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/Person.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/Person.java index 2326f40f..3859d1f1 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/Person.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/Person.java @@ -20,14 +20,13 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Index; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.persistence.Transient; -import java.io.Serializable; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Index; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; import java.util.Collection; import java.util.List; diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/Role.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/Role.java index c8c7e71f..7a382448 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/Role.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/Role.java @@ -15,11 +15,10 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.envers.Audited; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Index; -import javax.persistence.Table; -import java.io.Serializable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Index; +import jakarta.persistence.Table; /** * @author mpostelnicu diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/StatusChangedComment.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/StatusChangedComment.java index f3cd6a2a..a430e8cc 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/StatusChangedComment.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/StatusChangedComment.java @@ -4,10 +4,10 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.envers.Audited; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Index; -import javax.persistence.Table; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Index; +import jakarta.persistence.Table; @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @Entity diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/Statusable.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/Statusable.java index b8cbdd2d..496d2a68 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/Statusable.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/Statusable.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore; +import static org.devgateway.toolkit.persistence.dao.DBConstants.Status.PUBLISHED; + /** * @author mihai *

@@ -12,4 +14,8 @@ public interface Statusable { String getStatus(); + @JsonIgnore + default boolean isPublished() { + return PUBLISHED.equals(getStatus()); + } } diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/TestForm.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/TestForm.java index c37960c4..bba0a256 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/TestForm.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/TestForm.java @@ -20,15 +20,14 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.envers.Audited; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.OrderColumn; -import java.io.Serializable; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OrderColumn; import java.util.ArrayList; import java.util.Date; import java.util.List; diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/TestFormChild.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/TestFormChild.java index ea43d796..e683445e 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/TestFormChild.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/TestFormChild.java @@ -4,10 +4,10 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.envers.Audited; -import javax.persistence.Entity; -import javax.persistence.Index; -import javax.persistence.ManyToOne; -import javax.persistence.Table; +import jakarta.persistence.Entity; +import jakarta.persistence.Index; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; /** * @author idobre diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/categories/Category.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/categories/Category.java index 9995aaf7..51bd6a36 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/categories/Category.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/categories/Category.java @@ -17,11 +17,10 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.envers.Audited; -import javax.persistence.DiscriminatorColumn; -import javax.persistence.Entity; -import javax.persistence.Index; -import javax.persistence.Table; -import java.io.Serializable; +import jakarta.persistence.DiscriminatorColumn; +import jakarta.persistence.Entity; +import jakarta.persistence.Index; +import jakarta.persistence.Table; /** * @author idobre diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/categories/Group.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/categories/Group.java index abab2483..3850016d 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/categories/Group.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/categories/Group.java @@ -16,16 +16,14 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.envers.Audited; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.OneToMany; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToMany; import java.util.HashSet; import java.util.Set; /** - * * @author mpostelnicu - * */ @Entity @Audited diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/CSVDataset.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/CSVDataset.java new file mode 100644 index 00000000..fa9301a4 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/CSVDataset.java @@ -0,0 +1,41 @@ +package org.devgateway.toolkit.persistence.dao.data; + +import org.devgateway.toolkit.persistence.dao.FileMetadata; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.envers.Audited; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.OneToMany; +import java.util.Set; + +@Entity +@Audited +@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class CSVDataset extends Dataset { + + @Audited + private String description; + + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + @OneToMany(cascade = CascadeType.ALL) + @Audited + private Set files; + + public Set getFiles() { + return files; + } + + public void setFiles(final Set files) { + this.files = files; + } + + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/Dataset.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/Dataset.java new file mode 100644 index 00000000..28db48a5 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/Dataset.java @@ -0,0 +1,41 @@ +package org.devgateway.toolkit.persistence.dao.data; + +import org.devgateway.toolkit.persistence.dao.AbstractAuditableEntity; +import org.devgateway.toolkit.persistence.dao.AbstractStatusAuditableEntity; +import org.hibernate.envers.Audited; + +import jakarta.persistence.MappedSuperclass; +import jakarta.validation.constraints.NotNull; +import java.io.Serializable; + +@MappedSuperclass +public abstract class Dataset extends AbstractStatusAuditableEntity implements Serializable { + + @NotNull + @Audited + private Integer year; + + @Audited + private String destinationService; + + @Override + public AbstractAuditableEntity getParent() { + return null; + } + + public Integer getYear() { + return year; + } + + public void setYear(final Integer year) { + this.year = year; + } + + public void setDestinationService(final String destinationService) { + this.destinationService = destinationService; + } + + public String getDestinationService() { + return destinationService; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/TetsimDataset.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/TetsimDataset.java new file mode 100644 index 00000000..68f1276d --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/TetsimDataset.java @@ -0,0 +1,215 @@ +package org.devgateway.toolkit.persistence.dao.data; + +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.envers.Audited; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToOne; +import java.math.BigDecimal; + +@Entity +@Audited +@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class TetsimDataset extends Dataset { + + @Audited + private BigDecimal cigaretteConsumption; + + @Audited + private BigDecimal vatRate; + + @Audited + private BigDecimal cigaretteDeclaredCustomValue; + + @Audited + private BigDecimal adultPopulation; + + @Audited + private BigDecimal smokingPrevalence; + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @Audited + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TetsimPriceVariable retailPrice = new TetsimPriceVariable(this); + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @Audited + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TetsimPriceVariable marketShare = new TetsimPriceVariable(this); + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @Audited + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TetsimPriceVariable cif = new TetsimPriceVariable(this); + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @Audited + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TetsimPriceVariable tobaccoLevy = new TetsimPriceVariable(this); + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @Audited + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TetsimPriceVariable exciseTax = new TetsimPriceVariable(this); + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @Audited + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TetsimPriceVariable customsDuty = new TetsimPriceVariable(this); + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @Audited + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TetsimPriceVariable elasticityOfDemandPrice = new TetsimPriceVariable(this); + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @Audited + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TetsimPriceVariable elasticityOfDemandCrossPrice = new TetsimPriceVariable(this); + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @Audited + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TetsimPriceVariable changeInIllicitNot = new TetsimPriceVariable(this); + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @Audited + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TetsimPriceVariable overshifting = new TetsimPriceVariable(this); + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @Audited + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TetsimPriceVariable undershifting = new TetsimPriceVariable(this); + + public BigDecimal getCigaretteConsumption() { + return cigaretteConsumption; + } + + public void setCigaretteConsumption(final BigDecimal cigaretteConsumption) { + this.cigaretteConsumption = cigaretteConsumption; + } + + public BigDecimal getVatRate() { + return vatRate; + } + + public void setVatRate(final BigDecimal vatRate) { + this.vatRate = vatRate; + } + + public BigDecimal getCigaretteDeclaredCustomValue() { + return cigaretteDeclaredCustomValue; + } + + public void setCigaretteDeclaredCustomValue(final BigDecimal cigaretteDeclaredCustomValue) { + this.cigaretteDeclaredCustomValue = cigaretteDeclaredCustomValue; + } + + public BigDecimal getAdultPopulation() { + return adultPopulation; + } + + public void setAdultPopulation(final BigDecimal adultPopulation) { + this.adultPopulation = adultPopulation; + } + + public BigDecimal getSmokingPrevalence() { + return smokingPrevalence; + } + + public void setSmokingPrevalence(final BigDecimal smokingPrevalence) { + this.smokingPrevalence = smokingPrevalence; + } + + public TetsimPriceVariable getRetailPrice() { + return retailPrice; + } + + public void setRetailPrice(final TetsimPriceVariable retailPrice) { + this.retailPrice = retailPrice; + } + + public TetsimPriceVariable getMarketShare() { + return marketShare; + } + + public void setMarketShare(final TetsimPriceVariable marketShare) { + this.marketShare = marketShare; + } + + public TetsimPriceVariable getCif() { + return cif; + } + + public void setCif(final TetsimPriceVariable cif) { + this.cif = cif; + } + + public TetsimPriceVariable getTobaccoLevy() { + return tobaccoLevy; + } + + public void setTobaccoLevy(final TetsimPriceVariable tobaccoLevy) { + this.tobaccoLevy = tobaccoLevy; + } + + public TetsimPriceVariable getExciseTax() { + return exciseTax; + } + + public void setExciseTax(final TetsimPriceVariable exciseTax) { + this.exciseTax = exciseTax; + } + + public TetsimPriceVariable getCustomsDuty() { + return customsDuty; + } + + public void setCustomsDuty(final TetsimPriceVariable customsDuty) { + this.customsDuty = customsDuty; + } + + public TetsimPriceVariable getElasticityOfDemandPrice() { + return elasticityOfDemandPrice; + } + + public void setElasticityOfDemandPrice(final TetsimPriceVariable elasticityOfDemandPrice) { + this.elasticityOfDemandPrice = elasticityOfDemandPrice; + } + + public TetsimPriceVariable getElasticityOfDemandCrossPrice() { + return elasticityOfDemandCrossPrice; + } + + public void setElasticityOfDemandCrossPrice(final TetsimPriceVariable elasticityOfDemandCrossPrice) { + this.elasticityOfDemandCrossPrice = elasticityOfDemandCrossPrice; + } + + public TetsimPriceVariable getChangeInIllicitNot() { + return changeInIllicitNot; + } + + public void setChangeInIllicitNot(final TetsimPriceVariable changeInIllicitNot) { + this.changeInIllicitNot = changeInIllicitNot; + } + + public TetsimPriceVariable getOvershifting() { + return overshifting; + } + + public void setOvershifting(final TetsimPriceVariable overshifting) { + this.overshifting = overshifting; + } + + public TetsimPriceVariable getUndershifting() { + return undershifting; + } + + public void setUndershifting(final TetsimPriceVariable undershifting) { + this.undershifting = undershifting; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/TetsimPriceVariable.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/TetsimPriceVariable.java new file mode 100644 index 00000000..fb015e94 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/TetsimPriceVariable.java @@ -0,0 +1,55 @@ +package org.devgateway.toolkit.persistence.dao.data; + +import org.devgateway.toolkit.persistence.dao.AbstractAuditableEntity; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.envers.Audited; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import java.util.HashSet; +import java.util.Set; + +@Entity +@Audited +@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class TetsimPriceVariable extends AbstractAuditableEntity { + + @ManyToOne + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TetsimDataset dataset; + + @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private Set values = new HashSet<>(); + + public TetsimPriceVariable() { + } + + public TetsimPriceVariable(final TetsimDataset dataset) { + this.dataset = dataset; + } + + @Override + public AbstractAuditableEntity getParent() { + return dataset; + } + + public TetsimDataset getDataset() { + return dataset; + } + + public void setDataset(final TetsimDataset dataset) { + this.dataset = dataset; + } + + public Set getValues() { + return values; + } + + public void setValues(final Set values) { + this.values = values; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/TetsimTobaccoProductValue.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/TetsimTobaccoProductValue.java new file mode 100644 index 00000000..8cce7e60 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/TetsimTobaccoProductValue.java @@ -0,0 +1,54 @@ +package org.devgateway.toolkit.persistence.dao.data; + +import org.devgateway.toolkit.persistence.dao.AbstractAuditableEntity; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.envers.Audited; + +import jakarta.persistence.Entity; +import jakarta.persistence.ManyToOne; +import java.math.BigDecimal; + +@Entity +@Audited +@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class TetsimTobaccoProductValue extends AbstractAuditableEntity { + + @ManyToOne + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TetsimPriceVariable priceVariable; + + @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private TobaccoProduct product; + + private BigDecimal value; + + public TobaccoProduct getProduct() { + return product; + } + + public void setProduct(final TobaccoProduct product) { + this.product = product; + } + + public BigDecimal getValue() { + return value; + } + + public void setValue(final BigDecimal value) { + this.value = value; + } + + public TetsimPriceVariable getPriceVariable() { + return priceVariable; + } + + public void setPriceVariable(final TetsimPriceVariable priceVariable) { + this.priceVariable = priceVariable; + } + + @Override + public AbstractAuditableEntity getParent() { + return priceVariable; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/TobaccoProduct.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/TobaccoProduct.java new file mode 100644 index 00000000..adf8b856 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dao/data/TobaccoProduct.java @@ -0,0 +1,35 @@ +package org.devgateway.toolkit.persistence.dao.data; + +import java.util.EnumSet; +import java.util.List; + +public enum TobaccoProduct { + + IMPORTED("Imported"), + PREMIUM("Premium"), + POPULAR("Popular"), + DISCOUNT("Discount"), + ILLICIT("Illicit", true); + + public static final EnumSet ALL = EnumSet.of(IMPORTED, PREMIUM, POPULAR, DISCOUNT, ILLICIT); + + private final String label; + private final Boolean illicit; + + TobaccoProduct(String label) { + this(label, false); + } + + TobaccoProduct(String label, Boolean illicit) { + this.label = label; + this.illicit = illicit; + } + + public String getLabel() { + return label; + } + + public Boolean isIllicit() { + return illicit; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/derby/CustomDerbyDialect.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/derby/CustomDerbyDialect.java new file mode 100644 index 00000000..c6af8cd6 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/derby/CustomDerbyDialect.java @@ -0,0 +1,28 @@ +package org.devgateway.toolkit.persistence.derby; + +import org.hibernate.dialect.DerbyDialect; +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.type.descriptor.jdbc.BlobJdbcType; +import org.hibernate.type.spi.TypeConfiguration; + +import static java.sql.Types.VARBINARY; + +/** + * Setup non-default derby configurations. + * + * @author Nadejda Mandrescu + */ +public class CustomDerbyDialect extends DerbyDialect { + + public CustomDerbyDialect() { + super(); + } + + @Override + public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + super.contributeTypes(typeContributions, serviceRegistry); + typeContributions.getTypeConfiguration().getJdbcTypeRegistry() + .addDescriptor(VARBINARY, BlobJdbcType.BLOB_BINDING); + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/derby/DerbyDialect.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/derby/DerbyDialect.java deleted file mode 100644 index 609a22e9..00000000 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/derby/DerbyDialect.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.devgateway.toolkit.persistence.derby; - -import org.hibernate.dialect.DerbyTenSevenDialect; - -import static java.sql.Types.VARBINARY; - -/** - * Setup non-default derby configurations. - * - * @author Nadejda Mandrescu - */ -public class DerbyDialect extends DerbyTenSevenDialect { - - public DerbyDialect() { - super(); - registerColumnType(VARBINARY, "BLOB($l)"); - } -} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/CssStyle.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/CssStyle.java new file mode 100644 index 00000000..bf35df37 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/CssStyle.java @@ -0,0 +1,45 @@ +package org.devgateway.toolkit.persistence.dto; + +import java.io.Serializable; + +public class CssStyle implements Serializable { + private String backgroundColor; + + private String textColor; + + private String className; + + private String color; + + public String getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(final String backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public String getTextColor() { + return textColor; + } + + public void setTextColor(final String textColor) { + this.textColor = textColor; + } + + public String getClassName() { + return className; + } + + public void setClassName(final String className) { + this.className = className; + } + + public String getColor() { + return color; + } + + public void setColor(final String color) { + this.color = color; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceCategory.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceCategory.java new file mode 100644 index 00000000..5bd56cd5 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceCategory.java @@ -0,0 +1,85 @@ +package org.devgateway.toolkit.persistence.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.devgateway.toolkit.persistence.serializer.ServiceTextTranslationDeserializer; +import org.devgateway.toolkit.persistence.serializer.ServiceTextTranslationSerializer; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class ServiceCategory extends ServiceEntity { + + private String code; + + private String value; + + private Integer position; + + private CssStyle categoryStyle; + + private String type; + + private String parent; + + @JsonDeserialize(using = ServiceTextTranslationDeserializer.class) + @JsonSerialize(using = ServiceTextTranslationSerializer.class) + private List labels; + + public String getCode() { + return code; + } + + public void setCode(final String code) { + this.code = code; + } + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } + + public Integer getPosition() { + return position; + } + + public void setPosition(final Integer position) { + this.position = position; + } + + public CssStyle getCategoryStyle() { + return categoryStyle; + } + + public void setCategoryStyle(final CssStyle categoryStyle) { + this.categoryStyle = categoryStyle; + } + + public String getType() { + return type; + } + + public void setType(final String type) { + this.type = type; + } + + public List getLabels() { + return labels; + } + + public void setLabels(final List labels) { + this.labels = labels; + } + + public String getParent() { + return parent; + } + + public void setParent(String parent) { + this.parent = parent; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceDataset.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceDataset.java new file mode 100644 index 00000000..a704f5ca --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceDataset.java @@ -0,0 +1,19 @@ +package org.devgateway.toolkit.persistence.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.time.ZonedDateTime; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class ServiceDataset extends ServiceCategory { + + private ZonedDateTime createdDate; + + public ZonedDateTime getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(final ZonedDateTime createdDate) { + this.createdDate = createdDate; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceDimension.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceDimension.java new file mode 100644 index 00000000..92e90d9f --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceDimension.java @@ -0,0 +1,8 @@ +package org.devgateway.toolkit.persistence.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class ServiceDimension extends ServiceCategory { + +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceEntity.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceEntity.java new file mode 100644 index 00000000..2599a8ce --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceEntity.java @@ -0,0 +1,23 @@ +package org.devgateway.toolkit.persistence.dto; + +import java.io.Serializable; + +public class ServiceEntity implements Serializable { + + private Long id; + + ServiceEntity() { + } + + public ServiceEntity(final Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public void setId(final Long id) { + this.id = id; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceFilter.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceFilter.java new file mode 100644 index 00000000..1dafd366 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceFilter.java @@ -0,0 +1,17 @@ +package org.devgateway.toolkit.persistence.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class ServiceFilter extends ServiceCategory { + + private String fieldType; + + public String getFieldType() { + return fieldType; + } + + public void setFieldType(final String fieldType) { + this.fieldType = fieldType; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceMeasure.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceMeasure.java new file mode 100644 index 00000000..7d878333 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceMeasure.java @@ -0,0 +1,38 @@ +package org.devgateway.toolkit.persistence.dto; + +public class ServiceMeasure extends ServiceCategory { + + private String filter; + + private String expression; + + private String delegate; + + public ServiceMeasure() { + } + + public String getFilter() { + return filter; + } + + public void setFilter(final String filter) { + this.filter = filter; + } + + public String getExpression() { + return expression; + } + + public void setExpression(final String expression) { + this.expression = expression; + } + + public String getDelegate() { + return delegate; + } + + public void setDelegate(final String delegate) { + this.delegate = delegate; + } + +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceMetadata.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceMetadata.java new file mode 100644 index 00000000..c8ef6f9d --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceMetadata.java @@ -0,0 +1,103 @@ +package org.devgateway.toolkit.persistence.dto; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class ServiceMetadata implements Serializable { + + private String id; + + private String name; + + private String description; + + private String url; + + private String type; + + private String status; + + private String label; + + private Boolean tetsim; + + private List dimensions = new ArrayList<>(); + + public String getId() { + return id; + } + + public void setId(final String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } + + public String getUrl() { + return url; + } + + public void setUrl(final String url) { + this.url = url; + } + + public String getType() { + return type; + } + + public void setType(final String type) { + this.type = type; + } + + @Override + public String toString() { + return getName(); + } + + public String getStatus() { + return status; + } + + public void setStatus(final String status) { + this.status = status; + } + + public List getDimensions() { + return dimensions; + } + + public void setDimensions(final List dimensions) { + this.dimensions = dimensions; + } + + public String getLabel() { + return label; + } + + public void setLabel(final String label) { + this.label = label; + } + + public Boolean isTetsim() { + return tetsim; + } + + public void setTetsim(final Boolean tetsim) { + this.tetsim = tetsim; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceTextTranslation.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceTextTranslation.java new file mode 100644 index 00000000..5b4ad357 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/ServiceTextTranslation.java @@ -0,0 +1,33 @@ +package org.devgateway.toolkit.persistence.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.io.Serializable; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class ServiceTextTranslation implements Serializable { + private String text; + private String language; + + private ServiceCategory parent; + + public String getText() { + return text; + } + + public void setText(final String text) { + this.text = text; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(final String language) { + this.language = language; + } + + public void setParent(final ServiceCategory parent) { + this.parent = parent; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/TetsimExportOutput.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/TetsimExportOutput.java new file mode 100644 index 00000000..c2367e19 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/TetsimExportOutput.java @@ -0,0 +1,514 @@ +package org.devgateway.toolkit.persistence.dto; + +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; + +import java.io.Serializable; + +/** + * + * + * @author vchihai + */ +public class TetsimExportOutput implements Serializable { + + private Integer year; + + private Integer taxChange; + + private TobaccoProduct tobaccoProduct; + + private Double legalConsumptionOvershift; + + private Double legalConsumptionChangeOvershift; + + private Double consumptionIllicitOvershift; + + private Double exciseRevOvershift; + + private Double exciseRevChangeOvershift; + + private Double totalGovRevOvershift; + + private Double exciseBurdenOvershift; + + private Double totalTaxBurdenOvershift; + + private Double baselineTotalTaxBurdenOvershift; + + private Double retailPriceOvershift; + + private Double notOvershift; + + private Double exciseTaxOvershift; + + private Double vatOvershift; + + private Double levyOvershift; + + private Double legalConsumptionUndershift; + + private Double legalConsumptionChangeUndershift; + + private Double consumptionIllicitUndershift; + + private Double exciseRevUndershift; + + private Double exciseRevChangeUndershift; + + private Double totalGovRevUndershift; + + private Double exciseBurdenUndershift; + + private Double totalTaxBurdenUndershift; + + private Double baselineTotalTaxBurdenUndershift; + + private Double retailPriceUndershift; + + private Double notUndershift; + + private Double exciseTaxUndershift; + + private Double vatUndershift; + + private Double levyUndershift; + + private Double legalConsumptionPerfectshift; + + private Double legalConsumptionChangePerfectshift; + + private Double consumptionIllicitPerfectshift; + + private Double exciseRevPerfectshift; + + private Double exciseRevChangePerfectshift; + + private Double totalGovRevPerfectshift; + + private Double exciseBurdenPerfectshift; + + private Double totalTaxBurdenPerfectshift; + + private Double baselineTotalTaxBurdenPerfectshift; + + private Double retailPricePerfectshift; + + private Double notPerfectshift; + + private Double exciseTaxPerfectshift; + + private Double vatPerfectshift; + + private Double levyPerfectshift; + + public TetsimExportOutput() { + } + + public TetsimExportOutput(TetsimOutput overShift, TetsimOutput underShift, TetsimOutput perfectShift) { + this.year = overShift.getYear(); + this.taxChange = overShift.getTaxChange(); + this.tobaccoProduct = overShift.getTobaccoProduct(); + this.legalConsumptionOvershift = overShift.getLegalConsumption(); + this.legalConsumptionChangeOvershift = overShift.getLegalConsumptionChange(); + this.consumptionIllicitOvershift = overShift.getConsumptionIllicit(); + this.exciseRevOvershift = overShift.getExciseRev(); + this.exciseRevChangeOvershift = overShift.getExciseRevChange(); + this.totalGovRevOvershift = overShift.getTotalGovRev(); + this.exciseBurdenOvershift = overShift.getExciseBurden(); + this.totalTaxBurdenOvershift = overShift.getTotalTaxBurden(); + this.baselineTotalTaxBurdenOvershift = overShift.getTotalTaxBurdenBaseline(); + this.retailPriceOvershift = overShift.getRetailPrice(); + this.notOvershift = overShift.getNot(); + this.exciseTaxOvershift = overShift.getExciseTax(); + this.vatOvershift = overShift.getVat(); + this.levyOvershift = overShift.getLevy(); + this.legalConsumptionUndershift = underShift.getLegalConsumption(); + this.legalConsumptionChangeUndershift = underShift.getLegalConsumptionChange(); + this.consumptionIllicitUndershift = underShift.getConsumptionIllicit(); + this.exciseRevUndershift = underShift.getExciseRev(); + this.exciseRevChangeUndershift = underShift.getExciseRevChange(); + this.totalGovRevUndershift = underShift.getTotalGovRev(); + this.exciseBurdenUndershift = underShift.getExciseBurden(); + this.totalTaxBurdenUndershift = underShift.getTotalTaxBurden(); + this.baselineTotalTaxBurdenUndershift = underShift.getTotalTaxBurdenBaseline(); + this.retailPriceUndershift = underShift.getRetailPrice(); + this.notUndershift = underShift.getNot(); + this.exciseTaxUndershift = underShift.getExciseTax(); + this.vatUndershift = underShift.getVat(); + this.levyUndershift = underShift.getLevy(); + this.legalConsumptionPerfectshift = perfectShift.getLegalConsumption(); + this.legalConsumptionChangePerfectshift = perfectShift.getLegalConsumptionChange(); + this.consumptionIllicitPerfectshift = perfectShift.getConsumptionIllicit(); + this.exciseRevPerfectshift = perfectShift.getExciseRev(); + this.exciseRevChangePerfectshift = perfectShift.getExciseRevChange(); + this.totalGovRevPerfectshift = perfectShift.getTotalGovRev(); + this.exciseBurdenPerfectshift = perfectShift.getExciseBurden(); + this.totalTaxBurdenPerfectshift = perfectShift.getTotalTaxBurden(); + this.baselineTotalTaxBurdenPerfectshift = perfectShift.getTotalTaxBurdenBaseline(); + this.retailPricePerfectshift = perfectShift.getRetailPrice(); + this.notPerfectshift = perfectShift.getNot(); + this.exciseTaxPerfectshift = perfectShift.getExciseTax(); + this.vatPerfectshift = perfectShift.getVat(); + this.levyPerfectshift = perfectShift.getLevy(); + } + + public Integer getYear() { + return year; + } + + public void setYear(final Integer year) { + this.year = year; + } + + public Integer getTaxChange() { + return taxChange; + } + + public void setTaxChange(final Integer taxChange) { + this.taxChange = taxChange; + } + + public TobaccoProduct getTobaccoProduct() { + return tobaccoProduct; + } + + public void setTobaccoProduct(final TobaccoProduct tobaccoProduct) { + this.tobaccoProduct = tobaccoProduct; + } + + public Double getLegalConsumptionOvershift() { + return legalConsumptionOvershift; + } + + public void setLegalConsumptionOvershift(final Double legalConsumptionOvershift) { + this.legalConsumptionOvershift = legalConsumptionOvershift; + } + + public Double getLegalConsumptionChangeOvershift() { + return legalConsumptionChangeOvershift; + } + + public void setLegalConsumptionChangeOvershift(final Double legalConsumptionChangeOvershift) { + this.legalConsumptionChangeOvershift = legalConsumptionChangeOvershift; + } + + public Double getConsumptionIllicitOvershift() { + return consumptionIllicitOvershift; + } + + public void setConsumptionIllicitOvershift(final Double consumptionIllicitOvershift) { + this.consumptionIllicitOvershift = consumptionIllicitOvershift; + } + + public Double getExciseRevOvershift() { + return exciseRevOvershift; + } + + public void setExciseRevOvershift(final Double exciseRevOvershift) { + this.exciseRevOvershift = exciseRevOvershift; + } + + public Double getExciseRevChangeOvershift() { + return exciseRevChangeOvershift; + } + + public void setExciseRevChangeOvershift(final Double exciseRevChangeOvershift) { + this.exciseRevChangeOvershift = exciseRevChangeOvershift; + } + + public Double getTotalGovRevOvershift() { + return totalGovRevOvershift; + } + + public void setTotalGovRevOvershift(final Double totalGovRevOvershift) { + this.totalGovRevOvershift = totalGovRevOvershift; + } + + public Double getExciseBurdenOvershift() { + return exciseBurdenOvershift; + } + + public void setExciseBurdenOvershift(final Double exciseBurdenOvershift) { + this.exciseBurdenOvershift = exciseBurdenOvershift; + } + + public Double getTotalTaxBurdenOvershift() { + return totalTaxBurdenOvershift; + } + + public void setTotalTaxBurdenOvershift(final Double totalTaxBurdenOvershift) { + this.totalTaxBurdenOvershift = totalTaxBurdenOvershift; + } + + public Double getRetailPriceOvershift() { + return retailPriceOvershift; + } + + public void setRetailPriceOvershift(final Double retailPriceOvershift) { + this.retailPriceOvershift = retailPriceOvershift; + } + + public Double getNotOvershift() { + return notOvershift; + } + + public void setNotOvershift(final Double notOvershift) { + this.notOvershift = notOvershift; + } + + public Double getExciseTaxOvershift() { + return exciseTaxOvershift; + } + + public void setExciseTaxOvershift(final Double exciseTaxOvershift) { + this.exciseTaxOvershift = exciseTaxOvershift; + } + + public Double getVatOvershift() { + return vatOvershift; + } + + public void setVatOvershift(final Double vatOvershift) { + this.vatOvershift = vatOvershift; + } + + public Double getLevyOvershift() { + return levyOvershift; + } + + public void setLevyOvershift(final Double levyOvershift) { + this.levyOvershift = levyOvershift; + } + + public Double getLegalConsumptionUndershift() { + return legalConsumptionUndershift; + } + + public void setLegalConsumptionUndershift(final Double legalConsumptionUndershift) { + this.legalConsumptionUndershift = legalConsumptionUndershift; + } + + public Double getLegalConsumptionChangeUndershift() { + return legalConsumptionChangeUndershift; + } + + public void setLegalConsumptionChangeUndershift(final Double legalConsumptionChangeUndershift) { + this.legalConsumptionChangeUndershift = legalConsumptionChangeUndershift; + } + + public Double getConsumptionIllicitUndershift() { + return consumptionIllicitUndershift; + } + + public void setConsumptionIllicitUndershift(final Double consumptionIllicitUndershift) { + this.consumptionIllicitUndershift = consumptionIllicitUndershift; + } + + public Double getExciseRevUndershift() { + return exciseRevUndershift; + } + + public void setExciseRevUndershift(final Double exciseRevUndershift) { + this.exciseRevUndershift = exciseRevUndershift; + } + + public Double getExciseRevChangeUndershift() { + return exciseRevChangeUndershift; + } + + public void setExciseRevChangeUndershift(final Double exciseRevChangeUndershift) { + this.exciseRevChangeUndershift = exciseRevChangeUndershift; + } + + public Double getTotalGovRevUndershift() { + return totalGovRevUndershift; + } + + public void setTotalGovRevUndershift(final Double totalGovRevUndershift) { + this.totalGovRevUndershift = totalGovRevUndershift; + } + + public Double getExciseBurdenUndershift() { + return exciseBurdenUndershift; + } + + public void setExciseBurdenUndershift(final Double exciseBurdenUndershift) { + this.exciseBurdenUndershift = exciseBurdenUndershift; + } + + public Double getTotalTaxBurdenUndershift() { + return totalTaxBurdenUndershift; + } + + public void setTotalTaxBurdenUndershift(final Double totalTaxBurdenUndershift) { + this.totalTaxBurdenUndershift = totalTaxBurdenUndershift; + } + + public Double getRetailPriceUndershift() { + return retailPriceUndershift; + } + + public void setRetailPriceUndershift(final Double retailPriceUndershift) { + this.retailPriceUndershift = retailPriceUndershift; + } + + public Double getNotUndershift() { + return notUndershift; + } + + public void setNotUndershift(final Double notUndershift) { + this.notUndershift = notUndershift; + } + + public Double getExciseTaxUndershift() { + return exciseTaxUndershift; + } + + public void setExciseTaxUndershift(final Double exciseTaxUndershift) { + this.exciseTaxUndershift = exciseTaxUndershift; + } + + public Double getVatUndershift() { + return vatUndershift; + } + + public void setVatUndershift(final Double vatUndershift) { + this.vatUndershift = vatUndershift; + } + + public Double getLevyUndershift() { + return levyUndershift; + } + + public void setLevyUndershift(final Double levyUndershift) { + this.levyUndershift = levyUndershift; + } + + public Double getBaselineTotalTaxBurdenOvershift() { + return baselineTotalTaxBurdenOvershift; + } + + public void setBaselineTotalTaxBurdenOvershift(final Double baselineTotalTaxBurdenOvershift) { + this.baselineTotalTaxBurdenOvershift = baselineTotalTaxBurdenOvershift; + } + + public Double getBaselineTotalTaxBurdenUndershift() { + return baselineTotalTaxBurdenUndershift; + } + + public void setBaselineTotalTaxBurdenUndershift(final Double baselineTotalTaxBurdenUndershift) { + this.baselineTotalTaxBurdenUndershift = baselineTotalTaxBurdenUndershift; + } + + public Double getLegalConsumptionPerfectshift() { + return legalConsumptionPerfectshift; + } + + public void setLegalConsumptionPerfectshift(final Double legalConsumptionPerfectshift) { + this.legalConsumptionPerfectshift = legalConsumptionPerfectshift; + } + + public Double getLegalConsumptionChangePerfectshift() { + return legalConsumptionChangePerfectshift; + } + + public void setLegalConsumptionChangePerfectshift(final Double legalConsumptionChangePerfectshift) { + this.legalConsumptionChangePerfectshift = legalConsumptionChangePerfectshift; + } + + public Double getConsumptionIllicitPerfectshift() { + return consumptionIllicitPerfectshift; + } + + public void setConsumptionIllicitPerfectshift(final Double consumptionIllicitPerfectshift) { + this.consumptionIllicitPerfectshift = consumptionIllicitPerfectshift; + } + + public Double getExciseRevPerfectshift() { + return exciseRevPerfectshift; + } + + public void setExciseRevPerfectshift(final Double exciseRevPerfectshift) { + this.exciseRevPerfectshift = exciseRevPerfectshift; + } + + public Double getExciseRevChangePerfectshift() { + return exciseRevChangePerfectshift; + } + + public void setExciseRevChangePerfectshift(final Double exciseRevChangePerfectshift) { + this.exciseRevChangePerfectshift = exciseRevChangePerfectshift; + } + + public Double getTotalGovRevPerfectshift() { + return totalGovRevPerfectshift; + } + + public void setTotalGovRevPerfectshift(final Double totalGovRevPerfectshift) { + this.totalGovRevPerfectshift = totalGovRevPerfectshift; + } + + public Double getExciseBurdenPerfectshift() { + return exciseBurdenPerfectshift; + } + + public void setExciseBurdenPerfectshift(final Double exciseBurdenPerfectshift) { + this.exciseBurdenPerfectshift = exciseBurdenPerfectshift; + } + + public Double getTotalTaxBurdenPerfectshift() { + return totalTaxBurdenPerfectshift; + } + + public void setTotalTaxBurdenPerfectshift(final Double totalTaxBurdenPerfectshift) { + this.totalTaxBurdenPerfectshift = totalTaxBurdenPerfectshift; + } + + public Double getBaselineTotalTaxBurdenPerfectshift() { + return baselineTotalTaxBurdenPerfectshift; + } + + public void setBaselineTotalTaxBurdenPerfectshift(final Double baselineTotalTaxBurdenPerfectshift) { + this.baselineTotalTaxBurdenPerfectshift = baselineTotalTaxBurdenPerfectshift; + } + + public Double getRetailPricePerfectshift() { + return retailPricePerfectshift; + } + + public void setRetailPricePerfectshift(final Double retailPricePerfectshift) { + this.retailPricePerfectshift = retailPricePerfectshift; + } + + public Double getNotPerfectshift() { + return notPerfectshift; + } + + public void setNotPerfectshift(final Double notPerfectshift) { + this.notPerfectshift = notPerfectshift; + } + + public Double getExciseTaxPerfectshift() { + return exciseTaxPerfectshift; + } + + public void setExciseTaxPerfectshift(final Double exciseTaxPerfectshift) { + this.exciseTaxPerfectshift = exciseTaxPerfectshift; + } + + public Double getVatPerfectshift() { + return vatPerfectshift; + } + + public void setVatPerfectshift(final Double vatPerfectshift) { + this.vatPerfectshift = vatPerfectshift; + } + + public Double getLevyPerfectshift() { + return levyPerfectshift; + } + + public void setLevyPerfectshift(final Double levyPerfectshift) { + this.levyPerfectshift = levyPerfectshift; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/TetsimOutput.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/TetsimOutput.java new file mode 100644 index 00000000..1c38fc0d --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/dto/TetsimOutput.java @@ -0,0 +1,193 @@ +package org.devgateway.toolkit.persistence.dto; + +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; + +import java.io.Serializable; + +/** + * + * + * @author vchihai + */ +public class TetsimOutput implements Serializable { + + private Integer year; + + private Integer taxChange; + + private TobaccoProduct tobaccoProduct; + + private String shifting; + + private Double legalConsumption; + + private Double legalConsumptionChange; + + private Double consumptionIllicit; + + private Double exciseRev; + + private Double exciseRevChange; + + private Double totalGovRev; + + private Double exciseBurden; + + private Double totalTaxBurden; + + private Double totalTaxBurdenBaseline; + + private Double retailPrice; + + private Double not; + + private Double exciseTax; + + private Double vat; + + private Double levy; + + public Integer getYear() { + return year; + } + + public void setYear(final Integer year) { + this.year = year; + } + + public Integer getTaxChange() { + return taxChange; + } + + public void setTaxChange(final Integer taxChange) { + this.taxChange = taxChange; + } + + public TobaccoProduct getTobaccoProduct() { + return tobaccoProduct; + } + + public void setTobaccoProduct(final TobaccoProduct tobaccoProduct) { + this.tobaccoProduct = tobaccoProduct; + } + + public String getShifting() { + return shifting; + } + + public void setShifting(final String shifting) { + this.shifting = shifting; + } + + public Double getLegalConsumption() { + return legalConsumption; + } + + public void setLegalConsumption(final Double legalConsumption) { + this.legalConsumption = legalConsumption; + } + + public Double getConsumptionIllicit() { + return consumptionIllicit; + } + + public void setConsumptionIllicit(final Double consumptionIllicit) { + this.consumptionIllicit = consumptionIllicit; + } + + public Double getExciseRev() { + return exciseRev; + } + + public void setExciseRev(final Double exciseRev) { + this.exciseRev = exciseRev; + } + + public Double getTotalGovRev() { + return totalGovRev; + } + + public void setTotalGovRev(final Double totalGovRev) { + this.totalGovRev = totalGovRev; + } + + public Double getExciseBurden() { + return exciseBurden; + } + + public void setExciseBurden(final Double exciseBurden) { + this.exciseBurden = exciseBurden; + } + + public Double getTotalTaxBurden() { + return totalTaxBurden; + } + + public void setTotalTaxBurden(final Double totalTaxBurden) { + this.totalTaxBurden = totalTaxBurden; + } + + public Double getRetailPrice() { + return retailPrice; + } + + public void setRetailPrice(final Double retailPrice) { + this.retailPrice = retailPrice; + } + + public Double getNot() { + return not; + } + + public void setNot(final Double not) { + this.not = not; + } + + public Double getExciseTax() { + return exciseTax; + } + + public void setExciseTax(final Double exciseTax) { + this.exciseTax = exciseTax; + } + + public Double getVat() { + return vat; + } + + public void setVat(final Double vat) { + this.vat = vat; + } + + public Double getLevy() { + return levy; + } + + public void setLevy(final Double levy) { + this.levy = levy; + } + + public Double getLegalConsumptionChange() { + return legalConsumptionChange; + } + + public void setLegalConsumptionChange(final Double legalConsumptionChange) { + this.legalConsumptionChange = legalConsumptionChange; + } + + public Double getExciseRevChange() { + return exciseRevChange; + } + + public void setExciseRevChange(final Double exciseRevChange) { + this.exciseRevChange = exciseRevChange; + } + + public Double getTotalTaxBurdenBaseline() { + return totalTaxBurdenBaseline; + } + + public void setTotalTaxBurdenBaseline(final Double totalTaxBurdenBaseline) { + this.totalTaxBurdenBaseline = totalTaxBurdenBaseline; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/excel/reader/XExcelFileReader.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/excel/reader/XExcelFileReader.java index f65ef6e9..75de2237 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/excel/reader/XExcelFileReader.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/excel/reader/XExcelFileReader.java @@ -1,6 +1,6 @@ package org.devgateway.toolkit.persistence.excel.reader; -import org.apache.poi.hssf.util.CellReference; +import org.apache.poi.ss.util.CellReference; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable; import org.apache.poi.xssf.eventusermodel.XSSFReader; @@ -141,7 +141,7 @@ private String getCellValue(final String cellType) throws XMLStreamException { if (xmlReader.getLocalName().equals("v")) { if (cellType != null && cellType.equals("s")) { final int idx = Integer.parseInt(xmlReader.getElementText()); - return new XSSFRichTextString(stringsTable.getEntryAt(idx)).toString(); + return stringsTable.getItemAt(idx).toString(); } else { return xmlReader.getElementText(); } diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/CacheHibernateQueryResult.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/CacheHibernateQueryResult.java index 2ccc0b22..62db4a56 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/CacheHibernateQueryResult.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/CacheHibernateQueryResult.java @@ -5,7 +5,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.persistence.QueryHint; +import jakarta.persistence.QueryHint; import org.springframework.data.jpa.repository.QueryHints; diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/SpecificationContext.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/SpecificationContext.java index ea6b044b..93ea2d9c 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/SpecificationContext.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/SpecificationContext.java @@ -1,8 +1,8 @@ package org.devgateway.toolkit.persistence.repository; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Root; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Root; /** * @author Nadejda Mandrescu diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/data/CSVDatasetRepository.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/data/CSVDatasetRepository.java new file mode 100644 index 00000000..c1b3244a --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/data/CSVDatasetRepository.java @@ -0,0 +1,27 @@ +package org.devgateway.toolkit.persistence.repository.data; + +import org.devgateway.toolkit.persistence.dao.data.CSVDataset; +import org.devgateway.toolkit.persistence.repository.norepository.UniquePropertyRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import jakarta.transaction.Transactional; +import java.util.List; + +@Transactional +public interface CSVDatasetRepository extends DatasetRepository, + UniquePropertyRepository { + + @Query("select td from CSVDataset td where td.status like 'DELETED'") + List findAllDeleted(); + + @Query("select td from CSVDataset td where td.status like 'PUBLISHING' or td.status like 'UNPUBLISHING'") + List findAllInProgress(); + + @Query ("select count(e) from #{#entityName} e where (:year is null or e.year=:year) " + + "and e.status not in ('DELETED')") + long countByNonPublished(@Param("year") Integer year); + + @Query("select td from CSVDataset td where td.status not like 'DELETED' and td.destinationService like :service") + List findAllNotDeletedForService(@Param("service") String service); +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/data/DatasetRepository.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/data/DatasetRepository.java new file mode 100644 index 00000000..411af89d --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/data/DatasetRepository.java @@ -0,0 +1,13 @@ +package org.devgateway.toolkit.persistence.repository.data; + +import org.devgateway.toolkit.persistence.dao.data.Dataset; +import org.devgateway.toolkit.persistence.repository.norepository.BaseJpaRepository; +import org.springframework.data.repository.NoRepositoryBean; + +import java.util.List; + +@NoRepositoryBean +public interface DatasetRepository extends BaseJpaRepository { + + List findAllNotDeletedForService(String service); +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/data/TetsimDatasetRepository.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/data/TetsimDatasetRepository.java new file mode 100644 index 00000000..ab9c87b2 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/data/TetsimDatasetRepository.java @@ -0,0 +1,27 @@ +package org.devgateway.toolkit.persistence.repository.data; + +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.repository.norepository.UniquePropertyRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import jakarta.transaction.Transactional; +import java.util.List; + +@Transactional +public interface TetsimDatasetRepository extends DatasetRepository, + UniquePropertyRepository { + + @Query("select td from TetsimDataset td where td.status like 'DELETED'") + List findAllDeleted(); + + @Query("select td from TetsimDataset td where td.status like 'PUBLISHING' or td.status like 'UNPUBLISHING'") + List findAllInProgress(); + + @Query ("select count(e) from #{#entityName} e where (:year is null or e.year=:year) " + + "and e.status not in ('DELETED')") + long countByNonPublished(@Param("year") Integer year); + + @Query("select td from CSVDataset td where td.status not in ('DELETED') and td.destinationService like :service") + List findAllNotDeletedForService(@Param("service") String service); +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/norepository/SpecificationUtils.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/norepository/SpecificationUtils.java index cc0d5fa0..ff213865 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/norepository/SpecificationUtils.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/norepository/SpecificationUtils.java @@ -2,10 +2,10 @@ import org.apache.commons.lang3.StringUtils; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.Expression; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.Expression; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; /** * @author Nadejda Mandrescu diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/norepository/UniquePropertyRepository.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/norepository/UniquePropertyRepository.java index 6853ac8a..deacd49b 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/norepository/UniquePropertyRepository.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/repository/norepository/UniquePropertyRepository.java @@ -5,8 +5,8 @@ import org.springframework.data.repository.NoRepositoryBean; import org.springframework.transaction.annotation.Transactional; -import javax.persistence.criteria.Path; -import javax.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Path; +import jakarta.persistence.criteria.Predicate; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/serializer/ServiceTextTranslationDeserializer.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/serializer/ServiceTextTranslationDeserializer.java new file mode 100644 index 00000000..c919c21b --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/serializer/ServiceTextTranslationDeserializer.java @@ -0,0 +1,47 @@ +package org.devgateway.toolkit.persistence.serializer; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer; +import org.devgateway.toolkit.persistence.dto.ServiceTextTranslation; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author Viorel Chihai + */ +public class ServiceTextTranslationDeserializer extends StdScalarDeserializer> { + + protected ServiceTextTranslationDeserializer(Class> t) { + super(t); + } + + ServiceTextTranslationDeserializer() { + this(null); + } + + @Override + public List deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + if (jp.getCurrentToken() == JsonToken.START_OBJECT) { + JsonDeserializer deserializer = ctxt.findRootValueDeserializer(ctxt.constructType(Map.class)); + Map translations = (Map) deserializer.deserialize(jp, ctxt); + List textTranslations = new ArrayList<>(); + translations.forEach((key, value) -> { + ServiceTextTranslation translation = new ServiceTextTranslation(); + translation.setLanguage(key); + translation.setText(value); + textTranslations.add(translation); + }); + return textTranslations; + } + + return null; + } + +} + diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/serializer/ServiceTextTranslationSerializer.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/serializer/ServiceTextTranslationSerializer.java new file mode 100644 index 00000000..c28643bf --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/serializer/ServiceTextTranslationSerializer.java @@ -0,0 +1,35 @@ +package org.devgateway.toolkit.persistence.serializer; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.devgateway.toolkit.persistence.dto.ServiceTextTranslation; + +import java.io.IOException; +import java.util.List; + +/** + * @author Viorel Chihai + */ +public class ServiceTextTranslationSerializer extends StdSerializer> { + + protected ServiceTextTranslationSerializer(Class> t) { + super(t); + } + + ServiceTextTranslationSerializer() { + this(null); + } + + @Override + public void serialize(final List localeTexts, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) throws IOException { + + jsonGenerator.writeStartObject(); + for (ServiceTextTranslation localeText : localeTexts) { + jsonGenerator.writeStringField(localeText.getLanguage(), localeText.getText()); + } + jsonGenerator.writeEndObject(); + } + +} + diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/AdminSettingsServiceImpl.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/AdminSettingsServiceImpl.java index c9b542f1..64738666 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/AdminSettingsServiceImpl.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/AdminSettingsServiceImpl.java @@ -55,12 +55,12 @@ private void preProcessRebootAlert(final S as) { @Override public AdminSettings get() { List entries = repository().findAll(); - return entries.isEmpty() ? null : entries.get(0); + return entries.isEmpty() ? null : entries.get(0); } private AdminSettings getOrDefault() { List entries = repository().findAll(); - return entries.isEmpty() ? new AdminSettings() : entries.get(0); + return entries.isEmpty() ? new AdminSettings() : entries.get(0); } @Override diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/BaseJpaService.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/BaseJpaService.java index c58f88c1..aa1e7a3f 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/BaseJpaService.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/BaseJpaService.java @@ -16,6 +16,8 @@ public interface BaseJpaService { List findAll(Sort sort); + List findAllSorted(); + List findAll(Specification spec); Page findAll(Specification spec, Pageable pageable); diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/BaseJpaServiceImpl.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/BaseJpaServiceImpl.java index 0d98ab1f..b2fe66d2 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/BaseJpaServiceImpl.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/BaseJpaServiceImpl.java @@ -2,8 +2,6 @@ import org.devgateway.toolkit.persistence.dao.GenericPersistable; import org.devgateway.toolkit.persistence.repository.norepository.BaseJpaRepository; -import org.springframework.cache.annotation.CacheConfig; -import org.springframework.cache.annotation.Cacheable; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -30,6 +28,11 @@ public List findAll(final Sort sort) { return repository().findAll(sort); } + @Override + public List findAllSorted() { + return repository().findAll(getSort()); + } + @Override public List findAll(final Specification spec) { return repository().findAll(spec); @@ -89,6 +92,10 @@ public void delete(final T entity) { repository().delete(entity); } + public Sort getSort() { + return Sort.by(Sort.Direction.ASC, "id"); + } + protected abstract BaseJpaRepository repository(); } diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/FileMetadataServiceImpl.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/FileMetadataServiceImpl.java index 1a3782a2..50cb8321 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/FileMetadataServiceImpl.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/FileMetadataServiceImpl.java @@ -4,7 +4,6 @@ import org.devgateway.toolkit.persistence.repository.FileMetadataRepository; import org.devgateway.toolkit.persistence.repository.norepository.BaseJpaRepository; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.CacheConfig; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/PersonServiceImpl.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/PersonServiceImpl.java index 4aafb948..7d7436ef 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/PersonServiceImpl.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/PersonServiceImpl.java @@ -4,7 +4,6 @@ import org.devgateway.toolkit.persistence.repository.PersonRepository; import org.devgateway.toolkit.persistence.repository.norepository.BaseJpaRepository; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.CacheConfig; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/RoleServiceImpl.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/RoleServiceImpl.java index 6ebd4111..0830e818 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/RoleServiceImpl.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/RoleServiceImpl.java @@ -5,7 +5,6 @@ import org.devgateway.toolkit.persistence.repository.norepository.BaseJpaRepository; import org.devgateway.toolkit.persistence.repository.norepository.TextSearchableRepository; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.CacheConfig; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/TestFormServiceImpl.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/TestFormServiceImpl.java index 54019f33..c4f0ddd2 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/TestFormServiceImpl.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/TestFormServiceImpl.java @@ -5,7 +5,6 @@ import org.devgateway.toolkit.persistence.repository.norepository.BaseJpaRepository; import org.devgateway.toolkit.persistence.repository.norepository.UniquePropertyRepository; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.CacheConfig; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/category/GroupServiceImpl.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/category/GroupServiceImpl.java index cea24820..091f9d55 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/category/GroupServiceImpl.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/category/GroupServiceImpl.java @@ -6,7 +6,6 @@ import org.devgateway.toolkit.persistence.repository.norepository.TextSearchableRepository; import org.devgateway.toolkit.persistence.service.BaseJpaServiceImpl; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.CacheConfig; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/CSVDatasetService.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/CSVDatasetService.java new file mode 100644 index 00000000..4734870f --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/CSVDatasetService.java @@ -0,0 +1,7 @@ +package org.devgateway.toolkit.persistence.service.data; + +import org.devgateway.toolkit.persistence.dao.data.CSVDataset; + +public interface CSVDatasetService extends DatasetService { + +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/CSVDatasetServiceImpl.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/CSVDatasetServiceImpl.java new file mode 100644 index 00000000..66af8e14 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/CSVDatasetServiceImpl.java @@ -0,0 +1,58 @@ +package org.devgateway.toolkit.persistence.service.data; + +import org.devgateway.toolkit.persistence.dao.data.CSVDataset; +import org.devgateway.toolkit.persistence.repository.data.CSVDatasetRepository; +import org.devgateway.toolkit.persistence.repository.norepository.BaseJpaRepository; +import org.devgateway.toolkit.persistence.repository.norepository.UniquePropertyRepository; +import org.devgateway.toolkit.persistence.service.BaseJpaServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@CacheConfig(cacheNames = "servicesCache") +@Transactional(readOnly = true) +public class CSVDatasetServiceImpl extends BaseJpaServiceImpl implements CSVDatasetService { + + @Autowired + private CSVDatasetRepository csvDatasetRepository; + + @Override + public CSVDataset newInstance() { + return new CSVDataset(); + } + + @Override + protected BaseJpaRepository repository() { + return csvDatasetRepository; + } + + @Override + public UniquePropertyRepository uniquePropertyRepository() { + return csvDatasetRepository; + } + + @Override + public List findAllDeleted() { + return csvDatasetRepository.findAllDeleted(); + } + + @Override + public List findAllNotDeletedForService(final String service) { + return csvDatasetRepository.findAllNotDeletedForService(service); + } + + @Override + public List findAllInProgress() { + return csvDatasetRepository.findAllInProgress(); + } + + @Override + public long countByNonPublished(final Integer year) { + return csvDatasetRepository.countByNonPublished(year); + } + +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/DatasetService.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/DatasetService.java new file mode 100644 index 00000000..e5273ccd --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/DatasetService.java @@ -0,0 +1,19 @@ +package org.devgateway.toolkit.persistence.service.data; + +import org.devgateway.toolkit.persistence.dao.data.Dataset; +import org.devgateway.toolkit.persistence.service.BaseJpaService; +import org.devgateway.toolkit.persistence.service.UniquePropertyService; + +import java.util.List; + +public interface DatasetService extends BaseJpaService, UniquePropertyService { + + List findAllDeleted(); + + List findAllNotDeletedForService(String service); + + List findAllInProgress(); + + long countByNonPublished(Integer year); + +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/TetsimDatasetService.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/TetsimDatasetService.java new file mode 100644 index 00000000..2ac24018 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/TetsimDatasetService.java @@ -0,0 +1,7 @@ +package org.devgateway.toolkit.persistence.service.data; + +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; + +public interface TetsimDatasetService extends DatasetService { + +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/TetsimDatasetServiceImpl.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/TetsimDatasetServiceImpl.java new file mode 100644 index 00000000..1d337037 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/data/TetsimDatasetServiceImpl.java @@ -0,0 +1,58 @@ +package org.devgateway.toolkit.persistence.service.data; + +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.repository.data.TetsimDatasetRepository; +import org.devgateway.toolkit.persistence.repository.norepository.BaseJpaRepository; +import org.devgateway.toolkit.persistence.repository.norepository.UniquePropertyRepository; +import org.devgateway.toolkit.persistence.service.BaseJpaServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@CacheConfig(cacheNames = "servicesCache") +@Transactional(readOnly = true) +public class TetsimDatasetServiceImpl extends BaseJpaServiceImpl implements TetsimDatasetService { + + @Autowired + private TetsimDatasetRepository tetsimDatasetRepository; + + @Override + public TetsimDataset newInstance() { + return new TetsimDataset(); + } + + @Override + protected BaseJpaRepository repository() { + return tetsimDatasetRepository; + } + + @Override + public UniquePropertyRepository uniquePropertyRepository() { + return tetsimDatasetRepository; + } + + @Override + public List findAllDeleted() { + return tetsimDatasetRepository.findAllDeleted(); + } + + @Override + public List findAllInProgress() { + return tetsimDatasetRepository.findAllInProgress(); + } + + @Override + public long countByNonPublished(final Integer year) { + return tetsimDatasetRepository.countByNonPublished(year); + } + + @Override + public List findAllNotDeletedForService(final String service) { + return tetsimDatasetRepository.findAllNotDeletedForService(service); + } + +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/service/tetsim/TetsimOutputService.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/tetsim/TetsimOutputService.java new file mode 100644 index 00000000..1337df26 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/service/tetsim/TetsimOutputService.java @@ -0,0 +1,109 @@ +package org.devgateway.toolkit.persistence.service.tetsim; + +import com.google.common.collect.ImmutableList; +import com.opencsv.CSVWriter; +import com.opencsv.bean.HeaderColumnNameMappingStrategy; +import com.opencsv.bean.StatefulBeanToCsv; +import com.opencsv.bean.StatefulBeanToCsvBuilder; +import com.opencsv.exceptions.CsvDataTypeMismatchException; +import com.opencsv.exceptions.CsvRequiredFieldEmptyException; +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; +import org.devgateway.toolkit.persistence.dto.TetsimExportOutput; +import org.devgateway.toolkit.persistence.dto.TetsimOutput; +import org.devgateway.toolkit.persistence.service.data.TetsimDatasetService; +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputOvershiftCalculator; +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputPerfectshiftCalculator; +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputUndershiftCalculator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class TetsimOutputService { + + public static final int MAX_TAX_CHANGE = 100; + + public static final List TETSIM_CSV_FIELDS = new ImmutableList.Builder() + .add("year", "taxChange", "tobaccoProduct", "legalConsumptionOvershift", "legalConsumptionChangeOvershift", + "consumptionIllicitOvershift", "exciseRevOvershift", "exciseRevChangeOvershift", + "totalGovRevOvershift", "exciseBurdenOvershift", "totalTaxBurdenOvershift", + "baselineTotalTaxBurdenOvershift", "retailPriceOvershift", "notOvershift", "exciseTaxOvershift", + "vatOvershift", "levyOvershift", "legalConsumptionUndershift", "legalConsumptionChangeUndershift", + "consumptionIllicitUndershift", "exciseRevUndershift", "exciseRevChangeUndershift", + "totalGovRevUndershift", "exciseBurdenUndershift", "totalTaxBurdenUndershift", + "baselineTotalTaxBurdenUndershift", "retailPriceUndershift", "notUndershift", "exciseTaxUndershift", + "vatUndershift", "levyUndershift", "legalConsumptionPerfectshift", + "legalConsumptionChangePerfectshift", "consumptionIllicitPerfectshift", "exciseRevPerfectshift", + "exciseRevChangePerfectshift", "totalGovRevPerfectshift", "exciseBurdenPerfectshift", + "totalTaxBurdenPerfectshift", "baselineTotalTaxBurdenPerfectshift", "retailPricePerfectshift", + "notPerfectshift", "exciseTaxPerfectshift", "vatPerfectshift", "levyPerfectshift") + .build(); + @Autowired + private TetsimDatasetService tetsimDatasetService; + + /** + * Get the tetsim outputs + * + * @param datasetId + * @return + */ + public List getTetsimOutputs(Long datasetId) { + TetsimDataset dataset = tetsimDatasetService.findById(datasetId).get(); + List outputs = new ArrayList<>(); + + for (int i = 0; i <= MAX_TAX_CHANGE; i++) { + for (TobaccoProduct t : TobaccoProduct.values()) { + TetsimOutput overShift = new TetsimOutputOvershiftCalculator(dataset, i).calculate(t); + TetsimOutput underShift = new TetsimOutputUndershiftCalculator(dataset, i).calculate(t); + TetsimOutput perfectShift = new TetsimOutputPerfectshiftCalculator(dataset, i).calculate(t); + outputs.add(new TetsimExportOutput(overShift, underShift, perfectShift)); + } + } + + return outputs; + } + + + /** + * Get the tetsim outputs in csv format + * @param datasetId + * @return + * @throws IOException + * @throws CsvRequiredFieldEmptyException + * @throws CsvDataTypeMismatchException + */ + public byte[] getTetsimCSVDatasetOutputs(Long datasetId) throws IOException, CsvRequiredFieldEmptyException, + CsvDataTypeMismatchException { + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + OutputStreamWriter streamWriter = new OutputStreamWriter(stream); + + final List columns = TETSIM_CSV_FIELDS.stream() + .map(String::toUpperCase) + .collect(Collectors.toList()); + + HeaderColumnNameMappingStrategy columnStrategy = new HeaderColumnNameMappingStrategy<>(); + columnStrategy.setType(TetsimExportOutput.class); + columnStrategy.setColumnOrderOnWrite(Comparator.comparingInt(columns::indexOf)); + + StatefulBeanToCsv sbc = new StatefulBeanToCsvBuilder(streamWriter) + .withSeparator(CSVWriter.DEFAULT_SEPARATOR) + .withApplyQuotesToAll(false) + .withMappingStrategy(columnStrategy) + .build(); + + sbc.write(getTetsimOutputs(datasetId)); + streamWriter.flush(); + + return stream.toByteArray(); + } + +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/spring/CacheConfiguration.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/spring/CacheConfiguration.java index 94ff4d9b..4cab53b7 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/spring/CacheConfiguration.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/spring/CacheConfiguration.java @@ -14,23 +14,23 @@ */ package org.devgateway.toolkit.persistence.spring; +import org.ehcache.jsr107.EhcacheCachingProvider; import org.hibernate.cache.jcache.ConfigSettings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer; import org.springframework.cache.annotation.EnableCaching; -import org.springframework.cache.ehcache.EhCacheCacheManager; -import org.springframework.cache.ehcache.EhCacheManagerFactoryBean; import org.springframework.cache.jcache.JCacheCacheManager; -import org.springframework.cache.jcache.JCacheManagerFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.core.io.ClassPathResource; import org.springframework.data.auditing.DateTimeProvider; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -import javax.cache.CacheManager; -import javax.management.MBeanServer; +//import javax.cache.Caching; +//import javax.cache.CacheManager; +//import javax.management.MBeanServer; +import java.net.URISyntaxException; import java.time.ZonedDateTime; import java.util.Optional; @@ -42,19 +42,29 @@ @EnableCaching @EnableJpaAuditing(dateTimeProviderRef = "auditingDateTimeProvider") public class CacheConfiguration { + + private static final Logger logger = LoggerFactory.getLogger(CacheConfiguration.class); @Bean(name = "auditingDateTimeProvider") public DateTimeProvider dateTimeProvider() { return () -> Optional.of(ZonedDateTime.now()); } - @Autowired(required = false) - private MBeanServer mbeanServer; +// @Autowired(required = false) +// private MBeanServer mbeanServer; @Bean public HibernatePropertiesCustomizer hibernateSecondLevelCacheCustomizer(final JCacheCacheManager cacheManager) { return (properties) -> properties.put(ConfigSettings.CACHE_MANAGER, cacheManager.getCacheManager()); } +// @Bean +// public JCacheCacheManager cacheManager() throws URISyntaxException { +// logger.info("Location of ehcache.xml " + getClass().getResource("/ehcache.xml")); +// CacheManager cacheManager = Caching.getCachingProvider(EhcacheCachingProvider.class.getName()) +// .getCacheManager(getClass().getResource("/ehcache.xml").toURI(), getClass().getClassLoader()); +// return new JCacheCacheManager(cacheManager); +// } + } diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/spring/DatabaseConfiguration.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/spring/DatabaseConfiguration.java index fe09b9f5..4375d178 100644 --- a/persistence/src/main/java/org/devgateway/toolkit/persistence/spring/DatabaseConfiguration.java +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/spring/DatabaseConfiguration.java @@ -16,7 +16,6 @@ import com.zaxxer.hikari.HikariDataSource; import liquibase.integration.spring.SpringLiquibase; -import org.apache.derby.drda.NetworkServerControl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -24,64 +23,28 @@ import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.PropertySource; -import org.springframework.mock.jndi.SimpleNamingContextBuilder; +import org.springframework.context.annotation.PropertySources; -import javax.naming.NamingException; -import javax.persistence.EntityManagerFactory; +import jakarta.persistence.EntityManagerFactory; import javax.sql.DataSource; -import java.io.PrintWriter; -import java.net.InetAddress; -import java.util.Properties; /** * @author mpostelnicu * */ @Configuration -@PropertySource("classpath:/org/devgateway/toolkit/persistence/application.properties") +@PropertySources({ + @PropertySource("classpath:/org/devgateway/toolkit/persistence/application.properties"), + @PropertySource( + value = "classpath:/org/devgateway/toolkit/persistence/application-${spring.profiles.active}.properties", + ignoreResourceNotFound = true) +}) @Profile("!integration") public class DatabaseConfiguration { private static final Logger logger = LoggerFactory.getLogger(DatabaseConfiguration.class); - @Value("${dg-toolkit.derby.port}") - private int derbyPort; - - @Value("${dg-toolkit.datasource.jndi-name}") - private String datasourceJndiName; - - /** - * This bean creates the JNDI tree and registers the - * {@link javax.sql.DataSource} to this tree. This allows Pentaho Classic - * Engine to use a {@link javax.sql.DataSource} ,in our case backed by a - * connection pool instead of always opening up JDBC connections. Should - * significantly improve performance of all classic reports. In PRD use - * connection type=JNDI and name toolkitDS. To use it in PRD you need to add - * the configuration to the local PRD. Edit - * ~/.pentaho/simple-jndi/default.properties and add the following: - * toolkitDS/type=javax.sql.DataSource - * toolkitDS/driver=org.apache.derby.jdbc.ClientDriver toolkitDS/user=app - * toolkitDS/password=app - * toolkitDS/url=jdbc:derby://localhost//derby/toolkit - * - * @return - */ - @Bean - public SimpleNamingContextBuilder jndiBuilder() { - SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); - builder.bind(datasourceJndiName, dataSource()); - try { - builder.activate(); - } catch (IllegalStateException e) { - e.printStackTrace(); - } catch (NamingException e) { - e.printStackTrace(); - } - return builder; - } - /** * Creates a {@link javax.sql.DataSource} based on HikariCP {@link HikariDataSource} * @@ -89,26 +52,10 @@ public SimpleNamingContextBuilder jndiBuilder() { */ @Bean @ConfigurationProperties(prefix = "spring.datasource") - @DependsOn(value = {"derbyServer"}) public DataSource dataSource() { return DataSourceBuilder.create().build(); } - /** - * Graciously starts a Derby Database Server when the application starts up - * - * @return - * @throws Exception - */ - @Bean(destroyMethod = "shutdown") - public NetworkServerControl derbyServer() throws Exception { - Properties p = System.getProperties(); - p.put("derby.storage.pageCacheSize", "30000"); - p.put("derby.language.maxMemoryPerTable", "20000"); - NetworkServerControl nsc = new NetworkServerControl(InetAddress.getByName("localhost"), derbyPort); - nsc.start(new PrintWriter(java.lang.System.out, true)); - return nsc; - } @Bean public SpringLiquibaseRunner liquibaseAfterJPA(final SpringLiquibase springLiquibase, diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputBaseCalculator.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputBaseCalculator.java new file mode 100644 index 00000000..5753e5e0 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputBaseCalculator.java @@ -0,0 +1,708 @@ +package org.devgateway.toolkit.persistence.util.tetsim; + +import com.google.common.collect.ImmutableMap; +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; +import org.devgateway.toolkit.persistence.dto.TetsimOutput; + +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.Map; + +import static java.math.BigDecimal.ONE; +import static java.math.BigDecimal.TEN; +import static java.math.BigDecimal.ZERO; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.DISCOUNT; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.ILLICIT; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.IMPORTED; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.POPULAR; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.PREMIUM; +import static org.devgateway.toolkit.persistence.util.tetsim.TetsimUtil.getLegalTobaccoProducts; +import static org.devgateway.toolkit.persistence.util.tetsim.TetsimUtil.getTobaccoProductValueFromVariable; + +/** + * @author vchihai + */ +public abstract class TetsimOutputBaseCalculator implements TetsimOutputCalculator { + + public static final BigDecimal HUNDRED = TEN.scaleByPowerOfTen(1); + + public static final MathContext DEFAULT_CONTEXT = MathContext.DECIMAL64; + + protected final TetsimDataset dataset; + + protected final Integer percentageChange; + + protected final Double trackTracingAdditionalCost; + + protected final Double levyPercentageChange; + + protected final Double changeInTheDeclaredCustomValue = 0.0; + + public static final Map GAIN_SWITCH_TOBACCO_PRODUCT = new ImmutableMap.Builder() + .put(POPULAR, PREMIUM) + .put(DISCOUNT, POPULAR) + .put(ILLICIT, DISCOUNT) + .build(); + + public static final Map CONSUMPTION_DEPENDENT_TOBACCO_PRODUCT = new ImmutableMap.Builder() + .put(IMPORTED, PREMIUM) + .put(PREMIUM, POPULAR) + .put(POPULAR, DISCOUNT) + .put(DISCOUNT, ILLICIT) + .build(); + + public TetsimOutputBaseCalculator(TetsimDataset dataset, Integer percentageChange) { + this(dataset, percentageChange, 0.0, 0.0); + } + + public TetsimOutputBaseCalculator(TetsimDataset dataset, Integer percentageChange, + Double trackTracingAdditionalCost, Double levyPercentageChange) { + this.dataset = dataset; + this.percentageChange = percentageChange; + this.trackTracingAdditionalCost = trackTracingAdditionalCost; + this.levyPercentageChange = levyPercentageChange; + } + + protected abstract String getShifting(); + + protected abstract BigDecimal calculateAbsChangeShift(TobaccoProduct tobaccoProduct); + + @Override + public TetsimOutput calculate(TobaccoProduct tobaccoProduct) { + TetsimOutput tetsimOutput = new TetsimOutput(); + + tetsimOutput.setYear(this.dataset.getYear()); + tetsimOutput.setShifting(getShifting()); + tetsimOutput.setTobaccoProduct(tobaccoProduct); + tetsimOutput.setTaxChange(percentageChange.intValue()); + tetsimOutput.setLegalConsumption(calculateOutputLegalConsumption()); + tetsimOutput.setLegalConsumptionChange(calculateOutputLegalConsumptionChange()); + tetsimOutput.setConsumptionIllicit(calculateOutputConsumptionIllicit()); + tetsimOutput.setExciseRev(calculateOutputExciseRev()); + tetsimOutput.setExciseRevChange(calculateOutputExciseRevChange()); + tetsimOutput.setTotalGovRev(calculateOutputTotalGovRev()); + + tetsimOutput.setExciseBurden(calculateOutputExciseBurden(tobaccoProduct)); + tetsimOutput.setTotalTaxBurden(calculateOutputTotalTaxBurden(tobaccoProduct)); + tetsimOutput.setTotalTaxBurdenBaseline(calculateOutputBaselineTotalTaxBurden(tobaccoProduct)); + tetsimOutput.setRetailPrice(calculateOutputRetailPrice(tobaccoProduct)); + tetsimOutput.setNot(calculateOutputNot(tobaccoProduct)); + tetsimOutput.setExciseTax(calculateOutputExciseTax(tobaccoProduct)); + tetsimOutput.setVat(calculateOutputVat(tobaccoProduct)); + tetsimOutput.setLevy(calculateOutputLevy(tobaccoProduct)); + + return tetsimOutput; + } + + private double calculateOutputBaselineTotalTaxBurden(final TobaccoProduct tobaccoProduct) { + return calculateBaselineTotalTaxBurden(tobaccoProduct).doubleValue(); + } + + public Double calculateOutputLegalConsumption() { + return calculateTotalLegalConsumption().doubleValue(); + } + + public Double calculateOutputLegalConsumptionChange() { + return calculateTotalLegalConsumptionChange().doubleValue(); + } + + private Double calculateOutputConsumptionIllicit() { + return calculateConsumption(ILLICIT).doubleValue(); + } + + private Double calculateOutputExciseRev() { + return calculateTotalExciseRevenue().doubleValue(); + } + + private Double calculateOutputExciseRevChange() { + return calculateTotalExciseRevenueChange().doubleValue(); + } + + private Double calculateOutputTotalGovRev() { + return calculateTotalLegalGovernmentRevenue().doubleValue(); + } + + /** + * Calculate the Output Excise Burden + */ + private Double calculateOutputExciseBurden(TobaccoProduct tobaccoProduct) { + return calculateExciseBurden(tobaccoProduct).doubleValue(); + } + + /** + * Calculate the Output Total Tax Burden + */ + private Double calculateOutputTotalTaxBurden(TobaccoProduct tobaccoProduct) { + return calculateTotalTaxBurden(tobaccoProduct).doubleValue(); + } + + /** + * Calculate the Output Retail Price + */ + public Double calculateOutputRetailPrice(TobaccoProduct tobaccoProduct) { + return calculateRetailPrice(tobaccoProduct).doubleValue(); + } + + /** + * Calculate the Output NOT + */ + public Double calculateOutputNot(TobaccoProduct tobaccoProduct) { + return calculateNetTaxPrice(tobaccoProduct).doubleValue(); + } + + /** + * Calculate the Output Excise Tax + */ + public Double calculateOutputExciseTax(TobaccoProduct tobaccoProduct) { + return calculateExciseTaxDomesticProduction(tobaccoProduct).doubleValue(); + } + + /** + * Calculate the Output VAT + */ + public Double calculateOutputVat(TobaccoProduct tobaccoProduct) { + return calculateVat(tobaccoProduct).doubleValue(); + } + + /** + * Calculate the Output Levy + */ + public Double calculateOutputLevy(TobaccoProduct tobaccoProduct) { + return calculateTobaccoLevy(tobaccoProduct).doubleValue(); + } + + /** + * Calculates Net of Tax Price + * + * @param tobaccoProduct + */ + public BigDecimal calculateNetTaxPrice(TobaccoProduct tobaccoProduct) { + BigDecimal netTaxPrice = calculateBaselineNetTaxPrice(tobaccoProduct); + if (tobaccoProduct.equals(ILLICIT)) { + BigDecimal shift = getTobaccoProductValueFromVariable(dataset.getChangeInIllicitNot(), + tobaccoProduct); + BigDecimal discountRetailPriceDifference = calculateRetailPrice(DISCOUNT) + .subtract(calculateBaselineRetailPrice(DISCOUNT)); + return netTaxPrice.add(shift.multiply(discountRetailPriceDifference)); + } + + return netTaxPrice.add(calculateAbsChangeShift(tobaccoProduct)); + } + + /** + * Calculates Additional charges related to Track and Tracing + */ + private BigDecimal calculateAdditionalCharges() { + return BigDecimal.valueOf(trackTracingAdditionalCost); + } + + /** + * Calculate Tobacco levy + * CIF per pack * (levy rate + percentage change in levy) / 100 + */ + protected BigDecimal calculateTobaccoLevy(TobaccoProduct tobaccoProduct) { + BigDecimal cif = getTobaccoProductValueFromVariable(dataset.getCif(), tobaccoProduct); + BigDecimal levy = getTobaccoProductValueFromVariable(dataset.getTobaccoLevy(), tobaccoProduct); + + return cif.multiply(levy.add(BigDecimal.valueOf(levyPercentageChange))) + .divide(HUNDRED, DEFAULT_CONTEXT); + }; + + /** + * Excise tax from baseline * (1 + percent increase in excise tax/100) + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateExciseTaxDomesticProduction(TobaccoProduct tobaccoProduct) { + return calculateBaselineExciseTaxOnDomesticProduction(tobaccoProduct) + .multiply(ONE.add(BigDecimal.valueOf(percentageChange).divide(HUNDRED, DEFAULT_CONTEXT))); + } + + /** + * Excise tax from baseline * (1 + percent increase in excise tax/100) + * + * @param tobaccoProduct + * @return + */ + protected BigDecimal calculateExciseTaxImportedCigarettes(TobaccoProduct tobaccoProduct) { + if (tobaccoProduct.equals(IMPORTED)) { + return calculateBaselineExciseTaxOnImported(tobaccoProduct) + .multiply(ONE.add(BigDecimal.valueOf(percentageChange).divide(HUNDRED, DEFAULT_CONTEXT))); + } + + return ZERO; + } + + /** + * Customs value from baseline * (1 + percent increase in customs rate/100) + * + * @param tobaccoProduct + * @return + */ + protected BigDecimal calculateCustomsDutyImportedCigarettes(TobaccoProduct tobaccoProduct) { + if (tobaccoProduct.equals(IMPORTED)) { + return calculateBaselineCustomsDuty(tobaccoProduct) + .multiply( + ONE.add(BigDecimal.valueOf(changeInTheDeclaredCustomValue).divide(HUNDRED, DEFAULT_CONTEXT)) + ); + } + + return ZERO; + } + + /** + * Calculate the VAT with tax change + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateVat(TobaccoProduct tobaccoProduct) { + if (tobaccoProduct.equals(ILLICIT)) { + return ZERO; + } + + BigDecimal vatRate = dataset.getVatRate(); + + return calculateNetTaxPrice(tobaccoProduct) + .add(calculateAdditionalCharges()) + .add(calculateTobaccoLevy(tobaccoProduct)) + .add(calculateExciseTaxDomesticProduction(tobaccoProduct)) + .add(calculateExciseTaxImportedCigarettes(tobaccoProduct)) + .add(calculateCustomsDutyImportedCigarettes(tobaccoProduct)) + .multiply(vatRate) + .divide(HUNDRED, DEFAULT_CONTEXT); + } + + /** + * Calculate the Retail Price with tax change + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateRetailPrice(TobaccoProduct tobaccoProduct) { + return calculateNetTaxPrice(tobaccoProduct) + .add(calculateAdditionalCharges()) + .add(calculateTobaccoLevy(tobaccoProduct)) + .add(calculateExciseTaxDomesticProduction(tobaccoProduct)) + .add(calculateExciseTaxImportedCigarettes(tobaccoProduct)) + .add(calculateCustomsDutyImportedCigarettes(tobaccoProduct)) + .add(calculateVat(tobaccoProduct)); + } + + /** + * Calculate the Excise Burden with tax change + * excise tax/price * 100 + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateExciseBurden(TobaccoProduct tobaccoProduct) { + return calculateTobaccoLevy(tobaccoProduct) + .add(calculateExciseTaxDomesticProduction(tobaccoProduct)) + .add(calculateExciseTaxImportedCigarettes(tobaccoProduct)) + .divide(calculateRetailPrice(tobaccoProduct), DEFAULT_CONTEXT) + .multiply(HUNDRED); + } + + /** + * Calculate the Total Tax Burden with tax change + * all tax/price * 100 + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateTotalTaxBurden(TobaccoProduct tobaccoProduct) { + return calculateTobaccoLevy(tobaccoProduct) + .add(calculateExciseTaxDomesticProduction(tobaccoProduct)) + .add(calculateExciseTaxImportedCigarettes(tobaccoProduct)) + .add(calculateVat(tobaccoProduct)) + .divide(calculateRetailPrice(tobaccoProduct), DEFAULT_CONTEXT) + .multiply(HUNDRED); + } + + /** + * Calculate Consumption (million packs): + * Baseline Consumption *([1+price_elast*(price AT-price BT)/(price AT + price BT)] / + * [1-price_elast*(price AT-price BT)/(price AT + price BT)] + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculatePreConsumption(TobaccoProduct tobaccoProduct) { + BigDecimal baselineConsumption = calculateBaselineConsumption(tobaccoProduct); + BigDecimal priceElasticity = getTobaccoProductValueFromVariable(dataset.getElasticityOfDemandPrice(), + tobaccoProduct); + + BigDecimal baselineRetailPrice = calculateBaselineRetailPrice(tobaccoProduct); + BigDecimal retailPrice = calculateRetailPrice(tobaccoProduct); + + BigDecimal diffRetailPrice = retailPrice.subtract(baselineRetailPrice); + BigDecimal sumRetailPrice = retailPrice.add(baselineRetailPrice); + BigDecimal multiplyElasticityRetail = priceElasticity.multiply(diffRetailPrice) + .divide(sumRetailPrice, DEFAULT_CONTEXT); + + return baselineConsumption + .multiply(ONE.add(multiplyElasticityRetail)) + .divide(ONE.subtract(multiplyElasticityRetail), DEFAULT_CONTEXT); + } + + /** + * Calculate Gain from higher price category + * As prices change, some consumers decide to shift to cheaper products in order to maintain consumption. + * This calculates these shifts between segments. We assume imported is quite a unique category, + * so there is no shifting in/out of it. The others interact. + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateGainFromPrice(TobaccoProduct tobaccoProduct) { + if (GAIN_SWITCH_TOBACCO_PRODUCT.containsKey(tobaccoProduct)) { + TobaccoProduct switchProduct = GAIN_SWITCH_TOBACCO_PRODUCT.get(tobaccoProduct); + + BigDecimal consumption = calculatePreConsumption(tobaccoProduct); + BigDecimal crossElasticity = getTobaccoProductValueFromVariable(dataset.getElasticityOfDemandCrossPrice(), + tobaccoProduct); + + BigDecimal baselineRetailPrice = calculateBaselineRetailPrice(switchProduct); + BigDecimal retailPrice = calculateRetailPrice(switchProduct); + + BigDecimal diffRetailPrice = retailPrice.subtract(baselineRetailPrice); + BigDecimal sumRetailPrice = retailPrice.add(baselineRetailPrice); + BigDecimal multiplyElastRetail = crossElasticity.multiply(diffRetailPrice).divide(sumRetailPrice, + DEFAULT_CONTEXT); + + return consumption + .multiply(ONE.add(multiplyElastRetail)) + .divide(ONE.subtract(multiplyElastRetail), DEFAULT_CONTEXT) + .subtract(consumption); + } + + return ZERO; + } + + /** + * Calculate the consumption + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateConsumption(TobaccoProduct tobaccoProduct) { + BigDecimal consumption = calculatePreConsumption(tobaccoProduct); + BigDecimal gainFromPrice = calculateGainFromPrice(tobaccoProduct); + + if (CONSUMPTION_DEPENDENT_TOBACCO_PRODUCT.containsKey(tobaccoProduct)) { + BigDecimal gainFromPriceDependent = calculateGainFromPrice( + CONSUMPTION_DEPENDENT_TOBACCO_PRODUCT.get(tobaccoProduct)); + return consumption.add(gainFromPrice).subtract(gainFromPriceDependent); + } + + return consumption.add(gainFromPrice); + } + + /** + * Calculate the Total Legal Consumption (million packs): sum of all products except illicit + * @return + */ + public BigDecimal calculateTotalLegalConsumption() { + return getLegalTobaccoProducts().stream() + .map(tobaccoProduct -> calculateConsumption(tobaccoProduct)) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + public BigDecimal calculateTotalLegalConsumptionChange() { + BigDecimal totalLegalConsumption = calculateTotalLegalConsumption(); + BigDecimal totalLegalConsumptionBaseline = calculateBaselineTotalLegalConsumption(); + return totalLegalConsumption.divide(totalLegalConsumptionBaseline, DEFAULT_CONTEXT) + .subtract(ONE) + .multiply(HUNDRED); + } + + /** + * Calculate Revenue Tobacco levy: Levy per pack AT * consumption in mill packs + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateRevenueTobaccoLevy(TobaccoProduct tobaccoProduct) { + return calculateConsumption(tobaccoProduct).multiply(calculateTobaccoLevy(tobaccoProduct)); + } + + + /** + * Calculate Revenue Excise tax on domestic production: excise tax per pack AT * consumption in mill packs + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateRevenueExciseTaxDomesticProduction(TobaccoProduct tobaccoProduct) { + return calculateConsumption(tobaccoProduct).multiply(calculateExciseTaxDomesticProduction(tobaccoProduct)); + } + + public BigDecimal calculateBaselineExciseRevenueDomesticProduction(TobaccoProduct tobaccoProduct) { + return calculateBaselineConsumption(tobaccoProduct) + .multiply(calculateBaselineExciseTaxOnDomesticProduction(tobaccoProduct)); + } + + public BigDecimal calculateBaselineExciseRevenueImportedCigarettes(TobaccoProduct tobaccoProduct) { + return calculateBaselineConsumption(tobaccoProduct) + .multiply(calculateBaselineExciseTaxOnImported(tobaccoProduct)); + } + + /** + * Calculate Revenue Excise tax on imported production: excise tax (imported) per pack AT * consumption + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateRevenueExciseTaxImportedCigarettes(TobaccoProduct tobaccoProduct) { + return calculateConsumption(tobaccoProduct).multiply(calculateExciseTaxImportedCigarettes(tobaccoProduct)); + } + + /** + * Calculate Revenue Customs Duty on Imported Cigarettes: customs per pack * consumption + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateRevenueCustomsDutyImportedCigarettes(TobaccoProduct tobaccoProduct) { + return calculateConsumption(tobaccoProduct).multiply(calculateCustomsDutyImportedCigarettes(tobaccoProduct)); + } + + /** + * Calculate Revenue VAT: VAT per pack * consumption + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateRevenueVat(TobaccoProduct tobaccoProduct) { + return calculateConsumption(tobaccoProduct).multiply(calculateVat(tobaccoProduct)); + } + + /** + * Calculate Total Excise TaxesRevenue + * + * @param tobaccoProduct + */ + public BigDecimal calculateTotalExciseTaxesRevenue(TobaccoProduct tobaccoProduct) { + return calculateRevenueExciseTaxDomesticProduction(tobaccoProduct) + .add(calculateRevenueExciseTaxImportedCigarettes(tobaccoProduct)); + } + + public BigDecimal calculateBaselineTotalExciseTaxesRevenue(TobaccoProduct tobaccoProduct) { + return calculateBaselineExciseRevenueDomesticProduction(tobaccoProduct) + .add(calculateBaselineExciseRevenueImportedCigarettes(tobaccoProduct)); + } + + /** + * Calculate Total Excise Revenue: sum of excise tax + */ + public BigDecimal calculateTotalExciseRevenue() { + return getLegalTobaccoProducts().stream() + .map(tobaccoProduct -> calculateTotalExciseTaxesRevenue(tobaccoProduct)) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + public BigDecimal calculateTotalExciseRevenueChange() { + BigDecimal totalExciseRevenue = calculateTotalExciseRevenue(); + BigDecimal totalExciseRevenueBaseline = calculateBaselineTotalExciseRevenue(); + return totalExciseRevenue.divide(totalExciseRevenueBaseline, DEFAULT_CONTEXT) + .subtract(ONE) + .multiply(HUNDRED); + } + + /** + * Calculate Total Revenue + * + * @param tobaccoProduct + */ + public BigDecimal calculateTotalRevenue(TobaccoProduct tobaccoProduct) { + return calculateRevenueTobaccoLevy(tobaccoProduct) + .add(calculateRevenueExciseTaxDomesticProduction(tobaccoProduct)) + .add(calculateRevenueExciseTaxImportedCigarettes(tobaccoProduct)) + .add(calculateRevenueCustomsDutyImportedCigarettes(tobaccoProduct)) + .add(calculateRevenueVat(tobaccoProduct)); + } + + /** + * Calculate Total Government Revenue: excise tax + VAT + levy + customs + */ + public BigDecimal calculateTotalLegalGovernmentRevenue() { + return getLegalTobaccoProducts().stream() + .map(tobaccoProduct -> calculateTotalRevenue(tobaccoProduct)) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + + public BigDecimal calculateBaselineTobaccoLevy(TobaccoProduct tobaccoProduct) { + BigDecimal cif = getTobaccoProductValueFromVariable(dataset.getCif(), tobaccoProduct); + BigDecimal levy = getTobaccoProductValueFromVariable(dataset.getTobaccoLevy(), tobaccoProduct); + + return cif.multiply(levy) + .divide(HUNDRED); + } + + /** + * calculate CIF * levy / 100 + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateBaselineExciseTaxOnDomesticProduction(TobaccoProduct tobaccoProduct) { + if (tobaccoProduct.equals(IMPORTED)) { + return ZERO; + } + + return getTobaccoProductValueFromVariable(dataset.getExciseTax(), tobaccoProduct); + } + + /** + * If tobacco product is imported, return excise tax + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateBaselineExciseTaxOnImported(TobaccoProduct tobaccoProduct) { + if (tobaccoProduct.equals(IMPORTED)) { + return getTobaccoProductValueFromVariable(dataset.getExciseTax(), tobaccoProduct); + } + + return ZERO; + } + + /** + * If tobacco product is imported, calculate CIF * customs duty / 100 + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateBaselineCustomsDuty(TobaccoProduct tobaccoProduct) { + if (tobaccoProduct.equals(IMPORTED)) { + BigDecimal cif = getTobaccoProductValueFromVariable(dataset.getCif(), tobaccoProduct); + BigDecimal duty = getTobaccoProductValueFromVariable(dataset.getCustomsDuty(), tobaccoProduct); + + if (duty == null) { + return ZERO; + } + + return cif.multiply(duty) + .divide(HUNDRED); + } + + return ZERO; + } + + /** + * Calculate the Baseline Rate Price + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateBaselineRetailPrice(TobaccoProduct tobaccoProduct) { + return getTobaccoProductValueFromVariable(dataset.getRetailPrice(), tobaccoProduct); + } + + /** + * Calculate baseeline VAT: Baseline Retail Price * VAT rate / (100 + VAT rate) + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateBaselineVAT(TobaccoProduct tobaccoProduct) { + BigDecimal baselineRetailPrice = calculateBaselineRetailPrice(tobaccoProduct); + BigDecimal vatRate = dataset.getVatRate(); + + return baselineRetailPrice.multiply(vatRate) + .divide(HUNDRED.add(vatRate), DEFAULT_CONTEXT); + } + + /** + * Calculates the industry component of the price (the price minus all taxes). + * The first term backward calculates VAT, as price*(1+(VATrate/100)). + * It then minuses excise tax and customs and the levy + * + * Note: illicit segment differs, it is just the retail price + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateBaselineNetTaxPrice(TobaccoProduct tobaccoProduct) { + BigDecimal baselineRetailPrice = calculateBaselineRetailPrice(tobaccoProduct); + + if (tobaccoProduct.equals(ILLICIT)) { + return baselineRetailPrice; + } + + return baselineRetailPrice + .divide(ONE.add(dataset.getVatRate().divide(HUNDRED)), DEFAULT_CONTEXT) + .subtract(calculateBaselineTobaccoLevy(tobaccoProduct)) + .subtract(calculateBaselineExciseTaxOnDomesticProduction(tobaccoProduct)) + .subtract(calculateBaselineExciseTaxOnImported(tobaccoProduct)) + .subtract(calculateBaselineCustomsDuty(tobaccoProduct)); + } + + /** + * Calculates excise burden: (excise) / retail price * 100 + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateBaselineExciseBurden(TobaccoProduct tobaccoProduct) { + BigDecimal baselineTobaccoLevy = calculateBaselineTobaccoLevy(tobaccoProduct); + + return baselineTobaccoLevy + .add(calculateBaselineExciseTaxOnDomesticProduction(tobaccoProduct)) + .add(calculateBaselineExciseTaxOnImported(tobaccoProduct)) + .divide(calculateBaselineRetailPrice(tobaccoProduct), DEFAULT_CONTEXT) + .multiply(HUNDRED); + } + + /** + * Calculates total tax burden: (excise + VAT + customs) / retail price * 100 + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateBaselineTotalTaxBurden(TobaccoProduct tobaccoProduct) { + BigDecimal baselineTobaccoLevy = calculateBaselineTobaccoLevy(tobaccoProduct); + + return baselineTobaccoLevy + .add(calculateBaselineExciseTaxOnDomesticProduction(tobaccoProduct)) + .add(calculateBaselineExciseTaxOnImported(tobaccoProduct)) + .add(calculateBaselineCustomsDuty(tobaccoProduct)) + .add(calculateBaselineVAT(tobaccoProduct)) + .divide(calculateBaselineRetailPrice(tobaccoProduct), DEFAULT_CONTEXT) + .multiply(HUNDRED); + } + + /** + * Calculate Baseline Consumption (million packs): total market * share of market for each segment / 100 + * + * @param tobaccoProduct + * @return + */ + public BigDecimal calculateBaselineConsumption(TobaccoProduct tobaccoProduct) { + BigDecimal consumption = dataset.getCigaretteConsumption(); + BigDecimal marketShare = getTobaccoProductValueFromVariable(dataset.getMarketShare(), tobaccoProduct); + + return consumption + .multiply(marketShare) + .divide(HUNDRED, DEFAULT_CONTEXT); + } + + /** + * Calculate the Baseline Total Consumption (million packs): summ of all products except illicit + * @return + */ + public BigDecimal calculateBaselineTotalLegalConsumption() { + return getLegalTobaccoProducts().stream() + .map(tobaccoProduct -> calculateBaselineConsumption(tobaccoProduct)) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + public BigDecimal calculateBaselineTotalExciseRevenue() { + return getLegalTobaccoProducts().stream() + .map(tobaccoProduct -> calculateBaselineTotalExciseTaxesRevenue(tobaccoProduct)) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputCalculator.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputCalculator.java new file mode 100644 index 00000000..278f5ca8 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputCalculator.java @@ -0,0 +1,10 @@ +package org.devgateway.toolkit.persistence.util.tetsim; + +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; +import org.devgateway.toolkit.persistence.dto.TetsimOutput; + +public interface TetsimOutputCalculator { + + TetsimOutput calculate(TobaccoProduct tobaccoProduct); + +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputOvershiftCalculator.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputOvershiftCalculator.java new file mode 100644 index 00000000..26baef8a --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputOvershiftCalculator.java @@ -0,0 +1,33 @@ +package org.devgateway.toolkit.persistence.util.tetsim; + +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; + +import java.math.BigDecimal; + +import static org.devgateway.toolkit.persistence.util.tetsim.TetsimUtil.getTobaccoProductValueFromVariable; + +/** + * @author vchihai + */ +public class TetsimOutputOvershiftCalculator extends TetsimOutputBaseCalculator { + + public TetsimOutputOvershiftCalculator(TetsimDataset dataset, Integer percentageChange) { + super(dataset, percentageChange); + } + + @Override + protected String getShifting() { + return "Overshift"; + } + + @Override + public BigDecimal calculateAbsChangeShift(final TobaccoProduct tobaccoProduct) { + BigDecimal exciseTax = getTobaccoProductValueFromVariable(dataset.getExciseTax(), tobaccoProduct); + BigDecimal overshifting = getTobaccoProductValueFromVariable(dataset.getOvershifting(), tobaccoProduct); + + return exciseTax.multiply(BigDecimal.valueOf(percentageChange)) + .divide(HUNDRED) + .multiply(overshifting); + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputPerfectshiftCalculator.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputPerfectshiftCalculator.java new file mode 100644 index 00000000..fc4d61dc --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputPerfectshiftCalculator.java @@ -0,0 +1,28 @@ +package org.devgateway.toolkit.persistence.util.tetsim; + +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; + +import java.math.BigDecimal; + +import static org.devgateway.toolkit.persistence.util.tetsim.TetsimUtil.getTobaccoProductValueFromVariable; + +/** + * @author vchihai + */ +public class TetsimOutputPerfectshiftCalculator extends TetsimOutputBaseCalculator { + + public TetsimOutputPerfectshiftCalculator(TetsimDataset dataset, Integer percentageChange) { + super(dataset, percentageChange); + } + + @Override + protected String getShifting() { + return "Perfectshift"; + } + + @Override + public BigDecimal calculateAbsChangeShift(final TobaccoProduct tobaccoProduct) { + return BigDecimal.ZERO; + } +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputUndershiftCalculator.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputUndershiftCalculator.java new file mode 100644 index 00000000..bfe53a2c --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimOutputUndershiftCalculator.java @@ -0,0 +1,34 @@ +package org.devgateway.toolkit.persistence.util.tetsim; + +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; + +import java.math.BigDecimal; + +import static org.devgateway.toolkit.persistence.util.tetsim.TetsimUtil.getTobaccoProductValueFromVariable; + +/** + * @author vchihai + */ +public class TetsimOutputUndershiftCalculator extends TetsimOutputBaseCalculator { + + public TetsimOutputUndershiftCalculator(TetsimDataset dataset, Integer percentageChange) { + super(dataset, percentageChange); + } + + @Override + protected String getShifting() { + return "Undershift"; + } + + @Override + public BigDecimal calculateAbsChangeShift(final TobaccoProduct tobaccoProduct) { + BigDecimal exciseTax = getTobaccoProductValueFromVariable(dataset.getExciseTax(), tobaccoProduct); + BigDecimal undershifting = getTobaccoProductValueFromVariable(dataset.getUndershifting(), tobaccoProduct); + + return exciseTax.multiply(BigDecimal.valueOf(percentageChange)) + .divide(HUNDRED) + .multiply(undershifting); + } + +} diff --git a/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimUtil.java b/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimUtil.java new file mode 100644 index 00000000..c8c5e0a9 --- /dev/null +++ b/persistence/src/main/java/org/devgateway/toolkit/persistence/util/tetsim/TetsimUtil.java @@ -0,0 +1,35 @@ +package org.devgateway.toolkit.persistence.util.tetsim; + +import org.devgateway.toolkit.persistence.dao.data.TetsimPriceVariable; +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.ILLICIT; + +public final class TetsimUtil { + + private TetsimUtil() { + + } + + public static BigDecimal getTobaccoProductValueFromVariable(TetsimPriceVariable variable, + TobaccoProduct tobaccoProduct) { + return variable.getValues().stream() + .filter(t -> t.getProduct().equals(tobaccoProduct)) + .findFirst().get().getValue(); + } + + public static List getLegalTobaccoProducts() { + return Arrays.asList(TobaccoProduct.values()) + .stream() + .filter(tobaccoProduct -> !tobaccoProduct.equals(ILLICIT)) + .collect(Collectors.toList()); + } + + +} diff --git a/persistence/src/main/java/org/hibernate/proxy/HibernateProxyHelper.java b/persistence/src/main/java/org/hibernate/proxy/HibernateProxyHelper.java new file mode 100644 index 00000000..d5a62401 --- /dev/null +++ b/persistence/src/main/java/org/hibernate/proxy/HibernateProxyHelper.java @@ -0,0 +1,21 @@ +package org.hibernate.proxy; + +import org.hibernate.Hibernate; + + +public final class HibernateProxyHelper { + + private HibernateProxyHelper() { + // Prevent instantiation + } + + public static Class getClassWithoutInitializingProxy(Object object) { + if (object instanceof HibernateProxy) { + HibernateProxy proxy = (HibernateProxy)object; + LazyInitializer li = proxy.getHibernateLazyInitializer(); + return li.getPersistentClass(); + } else { + return object.getClass(); + } + } +} diff --git a/persistence/src/main/resources/Person.sql b/persistence/src/main/resources/Person.sql deleted file mode 100644 index 6270228c..00000000 --- a/persistence/src/main/resources/Person.sql +++ /dev/null @@ -1,26 +0,0 @@ -INSERT INTO PERSON -( - ID, - CHANGE_PASSWORD_NEXT_SIGN_IN, - EMAIL, - ENABLED, - FIRST_NAME, - LAST_NAME, - PASSWORD, - TITLE, - USERNAME, - GROUP_ID -) -VALUES -( - NEXT VALUE FOR HIBERNATE_SEQUENCE, - false, - NULL, - true, - NULL, - NULL, - '$2a$10$wvn/WOzcIGu.GGFGDhEzS.0KVIhHG3ypCNjH4ui1Xa8h3qgt2mdZ6', - NULL, - 'admin', - NULL -); \ No newline at end of file diff --git a/persistence/src/main/resources/Person_roles.sql b/persistence/src/main/resources/Person_roles.sql deleted file mode 100644 index e41283c9..00000000 --- a/persistence/src/main/resources/Person_roles.sql +++ /dev/null @@ -1,5 +0,0 @@ -INSERT INTO PERSON_ROLES(PERSON_ID, ROLES_ID) - SELECT p.ID, r.ID - FROM PERSON p, ROLE r - WHERE p.USERNAME = 'admin' - AND r.AUTHORITY IN ('ROLE_ADMIN', 'ROLE_USER'); diff --git a/persistence/src/main/resources/ehcache.xml b/persistence/src/main/resources/ehcache.xml index 06139dc6..fee00ffe 100644 --- a/persistence/src/main/resources/ehcache.xml +++ b/persistence/src/main/resources/ehcache.xml @@ -1,13 +1,14 @@ + xmlns:jcache="http://www.ehcache.org/v3/jsr107"> - + + 100000 - + 100000 @@ -18,4 +19,6 @@ - \ No newline at end of file + + + diff --git a/persistence/src/main/resources/liquibase-changelog.xml b/persistence/src/main/resources/liquibase-changelog.xml index a53e6add..c9def9ad 100644 --- a/persistence/src/main/resources/liquibase-changelog.xml +++ b/persistence/src/main/resources/liquibase-changelog.xml @@ -13,6 +13,15 @@ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> + + + + + + + + + 8:7abae053c67b929de53498ce1748868c @@ -47,7 +56,13 @@ - + + + + + + + @@ -57,7 +72,13 @@ - + @@ -125,4 +146,53 @@ + + + + + + + + + + + + + + + + + + + DTYPE = 'Currency' + + + + + + + + + + + + + + + + + + DTYPE = 'TobaccoProduct' + + + + + + + + + + + + \ No newline at end of file diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/excel/ExcelFileImportDefaultTest.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/excel/ExcelFileImportDefaultTest.java index d5e642a1..4cc01705 100644 --- a/persistence/src/test/java/org/devgateway/toolkit/persistence/excel/ExcelFileImportDefaultTest.java +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/excel/ExcelFileImportDefaultTest.java @@ -27,6 +27,7 @@ import java.lang.annotation.Annotation; import java.util.Locale; import java.util.Map; +import java.util.Set; import static org.slf4j.Logger.ROOT_LOGGER_NAME; @@ -120,6 +121,16 @@ public String[] getBeanDefinitionNames() { return new String[0]; } + @Override + public ObjectProvider getBeanProvider(Class requiredType, boolean allowEagerInit) { + return null; + } + + @Override + public ObjectProvider getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) { + return null; + } + @Override public String[] getBeanNamesForType(ResolvableType resolvableType) { return new String[0]; @@ -165,6 +176,16 @@ public A findAnnotationOnBean(String s, Class aClass) return null; } + @Override + public A findAnnotationOnBean(String beanName, Class annotationType, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException { + return null; + } + + @Override + public Set findAllAnnotationsOnBean(String beanName, Class annotationType, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException { + return null; + } + @Override public Object getBean(String s) throws BeansException { return null; diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/excel/test/TestAddressRepository.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/excel/test/TestAddressRepository.java index 247ace28..0e16290f 100644 --- a/persistence/src/test/java/org/devgateway/toolkit/persistence/excel/test/TestAddressRepository.java +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/excel/test/TestAddressRepository.java @@ -6,9 +6,11 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.repository.query.FluentQuery; import java.util.List; import java.util.Optional; +import java.util.function.Function; /** * @author idobre @@ -68,6 +70,11 @@ public void delete(TestAddress entity) { } + @Override + public void deleteAllById(Iterable longs) { + + } + @Override public void deleteAll(Iterable entities) { @@ -98,6 +105,16 @@ public TestAddress getOne(Long aLong) { return null; } + @Override + public TestAddress getById(Long aLong) { + return null; + } + + @Override + public TestAddress getReferenceById(Long aLong) { + return null; + } + @Override public List findAll(Example example, Sort sort) { return null; @@ -113,6 +130,21 @@ public S saveAndFlush(S entity) { return null; } + @Override + public List saveAllAndFlush(Iterable entities) { + return null; + } + + @Override + public void deleteAllInBatch(Iterable entities) { + + } + + @Override + public void deleteAllByIdInBatch(Iterable longs) { + + } + @Override public List saveAll(Iterable entities) { return null; @@ -162,4 +194,24 @@ public long count(Example example) { public boolean exists(Example example) { return false; } + + @Override + public boolean exists(Specification spec) { + return false; + } + + @Override + public long delete(Specification spec) { + return 0; + } + + @Override + public R findBy(Specification spec, Function, R> queryFunction) { + return null; + } + + @Override + public R findBy(Example example, Function, R> queryFunction) { + return null; + } } diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputBaseCalculatorTest.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputBaseCalculatorTest.java new file mode 100644 index 00000000..51668e69 --- /dev/null +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputBaseCalculatorTest.java @@ -0,0 +1,78 @@ +package org.devgateway.toolkit.persistence.tetsim; + +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.dao.data.TetsimPriceVariable; +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; +import org.devgateway.toolkit.persistence.tetsim.builder.TetsimDatasetBuilder; +import org.devgateway.toolkit.persistence.tetsim.builder.TetsimPriceVariableBuilder; +import org.devgateway.toolkit.persistence.tetsim.builder.TetsimTobaccoProductValueBuilder; +import org.junit.Before; + +import java.math.BigDecimal; + +import static java.math.BigDecimal.ZERO; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.DISCOUNT; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.ILLICIT; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.IMPORTED; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.POPULAR; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.PREMIUM; + +public class TetsimOutputBaseCalculatorTest { + + protected TetsimDataset datasetWithAllTobaccoProducts; + + double delta = 0.01; + + @Before + public void setUp() { + this.datasetWithAllTobaccoProducts = createTetsimDatasetWithAllTobaccoProducts(); + } + + protected TetsimDataset createTetsimDatasetWithAllTobaccoProducts() { + return new TetsimDatasetBuilder() + .withCigaretteConsumption(BigDecimal.valueOf(1150.0)) + .withVatRate(BigDecimal.valueOf(15)) + .withCigaretteDeclaredCustomValue(BigDecimal.valueOf(2.05)) + .withAdultPopulation(BigDecimal.valueOf(42571)) + .withSmokingPrevalence(BigDecimal.valueOf(16.9)) + .withRetailPrice(createPriceVariable(BigDecimal.valueOf(45), BigDecimal.valueOf(48), BigDecimal.valueOf(40), BigDecimal.valueOf(28), BigDecimal.valueOf(20))) + .withMarketShare(createPriceVariable(BigDecimal.valueOf(5), BigDecimal.valueOf(7.6), BigDecimal.valueOf(40), BigDecimal.valueOf(13), BigDecimal.valueOf(34.4))) + .withCif(createPriceVariable(BigDecimal.valueOf(2.05), BigDecimal.valueOf(2.05), BigDecimal.valueOf(2.05), BigDecimal.valueOf(2.05), BigDecimal.valueOf(2.05))) + .withTobaccoLevy(createPriceVariable(ZERO, ZERO, ZERO, ZERO, ZERO)) + .withExciseTax(createPriceVariable(BigDecimal.valueOf(18.78), BigDecimal.valueOf(18.78), BigDecimal.valueOf(18.78), BigDecimal.valueOf(18.78), ZERO)) + .withCustomDuty(createPriceVariable(BigDecimal.valueOf(45), null, null, null, null)) + .withElasticityPrice(createPriceVariable(BigDecimal.valueOf(-0.4), BigDecimal.valueOf(-0.4), BigDecimal.valueOf(-0.6), BigDecimal.valueOf(-0.8), BigDecimal.valueOf(-0.6))) + .withCrossElasticityPrice(createPriceVariable(ZERO, ZERO, BigDecimal.valueOf(0.2), BigDecimal.valueOf(0.3), BigDecimal.valueOf(0.3))) + .withChangeInIllicitNot(createPriceVariable(null, null,null, null, BigDecimal.valueOf(0.5))) + .withOvershifting(createPriceVariable(BigDecimal.valueOf(0.3), BigDecimal.valueOf(0.3), BigDecimal.valueOf(0.2), BigDecimal.valueOf(0.1), ZERO)) + .withUndershifting(createPriceVariable(BigDecimal.valueOf(-0.2), BigDecimal.valueOf(-0.2), BigDecimal.valueOf(-0.3), BigDecimal.valueOf(-0.15), ZERO)) + .build(); + } + + protected TetsimPriceVariable createPriceVariable(BigDecimal imported, BigDecimal premium, BigDecimal popular, + BigDecimal discount, BigDecimal illicit) { + return new TetsimPriceVariableBuilder() + .add(new TetsimTobaccoProductValueBuilder() + .withTobaccoProduct(IMPORTED) + .withValue(imported) + .build()) + .add(new TetsimTobaccoProductValueBuilder() + .withTobaccoProduct(PREMIUM) + .withValue(premium) + .build()) + .add(new TetsimTobaccoProductValueBuilder() + .withTobaccoProduct(POPULAR) + .withValue(popular) + .build()) + .add(new TetsimTobaccoProductValueBuilder() + .withTobaccoProduct(DISCOUNT) + .withValue(discount) + .build()) + .add(new TetsimTobaccoProductValueBuilder() + .withTobaccoProduct(ILLICIT) + .withValue(illicit) + .build()) + .build(); + } + +} \ No newline at end of file diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputCalculatorAbsChangeTest.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputCalculatorAbsChangeTest.java new file mode 100644 index 00000000..fe1c2096 --- /dev/null +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputCalculatorAbsChangeTest.java @@ -0,0 +1,82 @@ +package org.devgateway.toolkit.persistence.tetsim; + +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputOvershiftCalculator; +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputPerfectshiftCalculator; +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputUndershiftCalculator; +import org.junit.Before; +import org.junit.Test; + +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.DISCOUNT; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.ILLICIT; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.IMPORTED; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.POPULAR; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.PREMIUM; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TetsimOutputCalculatorAbsChangeTest extends TetsimOutputBaseCalculatorTest { + + @Before + public void setUp() { + super.setUp(); + } + + @Test + public void testOvershiftAbsChangeBaseline() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + assertEquals(0.00, tetsimOutputCalculator.calculateAbsChangeShift(IMPORTED).doubleValue(), + delta, "Check Abs change overshift imported baseline"); + assertEquals(0.00, tetsimOutputCalculator.calculateAbsChangeShift(PREMIUM).doubleValue(), + delta, "Check Abs change overshift premium baseline"); + } + + @Test + public void testOvershiftAbsChange() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertAll("TETSIM Overshift Abs Change", + () -> assertEquals(0.75, tetsimOutputCalculator.calculateAbsChangeShift(POPULAR).doubleValue(), + delta, "Check Abs change overshift popular"), + () -> assertEquals(0.38, tetsimOutputCalculator.calculateAbsChangeShift(DISCOUNT).doubleValue(), + delta, "Check Abs change overshift discount"), + () -> assertEquals(0.00, tetsimOutputCalculator.calculateAbsChangeShift(ILLICIT).doubleValue(), + delta, "Check Abs change overshift illicit") + ); + } + + @Test + public void testUndershiftAbsChangeBaseline() { + TetsimOutputUndershiftCalculator tetsimOutputCalculator = new TetsimOutputUndershiftCalculator(datasetWithAllTobaccoProducts, 0); + assertEquals(0.00, tetsimOutputCalculator.calculateAbsChangeShift(IMPORTED).doubleValue(), + delta, "Check Abs change undershift imported baseline"); + assertEquals(0.00, tetsimOutputCalculator.calculateAbsChangeShift(PREMIUM).doubleValue(), + delta, "Check Abs change undershift premium baseline"); + } + + @Test + public void testUndershiftAbsChange() { + TetsimOutputUndershiftCalculator tetsimOutputCalculator = new TetsimOutputUndershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertAll("TETSIM Undershift Abs Change", + () -> assertEquals(-1.13, tetsimOutputCalculator.calculateAbsChangeShift(POPULAR).doubleValue(), + delta, "Check Abs change undershift popular"), + () -> assertEquals(-0.56, tetsimOutputCalculator.calculateAbsChangeShift(DISCOUNT).doubleValue(), + delta, "Check Abs change undershift discount"), + () -> assertEquals(0.00, tetsimOutputCalculator.calculateAbsChangeShift(ILLICIT).doubleValue(), + delta, "Check Abs change undershift illicit") + ); + } + + @Test + public void testPerfectshiftAbsChange() { + TetsimOutputPerfectshiftCalculator tetsimOutputCalculator = new TetsimOutputPerfectshiftCalculator(datasetWithAllTobaccoProducts, 20); + assertAll("TETSIM Perfectshift Abs Change", + () -> assertEquals(0.00, tetsimOutputCalculator.calculateAbsChangeShift(POPULAR).doubleValue(), + delta, "Check Abs change undershift popular"), + () -> assertEquals(0.00, tetsimOutputCalculator.calculateAbsChangeShift(DISCOUNT).doubleValue(), + delta, "Check Abs change undershift discount"), + () -> assertEquals(0.00, tetsimOutputCalculator.calculateAbsChangeShift(ILLICIT).doubleValue(), + delta, "Check Abs change undershift illicit") + ); + } + +} \ No newline at end of file diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputCalculatorBaselineNumbersTest.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputCalculatorBaselineNumbersTest.java new file mode 100644 index 00000000..32b60e54 --- /dev/null +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputCalculatorBaselineNumbersTest.java @@ -0,0 +1,112 @@ +package org.devgateway.toolkit.persistence.tetsim; + +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputOvershiftCalculator; +import org.junit.Before; +import org.junit.Test; + +import static java.math.BigDecimal.ROUND_HALF_UP; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.DISCOUNT; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.ILLICIT; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.IMPORTED; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.POPULAR; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.PREMIUM; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TetsimOutputCalculatorBaselineNumbersTest extends TetsimOutputBaseCalculatorTest { + + @Before + public void setUp() { + super.setUp(); + } + + @Test + public void testBaselineNetOfTaxPrice() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + assertEquals(19.43, tetsimOutputCalculator.calculateBaselineNetTaxPrice(IMPORTED) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check baseline Net of Tax for Imported Product"); + } + + @Test + public void testBaselineNetOfTaxPriceWithPercentageChange() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(16.00, tetsimOutputCalculator.calculateBaselineNetTaxPrice(POPULAR) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check baseline Net of Tax for Popular Product with percentage change"); + } + + @Test + public void testBaselineIllicitNetOfTaxPriceWithPercentageChange() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(20.00, tetsimOutputCalculator.calculateBaselineNetTaxPrice(ILLICIT) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check baseline Net of Tax Price for Illicit Product with percentage change"); + } + + @Test + public void testBaselineIllicitRetailPrice() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + assertEquals(20.00, tetsimOutputCalculator.calculateBaselineRetailPrice(ILLICIT) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check baseline Retail Price for Illicit Product"); + } + + @Test + public void testBaselineRetailPriceWithPercentageChange() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(40.00, tetsimOutputCalculator.calculateBaselineRetailPrice(POPULAR) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check baseline Retail Price for Popular Product with percentage change"); + } + + @Test + public void testBaselineIllicitExciseTaxOnDomestic() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + assertEquals(0, tetsimOutputCalculator.calculateBaselineExciseTaxOnDomesticProduction(ILLICIT) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check baseline Excise Tax for Illicit Product"); + } + + @Test + public void testBaselineImportedExciseTaxOnDomestic() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + assertEquals(0, tetsimOutputCalculator.calculateBaselineExciseTaxOnDomesticProduction(IMPORTED) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check baseline Excise Tax for Imported Product"); + } + + @Test + public void testBaselinePopularExciseTaxOnDomestic() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + assertEquals(18.78, tetsimOutputCalculator.calculateBaselineExciseTaxOnDomesticProduction(POPULAR) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check baseline Excise Tax for Popular Product"); + } + + @Test + public void testBaselinePopularVAT() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + assertEquals(5.22, tetsimOutputCalculator.calculateBaselineVAT(POPULAR) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check baseline VAT for Popular Product"); + } + + @Test + public void testBaselineDiscountExciseBurden() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + assertEquals(67.07, tetsimOutputCalculator.calculateBaselineExciseBurden(DISCOUNT) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check baseline Excise Burden for Discount Product"); + } + + @Test + public void testBaselinePremiumTotalTaxBurden() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + assertEquals(52.17, tetsimOutputCalculator.calculateBaselineTotalTaxBurden(PREMIUM) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check baseline Total Tax Burden for Premium Product"); + } + + public void testBaselineTotalLegalConsumption() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(754.4, tetsimOutputCalculator.calculateBaselineTotalLegalConsumption() + .setScale(1, ROUND_HALF_UP).doubleValue(), "Check baseline Total Legal Consumption"); + } + + public void testBaselineExciseRevenue() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(14167.6, tetsimOutputCalculator.calculateBaselineTotalExciseRevenue() + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check baseline Total Excise Revenue"); + } + +} \ No newline at end of file diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputCalculatorQuantityAndRevenueTest.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputCalculatorQuantityAndRevenueTest.java new file mode 100644 index 00000000..86bcf9d1 --- /dev/null +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputCalculatorQuantityAndRevenueTest.java @@ -0,0 +1,63 @@ +package org.devgateway.toolkit.persistence.tetsim; + +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputOvershiftCalculator; +import org.junit.Before; +import org.junit.Test; + +import static java.math.BigDecimal.ROUND_HALF_UP; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.ILLICIT; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.IMPORTED; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.POPULAR; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TetsimOutputCalculatorQuantityAndRevenueTest extends TetsimOutputBaseCalculatorTest { + + @Before + public void setUp() { + super.setUp(); + } + + @Test + public void testBaselineTotalConsumption() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(754.4, tetsimOutputCalculator.calculateBaselineTotalLegalConsumption() + .setScale(1, ROUND_HALF_UP).doubleValue(), "Check baseline Total Consumption"); + } + + @Test + public void testPreConsumption() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(54.9, tetsimOutputCalculator.calculatePreConsumption(IMPORTED) + .setScale(1, ROUND_HALF_UP).doubleValue(), "Check Pre Consumption for Imported Tobacco Product"); + } + + @Test + public void testPreConsumptionIllicit() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(369.9, tetsimOutputCalculator.calculatePreConsumption(ILLICIT) + .setScale(1, ROUND_HALF_UP).doubleValue(), "Check Pre Consumption for Illicit Tobacco Product"); + } + + @Test + public void testGainFromPrice() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(17.8, tetsimOutputCalculator.calculateGainFromPrice(ILLICIT) + .setScale(1, ROUND_HALF_UP).doubleValue(), "Check Gain From Price for Illicit Tobacco Product"); + } + + @Test + public void testConsumptionPopular() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(432.2, tetsimOutputCalculator.calculateConsumption(POPULAR) + .setScale(1, ROUND_HALF_UP).doubleValue(), "Check Consumption for Popular Tobacco Product"); + } + + @Test + public void testConsumptionIllicit() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(387.6, tetsimOutputCalculator.calculateConsumption(ILLICIT) + .setScale(1, ROUND_HALF_UP).doubleValue(), "Check Consumption for Illicit Tobacco Product"); + } + +} \ No newline at end of file diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputOvershiftCalculatorNumbersTest.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputOvershiftCalculatorNumbersTest.java new file mode 100644 index 00000000..ed13a469 --- /dev/null +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputOvershiftCalculatorNumbersTest.java @@ -0,0 +1,56 @@ +package org.devgateway.toolkit.persistence.tetsim; + +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputOvershiftCalculator; +import org.junit.Before; +import org.junit.Test; + +import static java.math.BigDecimal.ROUND_HALF_UP; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.ILLICIT; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.IMPORTED; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.POPULAR; +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.PREMIUM; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TetsimOutputOvershiftCalculatorNumbersTest extends TetsimOutputBaseCalculatorTest { + + @Before + public void setUp() { + super.setUp(); + } + + @Test + public void testPopularNetTaxPrice() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(16.75, tetsimOutputCalculator.calculateNetTaxPrice(POPULAR) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check Overshift Net of Tax for Popular Product"); + } + + @Test + public void testIllicitNetTaxPrice() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(22.38, tetsimOutputCalculator.calculateNetTaxPrice(ILLICIT) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check Overshift Net of Tax for Illicit Product"); + } + + @Test + public void testPopularExciseTaxOnDomesticProduction() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(22.54, tetsimOutputCalculator.calculateExciseTaxDomesticProduction(POPULAR) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check Overshift Excise Tax on domestic production for Popular Product"); + } + + @Test + public void testPremiumVat() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(6.99, tetsimOutputCalculator.calculateVat(PREMIUM) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check Overshift VAT for Premium Product"); + } + + @Test + public void testImportedRetailPrice() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + assertEquals(50.62, tetsimOutputCalculator.calculateRetailPrice(IMPORTED) + .setScale(2, ROUND_HALF_UP).doubleValue(), "Check Overshift Retail Price for Imported Product"); + } + +} \ No newline at end of file diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputOvershiftCalculatorOverallTest.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputOvershiftCalculatorOverallTest.java new file mode 100644 index 00000000..7aabf15e --- /dev/null +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputOvershiftCalculatorOverallTest.java @@ -0,0 +1,62 @@ +package org.devgateway.toolkit.persistence.tetsim; + +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; +import org.devgateway.toolkit.persistence.dto.TetsimOutput; +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputOvershiftCalculator; +import org.junit.Before; +import org.junit.Test; + +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.POPULAR; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TetsimOutputOvershiftCalculatorOverallTest extends TetsimOutputBaseCalculatorTest { + + @Before + public void setUp() { + super.setUp(); + } + + @Test + public void testOverallOutputBaseline() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + + assertAll("TETSIM Overshift Baseline", + () -> assertEquals(754.40, output.getLegalConsumption(), delta, "TETSIM Overshift - Consumption Legal"), + () -> assertEquals(0, output.getLegalConsumptionChange(), delta, "TETSIM Overshift - Consumption Legal Change"), + () -> assertEquals(395.60, output.getConsumptionIllicit(), delta, "TETSIM Overshift - Consumption Illicit"), + () -> assertEquals(14167.63, output.getExciseRev(), delta, "TETSIM Overshift - Excise Revenue"), + () -> assertEquals(0, output.getExciseRevChange(), delta, "TETSIM Overshift - Excise Revenue Change"), + () -> assertEquals(18051.37, output.getTotalGovRev(), delta, "TETSIM Overshift - Government Revenue"), + () -> assertEquals(46.95, output.getExciseBurden(), delta, "TETSIM Overshift - Excise Burden"), + () -> assertEquals(60.00, output.getTotalTaxBurden(), delta, "TETSIM Overshift - Total Tax Burden"), + () -> assertEquals(40.00, output.getRetailPrice(), delta, "TETSIM Overshift - Retail Price"), + () -> assertEquals(16.00, output.getNot(), delta, "TETSIM Overshift - NOT"), + () -> assertEquals(18.78, output.getExciseTax(), delta, "TETSIM Overshift - Excise Tax"), + () -> assertEquals(5.21, output.getVat(), delta, "TETSIM Overshift - VAT"), + () -> assertEquals(0.00, output.getLevy(), delta, "TETSIM Overshift - Levy")); + } + + @Test + public void testOverallOutputWithTaxChange() { + TetsimOutputOvershiftCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 30); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + + assertAll("TETSIM Overshift With 30% Tax Change", + () -> assertEquals(648.79, output.getLegalConsumption(), delta, "TETSIM Overshift - Consumption Legal"), + () -> assertEquals(-13.99, output.getLegalConsumptionChange(), delta, "TETSIM Overshift - Consumption Legal Change"), + () -> assertEquals(383.73, output.getConsumptionIllicit(), delta, "TETSIM Overshift - Consumption Illicit"), + () -> assertEquals(15839.61, output.getExciseRev(), delta, "TETSIM Overshift - Excise Revenue"), + () -> assertEquals(11.80, output.getExciseRevChange(), delta, "TETSIM Overshift - Excise Revenue Change"), + () -> assertEquals(19873.25, output.getTotalGovRev(), delta, "TETSIM Overshift - Government Revenue"), + () -> assertEquals(51.10, output.getExciseBurden(), delta, "TETSIM Overshift - Excise Burden"), + () -> assertEquals(64.15, output.getTotalTaxBurden(), delta, "TETSIM Overshift - Total Tax Burden"), + () -> assertEquals(47.77, output.getRetailPrice(), delta, "TETSIM Overshift - Retail Price"), + () -> assertEquals(17.13, output.getNot(), delta, "TETSIM Overshift - NOT"), + () -> assertEquals(24.41, output.getExciseTax(), delta, "TETSIM Overshift - Excise Tax"), + () -> assertEquals(6.23, output.getVat(), delta, "TETSIM Overshift - VAT"), + () -> assertEquals(0.00, output.getLevy(), delta, "TETSIM Overshift - Levy")); + } + +} \ No newline at end of file diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputOvershiftCalculatorTest.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputOvershiftCalculatorTest.java new file mode 100644 index 00000000..06d1111d --- /dev/null +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputOvershiftCalculatorTest.java @@ -0,0 +1,180 @@ +package org.devgateway.toolkit.persistence.tetsim; + +import org.devgateway.toolkit.persistence.dto.TetsimOutput; +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputCalculator; +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputOvershiftCalculator; +import org.junit.Before; +import org.junit.Test; + +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.POPULAR; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TetsimOutputOvershiftCalculatorTest extends TetsimOutputBaseCalculatorTest { + + @Before + public void setUp() { + super.setUp(); + } + + @Test + public void testConsumptionLegalNoTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(754.4, output.getLegalConsumption(), delta, "Check Consumption Legal TETSIM Output Overshift"); + } + + @Test + public void testConsumptionLegalWithTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(680.19, output.getLegalConsumption(), delta, "Check Consumption Legal TETSIM Output Overshift (Tax Change)"); + } + + @Test + public void testConsumptionLegalWithTaxChange1() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 1); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(750.27, output.getLegalConsumption(), delta, "Check Consumption Legal TETSIM Output Overshift (Tax Change)"); + } + + @Test + public void testConsumptionIllicitNoTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(395.6, output.getConsumptionIllicit(), delta, "Check Consumption Illicit TETSIM Output Overshift"); + } + + @Test + public void testConsumptionIllicitWithTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(387.62, output.getConsumptionIllicit(), delta, "Check Consumption Illicit TETSIM Output Overshift (Tax Change)"); + } + + @Test + public void testTotalExciseRevenueNoTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(14167.63, output.getExciseRev(), delta, "Check Total Legal Excise Revenue TETSIM Output Overshift"); + } + + @Test + public void testTotalExciseRevenueWithTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(15328.9, output.getExciseRev(), delta, "Check Total Legal Excise Revenue TETSIM Output Overshift (Tax Change)"); + } + + @Test + public void testTotalLegalGovRevenueNoTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(18051.37, output.getTotalGovRev(), delta, "Check Total Legal Government Revenue TETSIM Output Overshift"); + } + + @Test + public void testTotalLegalGovRevenueWithTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(19315.54, output.getTotalGovRev(), delta, "Check Total Legal Government Revenue TETSIM Output Overshift (Tax Change)"); + } + + @Test + public void testExciseBurdenNoTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(46.95, output.getExciseBurden(), delta, "Check Excise Burden TETSIM Output Overshift"); + } + + @Test + public void testExciseBurdenWithTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(49.87, output.getExciseBurden(), delta, "Check Excise Burden TETSIM Output Overshift (Tax Change)"); + } + + @Test + public void testTotalTaxBurdenNoTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(60.0, output.getTotalTaxBurden(), delta, "Check Total Tax Burden TETSIM Output Overshift"); + } + + @Test + public void testTotalTaxBurdenWithTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(62.92, output.getTotalTaxBurden(), delta, "Check Total Tax Burden TETSIM Output Overshift (Tax Change)"); + } + + @Test + public void testRetailPriceNoTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(40.0, output.getRetailPrice(), delta, "Check Retail Price TETSIM Output Overshift (Baseline)"); + } + + @Test + public void testRetailPriceWithTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(45.18, output.getRetailPrice(), delta, "Check Retail Price TETSIM Output Overshift (Tax Change)"); + } + + @Test + public void testNOTNoTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(16.0, output.getNot(), delta, "Check NOT TETSIM Output Overshift"); + } + + @Test + public void testNOTWithTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(16.75, output.getNot(), delta, "Check NOT TETSIM Output Overshift (Tax Change)"); + } + + @Test + public void testExciseTaxNoTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(18.78, output.getExciseTax(), delta, "Check Excise Tax TETSIM Output Overshift"); + } + + @Test + public void testExciseTaxWithTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(22.54, output.getExciseTax(), delta, "Check Excise Tax TETSIM Output Overshift (Tax Change)"); + } + + @Test + public void testVatNoTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(5.22, output.getVat(), delta, "Check VAT TETSIM Output Overshift"); + } + + @Test + public void testVatWithTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(5.89, output.getVat(), delta, "Check VAT TETSIM Output Overshift (Tax Change)"); + } + + @Test + public void testLevyNoTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(0.00, output.getLevy(), delta, "Check Levy TETSIM Output Overshift"); + } + + @Test + public void testLevyWithTaxChange() { + TetsimOutputCalculator tetsimOutputCalculator = new TetsimOutputOvershiftCalculator(datasetWithAllTobaccoProducts, 20); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + assertEquals(0.00, output.getLevy(), delta, "Check Levy TETSIM Output Overshift (Tax Change)"); + } + +} \ No newline at end of file diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputPerfectshiftCalculatorOverallTest.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputPerfectshiftCalculatorOverallTest.java new file mode 100644 index 00000000..7f3a016a --- /dev/null +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputPerfectshiftCalculatorOverallTest.java @@ -0,0 +1,61 @@ +package org.devgateway.toolkit.persistence.tetsim; + +import org.devgateway.toolkit.persistence.dto.TetsimOutput; +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputPerfectshiftCalculator; +import org.junit.Before; +import org.junit.Test; + +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.POPULAR; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TetsimOutputPerfectshiftCalculatorOverallTest extends TetsimOutputBaseCalculatorTest { + + @Before + public void setUp() { + super.setUp(); + } + + @Test + public void testOverallOutputBaseline() { + TetsimOutputPerfectshiftCalculator tetsimOutputCalculator = new TetsimOutputPerfectshiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + + assertAll("TETSIM Perfectshift Baseline", + () -> assertEquals(754.40, output.getLegalConsumption(), delta, "TETSIM Perfectshift - Consumption Legal"), + () -> assertEquals(0, output.getLegalConsumptionChange(), delta, "TETSIM Perfectshift - Consumption Legal Change"), + () -> assertEquals(395.60, output.getConsumptionIllicit(), delta, "TETSIM Perfectshift - Consumption Illicit"), + () -> assertEquals(14167.63, output.getExciseRev(), delta, "TETSIM Perfectshift - Excise Revenue"), + () -> assertEquals(0, output.getExciseRevChange(), delta, "TETSIM Perfectshift - Excise Revenue Change"), + () -> assertEquals(18051.37, output.getTotalGovRev(), delta, "TETSIM Perfectshift - Government Revenue"), + () -> assertEquals(46.95, output.getExciseBurden(), delta, "TETSIM Perfectshift - Excise Burden"), + () -> assertEquals(60.00, output.getTotalTaxBurden(), delta, "TETSIM Perfectshift - Total Tax Burden"), + () -> assertEquals(40.00, output.getRetailPrice(), delta, "TETSIM Perfectshift - Retail Price"), + () -> assertEquals(16.00, output.getNot(), delta, "TETSIM Perfectshift - NOT"), + () -> assertEquals(18.78, output.getExciseTax(), delta, "TETSIM Perfectshift - Excise Tax"), + () -> assertEquals(5.21, output.getVat(), delta, "TETSIM Perfectshift - VAT"), + () -> assertEquals(0.00, output.getLevy(), delta, "TETSIM Perfectshift - Levy")); + } + + @Test + public void testOverallOutputWithTaxChange() { + TetsimOutputPerfectshiftCalculator tetsimOutputCalculator = new TetsimOutputPerfectshiftCalculator(datasetWithAllTobaccoProducts, 30); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + + assertAll("TETSIM Perfectshift With 30% Tax Change", + () -> assertEquals(661.37, output.getLegalConsumption(), delta, "TETSIM Perfectshift - Consumption Legal"), + () -> assertEquals(-12.33, output.getLegalConsumptionChange(), delta, "TETSIM Perfectshift - Consumption Legal Change"), + () -> assertEquals(384.78, output.getConsumptionIllicit(), delta, "TETSIM Perfectshift - Consumption Illicit"), + () -> assertEquals(16146.9, output.getExciseRev(), delta, "TETSIM Perfectshift - Excise Revenue"), + () -> assertEquals(13.97, output.getExciseRevChange(), delta, "TETSIM Perfectshift - Excise Revenue Change"), + () -> assertEquals(20146.86, output.getTotalGovRev(), delta, "TETSIM Perfectshift - Government Revenue"), + () -> assertEquals(52.53, output.getExciseBurden(), delta, "TETSIM Perfectshift - Excise Burden"), + () -> assertEquals(65.57, output.getTotalTaxBurden(), delta, "TETSIM Perfectshift - Total Tax Burden"), + () -> assertEquals(46.48, output.getRetailPrice(), delta, "TETSIM Perfectshift - Retail Price"), + () -> assertEquals(16.00, output.getNot(), delta, "TETSIM Perfectshift - NOT"), + () -> assertEquals(24.41, output.getExciseTax(), delta, "TETSIM Perfectshift - Excise Tax"), + () -> assertEquals(6.06, output.getVat(), delta, "TETSIM Perfectshift - VAT"), + () -> assertEquals(0.00, output.getLevy(), delta, "TETSIM Perfectshift - Levy")); + } + +} \ No newline at end of file diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputUndershiftCalculatorOverallTest.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputUndershiftCalculatorOverallTest.java new file mode 100644 index 00000000..0fac5cdc --- /dev/null +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/TetsimOutputUndershiftCalculatorOverallTest.java @@ -0,0 +1,62 @@ +package org.devgateway.toolkit.persistence.tetsim; + +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; +import org.devgateway.toolkit.persistence.dto.TetsimOutput; +import org.devgateway.toolkit.persistence.util.tetsim.TetsimOutputUndershiftCalculator; +import org.junit.Before; +import org.junit.Test; + +import static org.devgateway.toolkit.persistence.dao.data.TobaccoProduct.POPULAR; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TetsimOutputUndershiftCalculatorOverallTest extends TetsimOutputBaseCalculatorTest { + + @Before + public void setUp() { + super.setUp(); + } + + @Test + public void testOverallOutputBaseline() { + TetsimOutputUndershiftCalculator tetsimOutputCalculator = new TetsimOutputUndershiftCalculator(datasetWithAllTobaccoProducts, 0); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + + assertAll("TETSIM Undershift Baseline", + () -> assertEquals(754.40, output.getLegalConsumption(), delta, "TETSIM Undershift - Consumption Legal"), + () -> assertEquals(0, output.getLegalConsumptionChange(), delta, "TETSIM Undershift - Consumption Legal Change"), + () -> assertEquals(395.60, output.getConsumptionIllicit(), delta, "TETSIM Undershift - Consumption Illicit"), + () -> assertEquals(14167.63, output.getExciseRev(), delta, "TETSIM Undershift - Excise Revenue"), + () -> assertEquals(0, output.getExciseRevChange(), delta, "TETSIM Undershift - Excise Revenue Change"), + () -> assertEquals(18051.37, output.getTotalGovRev(), delta, "TETSIM Undershift - Government Revenue"), + () -> assertEquals(46.95, output.getExciseBurden(), delta, "TETSIM Undershift - Excise Burden"), + () -> assertEquals(60.00, output.getTotalTaxBurden(), delta, "TETSIM Undershift - Total Tax Burden"), + () -> assertEquals(40.00, output.getRetailPrice(), delta, "TETSIM Undershift - Retail Price"), + () -> assertEquals(16.00, output.getNot(), delta, "TETSIM Undershift - NOT"), + () -> assertEquals(18.78, output.getExciseTax(), delta, "TETSIM Undershift - Excise Tax"), + () -> assertEquals(5.21, output.getVat(), delta, "TETSIM Undershift - VAT"), + () -> assertEquals(0.00, output.getLevy(), delta, "TETSIM Undershift - Levy")); + } + + @Test + public void testOverallOutputWithTaxChange() { + TetsimOutputUndershiftCalculator tetsimOutputCalculator = new TetsimOutputUndershiftCalculator(datasetWithAllTobaccoProducts, 30); + TetsimOutput output = tetsimOutputCalculator.calculate(POPULAR); + + assertAll("TETSIM Undershift With 30% Tax Change", + () -> assertEquals(679.54, output.getLegalConsumption(), delta, "TETSIM Undershift - Consumption Legal"), + () -> assertEquals(-9.92, output.getLegalConsumptionChange(), delta, "TETSIM Undershift - Consumption Legal Change"), + () -> assertEquals(386.38, output.getConsumptionIllicit(), delta, "TETSIM Undershift - Consumption Illicit"), + () -> assertEquals(16590.46, output.getExciseRev(), delta, "TETSIM Undershift - Excise Revenue"), + () -> assertEquals(17.10, output.getExciseRevChange(), delta, "TETSIM Undershift - Excise Revenue Change"), + () -> assertEquals(20550.49, output.getTotalGovRev(), delta, "TETSIM Undershift - Government Revenue"), + () -> assertEquals(54.82, output.getExciseBurden(), delta, "TETSIM Undershift - Excise Burden"), + () -> assertEquals(67.86, output.getTotalTaxBurden(), delta, "TETSIM Undershift - Total Tax Burden"), + () -> assertEquals(44.54, output.getRetailPrice(), delta, "TETSIM Undershift - Retail Price"), + () -> assertEquals(14.31, output.getNot(), delta, "TETSIM Undershift - NOT"), + () -> assertEquals(24.41, output.getExciseTax(), delta, "TETSIM Undershift - Excise Tax"), + () -> assertEquals(5.81, output.getVat(), delta, "TETSIM Undershift - VAT"), + () -> assertEquals(0.00, output.getLevy(), delta, "TETSIM Undershift - Levy")); + } + +} \ No newline at end of file diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/builder/TetsimDatasetBuilder.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/builder/TetsimDatasetBuilder.java new file mode 100644 index 00000000..c71a83c2 --- /dev/null +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/builder/TetsimDatasetBuilder.java @@ -0,0 +1,100 @@ +package org.devgateway.toolkit.persistence.tetsim.builder; + +import org.devgateway.toolkit.persistence.dao.data.TetsimDataset; +import org.devgateway.toolkit.persistence.dao.data.TetsimPriceVariable; + +import java.math.BigDecimal; + +public class TetsimDatasetBuilder { + + private TetsimDataset dataset; + + public TetsimDatasetBuilder() { + dataset = new TetsimDataset(); + } + + public TetsimDatasetBuilder withCigaretteConsumption(BigDecimal consumption) { + dataset.setCigaretteConsumption(consumption); + return this; + } + + public TetsimDatasetBuilder withCigaretteDeclaredCustomValue(BigDecimal declaredCustomValue) { + dataset.setCigaretteDeclaredCustomValue(declaredCustomValue); + return this; + } + + public TetsimDatasetBuilder withAdultPopulation(BigDecimal adultPopulation) { + dataset.setAdultPopulation(adultPopulation); + return this; + } + + public TetsimDatasetBuilder withVatRate(BigDecimal vatRate) { + dataset.setVatRate(vatRate); + return this; + } + + public TetsimDatasetBuilder withSmokingPrevalence(BigDecimal smokingPrevalence) { + dataset.setSmokingPrevalence(smokingPrevalence); + return this; + } + + public TetsimDatasetBuilder withRetailPrice(TetsimPriceVariable retailPrice) { + dataset.setRetailPrice(retailPrice); + return this; + } + + public TetsimDatasetBuilder withMarketShare(TetsimPriceVariable marketShare) { + dataset.setMarketShare(marketShare); + return this; + } + + public TetsimDatasetBuilder withCif(TetsimPriceVariable cif) { + dataset.setCif(cif); + return this; + } + + public TetsimDatasetBuilder withTobaccoLevy(TetsimPriceVariable tobaccoLevy) { + dataset.setTobaccoLevy(tobaccoLevy); + return this; + } + + public TetsimDatasetBuilder withExciseTax(TetsimPriceVariable exciseTax) { + dataset.setExciseTax(exciseTax); + return this; + } + + public TetsimDatasetBuilder withCustomDuty(TetsimPriceVariable customDuty) { + dataset.setCustomsDuty(customDuty); + return this; + } + + public TetsimDatasetBuilder withElasticityPrice(TetsimPriceVariable elasticityPrice) { + dataset.setElasticityOfDemandPrice(elasticityPrice); + return this; + } + + public TetsimDatasetBuilder withCrossElasticityPrice(TetsimPriceVariable crossElasticityPrice) { + dataset.setElasticityOfDemandCrossPrice(crossElasticityPrice); + return this; + } + + public TetsimDatasetBuilder withChangeInIllicitNot(TetsimPriceVariable changeInIllicitNot) { + dataset.setChangeInIllicitNot(changeInIllicitNot); + return this; + } + + public TetsimDatasetBuilder withOvershifting(TetsimPriceVariable overshifting) { + dataset.setOvershifting(overshifting); + return this; + } + + public TetsimDatasetBuilder withUndershifting(TetsimPriceVariable undershifting) { + dataset.setUndershifting(undershifting); + return this; + } + + public TetsimDataset build() { + return dataset; + } + +} diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/builder/TetsimPriceVariableBuilder.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/builder/TetsimPriceVariableBuilder.java new file mode 100644 index 00000000..e58385e1 --- /dev/null +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/builder/TetsimPriceVariableBuilder.java @@ -0,0 +1,23 @@ +package org.devgateway.toolkit.persistence.tetsim.builder; + +import org.devgateway.toolkit.persistence.dao.data.TetsimPriceVariable; +import org.devgateway.toolkit.persistence.dao.data.TetsimTobaccoProductValue; + +public class TetsimPriceVariableBuilder { + + private TetsimPriceVariable priceVariable; + + public TetsimPriceVariableBuilder() { + this.priceVariable = new TetsimPriceVariable(); + } + + public TetsimPriceVariableBuilder add(TetsimTobaccoProductValue tetsimTobaccoProductValue) { + priceVariable.getValues().add(tetsimTobaccoProductValue); + return this; + } + + public TetsimPriceVariable build() { + return priceVariable; + } + +} diff --git a/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/builder/TetsimTobaccoProductValueBuilder.java b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/builder/TetsimTobaccoProductValueBuilder.java new file mode 100644 index 00000000..a665da59 --- /dev/null +++ b/persistence/src/test/java/org/devgateway/toolkit/persistence/tetsim/builder/TetsimTobaccoProductValueBuilder.java @@ -0,0 +1,30 @@ +package org.devgateway.toolkit.persistence.tetsim.builder; + +import org.devgateway.toolkit.persistence.dao.data.TetsimTobaccoProductValue; +import org.devgateway.toolkit.persistence.dao.data.TobaccoProduct; + +import java.math.BigDecimal; + +public class TetsimTobaccoProductValueBuilder { + + private TetsimTobaccoProductValue productValue; + + public TetsimTobaccoProductValueBuilder() { + this.productValue = new TetsimTobaccoProductValue(); + } + + public TetsimTobaccoProductValueBuilder withTobaccoProduct(TobaccoProduct tobaccoProduct) { + productValue.setProduct(tobaccoProduct); + return this; + } + + public TetsimTobaccoProductValueBuilder withValue(BigDecimal value) { + productValue.setValue(value); + return this; + } + + public TetsimTobaccoProductValue build() { + return productValue; + } + +} diff --git a/persistence/src/test/resources/test.properties b/persistence/src/test/resources/test.properties index 7a3693d7..1acd006f 100644 --- a/persistence/src/test/resources/test.properties +++ b/persistence/src/test/resources/test.properties @@ -13,5 +13,9 @@ logging.level.org.springframework.test=error logging.level.org.springframework.web=error logging.level.org.hibernate=error +spring.jpa.database-platform=org.hibernate.dialect.DerbyTenSevenDialect + spring.datasource.driver-class-name=org.apache.derby.jdbc.EmbeddedDriver spring.datasource.url=jdbc:derby:memory:toolkit;create=true + +derby.stream.error.file=target/derby.log diff --git a/pom.xml b/pom.xml index 4b012118..6aa6e303 100644 --- a/pom.xml +++ b/pom.xml @@ -12,37 +12,37 @@ 4.0.0 - org.devgateway.toolkit - toolkit + org.devgateway.tcdi + tcdi-admin 0.0.1-SNAPSHOT pom - DGToolkit - DG Toolkit archetype - quick and easy way to start new projects through a working template - + TCDI Admin + TCDI Admin UTF-8 - 1.8 - 3.8.9 - 2.2.11.RELEASE - 10.14.2.0 - 4.0.1 + 17 + 4.29.2 + 3.2.10 + 10.17.1.0 + 4.1.2 devgateway/toolkit - 0.4.13 - 3.0.0 - 2.22.1 - 2.5.3 - 3.27.0-GA + 1.2.2 + 3.5.0 + 3.5.1 + 3.1.1 + 3.30.2-GA + 6.6.1.Final + 2023.0.3 persistence web - ui + forms - persistence-mongodb - checkstyle + 2015 @@ -81,7 +81,7 @@ jcenter-snapshots jcenter - http://oss.jfrog.org/artifactory/oss-snapshot-local/ + https://oss.jfrog.org/artifactory/oss-snapshot-local/ devgateway-open-source @@ -112,18 +112,10 @@ javassist ${javassist.version} - - - org.devgateway.toolkit - checkstyle - 1.0 - compile - true - org.reflections reflections - 0.9.12 + 0.10.2 @@ -134,6 +126,14 @@ mongo-java-driver ${mongo.version} + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + @@ -143,15 +143,6 @@ org.apache.maven.plugins maven-checkstyle-plugin ${maven-checkstyle-plugin.version} - - - validate - validate - - check - - - checkstyle.xml checkstyle-suppressions.xml @@ -161,12 +152,21 @@ true warning + + + validate + validate + true + + check + + + - org.devgateway.toolkit + com.puppycrawl.tools checkstyle - 1.0 - compile + 8.42 @@ -199,8 +199,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.8 - 1.8 + 17 + 17 diff --git a/reporting/pom.xml b/reporting/pom.xml index 749837dd..7eed4d53 100644 --- a/reporting/pom.xml +++ b/reporting/pom.xml @@ -34,8 +34,8 @@ - org.devgateway.toolkit - toolkit + org.devgateway.tcdi + admin 0.0.1-SNAPSHOT diff --git a/ui/_.env b/ui/_.env new file mode 100644 index 00000000..5b0e37a3 --- /dev/null +++ b/ui/_.env @@ -0,0 +1,12 @@ +PROTOCOL=http +DOMAIN=localhost +ISO=za +REACT_APP_TITLE=Tobacco Control Data Initiative +REACT_APP_WP_API=$PROTOCOL://localhost/wp/wp-json +REACT_APP_WP_STYLES=$PROTOCOL://localhost/wp/wp-admin/load-styles.php?c=1&dir=ltr&load%5Bchunk_0%5D=dashicons,admin-bar,buttons,media-views,editor-buttons,wp-components,wp-block-editor,wp-nux,wp-editor,wp-block-library,wp-block-&load%5Bchunk_1%5D=library-theme,wp-edit-blocks,wp-edit-post,wp-format-library,wp-block-directory,common,forms,admin-menu,dashboard,list-tables,edi&load%5Bchunk_2%5D=t,revisions,media,themes,about,nav-menus,wp-pointer,widgets,site-icon,l10n,wp-auth-check&ver=5.5.6' id='wp-block-library-css +REACT_APP_GA_CODE= +REACT_APP_DEFAULT_LOCALE=en +REACT_APP_WP_HOSTS=http://localhost +REACT_APP_USE_HASH_LINKS=false +REACT_APP_THEME=za +REACT_APP_API_ROOT=$PROTOCOL://localhost% \ No newline at end of file diff --git a/ui/src/main/java/org/devgateway/toolkit/ui/application.properties b/ui/src/main/java/org/devgateway/toolkit/ui/application.properties index 88653873..fe544a52 100644 --- a/ui/src/main/java/org/devgateway/toolkit/ui/application.properties +++ b/ui/src/main/java/org/devgateway/toolkit/ui/application.properties @@ -10,4 +10,4 @@ # Development Gateway - initial API and implementation ############################################################################### spring.servlet.multipart.enabled = false -server.port = 8090 \ No newline at end of file +server.port = 8080 \ No newline at end of file diff --git a/web/pom.xml b/web/pom.xml index ecd29f92..1c086a9c 100644 --- a/web/pom.xml +++ b/web/pom.xml @@ -7,7 +7,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - web + tcdi-admin-web jar Web @@ -16,14 +16,14 @@ UTF-8 org.devgateway.toolkit.web.spring.WebApplication - 1.8 - 1.4 + 17 + 5.3.0 3.0.0 - org.devgateway.toolkit - toolkit + org.devgateway.tcdi + tcdi-admin 0.0.1-SNAPSHOT @@ -78,20 +78,22 @@ - de.flapdoodle.embed - de.flapdoodle.embed.mongo + org.junit.jupiter + junit-jupiter-api + 5.11.3 test - org.devgateway.toolkit - persistence - 0.0.1-SNAPSHOT + de.flapdoodle.embed + de.flapdoodle.embed.mongo + 4.17.0 + test - org.devgateway.toolkit - persistence-mongodb + org.devgateway.tcdi + tcdi-admin-persistence 0.0.1-SNAPSHOT @@ -112,33 +114,33 @@ - org.apache.poi - ooxml-schemas - ${ooxml-schemas.version} - - - org.apache.xmlbeans - xmlbeans - - + io.springfox + springfox-swagger-ui + ${swagger.version} io.springfox - springfox-swagger2 + springfox-boot-starter ${swagger.version} - io.springfox - springfox-spring-webmvc - ${swagger.version} + org.apache.poi + poi + ${poi.version} - io.springfox - springfox-swagger-ui - ${swagger.version} + org.apache.poi + poi-ooxml + ${poi.version} + + + + org.apache.poi + poi-ooxml-full + ${ooxml-schemas.version} diff --git a/web/src/main/java/org/devgateway/toolkit/web/WebConstants.java b/web/src/main/java/org/devgateway/toolkit/web/WebConstants.java deleted file mode 100644 index dce15350..00000000 --- a/web/src/main/java/org/devgateway/toolkit/web/WebConstants.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.devgateway.toolkit.web; - -public final class WebConstants { - private WebConstants() { - } - - // by default no custom base path for forms - public static final String FORMS_BASE_PATH = ""; -} diff --git a/web/src/main/java/org/devgateway/toolkit/web/application.properties b/web/src/main/java/org/devgateway/toolkit/web/application.properties index 5ad54bd1..f80ad51e 100644 --- a/web/src/main/java/org/devgateway/toolkit/web/application.properties +++ b/web/src/main/java/org/devgateway/toolkit/web/application.properties @@ -10,15 +10,18 @@ # Development Gateway - initial API and implementation ############################################################################### spring.servlet.multipart.enabled = false -server.port = 8090 +server.port = 8080 management.endpoints.web.base-path=/manage management.endpoints.web.expose=* management.endpoint.shutdown.enabled=true -server.servlet.application-display-name=DG-Toolkit +server.servlet.application-display-name=TCDI-Admin spring.profiles.active=default spring.mail.host=localhost spring.mail.port=25 +spring.mail.sender=tcdisupport@developmentgateway.org + +spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER # Defines role hierarchy. # Hierarchy is specified as a string. Newline separates rules and > symbol has the meaning of 'includes'. @@ -30,3 +33,6 @@ spring.mail.port=25 # Important: spring-security-core 4.x used space or new line to separate rules, since 5.x only new line can separate # new lines. Please make sure to update your rules. roleHierarchy=ROLE_ADMIN > ROLE_USER + +allowedApiEndpoints=/api/testAPI** + diff --git a/web/src/main/java/org/devgateway/toolkit/web/excelcharts/ExcelChartSheet.java b/web/src/main/java/org/devgateway/toolkit/web/excelcharts/ExcelChartSheet.java index 255a0aeb..f7dc3c59 100644 --- a/web/src/main/java/org/devgateway/toolkit/web/excelcharts/ExcelChartSheet.java +++ b/web/src/main/java/org/devgateway/toolkit/web/excelcharts/ExcelChartSheet.java @@ -3,6 +3,8 @@ import org.apache.poi.ss.usermodel.Chart; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.charts.ChartDataSource; +import org.apache.poi.xddf.usermodel.chart.XDDFDataSource; +import org.apache.poi.xssf.usermodel.XSSFChart; import java.util.List; diff --git a/web/src/main/java/org/devgateway/toolkit/web/excelcharts/util/XSSFChartUtil.java b/web/src/main/java/org/devgateway/toolkit/web/excelcharts/util/XSSFChartUtil.java index 625aa0d6..81b7439e 100644 --- a/web/src/main/java/org/devgateway/toolkit/web/excelcharts/util/XSSFChartUtil.java +++ b/web/src/main/java/org/devgateway/toolkit/web/excelcharts/util/XSSFChartUtil.java @@ -13,9 +13,9 @@ /** * @author idobre * @since 8/8/16 - * - * Package private class with utility methods. It's based on - * org.apache.poi.xssf.usermodel.charts.XSSFChartUtil class + *

+ * Package private class with utility methods. It's based on + * org.apache.poi.xssf.usermodel.charts.XSSFChartUtil class */ public final class XSSFChartUtil { private XSSFChartUtil() { @@ -24,11 +24,9 @@ private XSSFChartUtil() { /** * Builds CTAxDataSource object content from POI ChartDataSource. - * - * @param ctAxDataSource - * OOXML data source to build - * @param dataSource - * POI data source to use + * + * @param ctAxDataSource OOXML data source to build + * @param dataSource POI data source to use */ public static void buildAxDataSource(final CTAxDataSource ctAxDataSource, final ChartDataSource dataSource) { if (dataSource.isNumeric()) { @@ -48,14 +46,12 @@ public static void buildAxDataSource(final CTAxDataSource ctAxDataSource, final /** * Builds CTNumDataSource object content from POI ChartDataSource - * - * @param ctNumDataSource - * OOXML data source to build - * @param dataSource - * POI data source to use + * + * @param ctNumDataSource OOXML data source to build + * @param dataSource POI data source to use */ public static void buildNumDataSource(final CTNumDataSource ctNumDataSource, - final ChartDataSource dataSource) { + final ChartDataSource dataSource) { if (dataSource.isReference()) { buildNumRef(ctNumDataSource.addNewNumRef(), dataSource); } else { diff --git a/web/src/main/java/org/devgateway/toolkit/web/rest/controller/HTTPErrorController.java b/web/src/main/java/org/devgateway/toolkit/web/rest/controller/HTTPErrorController.java index 76125b68..3a85b99b 100644 --- a/web/src/main/java/org/devgateway/toolkit/web/rest/controller/HTTPErrorController.java +++ b/web/src/main/java/org/devgateway/toolkit/web/rest/controller/HTTPErrorController.java @@ -1,26 +1,25 @@ package org.devgateway.toolkit.web.rest.controller; +import org.devgateway.toolkit.web.util.SettingsUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.RequestDispatcher; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import static org.devgateway.toolkit.web.WebConstants.FORMS_BASE_PATH; - /** * @author Nadejda Mandrescu */ @RestController public class HTTPErrorController implements ErrorController { - @Override - public String getErrorPath() { - return null; - } + + @Autowired + private SettingsUtils settingsUtils; @RequestMapping("/error") public void handleError(final HttpServletRequest request, final HttpServletResponse response) throws IOException { @@ -29,9 +28,9 @@ public void handleError(final HttpServletRequest request, final HttpServletRespo int statusCode = Integer.parseInt(status.toString()); String contextPath = request.getContextPath(); if (statusCode == HttpStatus.NOT_FOUND.value()) { - response.sendRedirect(contextPath + FORMS_BASE_PATH + "/error/not-found"); + response.sendRedirect(contextPath + settingsUtils.getFormsBasePath() + "/error/not-found"); } else if (statusCode == HttpStatus.FORBIDDEN.value()) { - response.sendRedirect(contextPath + FORMS_BASE_PATH + "/error/access-denied"); + response.sendRedirect(contextPath + settingsUtils.getFormsBasePath() + "/error/access-denied"); } } } diff --git a/web/src/main/java/org/devgateway/toolkit/web/rest/controller/SaveCustomerController.java b/web/src/main/java/org/devgateway/toolkit/web/rest/controller/SaveCustomerController.java deleted file mode 100644 index 7105d7a4..00000000 --- a/web/src/main/java/org/devgateway/toolkit/web/rest/controller/SaveCustomerController.java +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Development Gateway, Inc and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the MIT License (MIT) - * which accompanies this distribution, and is available at - * https://opensource.org/licenses/MIT - * - * Contributors: - * Development Gateway - initial API and implementation - *******************************************************************************/ -package org.devgateway.toolkit.web.rest.controller; - -import java.util.List; - -import org.devgateway.toolkit.persistence.mongo.dao.Customer; -import org.devgateway.toolkit.persistence.mongo.repository.CustomerRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * - * @author mpostelnicu - * - */ -@RestController -public class SaveCustomerController { - - @Autowired - private CustomerRepository customerRepository; - - @RequestMapping("/createCustomer") - public List createCustomer() { - customerRepository.save(new Customer("Alice", "Smith")); - customerRepository.save(new Customer("Bob", "Smith")); - - List findAll = customerRepository.findAll(); - return findAll; - } -} \ No newline at end of file diff --git a/web/src/main/java/org/devgateway/toolkit/web/rest/controller/TestController.java b/web/src/main/java/org/devgateway/toolkit/web/rest/controller/TestController.java index 41c7627a..53d2f333 100644 --- a/web/src/main/java/org/devgateway/toolkit/web/rest/controller/TestController.java +++ b/web/src/main/java/org/devgateway/toolkit/web/rest/controller/TestController.java @@ -3,8 +3,6 @@ import io.swagger.annotations.ApiOperation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.cache.annotation.CacheConfig; -import org.springframework.cache.annotation.Cacheable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @@ -15,8 +13,6 @@ */ @RestController -@CacheConfig(cacheNames = "reportsApiCache") -@Cacheable public class TestController { private static final Logger logger = LoggerFactory.getLogger(TestController.class); diff --git a/web/src/main/java/org/devgateway/toolkit/web/rest/controller/TetsimController.java b/web/src/main/java/org/devgateway/toolkit/web/rest/controller/TetsimController.java new file mode 100644 index 00000000..be8deb38 --- /dev/null +++ b/web/src/main/java/org/devgateway/toolkit/web/rest/controller/TetsimController.java @@ -0,0 +1,53 @@ +package org.devgateway.toolkit.web.rest.controller; + +import com.opencsv.exceptions.CsvDataTypeMismatchException; +import com.opencsv.exceptions.CsvRequiredFieldEmptyException; +import io.swagger.annotations.ApiOperation; +import org.devgateway.toolkit.persistence.dto.TetsimExportOutput; +import org.devgateway.toolkit.persistence.service.tetsim.TetsimOutputService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + +/** + * @author vchihai + */ + +@RestController +@RequestMapping("{dg-toolkit.forms.base-path}/api/tetsim") +public class TetsimController { + + private static final Logger logger = LoggerFactory.getLogger(TetsimController.class); + + private final TetsimOutputService tetsimOutputService; + + public TetsimController(final TetsimOutputService tetsimOutputService) { + this.tetsimOutputService = tetsimOutputService; + } + + @ApiOperation(value = "TETSIM Output API") + @GetMapping(value = "/output", produces = "application/json") + public List getTetsimOutput(@RequestParam() final Long id) { + List outputs = tetsimOutputService.getTetsimOutputs(id); + + return outputs; + } + + @ApiOperation(value = "Download TETSIM dataset in csv format") + @GetMapping(value = "/output/csv", produces = "text/csv") + public void exportTetsimOutput(HttpServletResponse response, @RequestParam() final Long id) + throws CsvRequiredFieldEmptyException, CsvDataTypeMismatchException, IOException { + + response.setContentType("text/csv"); + response.setHeader("Content-Disposition", "attachment; filename=\"dataset.csv\""); + response.getOutputStream().write(tetsimOutputService.getTetsimCSVDatasetOutputs(id)); + } + +} diff --git a/web/src/main/java/org/devgateway/toolkit/web/spring/CustomRestMvcConfiguration.java b/web/src/main/java/org/devgateway/toolkit/web/spring/CustomRestMvcConfiguration.java index 160ab216..383947a5 100644 --- a/web/src/main/java/org/devgateway/toolkit/web/spring/CustomRestMvcConfiguration.java +++ b/web/src/main/java/org/devgateway/toolkit/web/spring/CustomRestMvcConfiguration.java @@ -1,28 +1,16 @@ package org.devgateway.toolkit.web.spring; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.rest.core.config.RepositoryRestConfiguration; import org.springframework.data.rest.core.mapping.RepositoryDetectionStrategy.RepositoryDetectionStrategies; import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer; +import org.springframework.web.servlet.config.annotation.CorsRegistry; -/** - * We only allow to expose repositories that are annotated - * - * @author mpostelnicu - * http://docs.spring.io/spring-data/rest/docs/current/reference/html/#_which_repositories_get_exposed_by_defaults - */ @Configuration -public class CustomRestMvcConfiguration { +public class CustomRestMvcConfiguration implements RepositoryRestConfigurer { - @Bean - public RepositoryRestConfigurer repositoryRestConfigurer() { - return new RepositoryRestConfigurer() { - - @Override - public void configureRepositoryRestConfiguration(final RepositoryRestConfiguration config) { - config.setRepositoryDetectionStrategy(RepositoryDetectionStrategies.ANNOTATED); - } - }; + @Override + public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) { + config.setRepositoryDetectionStrategy(RepositoryDetectionStrategies.ANNOTATED); } } \ No newline at end of file diff --git a/web/src/main/java/org/devgateway/toolkit/web/spring/SwaggerConfig.java b/web/src/main/java/org/devgateway/toolkit/web/spring/SwaggerConfig.java index eaeedab5..2a341ee7 100644 --- a/web/src/main/java/org/devgateway/toolkit/web/spring/SwaggerConfig.java +++ b/web/src/main/java/org/devgateway/toolkit/web/spring/SwaggerConfig.java @@ -7,12 +7,10 @@ import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; import static springfox.documentation.builders.PathSelectors.regex; @Configuration -@EnableSwagger2WebMvc public class SwaggerConfig { @Bean public Docket yaliApi() { diff --git a/web/src/main/java/org/devgateway/toolkit/web/spring/WebSecurityConfig.java b/web/src/main/java/org/devgateway/toolkit/web/spring/WebSecurityConfig.java index 708e9269..8f3c702b 100644 --- a/web/src/main/java/org/devgateway/toolkit/web/spring/WebSecurityConfig.java +++ b/web/src/main/java/org/devgateway/toolkit/web/spring/WebSecurityConfig.java @@ -12,6 +12,7 @@ package org.devgateway.toolkit.web.spring; import org.devgateway.toolkit.persistence.spring.CustomJPAUserDetailsService; +import org.devgateway.toolkit.web.util.SettingsUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; @@ -23,20 +24,26 @@ import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl; import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; +import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.FilterInvocation; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.springframework.security.web.context.SecurityContextPersistenceFilter; import org.springframework.security.web.firewall.HttpFirewall; import org.springframework.security.web.firewall.StrictHttpFirewall; -import static org.devgateway.toolkit.web.WebConstants.FORMS_BASE_PATH; +import java.util.Arrays; +import java.util.stream.Collectors; /** * @author mpostelnicu This configures the spring security for the Web project. @@ -49,7 +56,7 @@ // them overlayed, it must pick that one first) @PropertySource("classpath:allowedApiEndpoints.properties") @EnableWebSecurity -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { +public class WebSecurityConfig { @Autowired protected CustomJPAUserDetailsService customJPAUserDetailsService; @@ -63,6 +70,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private PasswordEncoder passwordEncoder; + @Autowired + private SettingsUtils settingsUtils; + @Bean public HttpFirewall allowUrlEncodedSlashHttpFirewall() { final StrictHttpFirewall firewall = new StrictHttpFirewall(); @@ -84,24 +94,80 @@ public SecurityContextPersistenceFilter securityContextPersistenceFilter() { return securityContextPersistenceFilter; } - @Override - public void configure(final WebSecurity web) throws Exception { - web.httpFirewall(allowUrlEncodedSlashHttpFirewall()) - .ignoring().antMatchers(allowedApiEndpoints).and() - .ignoring().antMatchers( - FORMS_BASE_PATH + "/login", - FORMS_BASE_PATH + "/forgotPassword/**"); +// @Override +// public void configure(final WebSecurity web) throws Exception { +// web.httpFirewall(allowUrlEncodedSlashHttpFirewall()) +// .ignoring().antMatchers(getAllowedAPIEndpointsWithBasePath()).and() +// .ignoring().antMatchers( +// settingsUtils.getFormsBasePath() + "/login", +// settingsUtils.getFormsBasePath() + "/forgotPassword/**"); +// } + + private String[] getAllowedAPIEndpointsWithBasePath() { + if (allowedApiEndpoints != null) { + return Arrays.stream(allowedApiEndpoints) + .map(s -> settingsUtils.getFormsBasePath() + s) + .collect(Collectors.toList()).toArray(new String[allowedApiEndpoints.length]); + } + + return new String[]{}; + } + +// @Override +// protected void configure(final HttpSecurity http) throws Exception { +// http.authorizeRequests().expressionHandler(webExpressionHandler()) // inject role hierarchy +// .antMatchers(settingsUtils.getFormsBasePath() + "/monitoring/**").access("hasRole('ROLE_ADMIN')") +// .antMatchers(settingsUtils.getFormsBasePath() + "/**").authenticated().and() +// .formLogin().loginPage(settingsUtils.getFormsBasePath() + "/login").permitAll().and() +// .requestCache().and().logout().permitAll().and() +// .sessionManagement().and().csrf().disable(); +// http.addFilter(securityContextPersistenceFilter()); +// } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.securityContext(securityContext -> securityContext.securityContextRepository(httpSessionSecurityContextRepository())) + .authorizeHttpRequests(authz -> authz + .requestMatchers(settingsUtils.getFormsBasePath() + "/monitoring/**").hasRole("ADMIN") + .requestMatchers(settingsUtils.getFormsBasePath() + "/**").authenticated() + ) + .formLogin(form -> form + .loginPage(settingsUtils.getFormsBasePath() + "/login").permitAll() + ) + .requestCache(requestCache -> requestCache.disable()) + .logout(logout -> logout.permitAll()) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)) + .csrf(csrf -> csrf.disable()); + + // Apply the custom SecurityExpressionHandler here + http.setSharedObject(SecurityExpressionHandler.class, webExpressionHandler()); + +// http.setSharedObject(HttpFirewall.class, allowUrlEncodedSlashHttpFirewall()); +// +// http.ignoring() +// .requestMatchers(getAllowedAPIEndpointsWithBasePath()) +// .requestMatchers(settingsUtils.getFormsBasePath() + "/login", settingsUtils.getFormsBasePath() + "/forgotPassword/**"); +// // Firewall configuration, equivalent to 'allowUrlEncodedSlashHttpFirewall' +// http.getSharedObject(WebSecurity.class) +// .httpFirewall(allowUrlEncodedSlashHttpFirewall()); + + // Ignoring paths (migrated from 'configure(WebSecurity web)') +// http.getSharedObject(WebSecurity.class) +// .ignoring() +// .requestMatchers(getAllowedAPIEndpointsWithBasePath()) +// .requestMatchers(settingsUtils.getFormsBasePath() + "/login", settingsUtils.getFormsBasePath() + "/forgotPassword/**"); + + return http.build(); } - @Override - protected void configure(final HttpSecurity http) throws Exception { - http.authorizeRequests().expressionHandler(webExpressionHandler()) // inject role hierarchy - .antMatchers(FORMS_BASE_PATH + "/monitoring/**").access("hasRole('ROLE_ADMIN')") - .antMatchers(FORMS_BASE_PATH + "/**").authenticated().and() - .formLogin().loginPage(FORMS_BASE_PATH + "/login").permitAll().and() - .requestCache().and().logout().permitAll().and() - .sessionManagement().and().csrf().disable(); - http.addFilter(securityContextPersistenceFilter()); + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return (web) -> { + web.httpFirewall(allowUrlEncodedSlashHttpFirewall()); + web.ignoring() + .requestMatchers(getAllowedAPIEndpointsWithBasePath()) + .requestMatchers(settingsUtils.getFormsBasePath() + "/login", settingsUtils.getFormsBasePath() + "/forgotPassword/**"); + }; } /** @@ -128,9 +194,16 @@ RoleHierarchy roleHierarchy() { } @Bean - @Override - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); + public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } + + @Bean + public DaoAuthenticationProvider authenticationProvider() { + DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); + authenticationProvider.setUserDetailsService(customJPAUserDetailsService); + authenticationProvider.setPasswordEncoder(passwordEncoder); + return authenticationProvider; } @Autowired diff --git a/web/src/main/java/org/devgateway/toolkit/web/util/SettingsUtils.java b/web/src/main/java/org/devgateway/toolkit/web/util/SettingsUtils.java index 0e007e89..ca9eb907 100644 --- a/web/src/main/java/org/devgateway/toolkit/web/util/SettingsUtils.java +++ b/web/src/main/java/org/devgateway/toolkit/web/util/SettingsUtils.java @@ -8,9 +8,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import org.springframework.util.ObjectUtils; +import java.util.Calendar; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * @author idobre @@ -18,6 +21,11 @@ */ @Service public class SettingsUtils { + + public static final int START_YEAR = 2000; + + public static final String DEFAULT_LANGUAGE = "en_US"; + protected static Logger logger = LoggerFactory.getLogger(SettingsUtils.class); @Autowired @@ -28,6 +36,12 @@ public class SettingsUtils { @Value("${googleAnalyticsTrackingId:#{null}}") private String googleAnalyticsTrackingId; + @Value("${dg-toolkit.forms.base-path}") + private String formsBasePath; + + @Autowired + private AdminSettingsRepository adminSettingsRepository; + public String getGoogleAnalyticsTrackingId() { return googleAnalyticsTrackingId; } @@ -54,11 +68,14 @@ private void init() { } } + public List getYearsRange() { + return IntStream.rangeClosed(getStartYear(), Calendar.getInstance().get(Calendar.YEAR)). + boxed().sorted(Collections.reverseOrder()).collect(Collectors.toList()); + } - public static final String DEFAULT_LANGUAGE = "en_US"; - - @Autowired - private AdminSettingsRepository adminSettingsRepository; + public int getStartYear() { + return START_YEAR; + } public AdminSettings getSettings() { List list = adminSettingsRepository.findAll(); @@ -69,5 +86,11 @@ public AdminSettings getSettings() { } } + public String getFormsBasePath() { + return formsBasePath; + } + public void setFormsBasePath(final String formsBasePath) { + this.formsBasePath = formsBasePath; + } } diff --git a/web/src/test/java/org/devgateway/toolkit/web/AbstractSpringDataRestControllerTest.java b/web/src/test/java/org/devgateway/toolkit/web/AbstractSpringDataRestControllerTest.java index cc9809b5..3021373e 100644 --- a/web/src/test/java/org/devgateway/toolkit/web/AbstractSpringDataRestControllerTest.java +++ b/web/src/test/java/org/devgateway/toolkit/web/AbstractSpringDataRestControllerTest.java @@ -8,7 +8,7 @@ import java.util.Collections; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.junit.Before; diff --git a/web/src/test/resources/test.properties b/web/src/test/resources/test.properties index f88ef6bd..52724287 100644 --- a/web/src/test/resources/test.properties +++ b/web/src/test/resources/test.properties @@ -15,5 +15,9 @@ logging.level.org.springframework.test=error logging.level.org.springframework.web=error logging.level.org.hibernate=error +spring.jpa.database-platform=org.hibernate.dialect.DerbyTenSevenDialect + spring.datasource.driver-class-name=org.apache.derby.jdbc.EmbeddedDriver -spring.datasource.url=jdbc:derby:memory:toolkit;create=true \ No newline at end of file +spring.datasource.url=jdbc:derby:memory:toolkit;create=true + +derby.stream.error.file=target/derby.log \ No newline at end of file