feat: initial commit - Z3 backend (Clean Architecture / DDD)
This commit is contained in:
commit
4efa3d8bbf
566 changed files with 40611 additions and 0 deletions
5
.dockerignore
Normal file
5
.dockerignore
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#*
|
||||
#!target/*-runner
|
||||
#!target/*-runner.jar
|
||||
#!target/lib/*
|
||||
#!target/quarkus-app/*
|
||||
46
.gitignore
vendored
Normal file
46
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#Maven
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
release.properties
|
||||
.flattened-pom.xml
|
||||
|
||||
# Eclipse
|
||||
.project
|
||||
.classpath
|
||||
.settings/
|
||||
bin/
|
||||
|
||||
# IntelliJ
|
||||
.idea
|
||||
*.ipr
|
||||
*.iml
|
||||
*.iws
|
||||
|
||||
# NetBeans
|
||||
nb-configuration.xml
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode
|
||||
.factorypath
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Vim
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# patch
|
||||
*.orig
|
||||
*.rej
|
||||
|
||||
# Local environment
|
||||
.env
|
||||
|
||||
# Plugin directory
|
||||
/.quarkus/cli/plugins/
|
||||
|
||||
# KEYS
|
||||
*.pem
|
||||
56
.gitlab-ci.yml
Normal file
56
.gitlab-ci.yml
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
image: quay.io/buildah/stable
|
||||
|
||||
stages:
|
||||
- test
|
||||
- release
|
||||
- build
|
||||
|
||||
branch-release:
|
||||
image: docker.io/bitnami/git
|
||||
variables:
|
||||
GIT_STRATEGY: clone
|
||||
stage: release
|
||||
script:
|
||||
# create branch ; if the tag is v2024.01, the branch will be rel/2024.01 (without the v)
|
||||
- git switch -c rel/${CI_COMMIT_TAG:1}
|
||||
- git push origin rel/${CI_COMMIT_TAG:1}
|
||||
rules:
|
||||
# only for tags like v2024.01, v2024.01.01, v2024.01-1, v2024.01.01-1
|
||||
- if: $CI_COMMIT_TAG =~ /^v\d{4}\.\d{2}(\.\d{2})?(-\d+)?$/
|
||||
|
||||
build-staging:
|
||||
stage: build
|
||||
variables:
|
||||
IMAGE_TAG: $CI_REGISTRY_IMAGE:staging
|
||||
before_script:
|
||||
- buildah login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
||||
script:
|
||||
- buildah bud -t "$IMAGE_TAG" --build-arg GITLAB_MVN_TOKEN=$CI_JOB_TOKEN .
|
||||
- buildah push "$IMAGE_TAG"
|
||||
only:
|
||||
- main
|
||||
|
||||
build-feat:
|
||||
stage: build
|
||||
before_script:
|
||||
# CI_COMMIT_BRANCH without "feat/" prefix
|
||||
- export IMAGE_TAG=$CI_REGISTRY_IMAGE:${CI_COMMIT_BRANCH/feat\//feat-}
|
||||
- buildah login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
||||
script:
|
||||
- buildah bud -t "$IMAGE_TAG" --build-arg GITLAB_MVN_TOKEN=$CI_JOB_TOKEN .
|
||||
- buildah push "$IMAGE_TAG"
|
||||
rules:
|
||||
- when: manual
|
||||
if: '$CI_COMMIT_BRANCH =~ /^feat\//'
|
||||
|
||||
build-release:
|
||||
stage: build
|
||||
variables:
|
||||
IMAGE_TAG: $CI_REGISTRY_IMAGE:latest
|
||||
before_script:
|
||||
- buildah login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
||||
script:
|
||||
- buildah bud -t "$IMAGE_TAG" --build-arg GITLAB_MVN_TOKEN=$CI_JOB_TOKEN .
|
||||
- buildah push "$IMAGE_TAG"
|
||||
only:
|
||||
- /^rel\//
|
||||
1
.mvn/wrapper/.gitignore
vendored
Normal file
1
.mvn/wrapper/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
maven-wrapper.jar
|
||||
98
.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
98
.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.Authenticator;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
public final class MavenWrapperDownloader
|
||||
{
|
||||
private static final String WRAPPER_VERSION = "3.2.0";
|
||||
|
||||
private static final boolean VERBOSE = Boolean.parseBoolean( System.getenv( "MVNW_VERBOSE" ) );
|
||||
|
||||
public static void main( String[] args )
|
||||
{
|
||||
log( "Apache Maven Wrapper Downloader " + WRAPPER_VERSION );
|
||||
|
||||
if ( args.length != 2 )
|
||||
{
|
||||
System.err.println( " - ERROR wrapperUrl or wrapperJarPath parameter missing" );
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
log( " - Downloader started" );
|
||||
final URL wrapperUrl = new URL( args[0] );
|
||||
final String jarPath = args[1].replace( "..", "" ); // Sanitize path
|
||||
final Path wrapperJarPath = Paths.get( jarPath ).toAbsolutePath().normalize();
|
||||
downloadFileFromURL( wrapperUrl, wrapperJarPath );
|
||||
log( "Done" );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
System.err.println( "- Error downloading: " + e.getMessage() );
|
||||
if ( VERBOSE )
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.exit( 1 );
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadFileFromURL( URL wrapperUrl, Path wrapperJarPath )
|
||||
throws IOException
|
||||
{
|
||||
log( " - Downloading to: " + wrapperJarPath );
|
||||
if ( System.getenv( "MVNW_USERNAME" ) != null && System.getenv( "MVNW_PASSWORD" ) != null )
|
||||
{
|
||||
final String username = System.getenv( "MVNW_USERNAME" );
|
||||
final char[] password = System.getenv( "MVNW_PASSWORD" ).toCharArray();
|
||||
Authenticator.setDefault( new Authenticator()
|
||||
{
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication()
|
||||
{
|
||||
return new PasswordAuthentication( username, password );
|
||||
}
|
||||
} );
|
||||
}
|
||||
try ( InputStream inStream = wrapperUrl.openStream() )
|
||||
{
|
||||
Files.copy( inStream, wrapperJarPath, StandardCopyOption.REPLACE_EXISTING );
|
||||
}
|
||||
log( " - Downloader complete" );
|
||||
}
|
||||
|
||||
private static void log( String msg )
|
||||
{
|
||||
if ( VERBOSE )
|
||||
{
|
||||
System.out.println( msg );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
18
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
18
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.7/apache-maven-3.9.7-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
|
||||
245
CHANGELOG.md
Normal file
245
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
## (2025-03-27)
|
||||
## 1.1.0 (2025-03-27)
|
||||
|
||||
### Features
|
||||
|
||||
* **global:** Add some statistics resources to get some graphics ([8f12c0f](https://gitlab.pegase.tech/z3/z3-backend/commit/8f12c0f1947ff9c61e1dbe9fe608d4e6b03c8f21))
|
||||
* **global:** Add statistics domain and simplify UUID handling ([377249d](https://gitlab.pegase.tech/z3/z3-backend/commit/377249d5de7f3ec788c3372b661dbb61d638a2b9))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **domain:** Allow Referer path to be empty ([1884049](https://gitlab.pegase.tech/z3/z3-backend/commit/188404953b2171df239c0a10b775bae79bda8919))
|
||||
* **domain:** DomainNameService could not reliably allow assign a fqdn to a brand that already owns it ([07e02be](https://gitlab.pegase.tech/z3/z3-backend/commit/07e02be02d2c025148726a0e44e92e383b707fa8)), closes [#13](https://gitlab.pegase.tech/z3/z3-backend/issues/13)
|
||||
* **domain:** Fix CreateFingerPrintTest ([bce237d](https://gitlab.pegase.tech/z3/z3-backend/commit/bce237d76428f7498a53b33c396067fe43277572))
|
||||
* **domain:** Link Statistic for visits was no correctly using nullable ([7e885a4](https://gitlab.pegase.tech/z3/z3-backend/commit/7e885a4558390b565f9ae406dbd956b68a5f3868))
|
||||
* **infrastructure:** GeoIpServiceImpl was not loading correctly resources files ([e918708](https://gitlab.pegase.tech/z3/z3-backend/commit/e918708cb995b54aac3f4db800ad625017c55d4f))
|
||||
* **infrastructure:** UserAgentAnalyser was not loading correctly yml rule files ([190dc6e](https://gitlab.pegase.tech/z3/z3-backend/commit/190dc6e790cdf1e34364cdd75fc3a1df10ff0e87))
|
||||
## 1.0.5 (2025-03-05)
|
||||
|
||||
### Features
|
||||
|
||||
* **global:** Allow brands to have an associated list of Fqdn ([fe7708d](https://gitlab.pegase.tech/z3/z3-backend/commit/fe7708da0baf8954ab4a0703a6d3b5f143fb9aa2))
|
||||
* **global:** Link Export now uses brand first available fqdn or the resolver fqdn ([011c261](https://gitlab.pegase.tech/z3/z3-backend/commit/011c2613b3ceb604df8b69a42629d87459de1440))
|
||||
* **global:** Link resolve change of behavior and using `host` parameter ([d56b0a6](https://gitlab.pegase.tech/z3/z3-backend/commit/d56b0a6043dbcd94e4bb9091093809c59c4ac329))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **application:** Craete and update brand properly validates fqdns ([93492f9](https://gitlab.pegase.tech/z3/z3-backend/commit/93492f96e30c8bf7c4d27d3c9d6f912bdf770dc4))
|
||||
* **application:** Fix create brand request validation ([639c577](https://gitlab.pegase.tech/z3/z3-backend/commit/639c5774c6eae62b98293d5c8a27da080eddb571))
|
||||
* **application:** Fixes [#4](https://gitlab.pegase.tech/z3/z3-backend/issues/4) choosing tag while importing links ([ad37d91](https://gitlab.pegase.tech/z3/z3-backend/commit/ad37d91fbf4bf53f8677334a0389e67d251f8227))
|
||||
* **application:** Handle Unicode BOM on csv file import ([214c827](https://gitlab.pegase.tech/z3/z3-backend/commit/214c827c39b11a4e5e5b28205605fac1e20b5cb2))
|
||||
* **application:** RedirectLinkOutputTest was wrong after rebase with main ([22d74c1](https://gitlab.pegase.tech/z3/z3-backend/commit/22d74c19fced37424c21c437d75f636f8bd341f2))
|
||||
* **domain:** Closes [#7](https://gitlab.pegase.tech/z3/z3-backend/issues/7) ([0300d7f](https://gitlab.pegase.tech/z3/z3-backend/commit/0300d7f5fcc3e3aee7fc7d79c19b2fb6f6aefac2))
|
||||
* **domain:** Correct Validation error field name on Create and Update brand ([96ca5f0](https://gitlab.pegase.tech/z3/z3-backend/commit/96ca5f0c3b066852f7ad38f72be6f44f1a46f2c6))
|
||||
* **domain:** Prevent link upsert on other brands while importing ([a81ffde](https://gitlab.pegase.tech/z3/z3-backend/commit/a81ffdeeafa527a64a805250a3ecd0137ccdff7c))
|
||||
* **infrastructure:** LinkRepository could output null for count queries ([9ed8300](https://gitlab.pegase.tech/z3/z3-backend/commit/9ed8300ede944574d96f91d835b07f6bdb20389e))
|
||||
* **infrastructure:** ReportingSubscriptionDatabaseRepository fix querying by userUuid ([82c24bf](https://gitlab.pegase.tech/z3/z3-backend/commit/82c24bf5acb24acf936e3bd484b6fa4e2e831ced))
|
||||
* **infrastructure:** Simplify repositories cache usage ([f939928](https://gitlab.pegase.tech/z3/z3-backend/commit/f939928d812ff9b3c9d0b4f0b50b03968683ab82))
|
||||
## 1.0.3 (2025-01-09)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **global:** SendMessage can now output it success status
|
||||
|
||||
### Features
|
||||
|
||||
* **global:** Add Reporting Subscriptions for users ([da78839](https://gitlab.pegase.tech/z3/z3-backend/commit/da78839458761d5be909e71785c0af9a2810fe72))
|
||||
* **global:** Send scheduled invalid links reports ([fc059b5](https://gitlab.pegase.tech/z3/z3-backend/commit/fc059b576506084fdebf17f2f95bcc7666e4cef3))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** Fix Hibernate warning on compilation ([0b8dec5](https://gitlab.pegase.tech/z3/z3-backend/commit/0b8dec52decba550bc059a8ce68e9dd645c43971))
|
||||
* **domain:** GetGlobalStatistics count is wrong + add more tests ([8df73ea](https://gitlab.pegase.tech/z3/z3-backend/commit/8df73ea5ea75423dbca7b3346408ef5f2bfe263c))
|
||||
* **domain:** Remove lang3 dep in SendReports use case ([60d3e72](https://gitlab.pegase.tech/z3/z3-backend/commit/60d3e72d242069eeb1fd325775a074fd29e28876))
|
||||
* **domain:** When Link is updated it now changes its updatedAt timestamp ([8eeb8d9](https://gitlab.pegase.tech/z3/z3-backend/commit/8eeb8d934da239ac0aeb5a2e863798012eeab85b))
|
||||
* **global:** GetLinksStatistics regression fix ([e9cc5df](https://gitlab.pegase.tech/z3/z3-backend/commit/e9cc5dfd6881ae853d9e2b80b298b09108ccf67c))
|
||||
* **global:** Use Flyway to apply a migration with seeded data ([be00a1a](https://gitlab.pegase.tech/z3/z3-backend/commit/be00a1a5807adf9445574d9083bda91423b8baba))
|
||||
* **global:** Use ZonedDateTime as value-object and return them from presenter for Links usecases ([d0ee9a6](https://gitlab.pegase.tech/z3/z3-backend/commit/d0ee9a673cc592c63f950dc3b1cc523cda2893c7))
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* **global:** SendMessage can now output it success status ([6b68299](https://gitlab.pegase.tech/z3/z3-backend/commit/6b68299c853021112f68fa016cf7e99a883d3a42))
|
||||
## 1.0.2 (2024-12-10)
|
||||
|
||||
### Features
|
||||
|
||||
* **application:** Ajout d'un message sur une demande de redirection d'un lien invalide ([4c28c8f](https://gitlab.pegase.tech/z3/z3-backend/commit/4c28c8f67c08c68f727c222b933451d8aea8b01f))
|
||||
* **domain:** Allow to put any text on source and slugify it on import ([a9f69b7](https://gitlab.pegase.tech/z3/z3-backend/commit/a9f69b75ebc21a5853584bc358b830d305a77cc2))
|
||||
* **global:** Allow to set tag while importing links ([3656677](https://gitlab.pegase.tech/z3/z3-backend/commit/3656677833632159dfc284904c5b107b8176b609))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **application:** Add no-cache header for public redirection ([20c85f7](https://gitlab.pegase.tech/z3/z3-backend/commit/20c85f7c1f563c4448176b736c25262727193372))
|
||||
* **application:** Correction of import for user requests ([9942f65](https://gitlab.pegase.tech/z3/z3-backend/commit/9942f658baf69c75362c4085837863d3621f90b3))
|
||||
* **application:** Slugify source on create link endpoint ([3e760a3](https://gitlab.pegase.tech/z3/z3-backend/commit/3e760a321dc79e809706252d5992df63542bfdfb))
|
||||
* **domain:** Import links for catalog was not setting correct brand ([02d6507](https://gitlab.pegase.tech/z3/z3-backend/commit/02d650728ad394c0df86993ef6f59051cf1436d5))
|
||||
* **domain:** Import links was returning the wrong imported links number ([9ec5c2d](https://gitlab.pegase.tech/z3/z3-backend/commit/9ec5c2dc377ebf859e8c1b8d8579501b8ec93cc2))
|
||||
* **domain:** Reset user password was not persisting the updated credential ([5e811bd](https://gitlab.pegase.tech/z3/z3-backend/commit/5e811bd3c428054fa00dc5dfb300b16900b74d19))
|
||||
* **infrastructure:** Slugifyer now replaces undescores ([34ab963](https://gitlab.pegase.tech/z3/z3-backend/commit/34ab963a68464be0ff0257b5fec91154b0d229c5))
|
||||
## 1.0.1 (2024-12-08)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **global:** Allow to assign some brands to any user
|
||||
|
||||
### Features
|
||||
|
||||
* **global:** Allow to assign some brands to any user ([6e820e7](https://gitlab.pegase.tech/z3/z3-backend/commit/6e820e772e690e9f129ce55b63fb377da9c4d1fb))
|
||||
* **global:** Change user password ([acb99eb](https://gitlab.pegase.tech/z3/z3-backend/commit/acb99ebcec6a6de5480a3ef3f57ffa274192339d))
|
||||
* **global:** Complete Global statistics feature ([0f5074d](https://gitlab.pegase.tech/z3/z3-backend/commit/0f5074da602002af7988656781afa302c3cdd711))
|
||||
* **global:** Get statistics for Brand, Catalog and Tag ([26db02b](https://gitlab.pegase.tech/z3/z3-backend/commit/26db02b5df14151972fbfab8c73f6072267b5df6))
|
||||
* **global:** Reset user password feature ([a59ae02](https://gitlab.pegase.tech/z3/z3-backend/commit/a59ae027ff944c182f168bdf89406f27a8d39091))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **application:** Add not null to create and update users requests ([a35dfe4](https://gitlab.pegase.tech/z3/z3-backend/commit/a35dfe40430a889361118049b1fcea882e05d5df))
|
||||
* **application:** Allow admin users to update users ([13f141c](https://gitlab.pegase.tech/z3/z3-backend/commit/13f141c24e6512d79ab6250a59f6341fee2c7c5f))
|
||||
* **application:** Remove Role check on get brand resource ([492d842](https://gitlab.pegase.tech/z3/z3-backend/commit/492d842664842e1baa477e2fbbf75e1f228b06bd))
|
||||
## 0.0.1 (2024-09-10)
|
||||
## (2025-03-27)
|
||||
|
||||
### Features
|
||||
|
||||
* **global:** Add some statistics resources to get some graphics ([8f12c0f](https://gitlab.pegase.tech/z3/z3-backend/commit/8f12c0f1947ff9c61e1dbe9fe608d4e6b03c8f21))
|
||||
* **global:** Add statistics domain and simplify UUID handling ([377249d](https://gitlab.pegase.tech/z3/z3-backend/commit/377249d5de7f3ec788c3372b661dbb61d638a2b9))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **domain:** Allow Referer path to be empty ([1884049](https://gitlab.pegase.tech/z3/z3-backend/commit/188404953b2171df239c0a10b775bae79bda8919))
|
||||
* **domain:** Link Statistic for visits was no correctly using nullable ([7e885a4](https://gitlab.pegase.tech/z3/z3-backend/commit/7e885a4558390b565f9ae406dbd956b68a5f3868))
|
||||
## (2025-03-05)
|
||||
|
||||
## [1.0.5](https://gitlab.pegase.tech/z3/z3-backend/compare/1.0.4...1.0.5) (2025-02-04)
|
||||
|
||||
### Features
|
||||
|
||||
* **global:** Allow brands to have an associated list of
|
||||
Fqdn ([fe7708d](https://gitlab.pegase.tech/z3/z3-backend/commit/fe7708da0baf8954ab4a0703a6d3b5f143fb9aa2))
|
||||
* **global:** Link Export now uses brand first available fqdn or the resolver
|
||||
fqdn ([011c261](https://gitlab.pegase.tech/z3/z3-backend/commit/011c2613b3ceb604df8b69a42629d87459de1440))
|
||||
* **global:** Link resolve change of behavior and using `host`
|
||||
parameter ([d56b0a6](https://gitlab.pegase.tech/z3/z3-backend/commit/d56b0a6043dbcd94e4bb9091093809c59c4ac329))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **application:** Craete and update brand properly validates
|
||||
fqdns ([93492f9](https://gitlab.pegase.tech/z3/z3-backend/commit/93492f96e30c8bf7c4d27d3c9d6f912bdf770dc4))
|
||||
* **application:** RedirectLinkOutputTest was wrong after rebase with
|
||||
main ([22d74c1](https://gitlab.pegase.tech/z3/z3-backend/commit/22d74c19fced37424c21c437d75f636f8bd341f2))
|
||||
* **domain:** Correct Validation error field name on Create and Update
|
||||
brand ([96ca5f0](https://gitlab.pegase.tech/z3/z3-backend/commit/96ca5f0c3b066852f7ad38f72be6f44f1a46f2c6))
|
||||
|
||||
## (2025-03-05)
|
||||
|
||||
## [1.0.4](https://gitlab.pegase.tech/z3/z3-backend/compare/1.0.3...1.0.4) (2025-02-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **application:** Fix create brand request
|
||||
validation ([639c577](https://gitlab.pegase.tech/z3/z3-backend/commit/639c5774c6eae62b98293d5c8a27da080eddb571))
|
||||
* **application:** Fixes [#4](https://gitlab.pegase.tech/z3/z3-backend/issues/4) choosing tag while
|
||||
importing
|
||||
links ([ad37d91](https://gitlab.pegase.tech/z3/z3-backend/commit/ad37d91fbf4bf53f8677334a0389e67d251f8227))
|
||||
* **application:** Handle Unicode BOM on csv file
|
||||
import ([214c827](https://gitlab.pegase.tech/z3/z3-backend/commit/214c827c39b11a4e5e5b28205605fac1e20b5cb2))
|
||||
* **domain:**
|
||||
Closes [#7](https://gitlab.pegase.tech/z3/z3-backend/issues/7) ([0300d7f](https://gitlab.pegase.tech/z3/z3-backend/commit/0300d7f5fcc3e3aee7fc7d79c19b2fb6f6aefac2))
|
||||
* **domain:** Prevent link upsert on other brands while
|
||||
importing ([a81ffde](https://gitlab.pegase.tech/z3/z3-backend/commit/a81ffdeeafa527a64a805250a3ecd0137ccdff7c))
|
||||
* **infrastructure:** LinkRepository could output null for count
|
||||
queries ([9ed8300](https://gitlab.pegase.tech/z3/z3-backend/commit/9ed8300ede944574d96f91d835b07f6bdb20389e))
|
||||
* **infrastructure:** ReportingSubscriptionDatabaseRepository fix querying by
|
||||
userUuid ([82c24bf](https://gitlab.pegase.tech/z3/z3-backend/commit/82c24bf5acb24acf936e3bd484b6fa4e2e831ced))
|
||||
* **infrastructure:** Simplify repositories cache
|
||||
usage ([f939928](https://gitlab.pegase.tech/z3/z3-backend/commit/f939928d812ff9b3c9d0b4f0b50b03968683ab82))
|
||||
|
||||
## [1.0.3](https://gitlab.pegase.tech/z3/z3-backend/compare/1.0.2...1.0.3) (2025-01-09)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **global:** SendMessage can now output it success status
|
||||
|
||||
### Features
|
||||
|
||||
* **global:** Add Reporting Subscriptions for
|
||||
users ([da78839](https://gitlab.pegase.tech/z3/z3-backend/commit/da78839458761d5be909e71785c0af9a2810fe72))
|
||||
* **global:** Send scheduled invalid links
|
||||
reports ([fc059b5](https://gitlab.pegase.tech/z3/z3-backend/commit/fc059b576506084fdebf17f2f95bcc7666e4cef3))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** Fix Hibernate warning on
|
||||
compilation ([0b8dec5](https://gitlab.pegase.tech/z3/z3-backend/commit/0b8dec52decba550bc059a8ce68e9dd645c43971))
|
||||
* **domain:** GetGlobalStatistics count is wrong + add more
|
||||
tests ([8df73ea](https://gitlab.pegase.tech/z3/z3-backend/commit/8df73ea5ea75423dbca7b3346408ef5f2bfe263c))
|
||||
* **domain:** Remove lang3 dep in SendReports use
|
||||
case ([60d3e72](https://gitlab.pegase.tech/z3/z3-backend/commit/60d3e72d242069eeb1fd325775a074fd29e28876))
|
||||
* **domain:** When Link is updated it now changes its updatedAt
|
||||
timestamp ([8eeb8d9](https://gitlab.pegase.tech/z3/z3-backend/commit/8eeb8d934da239ac0aeb5a2e863798012eeab85b))
|
||||
* **global:** GetLinksStatistics regression
|
||||
fix ([e9cc5df](https://gitlab.pegase.tech/z3/z3-backend/commit/e9cc5dfd6881ae853d9e2b80b298b09108ccf67c))
|
||||
* **global:** Use Flyway to apply a migration with seeded
|
||||
data ([be00a1a](https://gitlab.pegase.tech/z3/z3-backend/commit/be00a1a5807adf9445574d9083bda91423b8baba))
|
||||
* **global:** Use ZonedDateTime as value-object and return them from presenter for Links
|
||||
usecases ([d0ee9a6](https://gitlab.pegase.tech/z3/z3-backend/commit/d0ee9a673cc592c63f950dc3b1cc523cda2893c7))
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* **global:** SendMessage can now output it success
|
||||
status ([6b68299](https://gitlab.pegase.tech/z3/z3-backend/commit/6b68299c853021112f68fa016cf7e99a883d3a42))
|
||||
|
||||
## [1.0.2](https://gitlab.pegase.tech/z3/z3-backend/compare/1.0.1...1.0.2) (2024-12-10)
|
||||
|
||||
### Features
|
||||
|
||||
* **application:** Ajout d'un message sur une demande de redirection d'un lien
|
||||
invalide ([4c28c8f](https://gitlab.pegase.tech/z3/z3-backend/commit/4c28c8f67c08c68f727c222b933451d8aea8b01f))
|
||||
* **domain:** Allow to put any text on source and slugify it on
|
||||
import ([a9f69b7](https://gitlab.pegase.tech/z3/z3-backend/commit/a9f69b75ebc21a5853584bc358b830d305a77cc2))
|
||||
* **global:** Allow to set tag while importing
|
||||
links ([3656677](https://gitlab.pegase.tech/z3/z3-backend/commit/3656677833632159dfc284904c5b107b8176b609))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **application:** Add no-cache header for public
|
||||
redirection ([20c85f7](https://gitlab.pegase.tech/z3/z3-backend/commit/20c85f7c1f563c4448176b736c25262727193372))
|
||||
* **application:** Correction of import for user
|
||||
requests ([9942f65](https://gitlab.pegase.tech/z3/z3-backend/commit/9942f658baf69c75362c4085837863d3621f90b3))
|
||||
* **application:** Slugify source on create link
|
||||
endpoint ([3e760a3](https://gitlab.pegase.tech/z3/z3-backend/commit/3e760a321dc79e809706252d5992df63542bfdfb))
|
||||
* **domain:** Import links for catalog was not setting correct
|
||||
brand ([02d6507](https://gitlab.pegase.tech/z3/z3-backend/commit/02d650728ad394c0df86993ef6f59051cf1436d5))
|
||||
* **domain:** Import links was returning the wrong imported links
|
||||
number ([9ec5c2d](https://gitlab.pegase.tech/z3/z3-backend/commit/9ec5c2dc377ebf859e8c1b8d8579501b8ec93cc2))
|
||||
* **domain:** Reset user password was not persisting the updated
|
||||
credential ([5e811bd](https://gitlab.pegase.tech/z3/z3-backend/commit/5e811bd3c428054fa00dc5dfb300b16900b74d19))
|
||||
* **infrastructure:** Slugifyer now replaces
|
||||
undescores ([34ab963](https://gitlab.pegase.tech/z3/z3-backend/commit/34ab963a68464be0ff0257b5fec91154b0d229c5))
|
||||
|
||||
## [1.0.1](https://gitlab.pegase.tech/z3/z3-backend/compare/a59ae027ff944c182f168bdf89406f27a8d39091...1.0.1) (2024-12-08)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **global:** Allow to assign some brands to any user
|
||||
|
||||
### Features
|
||||
|
||||
* **global:** Allow to assign some brands to any
|
||||
user ([6e820e7](https://gitlab.pegase.tech/z3/z3-backend/commit/6e820e772e690e9f129ce55b63fb377da9c4d1fb))
|
||||
* **global:** Change user
|
||||
password ([acb99eb](https://gitlab.pegase.tech/z3/z3-backend/commit/acb99ebcec6a6de5480a3ef3f57ffa274192339d))
|
||||
* **global:** Complete Global statistics
|
||||
feature ([0f5074d](https://gitlab.pegase.tech/z3/z3-backend/commit/0f5074da602002af7988656781afa302c3cdd711))
|
||||
* **global:** Get statistics for Brand, Catalog and
|
||||
Tag ([26db02b](https://gitlab.pegase.tech/z3/z3-backend/commit/26db02b5df14151972fbfab8c73f6072267b5df6))
|
||||
* **global:** Reset user password
|
||||
feature ([a59ae02](https://gitlab.pegase.tech/z3/z3-backend/commit/a59ae027ff944c182f168bdf89406f27a8d39091))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **application:** Add not null to create and update users
|
||||
requests ([a35dfe4](https://gitlab.pegase.tech/z3/z3-backend/commit/a35dfe40430a889361118049b1fcea882e05d5df))
|
||||
* **application:** Allow admin users to update
|
||||
users ([13f141c](https://gitlab.pegase.tech/z3/z3-backend/commit/13f141c24e6512d79ab6250a59f6341fee2c7c5f))
|
||||
* **application:** Remove Role check on get brand
|
||||
resource ([492d842](https://gitlab.pegase.tech/z3/z3-backend/commit/492d842664842e1baa477e2fbbf75e1f228b06bd))
|
||||
64
Dockerfile
Normal file
64
Dockerfile
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
FROM quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-21 AS build
|
||||
|
||||
ARG GITLAB_MVN_TOKEN
|
||||
COPY <<EOF /mvn-settings.xml
|
||||
<settings>
|
||||
<servers>
|
||||
<server>
|
||||
<id>gitlab-maven</id>
|
||||
<configuration>
|
||||
<httpHeaders>
|
||||
<property>
|
||||
<name>Job-Token</name>
|
||||
<value>$GITLAB_MVN_TOKEN</value>
|
||||
</property>
|
||||
</httpHeaders>
|
||||
</configuration>
|
||||
</server>
|
||||
</servers>
|
||||
</settings>
|
||||
EOF
|
||||
|
||||
COPY --chown=quarkus:quarkus config /code/config
|
||||
|
||||
COPY --chown=quarkus:quarkus mvnw /code/mvnw
|
||||
COPY --chown=quarkus:quarkus .mvn /code/.mvn
|
||||
COPY --chown=quarkus:quarkus pom.xml /code/pom.xml
|
||||
|
||||
COPY --chown=quarkus:quarkus z3-application/pom.xml /code/z3-application/pom.xml
|
||||
COPY --chown=quarkus:quarkus z3-application/src /code/z3-application/src
|
||||
|
||||
COPY --chown=quarkus:quarkus z3-cli/pom.xml /code/z3-cli/pom.xml
|
||||
COPY --chown=quarkus:quarkus z3-cli/src /code/z3-cli/src
|
||||
|
||||
COPY --chown=quarkus:quarkus z3-domain/pom.xml /code/z3-domain/pom.xml
|
||||
COPY --chown=quarkus:quarkus z3-domain/src /code/z3-domain/src
|
||||
|
||||
COPY --chown=quarkus:quarkus z3-infrastructure/pom.xml /code/z3-infrastructure/pom.xml
|
||||
COPY --chown=quarkus:quarkus z3-infrastructure/src /code/z3-infrastructure/src
|
||||
|
||||
COPY --chown=quarkus:quarkus z3-shared/pom.xml /code/z3-shared/pom.xml
|
||||
COPY --chown=quarkus:quarkus z3-shared/src /code/z3-shared/src
|
||||
|
||||
COPY --chown=quarkus:quarkus z3-statistics-domain/pom.xml /code/z3-statistics-domain/pom.xml
|
||||
COPY --chown=quarkus:quarkus z3-statistics-domain/src /code/z3-statistics-domain/src
|
||||
|
||||
COPY --chown=quarkus:quarkus z3-statistics-infrastructure/pom.xml /code/z3-statistics-infrastructure/pom.xml
|
||||
COPY --chown=quarkus:quarkus z3-statistics-infrastructure/src /code/z3-statistics-infrastructure/src
|
||||
|
||||
USER quarkus
|
||||
WORKDIR /code
|
||||
RUN ./mvnw package -DskipTests -Dquarkus.package.jar.type=uber-jar -s /mvn-settings.xml
|
||||
|
||||
FROM registry.access.redhat.com/ubi8/openjdk-21:1.20
|
||||
|
||||
ENV LANGUAGE='en_US:en'
|
||||
|
||||
COPY --from=build --chown=185 /code/z3-application/target/*-runner.jar /deployments/quarkus-run.jar
|
||||
|
||||
EXPOSE 8080
|
||||
USER 185
|
||||
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
|
||||
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
|
||||
|
||||
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
|
||||
176
README.md
Normal file
176
README.md
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
# Z3 – A link to the path
|
||||
|
||||
*Z3* est un raccourcisseur d'URL.
|
||||
|
||||
*Z3* s'inspire dans la forme des principes de clean architecture et de DDD. On trouve ainsi quatre
|
||||
modules Maven :
|
||||
|
||||
- `z3`: module parent ;
|
||||
- `z3-domain` : contient les entités, les objets-valeur, les use cases et les ports ;
|
||||
- `z3-infrastructure` : contient les implémentations des ports (adapters) ;
|
||||
- `z3-application` : contient les services applicatifs.
|
||||
|
||||
Le nom *Z3* est un clin d'œil à *Zelda 3 : A Link to the Past*, un jeu vidéo sorti en 1991 sur Super
|
||||
Nintendo.
|
||||
|
||||
## GENARATE CHANGELOG
|
||||
|
||||
- Package node à util `https://github.com/conventional-changelog/conventional-changelog`
|
||||
- Commande à utiliser `conventional-changelog -p conventionalcommits -i CHANGELOG.md -s`
|
||||
|
||||
## SCHEDULED TASKS
|
||||
|
||||
Liste des taches planifiés :
|
||||
|
||||
- Envoyer les rapports de liens invalides -> `APP_REPORT_INVALID_LINKS`
|
||||
|
||||
## CLI
|
||||
|
||||
- Pour lancer la cli en DEV : `mvn quarkus:dev -Dquarkus.args=seed
|
||||
- Ou `java -jar target/z3-cli-1.1.0-SNAPSHOT-runner.jar seed`
|
||||
|
||||
## Configuration
|
||||
|
||||
### BDD supportées
|
||||
|
||||
- Postgres
|
||||
|
||||
### LOG
|
||||
|
||||
- Le loglevel peut être set avec `APP_LOG_LEVEL` -> `APP_LOG_LEVEL=DEBUG`
|
||||
|
||||
### UPLOADS
|
||||
|
||||
**! Cette valeur dois être raccord avec la partie front (Sveltekit pas exemple) !**
|
||||
|
||||
- La taille max des uploads peut être définie `APP_MAX_UPLOAD_SIZE` -> `APP_MAX_UPLOAD_SIZE=100M`
|
||||
|
||||
### SECURITE
|
||||
|
||||
**! Toutes les informations de configuration de cette partie doivent être sauvegardés pour conserver
|
||||
des données exploitables !**
|
||||
|
||||
#### JWT
|
||||
|
||||
Usage :
|
||||
|
||||
```text
|
||||
APP_JWT_ISSUER=http://localhost:8080/issuer
|
||||
APP_JWT_PUBLIC_KEY=publicKey.pem
|
||||
APP_JWT_PRIVATE_KEY=privateKey.pem
|
||||
```
|
||||
|
||||
Génerer des clés :
|
||||
|
||||
```shell
|
||||
openssl genrsa -out rsaPrivateKey.pem 2048
|
||||
openssl rsa -pubout -in rsaPrivateKey.pem -out publicKey.pem
|
||||
openssl pkcs8 -topk8 -nocrypt -inform pem -in rsaPrivateKey.pem -outform pem -out privateKey.pem
|
||||
```
|
||||
|
||||
#### ENCRYPTION
|
||||
|
||||
example :
|
||||
|
||||
```text
|
||||
AES_KEY="password"
|
||||
AES_SALT="salt"
|
||||
AES_KEY_LENGTH=256
|
||||
```
|
||||
|
||||
Notes :
|
||||
|
||||
- `KEY` Est une valeur texte quelconque
|
||||
- `SALT` Est une valeur texte quelconque
|
||||
- `KEY_LENGTH` Devrais être laissée à 256
|
||||
|
||||
### MAIL
|
||||
|
||||
Exemple (pour mailpit) :
|
||||
|
||||
```text
|
||||
APP_MAIL_FROM=z3@example.net
|
||||
APP_MAIL_HOST=127.0.0.1
|
||||
APP_MAIL_PORT=1025
|
||||
APP_MAIL_START_TLS=OPTIONAL
|
||||
APP_MAIL_TLS=false
|
||||
APP_MAIL_USERNAME=null
|
||||
APP_MAIL_PASSWORD=null
|
||||
APP_MAIL_DEV_SIMULATE=false
|
||||
```
|
||||
|
||||
Notes :
|
||||
|
||||
- `APP_MAIL_FROM` Est l'adresse email qui est inscrite dans le mail dans la partie `FROM:`
|
||||
- `MAIL_DEV_SIMULATE` Permet de simuler l'envoie de mails et donc de se passer d'un serveur SMTP.
|
||||
|
||||
### Création d'un compte initial
|
||||
|
||||
**! Cette partie nécessite un serveur SMTP, en local il est possible d'utiliser Mailpit par
|
||||
exemple !**
|
||||
|
||||
Mailpit :
|
||||
|
||||
```shell
|
||||
podman run -d \
|
||||
--name=mailpit \
|
||||
--restart unless-stopped \
|
||||
-p 8025:8025 \
|
||||
-p 1025:1025 \
|
||||
axllent/mailpit
|
||||
```
|
||||
|
||||
Exemple :
|
||||
|
||||
```text
|
||||
APP_CREATE_USER_ON_START=toto@example.net
|
||||
```
|
||||
|
||||
Notes :
|
||||
|
||||
- `CREATE_USER_ON_START` Peut etre vide, s'il ne l'est pas un nouvel utilisateur **Administrateur**
|
||||
sera crée. Les informations de connexion seront envoyés par email.
|
||||
|
||||
## TESTS
|
||||
|
||||
```sh
|
||||
mvn clean verify
|
||||
```
|
||||
|
||||
Reports for each modules can be found under target dirs.
|
||||
|
||||
## SECURITY
|
||||
|
||||
### Checking
|
||||
|
||||
Check for vulnerabilities
|
||||
|
||||
First time running requires downloading a list of CVE.
|
||||
|
||||
You can request an API key from [here](https://nvd.nist.gov/developers/request-an-api-key) to
|
||||
accelerate downloading theses. They are stored in
|
||||
`~/.m2/repository/org/owasp/dependency-check-data/`.
|
||||
|
||||
You can find more information form
|
||||
the [plugin Github repository](https://github.com/jeremylong/DependencyCheck).
|
||||
|
||||
```sh
|
||||
mvn org.owasp:dependency-check-maven:check
|
||||
```
|
||||
|
||||
To pass an api key you can use, or replace `$ENV_API_KEY_VAR` directly with the api key.
|
||||
|
||||
```sh
|
||||
mvn verify -Ddependency-check-maven.api_key=$ENV_API_KEY_VAR
|
||||
```
|
||||
|
||||
### Report
|
||||
|
||||
You may find report after ward in `target/dependency-check-report.html`
|
||||
|
||||
They are several reports configured but you can add more looking
|
||||
at [the documentation](https://jeremylong.github.io/DependencyCheck/dependency-check-maven/configuration.html).
|
||||
|
||||
Available are `HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, GITLAB, ALL`.
|
||||
|
||||
Now Z3 has enabled `HTML, JSON, SARIF and GITLAB`.
|
||||
9190
Uml/Z3Backend.gaphor
Normal file
9190
Uml/Z3Backend.gaphor
Normal file
File diff suppressed because it is too large
Load diff
18
brunoCollection/Auth/Change Password.bru
Normal file
18
brunoCollection/Auth/Change Password.bru
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
meta {
|
||||
name: Change Password
|
||||
type: http
|
||||
seq: 3
|
||||
}
|
||||
|
||||
put {
|
||||
url: http://localhost:8080/api/v1/auth/password
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"password" : "asd",
|
||||
"new-password" : "asd"
|
||||
}
|
||||
}
|
||||
28
brunoCollection/Auth/Login.bru
Normal file
28
brunoCollection/Auth/Login.bru
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
meta {
|
||||
name: Login
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
post {
|
||||
url: http://localhost:8080/api/v1/auth/login
|
||||
body: json
|
||||
auth: none
|
||||
}
|
||||
|
||||
headers {
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"login": "z3.admin",
|
||||
"password": "g4nWmGs0w^"
|
||||
}
|
||||
}
|
||||
|
||||
tests {
|
||||
let response = res.getBody();
|
||||
bru.setVar("jwt_token", response.token);
|
||||
}
|
||||
16
brunoCollection/Auth/Me.bru
Normal file
16
brunoCollection/Auth/Me.bru
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
meta {
|
||||
name: Me
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/auth/me
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
headers {
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
}
|
||||
3
brunoCollection/Auth/folder.bru
Normal file
3
brunoCollection/Auth/folder.bru
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
meta {
|
||||
name: Auth
|
||||
}
|
||||
26
brunoCollection/Brands/Create Brand.bru
Normal file
26
brunoCollection/Brands/Create Brand.bru
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
meta {
|
||||
name: Create Brand
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
post {
|
||||
url: http://localhost:8080/api/v1/brands
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"name" : "super brand 2",
|
||||
"fqdns": [
|
||||
"example.net",
|
||||
"example.io"
|
||||
]
|
||||
}
|
||||
}
|
||||
15
brunoCollection/Brands/Get Brand.bru
Normal file
15
brunoCollection/Brands/Get Brand.bru
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
meta {
|
||||
name: Get Brand
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/brands/2abe8b15-b204-4021-9847-6437188ec6d8
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
}
|
||||
18
brunoCollection/Brands/List Brands.bru
Normal file
18
brunoCollection/Brands/List Brands.bru
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
meta {
|
||||
name: List Brands
|
||||
type: http
|
||||
seq: 4
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/brands?page=1&perPage=15
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
params:query {
|
||||
page: 1
|
||||
perPage: 15
|
||||
~orderBy: source
|
||||
~direction: desc
|
||||
}
|
||||
26
brunoCollection/Brands/Update Brand.bru
Normal file
26
brunoCollection/Brands/Update Brand.bru
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
meta {
|
||||
name: Update Brand
|
||||
type: http
|
||||
seq: 3
|
||||
}
|
||||
|
||||
put {
|
||||
url: http://localhost:8080/api/v1/brands/super-brand-2
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
headers {
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"name": "Super Brand 2",
|
||||
"fqdns": [
|
||||
"example.net",
|
||||
"example.io"
|
||||
]
|
||||
}
|
||||
}
|
||||
3
brunoCollection/Brands/folder.bru
Normal file
3
brunoCollection/Brands/folder.bru
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
meta {
|
||||
name: Brands
|
||||
}
|
||||
23
brunoCollection/Catalogs/Create Catalog.bru
Normal file
23
brunoCollection/Catalogs/Create Catalog.bru
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
meta {
|
||||
name: Create Catalog
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
post {
|
||||
url: http://localhost:8080/api/v1/catalogs
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"name" : "super catalog",
|
||||
"brand": "1e86a493-ee75-494d-8da5-c61971c37b67"
|
||||
}
|
||||
}
|
||||
11
brunoCollection/Catalogs/Delete Catalog.bru
Normal file
11
brunoCollection/Catalogs/Delete Catalog.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Delete Catalog
|
||||
type: http
|
||||
seq: 3
|
||||
}
|
||||
|
||||
delete {
|
||||
url: http://localhost:8080/api/v1/catalogs/super-tag
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
15
brunoCollection/Catalogs/Get Catalog.bru
Normal file
15
brunoCollection/Catalogs/Get Catalog.bru
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
meta {
|
||||
name: Get Catalog
|
||||
type: http
|
||||
seq: 5
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/catalogs/super-catalog
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
}
|
||||
19
brunoCollection/Catalogs/List Catalogs.bru
Normal file
19
brunoCollection/Catalogs/List Catalogs.bru
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
meta {
|
||||
name: List Catalogs
|
||||
type: http
|
||||
seq: 4
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/catalogs?page=1&brand=b5a90f20-dd1c-4a8a-b820-aed3aa62e857&perPage=15
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
params:query {
|
||||
page: 1
|
||||
brand: b5a90f20-dd1c-4a8a-b820-aed3aa62e857
|
||||
perPage: 15
|
||||
~orderBy: source
|
||||
~direction: desc
|
||||
}
|
||||
18
brunoCollection/Catalogs/Update Catalog.bru
Normal file
18
brunoCollection/Catalogs/Update Catalog.bru
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
meta {
|
||||
name: Update Catalog
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
put {
|
||||
url: http://localhost:8080/api/v1/catalogs/97295da4-d7c8-4e15-86fb-81ee9f53a47e
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"name" : "super tagwrere",
|
||||
"color": "#fff"
|
||||
}
|
||||
}
|
||||
3
brunoCollection/Catalogs/folder.bru
Normal file
3
brunoCollection/Catalogs/folder.bru
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
meta {
|
||||
name: Catalogs
|
||||
}
|
||||
26
brunoCollection/Links/Create Link.bru
Normal file
26
brunoCollection/Links/Create Link.bru
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
meta {
|
||||
name: Create Link
|
||||
type: http
|
||||
seq: 3
|
||||
}
|
||||
|
||||
post {
|
||||
url: http://localhost:8080/api/v1/links
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
headers {
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"source" : "testkey",
|
||||
"target" : "https://example.org",
|
||||
"is_external": true,
|
||||
"tag": "",
|
||||
"catalog": ""
|
||||
}
|
||||
}
|
||||
11
brunoCollection/Links/Get Link.bru
Normal file
11
brunoCollection/Links/Get Link.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Get Link
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/links/3cisvgdo7r8fdqo774ci3apagt
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
11
brunoCollection/Links/Link export no brand.bru
Normal file
11
brunoCollection/Links/Link export no brand.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Link export no brand
|
||||
type: http
|
||||
seq: 5
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/links-export
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
11
brunoCollection/Links/Link export with brand.bru
Normal file
11
brunoCollection/Links/Link export with brand.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Link export with brand
|
||||
type: http
|
||||
seq: 6
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/links-export/brands/new-branddd
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
11
brunoCollection/Links/Link export with catalog.bru
Normal file
11
brunoCollection/Links/Link export with catalog.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Link export with catalog
|
||||
type: http
|
||||
seq: 7
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/links-export/catalogs/new-catalog
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
19
brunoCollection/Links/Link import.bru
Normal file
19
brunoCollection/Links/Link import.bru
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
meta {
|
||||
name: Link import
|
||||
type: http
|
||||
seq: 8
|
||||
}
|
||||
|
||||
post {
|
||||
url: http://localhost:8080/api/v1/links-import/brands/1e86a493-ee75-494d-8da5-c61971c37b67
|
||||
body: multipartForm
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
}
|
||||
|
||||
body:multipart-form {
|
||||
file: @file(postman-cloud:///1efaca96-04b8-4ff0-968f-73a0020ae3a0)
|
||||
}
|
||||
22
brunoCollection/Links/List Links.bru
Normal file
22
brunoCollection/Links/List Links.bru
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
meta {
|
||||
name: List Links
|
||||
type: http
|
||||
seq: 4
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/links?page=1&perPage=15&orderBy=source&direction=desc
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
params:query {
|
||||
page: 1
|
||||
perPage: 15
|
||||
orderBy: source
|
||||
direction: desc
|
||||
~tag: 1fefab47-ec13-4f9e-815a-1cef5e7d7db4
|
||||
~searchOn: source
|
||||
~keywords: example.net
|
||||
~catalog: 77657d43-7d33-48cd-88aa-7f73fa6d6ded
|
||||
}
|
||||
11
brunoCollection/Links/Statistics/For all Brands.bru
Normal file
11
brunoCollection/Links/Statistics/For all Brands.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: For all Brands
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/links/statistics/brands
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
19
brunoCollection/Links/Statistics/For all Catalogs of.bru
Normal file
19
brunoCollection/Links/Statistics/For all Catalogs of.bru
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
meta {
|
||||
name: For all Catalogs of
|
||||
type: http
|
||||
seq: 4
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/links/statistics/catalog?brand=582807fe-7a37-462d-97e4-10f30d055abb
|
||||
body: none
|
||||
auth: bearer
|
||||
}
|
||||
|
||||
params:query {
|
||||
brand: 582807fe-7a37-462d-97e4-10f30d055abb
|
||||
}
|
||||
|
||||
auth:bearer {
|
||||
token: {{jwt_token}}
|
||||
}
|
||||
19
brunoCollection/Links/Statistics/For all Tag of.bru
Normal file
19
brunoCollection/Links/Statistics/For all Tag of.bru
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
meta {
|
||||
name: For all Tag of
|
||||
type: http
|
||||
seq: 5
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/links/statistics/tag?brand=582807fe-7a37-462d-97e4-10f30d055abb
|
||||
body: none
|
||||
auth: bearer
|
||||
}
|
||||
|
||||
params:query {
|
||||
brand: 582807fe-7a37-462d-97e4-10f30d055abb
|
||||
}
|
||||
|
||||
auth:bearer {
|
||||
token: {{jwt_token}}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
meta {
|
||||
name: Global Statistics For Brand
|
||||
type: http
|
||||
seq: 3
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/links/statistics/582807fe-7a37-462d-97e4-10f30d055abb
|
||||
body: none
|
||||
auth: bearer
|
||||
}
|
||||
|
||||
auth:bearer {
|
||||
token: {{jwt_token}}
|
||||
}
|
||||
15
brunoCollection/Links/Statistics/Global Statistics.bru
Normal file
15
brunoCollection/Links/Statistics/Global Statistics.bru
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
meta {
|
||||
name: Global Statistics
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/links/statistics
|
||||
body: none
|
||||
auth: bearer
|
||||
}
|
||||
|
||||
auth:bearer {
|
||||
token: {{jwt_token}}
|
||||
}
|
||||
3
brunoCollection/Links/Statistics/folder.bru
Normal file
3
brunoCollection/Links/Statistics/folder.bru
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
meta {
|
||||
name: Statistics
|
||||
}
|
||||
20
brunoCollection/Links/Update Link.bru
Normal file
20
brunoCollection/Links/Update Link.bru
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
meta {
|
||||
name: Update Link
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
put {
|
||||
url: http://localhost:8080/api/v1/links/cle-1058
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"target": "https://example.net",
|
||||
"is_external": true,
|
||||
"tag": "",
|
||||
"catalog": ""
|
||||
}
|
||||
}
|
||||
11
brunoCollection/Links/Verify Link.bru
Normal file
11
brunoCollection/Links/Verify Link.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Verify Link
|
||||
type: http
|
||||
seq: 9
|
||||
}
|
||||
|
||||
put {
|
||||
url: http://localhost:8080/api/v1/links/3cisvgdo7r8fdqo774ci3apagt/verify
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
3
brunoCollection/Links/folder.bru
Normal file
3
brunoCollection/Links/folder.bru
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
meta {
|
||||
name: Links
|
||||
}
|
||||
29
brunoCollection/Public/Link Redirection With Additionals.bru
Normal file
29
brunoCollection/Public/Link Redirection With Additionals.bru
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
meta {
|
||||
name: Link Redirection With Additionals
|
||||
type: http
|
||||
seq: 3
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/presentation-de-aout?ip-address=80.0.2.1&dnt=false&lang=fr®ion=FR&referrer=https%3A%2F%2Fgoogle.com%2Fi-love-linux&screen-width=1200&screen-height=1080&screen-dpi=4&user-agent=Mozilla%2F5.0%20%28compatible%3B%20Sosospider%2F2.0%3B%20%2Bhttp%3A%2F%2Fhelp.soso.com%2Fwebspider.htm%29&fingerprint=fingerprint
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
params:query {
|
||||
ip-address: 80.0.2.1
|
||||
dnt: false
|
||||
lang: fr
|
||||
region: FR
|
||||
referrer: https%3A%2F%2Fgoogle.com%2Fi-love-linux
|
||||
screen-width: 1200
|
||||
screen-height: 1080
|
||||
screen-dpi: 4
|
||||
user-agent: Mozilla%2F5.0%20%28compatible%3B%20Sosospider%2F2.0%3B%20%2Bhttp%3A%2F%2Fhelp.soso.com%2Fwebspider.htm%29
|
||||
fingerprint: fingerprint
|
||||
~user-agent: Mozilla%252F5.0%2520%2528compatible%253B%2520Sosospider%252F2.0%253B%2520%252Bhttp%253A%252F%252Fhelp.soso.com%252Fwebspider.htm%2529
|
||||
~user-agent: Python-urllib%2F1.17
|
||||
~user-agent: gloubiboulga
|
||||
~user-agent: Mozilla%2F5.0%20%28X11%3B%20Linux%20x86_64%3B%20rv%3A136.0%29%20Gecko%2F20100101%20Firefox%2F136.0
|
||||
~user-agent: Mozilla%2F5.0%20%28compatible%3B%202GDPR%2F1.2%3B%20https%3A%2F%2F2gdpr.com%29
|
||||
}
|
||||
11
brunoCollection/Public/Link Redirection slim.bru
Normal file
11
brunoCollection/Public/Link Redirection slim.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Link Redirection slim
|
||||
type: http
|
||||
seq: 4
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/test
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
25
brunoCollection/Public/Link Redirection.bru
Normal file
25
brunoCollection/Public/Link Redirection.bru
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
meta {
|
||||
name: Link Redirection
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/test?ip-address=80.0.2.1&dnt=false&lang=fr®ion=FR&referrer=https%3A%2F%2Fgoogle.com%2Fi-love-linux&user-agent=Mozilla%2F5.0%20%28Windows%20NT%2010.0%3B%20Win64%3B%20x64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F133.0.0.0%20Safari%2F537.36&screen-width=1200&screen-height=1080&screen-dpi=4
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
params:query {
|
||||
ip-address: 80.0.2.1
|
||||
dnt: false
|
||||
lang: fr
|
||||
region: FR
|
||||
referrer: https%3A%2F%2Fgoogle.com%2Fi-love-linux
|
||||
user-agent: Mozilla%2F5.0%20%28Windows%20NT%2010.0%3B%20Win64%3B%20x64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F133.0.0.0%20Safari%2F537.36
|
||||
screen-width: 1200
|
||||
screen-height: 1080
|
||||
screen-dpi: 4
|
||||
~user-agent: Mozilla%2F5.0%20%28X11%3B%20Linux%20x86_64%3B%20rv%3A136.0%29%20Gecko%2F20100101%20Firefox%2F136.0
|
||||
~user-agent: gloubiboulga
|
||||
}
|
||||
11
brunoCollection/Public/Root Url.bru
Normal file
11
brunoCollection/Public/Root Url.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Root Url
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
3
brunoCollection/Public/folder.bru
Normal file
3
brunoCollection/Public/folder.bru
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
meta {
|
||||
name: Public
|
||||
}
|
||||
11
brunoCollection/Reporting/Get Reporting Subscriptions.bru
Normal file
11
brunoCollection/Reporting/Get Reporting Subscriptions.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Get Reporting Subscriptions
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/reporting/subscriptions/b12f92c0-361c-40bd-9fbc-48c83fcccc81
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
19
brunoCollection/Reporting/Update Reproting Subscriptions.bru
Normal file
19
brunoCollection/Reporting/Update Reproting Subscriptions.bru
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
meta {
|
||||
name: Update Reproting Subscriptions
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
post {
|
||||
url: http://localhost:8080/api/v1/reporting/subscriptions/b12f92c0-361c-40bd-9fbc-48c83fcccc81
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"brands": [
|
||||
"582807fe-7a37-462d-97e4-10f30d055abb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Invalid Links Per Week By Brands
|
||||
type: http
|
||||
seq: 5
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/statistics/invalid-links/per-week-per-brand
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Most Frequent Referrers With Brands
|
||||
type: http
|
||||
seq: 4
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/statistics/top/referrers
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Top Visited Sources With Brands
|
||||
type: http
|
||||
seq: 3
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/statistics/top/sources
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
11
brunoCollection/Statistics/Unique Visitors By Catalogs.bru
Normal file
11
brunoCollection/Statistics/Unique Visitors By Catalogs.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Unique Visitors By Catalogs
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/statistics/unique-visitors/catalogs
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
11
brunoCollection/Statistics/Unique Visitors by Brands.bru
Normal file
11
brunoCollection/Statistics/Unique Visitors by Brands.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Unique Visitors by Brands
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/statistics/unique-visitors/brands
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
23
brunoCollection/Tags/Create Tag.bru
Normal file
23
brunoCollection/Tags/Create Tag.bru
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
meta {
|
||||
name: Create Tag
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
post {
|
||||
url: http://localhost:8080/api/v1/tags
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"name" : "super tag",
|
||||
"color": "#fff"
|
||||
}
|
||||
}
|
||||
11
brunoCollection/Tags/Delete Tag.bru
Normal file
11
brunoCollection/Tags/Delete Tag.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Delete Tag
|
||||
type: http
|
||||
seq: 3
|
||||
}
|
||||
|
||||
delete {
|
||||
url: http://localhost:8080/api/v1/brands/super-tag
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
15
brunoCollection/Tags/Get Tag.bru
Normal file
15
brunoCollection/Tags/Get Tag.bru
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
meta {
|
||||
name: Get Tag
|
||||
type: http
|
||||
seq: 5
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/tags/c1c9205d-19e5-469f-83fa-b40837ea0fbe
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
}
|
||||
17
brunoCollection/Tags/List Tags.bru
Normal file
17
brunoCollection/Tags/List Tags.bru
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
meta {
|
||||
name: List Tags
|
||||
type: http
|
||||
seq: 4
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/tags?page=1
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
params:query {
|
||||
page: 1
|
||||
~orderBy: source
|
||||
~direction: desc
|
||||
}
|
||||
18
brunoCollection/Tags/Update Tag.bru
Normal file
18
brunoCollection/Tags/Update Tag.bru
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
meta {
|
||||
name: Update Tag
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
put {
|
||||
url: http://localhost:8080/api/v1/tags/97295da4-d7c8-4e15-86fb-81ee9f53a47e
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"name" : "super tagwrere",
|
||||
"color": "#fff"
|
||||
}
|
||||
}
|
||||
3
brunoCollection/Tags/folder.bru
Normal file
3
brunoCollection/Tags/folder.bru
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
meta {
|
||||
name: Tags
|
||||
}
|
||||
28
brunoCollection/Users/Create User.bru
Normal file
28
brunoCollection/Users/Create User.bru
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
meta {
|
||||
name: Create User
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
post {
|
||||
url: http://localhost:8080/api/v1/users
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"firstName" : "new first name",
|
||||
"lastName" : "new last name",
|
||||
"email" : "new.email@examspwle.net",
|
||||
"role": "ADMINISTRATOR",
|
||||
"login": "sdsd",
|
||||
"password": "NewPassword12.",
|
||||
"brands": []
|
||||
}
|
||||
}
|
||||
11
brunoCollection/Users/Delete User.bru
Normal file
11
brunoCollection/Users/Delete User.bru
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
meta {
|
||||
name: Delete User
|
||||
type: http
|
||||
seq: 3
|
||||
}
|
||||
|
||||
delete {
|
||||
url: http://localhost:8080/api/v1/users/2c98a5a6-029b-4c9a-a88b-53da3b86c65b
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
15
brunoCollection/Users/Get User.bru
Normal file
15
brunoCollection/Users/Get User.bru
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
meta {
|
||||
name: Get User
|
||||
type: http
|
||||
seq: 4
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/users/4fa30f46-d116-499e-9f3f-aa3afe04dabf
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
}
|
||||
18
brunoCollection/Users/List Users.bru
Normal file
18
brunoCollection/Users/List Users.bru
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
meta {
|
||||
name: List Users
|
||||
type: http
|
||||
seq: 6
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8080/api/v1/users?direction=desc&page=1&perPage=3
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
params:query {
|
||||
direction: desc
|
||||
page: 1
|
||||
perPage: 3
|
||||
~orderBy: source
|
||||
}
|
||||
15
brunoCollection/Users/Reset User Password.bru
Normal file
15
brunoCollection/Users/Reset User Password.bru
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
meta {
|
||||
name: Reset User Password
|
||||
type: http
|
||||
seq: 5
|
||||
}
|
||||
|
||||
post {
|
||||
url: http://localhost:8080/api/v1/users/5380d8b1-52d4-4986-8de9-d92ae7c0c970/reset
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
}
|
||||
20
brunoCollection/Users/Update User.bru
Normal file
20
brunoCollection/Users/Update User.bru
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
meta {
|
||||
name: Update User
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
put {
|
||||
url: http://localhost:8080/api/v1/users/4beed79f-ef03-4beb-b691-9556ae38ac76
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"firstName" : "new first name",
|
||||
"lastName" : "new last name",
|
||||
"email" : "new.email@example.net",
|
||||
"brands": []
|
||||
}
|
||||
}
|
||||
3
brunoCollection/Users/folder.bru
Normal file
3
brunoCollection/Users/folder.bru
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
meta {
|
||||
name: Users
|
||||
}
|
||||
9
brunoCollection/bruno.json
Normal file
9
brunoCollection/bruno.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"version": "1",
|
||||
"name": "Z3",
|
||||
"type": "collection",
|
||||
"ignore": [
|
||||
"node_modules",
|
||||
".git"
|
||||
]
|
||||
}
|
||||
20
brunoCollection/collection.bru
Normal file
20
brunoCollection/collection.bru
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
meta {
|
||||
name: Z3
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept-Language: fr
|
||||
}
|
||||
|
||||
auth {
|
||||
mode: bearer
|
||||
}
|
||||
|
||||
auth:bearer {
|
||||
token: {{jwt_token}}
|
||||
}
|
||||
|
||||
script:pre-request {
|
||||
req.setMaxRedirects(0);
|
||||
|
||||
}
|
||||
11
config/checkstyle-suppressions.xml
Normal file
11
config/checkstyle-suppressions.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!DOCTYPE suppressions PUBLIC
|
||||
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
|
||||
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
|
||||
|
||||
<suppressions>
|
||||
<suppress checks="MissingJavadocType" files=".*\.java"/>
|
||||
<suppress checks="MissingJavadocMethod" files=".*\.java"/>
|
||||
<suppress checks="VariableDeclarationUsageDistance" files=".*\.java"/>
|
||||
</suppressions>
|
||||
420
config/google_checks.xml
Normal file
420
config/google_checks.xml
Normal file
|
|
@ -0,0 +1,420 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
|
||||
<!--
|
||||
Checkstyle configuration that checks the Google coding conventions from Google Java Style
|
||||
that can be found at https://google.github.io/styleguide/javaguide.html
|
||||
|
||||
Checkstyle is very configurable. Be sure to read the documentation at
|
||||
http://checkstyle.org (or in your downloaded distribution).
|
||||
|
||||
To completely disable a check, just comment it out or delete it from the file.
|
||||
To suppress certain violations please review suppression filters.
|
||||
|
||||
Authors: Max Vetrenko, Ruslan Diachenko, Roman Ivanov.
|
||||
-->
|
||||
|
||||
<module name="Checker">
|
||||
|
||||
<property name="charset" value="UTF-8"/>
|
||||
|
||||
<property name="severity" value="${org.checkstyle.google.severity}" default="warning"/>
|
||||
|
||||
<property name="fileExtensions" value="java, properties, xml"/>
|
||||
<!-- Excludes all 'module-info.java' files -->
|
||||
<!-- See https://checkstyle.org/filefilters/index.html -->
|
||||
<module name="BeforeExecutionExclusionFileFilter">
|
||||
<property name="fileNamePattern" value="module\-info\.java$"/>
|
||||
</module>
|
||||
|
||||
<module name="SuppressWarningsFilter"/>
|
||||
|
||||
<!-- https://checkstyle.org/filters/suppressionfilter.html -->
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${org.checkstyle.google.suppressionfilter.config}"
|
||||
default="checkstyle-suppressions.xml"/>
|
||||
<property name="optional" value="true"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/filters/suppresswithnearbytextfilter.html -->
|
||||
<module name="SuppressWithNearbyTextFilter">
|
||||
<property name="nearbyTextPattern"
|
||||
value="CHECKSTYLE.SUPPRESS\: (\w+) for ([+-]\d+) lines"/>
|
||||
<property name="checkPattern" value="$1"/>
|
||||
<property name="lineRange" value="$2"/>
|
||||
</module>
|
||||
|
||||
<!-- Checks for whitespace -->
|
||||
<!-- See http://checkstyle.org/checks/whitespace/index.html -->
|
||||
<module name="FileTabCharacter">
|
||||
<property name="eachLine" value="true"/>
|
||||
</module>
|
||||
|
||||
<module name="LineLength">
|
||||
<property name="fileExtensions" value="java"/>
|
||||
<property name="max" value="100"/>
|
||||
<property name="ignorePattern"
|
||||
value="^package.*|^import.*|href\s*=\s*"[^"]*"|http://|https://|ftp://"/>
|
||||
</module>
|
||||
|
||||
<module name="TreeWalker">
|
||||
<module name="OuterTypeFilename"/>
|
||||
<module name="IllegalTokenText">
|
||||
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
|
||||
<property name="format"
|
||||
value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
|
||||
<property name="message"
|
||||
value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
|
||||
</module>
|
||||
<module name="AvoidEscapedUnicodeCharacters">
|
||||
<property name="allowEscapesForControlCharacters" value="true"/>
|
||||
<property name="allowByTailComment" value="true"/>
|
||||
<property name="allowNonPrintableEscapes" value="true"/>
|
||||
</module>
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="OneTopLevelClass"/>
|
||||
<module name="NoLineWrap">
|
||||
<property name="tokens" value="PACKAGE_DEF, IMPORT, STATIC_IMPORT"/>
|
||||
</module>
|
||||
<module name="NeedBraces">
|
||||
<property name="tokens"
|
||||
value="LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_IF, LITERAL_WHILE"/>
|
||||
</module>
|
||||
<module name="LeftCurly">
|
||||
<property name="tokens"
|
||||
value="ANNOTATION_DEF, CLASS_DEF, CTOR_DEF, ENUM_CONSTANT_DEF, ENUM_DEF,
|
||||
INTERFACE_DEF, LAMBDA, LITERAL_CASE, LITERAL_CATCH, LITERAL_DEFAULT,
|
||||
LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF,
|
||||
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, METHOD_DEF,
|
||||
OBJBLOCK, STATIC_INIT, RECORD_DEF, COMPACT_CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="RightCurly">
|
||||
<property name="id" value="RightCurlySame"/>
|
||||
<property name="tokens"
|
||||
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE,
|
||||
LITERAL_DO"/>
|
||||
</module>
|
||||
<module name="RightCurly">
|
||||
<property name="id" value="RightCurlyAlone"/>
|
||||
<property name="option" value="alone"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT,
|
||||
INSTANCE_INIT, ANNOTATION_DEF, ENUM_DEF, INTERFACE_DEF, RECORD_DEF,
|
||||
COMPACT_CTOR_DEF, LITERAL_SWITCH, LITERAL_CASE"/>
|
||||
</module>
|
||||
<module name="SuppressionXpathSingleFilter">
|
||||
<!-- suppression is required till https://github.com/checkstyle/checkstyle/issues/7541 -->
|
||||
<property name="id" value="RightCurlyAlone"/>
|
||||
<property name="query" value="//RCURLY[parent::SLIST[count(./*)=1]
|
||||
or preceding-sibling::*[last()][self::LCURLY]]"/>
|
||||
</module>
|
||||
<module name="WhitespaceAfter">
|
||||
<property name="tokens"
|
||||
value="COMMA, SEMI, TYPECAST, LITERAL_IF, LITERAL_ELSE, LITERAL_RETURN,
|
||||
LITERAL_WHILE, LITERAL_DO, LITERAL_FOR, LITERAL_FINALLY, DO_WHILE, ELLIPSIS,
|
||||
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_CATCH, LAMBDA,
|
||||
LITERAL_YIELD, LITERAL_CASE, LITERAL_WHEN"/>
|
||||
</module>
|
||||
<module name="WhitespaceAround">
|
||||
<property name="allowEmptyConstructors" value="true"/>
|
||||
<property name="allowEmptyLambdas" value="true"/>
|
||||
<property name="allowEmptyMethods" value="true"/>
|
||||
<property name="allowEmptyTypes" value="true"/>
|
||||
<property name="allowEmptyLoops" value="true"/>
|
||||
<property name="ignoreEnhancedForColon" value="false"/>
|
||||
<property name="tokens"
|
||||
value="ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR,
|
||||
BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, DO_WHILE, EQUAL, GE, GT, LAMBDA, LAND,
|
||||
LCURLY, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY,
|
||||
LITERAL_FOR, LITERAL_IF, LITERAL_RETURN, LITERAL_SWITCH, LITERAL_SYNCHRONIZED,
|
||||
LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN,
|
||||
NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION, RCURLY, SL, SLIST, SL_ASSIGN, SR,
|
||||
SR_ASSIGN, STAR, STAR_ASSIGN, LITERAL_ASSERT,
|
||||
TYPE_EXTENSION_AND, LITERAL_WHEN"/>
|
||||
<message key="ws.notFollowed"
|
||||
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks
|
||||
may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
|
||||
<message key="ws.notPreceded"
|
||||
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
|
||||
</module>
|
||||
<module name="SuppressionXpathSingleFilter">
|
||||
<property name="checks" value="WhitespaceAround"/>
|
||||
<property name="query" value="//*[self::LITERAL_IF or self::LITERAL_ELSE or self::STATIC_INIT
|
||||
or self::LITERAL_TRY or self::LITERAL_CATCH]/SLIST[count(./*)=1]
|
||||
| //*[self::STATIC_INIT or self::LITERAL_TRY or self::LITERAL_IF]
|
||||
//*[self::RCURLY][parent::SLIST[count(./*)=1]]"/>
|
||||
</module>
|
||||
<module name="RegexpSinglelineJava">
|
||||
<property name="format" value="\{[ ]+\}"/>
|
||||
<property name="message" value="Empty blocks should have no spaces. Empty blocks
|
||||
may only be represented as '{}' when not part of a
|
||||
multi-block statement (4.1.3)"/>
|
||||
</module>
|
||||
<module name="OneStatementPerLine"/>
|
||||
<module name="MultipleVariableDeclarations"/>
|
||||
<module name="ArrayTypeStyle"/>
|
||||
<module name="MissingSwitchDefault"/>
|
||||
<module name="FallThrough"/>
|
||||
<module name="UpperEll"/>
|
||||
<module name="ModifierOrder"/>
|
||||
<module name="EmptyLineSeparator">
|
||||
<property name="tokens"
|
||||
value="PACKAGE_DEF, IMPORT, STATIC_IMPORT, CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
|
||||
STATIC_INIT, INSTANCE_INIT, METHOD_DEF, CTOR_DEF, VARIABLE_DEF, RECORD_DEF,
|
||||
COMPACT_CTOR_DEF"/>
|
||||
<property name="allowNoEmptyLineBetweenFields" value="true"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapDot"/>
|
||||
<property name="tokens" value="DOT"/>
|
||||
<property name="option" value="nl"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapComma"/>
|
||||
<property name="tokens" value="COMMA"/>
|
||||
<property name="option" value="EOL"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<!-- ELLIPSIS is EOL until https://github.com/google/styleguide/issues/259 -->
|
||||
<property name="id" value="SeparatorWrapEllipsis"/>
|
||||
<property name="tokens" value="ELLIPSIS"/>
|
||||
<property name="option" value="EOL"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<!-- ARRAY_DECLARATOR is EOL until https://github.com/google/styleguide/issues/258 -->
|
||||
<property name="id" value="SeparatorWrapArrayDeclarator"/>
|
||||
<property name="tokens" value="ARRAY_DECLARATOR"/>
|
||||
<property name="option" value="EOL"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapMethodRef"/>
|
||||
<property name="tokens" value="METHOD_REF"/>
|
||||
<property name="option" value="nl"/>
|
||||
</module>
|
||||
<module name="PackageName">
|
||||
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Package name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="TypeName">
|
||||
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
|
||||
ANNOTATION_DEF, RECORD_DEF"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="MemberName">
|
||||
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Member name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="ParameterName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="LambdaParameterName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Lambda parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="CatchParameterName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="LocalVariableName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="PatternVariableName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Pattern variable name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="ClassTypeParameterName">
|
||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Class type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="RecordComponentName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Record component name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="RecordTypeParameterName">
|
||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Record type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="MethodTypeParameterName">
|
||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Method type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="InterfaceTypeParameterName">
|
||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Interface type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="NoFinalizer"/>
|
||||
<module name="GenericWhitespace">
|
||||
<message key="ws.followed"
|
||||
value="GenericWhitespace ''{0}'' is followed by whitespace."/>
|
||||
<message key="ws.preceded"
|
||||
value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
|
||||
<message key="ws.illegalFollow"
|
||||
value="GenericWhitespace ''{0}'' should followed by whitespace."/>
|
||||
<message key="ws.notPreceded"
|
||||
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
|
||||
</module>
|
||||
<module name="Indentation">
|
||||
<property name="basicOffset" value="2"/>
|
||||
<property name="braceAdjustment" value="2"/>
|
||||
<property name="caseIndent" value="2"/>
|
||||
<property name="throwsIndent" value="4"/>
|
||||
<property name="lineWrappingIndentation" value="4"/>
|
||||
<property name="arrayInitIndent" value="2"/>
|
||||
</module>
|
||||
<module name="AbbreviationAsWordInName">
|
||||
<property name="ignoreFinal" value="false"/>
|
||||
<property name="allowedAbbreviationLength" value="0"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, ANNOTATION_FIELD_DEF,
|
||||
PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF, PATTERN_VARIABLE_DEF, RECORD_DEF,
|
||||
RECORD_COMPONENT_DEF"/>
|
||||
</module>
|
||||
<module name="NoWhitespaceBeforeCaseDefaultColon"/>
|
||||
<module name="OverloadMethodsDeclarationOrder"/>
|
||||
<module name="ConstructorsDeclarationGrouping"/>
|
||||
<module name="VariableDeclarationUsageDistance"/>
|
||||
<module name="CustomImportOrder">
|
||||
<property name="sortImportsInGroupAlphabetically" value="true"/>
|
||||
<property name="separateLineBetweenGroups" value="true"/>
|
||||
<property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE"/>
|
||||
<property name="tokens" value="IMPORT, STATIC_IMPORT, PACKAGE_DEF"/>
|
||||
</module>
|
||||
<module name="MethodParamPad">
|
||||
<property name="tokens"
|
||||
value="CTOR_DEF, LITERAL_NEW, METHOD_CALL, METHOD_DEF, CTOR_CALL,
|
||||
SUPER_CTOR_CALL, ENUM_CONSTANT_DEF, RECORD_DEF, RECORD_PATTERN_DEF"/>
|
||||
</module>
|
||||
<module name="NoWhitespaceBefore">
|
||||
<property name="tokens"
|
||||
value="COMMA, SEMI, POST_INC, POST_DEC, DOT,
|
||||
LABELED_STAT, METHOD_REF"/>
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
</module>
|
||||
<module name="ParenPad">
|
||||
<property name="tokens"
|
||||
value="ANNOTATION, ANNOTATION_FIELD_DEF, CTOR_CALL, CTOR_DEF, DOT, ENUM_CONSTANT_DEF,
|
||||
EXPR, LITERAL_CATCH, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW,
|
||||
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_WHILE, METHOD_CALL,
|
||||
METHOD_DEF, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, LAMBDA,
|
||||
RECORD_DEF, RECORD_PATTERN_DEF"/>
|
||||
</module>
|
||||
<module name="OperatorWrap">
|
||||
<property name="option" value="NL"/>
|
||||
<property name="tokens"
|
||||
value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR,
|
||||
LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF,
|
||||
TYPE_EXTENSION_AND "/>
|
||||
</module>
|
||||
<module name="AnnotationLocation">
|
||||
<property name="id" value="AnnotationLocationMostCases"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF,
|
||||
RECORD_DEF, COMPACT_CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="AnnotationLocation">
|
||||
<property name="id" value="AnnotationLocationVariables"/>
|
||||
<property name="tokens" value="VARIABLE_DEF"/>
|
||||
<property name="allowSamelineMultipleAnnotations" value="true"/>
|
||||
</module>
|
||||
<module name="NonEmptyAtclauseDescription"/>
|
||||
<module name="InvalidJavadocPosition"/>
|
||||
<module name="JavadocTagContinuationIndentation"/>
|
||||
<module name="SummaryJavadoc">
|
||||
<property name="forbiddenSummaryFragments"
|
||||
value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
|
||||
</module>
|
||||
<module name="JavadocParagraph">
|
||||
<property name="allowNewlineParagraph" value="false"/>
|
||||
</module>
|
||||
<module name="RequireEmptyLineBeforeBlockTagGroup"/>
|
||||
<module name="AtclauseOrder">
|
||||
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
|
||||
<property name="target"
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
|
||||
</module>
|
||||
<module name="JavadocMethod">
|
||||
<property name="accessModifiers" value="public"/>
|
||||
<property name="allowMissingParamTags" value="true"/>
|
||||
<property name="allowMissingReturnTag" value="true"/>
|
||||
<property name="allowedAnnotations" value="Override, Test"/>
|
||||
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF, COMPACT_CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="MissingJavadocMethod">
|
||||
<property name="scope" value="protected"/>
|
||||
<property name="allowMissingPropertyJavadoc" value="true"/>
|
||||
<property name="allowedAnnotations" value="Override, Test"/>
|
||||
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF,
|
||||
COMPACT_CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="SuppressionXpathSingleFilter">
|
||||
<property name="checks" value="MissingJavadocMethod"/>
|
||||
<property name="query" value="//*[self::METHOD_DEF or self::CTOR_DEF
|
||||
or self::ANNOTATION_FIELD_DEF or self::COMPACT_CTOR_DEF]
|
||||
[ancestor::*[self::INTERFACE_DEF or self::CLASS_DEF
|
||||
or self::RECORD_DEF or self::ENUM_DEF]
|
||||
[not(./MODIFIERS/LITERAL_PUBLIC)]]"/>
|
||||
</module>
|
||||
<module name="MissingJavadocType">
|
||||
<property name="scope" value="protected"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
|
||||
RECORD_DEF, ANNOTATION_DEF"/>
|
||||
<property name="excludeScope" value="nothing"/>
|
||||
</module>
|
||||
<module name="MethodName">
|
||||
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Method name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="SuppressionXpathSingleFilter">
|
||||
<property name="checks" value="MethodName"/>
|
||||
<property name="query" value="//METHOD_DEF[
|
||||
./MODIFIERS/ANNOTATION//IDENT[contains(@text, 'Test')]
|
||||
]/IDENT"/>
|
||||
<property name="message" value="'[a-z][a-z0-9][a-zA-Z0-9]*(?:_[a-z][a-z0-9][a-zA-Z0-9]*)*'"/>
|
||||
</module>
|
||||
<module name="SingleLineJavadoc"/>
|
||||
<module name="EmptyCatchBlock">
|
||||
<property name="exceptionVariableName" value="expected"/>
|
||||
</module>
|
||||
<module name="CommentsIndentation">
|
||||
<property name="tokens" value="SINGLE_LINE_COMMENT, BLOCK_COMMENT_BEGIN"/>
|
||||
</module>
|
||||
<!-- https://checkstyle.org/filters/suppressionxpathfilter.html -->
|
||||
<module name="SuppressionXpathFilter">
|
||||
<property name="file" value="${org.checkstyle.google.suppressionxpathfilter.config}"
|
||||
default="checkstyle-xpath-suppressions.xml"/>
|
||||
<property name="optional" value="true"/>
|
||||
</module>
|
||||
<module name="SuppressWarningsHolder"/>
|
||||
<module name="SuppressionCommentFilter">
|
||||
<property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
|
||||
<property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
|
||||
<property name="checkFormat" value="$1"/>
|
||||
</module>
|
||||
<module name="SuppressWithNearbyCommentFilter">
|
||||
<property name="commentFormat" value="CHECKSTYLE.SUPPRESS\: ([\w\|]+)"/>
|
||||
<!-- $1 refers to the first match group in the regex defined in commentFormat -->
|
||||
<property name="checkFormat" value="$1"/>
|
||||
<!-- The check is suppressed in the next line of code after the comment -->
|
||||
<property name="influenceFormat" value="1"/>
|
||||
</module>
|
||||
</module>
|
||||
</module>
|
||||
308
mvnw
vendored
Executable file
308
mvnw
vendored
Executable file
|
|
@ -0,0 +1,308 @@
|
|||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Apache Maven Wrapper startup batch script, version 3.2.0
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /usr/local/etc/mavenrc ] ; then
|
||||
. /usr/local/etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "$(uname)" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
|
||||
else
|
||||
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=$(java-config --jre-home)
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="$(which javac)"
|
||||
if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=$(which readlink)
|
||||
if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||
javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
|
||||
else
|
||||
javaExecutable="$(readlink -f "\"$javaExecutable\"")"
|
||||
fi
|
||||
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=$(cd "$wdir/.." || exit 1; pwd)
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
printf '%s' "$(cd "$basedir" || exit 1; pwd)"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
# Remove \r in case we run on Windows within Git Bash
|
||||
# and check out the repository with auto CRLF management
|
||||
# enabled. Otherwise, we may read lines that are delimited with
|
||||
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
|
||||
# splitting rules.
|
||||
tr -s '\r\n' ' ' < "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
printf '%s\n' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
|
||||
log "$MAVEN_PROJECTBASEDIR"
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if [ -r "$wrapperJarPath" ]; then
|
||||
log "Found $wrapperJarPath"
|
||||
else
|
||||
log "Couldn't find $wrapperJarPath, downloading it ..."
|
||||
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
else
|
||||
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
fi
|
||||
while IFS="=" read -r key value; do
|
||||
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
|
||||
safeValue=$(echo "$value" | tr -d '\r')
|
||||
case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
|
||||
esac
|
||||
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
log "Downloading from: $wrapperUrl"
|
||||
|
||||
if $cygwin; then
|
||||
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
log "Found wget ... using wget"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
else
|
||||
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
log "Found curl ... using curl"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
else
|
||||
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
else
|
||||
log "Falling back to using Java to download"
|
||||
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaSource=$(cygpath --path --windows "$javaSource")
|
||||
javaClass=$(cygpath --path --windows "$javaClass")
|
||||
fi
|
||||
if [ -e "$javaSource" ]; then
|
||||
if [ ! -e "$javaClass" ]; then
|
||||
log " - Compiling MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/javac" "$javaSource")
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
log " - Running MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||
wrapperSha256Sum=""
|
||||
while IFS="=" read -r key value; do
|
||||
case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
|
||||
esac
|
||||
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ -n "$wrapperSha256Sum" ]; then
|
||||
wrapperSha256Result=false
|
||||
if command -v sha256sum > /dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
elif command -v shasum > /dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
else
|
||||
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
|
||||
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
|
||||
exit 1
|
||||
fi
|
||||
if [ $wrapperSha256Result = false ]; then
|
||||
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
|
||||
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
|
||||
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
# shellcheck disable=SC2086 # safe args
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
$MAVEN_DEBUG_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||
205
mvnw.cmd
vendored
Executable file
205
mvnw.cmd
vendored
Executable file
|
|
@ -0,0 +1,205 @@
|
|||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Apache Maven Wrapper startup batch script, version 3.2.0
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
|
||||
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Found %WRAPPER_JAR%
|
||||
)
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %WRAPPER_URL%
|
||||
)
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||
SET WRAPPER_SHA_256_SUM=""
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
|
||||
)
|
||||
IF NOT %WRAPPER_SHA_256_SUM%=="" (
|
||||
powershell -Command "&{"^
|
||||
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
|
||||
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
|
||||
" Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
|
||||
" Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
|
||||
" Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
|
||||
" exit 1;"^
|
||||
"}"^
|
||||
"}"
|
||||
if ERRORLEVEL 1 goto error
|
||||
)
|
||||
|
||||
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||
@REM work with both Windows and non-Windows executions.
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
%MAVEN_JAVA_EXE% ^
|
||||
%JVM_CONFIG_MAVEN_PROPS% ^
|
||||
%MAVEN_OPTS% ^
|
||||
%MAVEN_DEBUG_OPTS% ^
|
||||
-classpath %WRAPPER_JAR% ^
|
||||
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
|
||||
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
|
||||
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%"=="on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
|
||||
|
||||
cmd /C exit /B %ERROR_CODE%
|
||||
201
pom.xml
Normal file
201
pom.xml
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<artifactId>z3</artifactId>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<configuration>
|
||||
<assemblyAnalyzerEnabled>false</assemblyAnalyzerEnabled>
|
||||
<formats>
|
||||
<format>HTML</format>
|
||||
<format>SARIF</format>
|
||||
<format>JSON</format>
|
||||
<format>GITLAB</format>
|
||||
</formats>
|
||||
<nuspecAnalyzerEnabled>false</nuspecAnalyzerEnabled>
|
||||
<nvdApiKey>${dependency-check-maven.api_key}</nvdApiKey>
|
||||
<ossindexAnalyzerEnabled>false</ossindexAnalyzerEnabled>
|
||||
<retireJsAnalyzerEnabled>false</retireJsAnalyzerEnabled>
|
||||
</configuration>
|
||||
<groupId>org.owasp</groupId>
|
||||
<version>${dependency-check-maven.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- FIX warnings about maybe mockito, maybe removed when bumping quarkus-->
|
||||
<argLine>-XX:+EnableDynamicAgentLoading -Xshare:off</argLine>
|
||||
<!-- To remove JBoss Log error on build and testing for all modules-->
|
||||
<systemPropertyVariables>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
<maven.home>${maven.home}</maven.home>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
<version>${surefire-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<configuration>
|
||||
<configLocation>/config/google_checks.xml</configLocation>
|
||||
<consoleOutput>true</consoleOutput>
|
||||
<failsOnError>true</failsOnError>
|
||||
<linkXRef>false</linkXRef>
|
||||
<suppressionsLocation>/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<version>${checkstyle.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<id>check-style</id>
|
||||
<phase>validate</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<version>${checkstyle-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<groupId>org.owasp</groupId>
|
||||
<version>${dependency-check-maven.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>happy-core</artifactId>
|
||||
<groupId>tech.pegase.happy</groupId>
|
||||
<version>${pegase-happy.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-smallrye-jwt</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-smallrye-jwt-build</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-cache</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>jspecify</artifactId>
|
||||
<groupId>org.jspecify</groupId>
|
||||
<version>${jspecify.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<artifactId>${quarkus.platform.artifact-id}</artifactId>
|
||||
<groupId>${quarkus.platform.group-id}</groupId>
|
||||
<scope>import</scope>
|
||||
<type>pom</type>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>gitlab-maven</id>
|
||||
<url>https://gitlab.pegase.tech/api/v4/projects/68/packages/maven</url>
|
||||
</repository>
|
||||
|
||||
<snapshotRepository>
|
||||
<id>gitlab-maven</id>
|
||||
<url>https://gitlab.pegase.tech/api/v4/projects/68/packages/maven</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
<groupId>tech.pegase.z3</groupId>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<modules>
|
||||
<module>z3-domain</module>
|
||||
<module>z3-infrastructure</module>
|
||||
<module>z3-application</module>
|
||||
<module>z3-shared</module>
|
||||
<module>z3-cli</module>
|
||||
<module>z3-statistics-domain</module>
|
||||
<module>z3-statistics-infrastructure</module>
|
||||
</modules>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<activation>
|
||||
<property>
|
||||
<name>native</name>
|
||||
</property>
|
||||
</activation>
|
||||
<id>native</id>
|
||||
<properties>
|
||||
<quarkus.native.enabled>true</quarkus.native.enabled>
|
||||
<skipITs>false</skipITs>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<properties>
|
||||
<apache-tika.version>3.0.0</apache-tika.version>
|
||||
<blaze-persistence.version>1.6.14</blaze-persistence.version>
|
||||
<bouncycastle-bcpkix.version>1.79</bouncycastle-bcpkix.version>
|
||||
<checkstyle-maven-plugin.version>3.6.0</checkstyle-maven-plugin.version>
|
||||
<checkstyle.version>10.21.1</checkstyle.version>
|
||||
<commons-csv.version>1.13.0</commons-csv.version>
|
||||
<commons-validator.version>1.9.0</commons-validator.version>
|
||||
<crawler-detect.version>1.0.0</crawler-detect.version>
|
||||
<dependency-check-maven.api_key/>
|
||||
<dependency-check-maven.version>12.0.0</dependency-check-maven.version>
|
||||
<failsafe-plugin.version>3.5.2</failsafe-plugin.version>
|
||||
<jacoco.version>0.8.12</jacoco.version>
|
||||
<jspecify.version>1.0.0</jspecify.version>
|
||||
<log4j2.version>2.24.3</log4j2.version>
|
||||
<maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
|
||||
<maven.compiler.release>21</maven.compiler.release>
|
||||
<maxmind-geoip2.version>2.15.0</maxmind-geoip2.version>
|
||||
<net-datafaker.version>2.4.2</net-datafaker.version>
|
||||
<opencsv.version>5.9</opencsv.version>
|
||||
<pegase-happy.version>1.0.1</pegase-happy.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
|
||||
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
|
||||
<quarkus.platform.version>3.17.6</quarkus.platform.version>
|
||||
<seancfoley-ipaddress.version>5.5.1</seancfoley-ipaddress.version>
|
||||
<skipITs>true</skipITs>
|
||||
<slugify-dep-icu4j-icu.version>76.1</slugify-dep-icu4j-icu.version>
|
||||
<slugify.version>3.0.7</slugify.version>
|
||||
<spring-security.version>6.4.2</spring-security.version>
|
||||
<surefire-plugin.version>3.5.2</surefire-plugin.version>
|
||||
<yauaa-useragent.version>7.30.0</yauaa-useragent.version>
|
||||
<z3.version>1.1.0-SNAPSHOT</z3.version>
|
||||
<z3.version>1.1.0-SNAPSHOT</z3.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>gitlab-maven</id>
|
||||
<url>https://gitlab.pegase.tech/api/v4/projects/68/packages/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
</project>
|
||||
43
z3-application/.env.example
Normal file
43
z3-application/.env.example
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# DATABASE
|
||||
APP_DB_KIND=
|
||||
APP_DB_USERNAME=
|
||||
APP_DB_PASSWORD=
|
||||
APP_DB_JDBC_URL=
|
||||
|
||||
# EXPORT
|
||||
APP_RESOLVER_FQDN=example.net
|
||||
|
||||
# LOG
|
||||
APP_LOG_LEVEL=INFO
|
||||
|
||||
# MAX UPLOAD SIZE
|
||||
APP_MAX_UPLOAD_SIZE=100M
|
||||
|
||||
# SECURITY
|
||||
APP_JWT_ISSUER=
|
||||
APP_JWT_PUBLIC_KEY=
|
||||
APP_JWT_PRIVATE_KEY=
|
||||
# ENCRYPTION
|
||||
AES_KEY=
|
||||
AES_SALT=
|
||||
AES_KEY_LENGTH=
|
||||
|
||||
# MAIL
|
||||
APP_MAIL_FROM=z3@example.net
|
||||
APP_MAIL_HOST=localhost
|
||||
APP_MAIL_PORT=1025
|
||||
APP_MAIL_START_TLS=OPTIONAL
|
||||
APP_MAIL_TLS=false
|
||||
APP_MAIL_USERNAME=null
|
||||
APP_MAIL_PASSWORD=null
|
||||
APP_MAIL_DEV_SIMULATE=false
|
||||
|
||||
# - ACCOUNT CREATION - optional - an email is sent
|
||||
APP_CREATE_USER_ON_START=
|
||||
|
||||
# - SCHEDULING
|
||||
# By default, the syntax used for cron expressions is based on Quartz
|
||||
# - https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html
|
||||
# You can change the syntax using the following property:
|
||||
# quarkus.scheduler.cron-type=unix
|
||||
APP_REPORT_INVALID_LINKS=
|
||||
187
z3-application/pom.xml
Normal file
187
z3-application/pom.xml
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<artifactId>z3-application</artifactId>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>quarkus-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
<goal>generate-code</goal>
|
||||
<goal>generate-code-tests</goal>
|
||||
<goal>native-image-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<extensions>true</extensions>
|
||||
<groupId>${quarkus.platform.group-id}</groupId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<compilerArgs>
|
||||
<arg>-parameters</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- FIX warnings about maybe mockito, maybe removed when bumping quarkus-->
|
||||
<argLine>-XX:+EnableDynamicAgentLoading -Xshare:off</argLine>
|
||||
<!-- To remove JBoss Log error on build and testing for all modules-->
|
||||
<systemPropertyVariables>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
<maven.home>${maven.home}</maven.home>
|
||||
<quarkus.jacoco.data-file>${project.build.directory}/coverage-reports/jacoco.exec
|
||||
</quarkus.jacoco.data-file>
|
||||
<quarkus.jacoco.report-location>${project.build.directory}/coverage-jacoco
|
||||
</quarkus.jacoco.report-location>
|
||||
<quarkus.jacoco.reuse-data-file>true</quarkus.jacoco.reuse-data-file>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
<version>${surefire-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
<maven.home>${maven.home}</maven.home>
|
||||
<native.image.path>${project.build.directory}/${project.build.finalName}-runner
|
||||
</native.image.path>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<version>${failsafe-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<artifactId>z3-domain</artifactId>
|
||||
<groupId>tech.pegase.z3</groupId>
|
||||
<version>${z3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>z3-infrastructure</artifactId>
|
||||
<groupId>tech.pegase.z3</groupId>
|
||||
<version>${z3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>z3-statistics-domain</artifactId>
|
||||
<groupId>tech.pegase.z3</groupId>
|
||||
<version>${z3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>z3-statistics-infrastructure</artifactId>
|
||||
<groupId>tech.pegase.z3</groupId>
|
||||
<version>${z3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>z3-shared</artifactId>
|
||||
<groupId>tech.pegase.z3</groupId>
|
||||
<version>${z3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-arc</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-rest</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-rest-jackson</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-narayana-jta</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-hibernate-validator</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-scheduler</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-vertx</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-jdbc-h2</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-flyway</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>flyway-database-postgresql</artifactId>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-junit5-mockito</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>quarkus-jacoco</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>happy-quarkus</artifactId>
|
||||
<groupId>tech.pegase.happy</groupId>
|
||||
<version>${pegase-happy.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>opencsv</artifactId>
|
||||
<groupId>com.opencsv</groupId>
|
||||
<version>${opencsv.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>tika-core</artifactId>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<version>${apache-tika.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>ipaddress</artifactId>
|
||||
<groupId>com.github.seancfoley</groupId>
|
||||
<version>${seancfoley-ipaddress.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<artifactId>z3</artifactId>
|
||||
<groupId>tech.pegase.z3</groupId>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>22</maven.compiler.source>
|
||||
<maven.compiler.target>22</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package tech.pegase.z3.application.api;
|
||||
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
@Path("/")
|
||||
public class RootResource {
|
||||
|
||||
@Inject
|
||||
public RootResource() {}
|
||||
|
||||
@GET
|
||||
@Path("/")
|
||||
@PermitAll
|
||||
public Response getRoot() {
|
||||
return Response.ok().entity("Z3 App running").build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package tech.pegase.z3.application.api.v1.auth;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.PUT;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.context.UserContext;
|
||||
import tech.pegase.z3.application.exception.ServerErrorException;
|
||||
import tech.pegase.z3.application.presenter.auth.ChangePasswordPresenter;
|
||||
import tech.pegase.z3.application.presenter.auth.ChangePasswordPresenter.MessageDto;
|
||||
import tech.pegase.z3.application.request.auth.ChangePasswordRequest;
|
||||
import tech.pegase.z3.domain.usecase.users.ChangeUserPassword;
|
||||
|
||||
@Path("/api/v1/auth")
|
||||
@Authenticated
|
||||
public class ChangePasswordResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final ChangeUserPassword changeUserPassword;
|
||||
private final ChangePasswordPresenter changePasswordPresenter;
|
||||
private final UserContext userContext;
|
||||
|
||||
ChangePasswordResource(
|
||||
UseCaseExecutor executor,
|
||||
ChangeUserPassword useCase,
|
||||
ChangePasswordPresenter presenter,
|
||||
UserContext userContext) {
|
||||
useCaseExecutor = executor;
|
||||
changeUserPassword = useCase;
|
||||
changePasswordPresenter = presenter;
|
||||
this.userContext = userContext;
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/password")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<MessageDto> updateUser(@Valid ChangePasswordRequest request) {
|
||||
var userContextId = userContext.getId();
|
||||
|
||||
if (userContextId == null) {
|
||||
throw new ServerErrorException("Cannot get user context");
|
||||
}
|
||||
|
||||
return useCaseExecutor
|
||||
.forUseCase(changeUserPassword)
|
||||
.withParameter(
|
||||
new ChangeUserPassword.Input.WhereId(
|
||||
userContextId, request.getPassword(), request.getNewPassword()))
|
||||
.withPresenter(changePasswordPresenter)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package tech.pegase.z3.application.api.v1.auth;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.context.UserContext;
|
||||
import tech.pegase.z3.application.exception.ServerErrorException;
|
||||
import tech.pegase.z3.application.presenter.user.GetUserPresenter;
|
||||
import tech.pegase.z3.application.presenter.user.GetUserPresenter.UserDto;
|
||||
import tech.pegase.z3.domain.usecase.users.GetUser;
|
||||
|
||||
@Path("/api/v1/auth")
|
||||
@ApplicationScoped
|
||||
public class GetProfileResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final GetUser getUserUseCase;
|
||||
private final GetUserPresenter getUserPresenter;
|
||||
private final UserContext userContext;
|
||||
|
||||
public GetProfileResource(
|
||||
UseCaseExecutor executor,
|
||||
GetUser getUserUseCase,
|
||||
GetUserPresenter getUserPresenter,
|
||||
UserContext userContext) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.getUserUseCase = getUserUseCase;
|
||||
this.getUserPresenter = getUserPresenter;
|
||||
this.userContext = userContext;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/me")
|
||||
@Authenticated
|
||||
public RestResponse<UserDto> currentUser() {
|
||||
var userContextId = userContext.getId();
|
||||
|
||||
if (userContextId == null) {
|
||||
throw new ServerErrorException("Cannot get user context");
|
||||
}
|
||||
|
||||
return useCaseExecutor
|
||||
.forUseCase(getUserUseCase)
|
||||
.withParameter(new GetUser.Input.ForId(userContextId))
|
||||
.withPresenter(getUserPresenter)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package tech.pegase.z3.application.api.v1.auth;
|
||||
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.presenter.auth.AuthenticateUserPresenter;
|
||||
import tech.pegase.z3.application.presenter.auth.AuthenticateUserPresenter.JwtTokenJsonDto;
|
||||
import tech.pegase.z3.application.request.auth.AuthRequest;
|
||||
import tech.pegase.z3.domain.usecase.auth.AuthenticateUser;
|
||||
|
||||
@NullMarked
|
||||
@Path("/api/v1/auth")
|
||||
@ApplicationScoped
|
||||
public class LoginResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final AuthenticateUser authenticateUserUseCase;
|
||||
private final AuthenticateUserPresenter authenticateUserPresenter;
|
||||
|
||||
public LoginResource(
|
||||
UseCaseExecutor executor,
|
||||
AuthenticateUser useCase,
|
||||
AuthenticateUserPresenter presenter) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.authenticateUserUseCase = useCase;
|
||||
this.authenticateUserPresenter = presenter;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/login")
|
||||
@PermitAll
|
||||
public RestResponse<JwtTokenJsonDto> auth(@Valid AuthRequest request) {
|
||||
// TODO: add rate limiting.
|
||||
return useCaseExecutor
|
||||
.forUseCase(authenticateUserUseCase)
|
||||
.withParameter(
|
||||
new AuthenticateUser.Input.Authenticate(request.getLogin(), request.getPassword()))
|
||||
.withPresenter(authenticateUserPresenter)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
@NullMarked
|
||||
package tech.pegase.z3.application.api.v1.auth;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package tech.pegase.z3.application.api.v1.brand;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.presenter.brand.CreateBrandPresenter;
|
||||
import tech.pegase.z3.application.presenter.brand.CreateBrandPresenter.BrandDto;
|
||||
import tech.pegase.z3.application.request.brand.CreateBrandRequest;
|
||||
import tech.pegase.z3.domain.usecase.brands.CreateBrand;
|
||||
import tech.pegase.z3.domain.usecase.brands.CreateBrand.Input;
|
||||
|
||||
@Authenticated
|
||||
@Path("/api/v1/brands")
|
||||
public class CreateBrandResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final CreateBrand createBrand;
|
||||
private final CreateBrandPresenter createBrandPresenter;
|
||||
|
||||
@Inject
|
||||
public CreateBrandResource(
|
||||
UseCaseExecutor executor, CreateBrand useCase, CreateBrandPresenter presenter) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.createBrand = useCase;
|
||||
this.createBrandPresenter = presenter;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/")
|
||||
@RolesAllowed("ADMINISTRATOR")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<BrandDto> create(@Valid CreateBrandRequest request) {
|
||||
var parameter = new Input.With(request.getName(), request.getFqdns());
|
||||
return useCaseExecutor
|
||||
.forUseCase(createBrand)
|
||||
.withParameter(parameter)
|
||||
.withPresenter(createBrandPresenter)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package tech.pegase.z3.application.api.v1.brand;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.presenter.brand.GetBrandPresenter;
|
||||
import tech.pegase.z3.application.presenter.brand.GetBrandPresenter.BrandDto;
|
||||
import tech.pegase.z3.domain.usecase.brands.GetBrand;
|
||||
import tech.pegase.z3.domain.usecase.brands.GetBrand.Input.ForSlug;
|
||||
import tech.pegase.z3.domain.valueobject.Slug;
|
||||
|
||||
@Path("/api/v1/brands")
|
||||
@Authenticated
|
||||
public class GetBrandResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final GetBrand getBrand;
|
||||
private final GetBrandPresenter getBrandResponsePresenter;
|
||||
|
||||
@Inject
|
||||
public GetBrandResource(
|
||||
UseCaseExecutor executor, GetBrand useCase, GetBrandPresenter presenter) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.getBrand = useCase;
|
||||
this.getBrandResponsePresenter = presenter;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{brand}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<BrandDto> getBrand(@PathParam("brand") Slug brand) {
|
||||
return useCaseExecutor
|
||||
.forUseCase(getBrand)
|
||||
.withParameter(new ForSlug(brand))
|
||||
.withPresenter(getBrandResponsePresenter)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package tech.pegase.z3.application.api.v1.brand;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.BeanParam;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.dto.PaginatedDto;
|
||||
import tech.pegase.z3.application.presenter.brand.ListBrandsPresenter;
|
||||
import tech.pegase.z3.application.presenter.brand.ListBrandsPresenter.BrandDto;
|
||||
import tech.pegase.z3.application.request.brand.PaginatedBrandListRequest;
|
||||
import tech.pegase.z3.domain.usecase.brands.ListBrands;
|
||||
import tech.pegase.z3.shared.pagination.Pagination;
|
||||
|
||||
@Path("/api/v1/brands")
|
||||
@Authenticated
|
||||
public class ListBrandsResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final ListBrands listBrands;
|
||||
private final ListBrandsPresenter listBrandsPresenter;
|
||||
|
||||
@Inject
|
||||
public ListBrandsResource(
|
||||
UseCaseExecutor executor, ListBrands useCase, ListBrandsPresenter presenter) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.listBrands = useCase;
|
||||
this.listBrandsPresenter = presenter;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<PaginatedDto<BrandDto>> getPaginatedBrandList(
|
||||
@BeanParam @Valid PaginatedBrandListRequest request) {
|
||||
return useCaseExecutor
|
||||
.forUseCase(listBrands)
|
||||
.withParameter(getParameterFromRequest(request))
|
||||
.withPresenter(listBrandsPresenter)
|
||||
.run();
|
||||
}
|
||||
|
||||
private ListBrands.Input getParameterFromRequest(PaginatedBrandListRequest request) {
|
||||
var pagination = Pagination.fromPageNumberAndPageSize(request.getPage(), request.getPerPage());
|
||||
|
||||
return new ListBrands.Input.WithPagination(pagination);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package tech.pegase.z3.application.api.v1.brand;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.PUT;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.presenter.brand.UpdateBrandPresenter;
|
||||
import tech.pegase.z3.application.presenter.brand.UpdateBrandPresenter.BrandDto;
|
||||
import tech.pegase.z3.application.request.brand.UpdateBrandRequest;
|
||||
import tech.pegase.z3.domain.usecase.brands.UpdateBrand;
|
||||
import tech.pegase.z3.domain.usecase.brands.UpdateBrand.Input.ForSlug;
|
||||
import tech.pegase.z3.domain.valueobject.Slug;
|
||||
|
||||
@Path("/api/v1/brands")
|
||||
@Authenticated
|
||||
public class UpdateBrandResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final UpdateBrand updateBrandUseCase;
|
||||
private final UpdateBrandPresenter updateBrandPresenter;
|
||||
|
||||
@Inject
|
||||
UpdateBrandResource(
|
||||
UseCaseExecutor executor, UpdateBrand useCase, UpdateBrandPresenter presenter) {
|
||||
useCaseExecutor = executor;
|
||||
updateBrandUseCase = useCase;
|
||||
updateBrandPresenter = presenter;
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/{brand}")
|
||||
@RolesAllowed("ADMINISTRATOR")
|
||||
public RestResponse<BrandDto> updateBrand(
|
||||
@PathParam("brand") Slug brand, @Valid UpdateBrandRequest request) {
|
||||
return useCaseExecutor
|
||||
.forUseCase(updateBrandUseCase)
|
||||
.withParameter(new ForSlug(brand, request.getName(), request.getFqdns()))
|
||||
.withPresenter(updateBrandPresenter)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
@NullMarked
|
||||
package tech.pegase.z3.application.api.v1.brand;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package tech.pegase.z3.application.api.v1.catalog;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.presenter.catalog.CreateCatalogPresenter;
|
||||
import tech.pegase.z3.application.presenter.catalog.CreateCatalogPresenter.CatalogDto;
|
||||
import tech.pegase.z3.application.request.catalog.CreateCatalogRequest;
|
||||
import tech.pegase.z3.domain.usecase.catalogs.CreateCatalog;
|
||||
import tech.pegase.z3.domain.usecase.catalogs.CreateCatalog.Input;
|
||||
|
||||
@Authenticated
|
||||
@Path("/api/v1/catalogs")
|
||||
public class CreateCatalogResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final CreateCatalog createCatalog;
|
||||
private final CreateCatalogPresenter createCatalogPresenter;
|
||||
|
||||
@Inject
|
||||
public CreateCatalogResource(
|
||||
UseCaseExecutor executor,
|
||||
CreateCatalog useCase,
|
||||
CreateCatalogPresenter presenter) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.createCatalog = useCase;
|
||||
this.createCatalogPresenter = presenter;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<CatalogDto> create(@Valid CreateCatalogRequest request) {
|
||||
Input parameter = new Input.With(request.getName(), request.getBrand());
|
||||
return useCaseExecutor
|
||||
.forUseCase(createCatalog)
|
||||
.withParameter(parameter)
|
||||
.withPresenter(createCatalogPresenter)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package tech.pegase.z3.application.api.v1.catalog;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.presenter.catalog.GetCatalogPresenter;
|
||||
import tech.pegase.z3.application.presenter.catalog.GetCatalogPresenter.CatalogDto;
|
||||
import tech.pegase.z3.domain.usecase.catalogs.GetCatalog;
|
||||
import tech.pegase.z3.domain.usecase.catalogs.GetCatalog.Input.ForSlug;
|
||||
import tech.pegase.z3.domain.valueobject.Slug;
|
||||
|
||||
@Path("/api/v1/catalogs")
|
||||
@Authenticated
|
||||
public class GetCatalogResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final GetCatalog getCatalog;
|
||||
private final GetCatalogPresenter getCatalogResponsePresenter;
|
||||
|
||||
@Inject
|
||||
public GetCatalogResource(
|
||||
UseCaseExecutor executor, GetCatalog useCase, GetCatalogPresenter presenter) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.getCatalog = useCase;
|
||||
this.getCatalogResponsePresenter = presenter;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{catalog}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<CatalogDto> getCatalog(@PathParam("catalog") Slug catalog) {
|
||||
return useCaseExecutor
|
||||
.forUseCase(getCatalog)
|
||||
.withParameter(new ForSlug(catalog))
|
||||
.withPresenter(getCatalogResponsePresenter)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package tech.pegase.z3.application.api.v1.catalog;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.BeanParam;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.dto.PaginatedDto;
|
||||
import tech.pegase.z3.application.presenter.catalog.ListCatalogsPresenter;
|
||||
import tech.pegase.z3.application.presenter.catalog.ListCatalogsPresenter.CatalogDto;
|
||||
import tech.pegase.z3.application.request.catalog.PaginatedCatalogListRequest;
|
||||
import tech.pegase.z3.domain.usecase.catalogs.ListCatalogs;
|
||||
import tech.pegase.z3.shared.pagination.Pagination;
|
||||
|
||||
@Path("/api/v1/catalogs")
|
||||
@Authenticated
|
||||
public class ListCatalogsResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final ListCatalogs listCatalogs;
|
||||
private final ListCatalogsPresenter listCatalogsPresenter;
|
||||
|
||||
@Inject
|
||||
public ListCatalogsResource(
|
||||
UseCaseExecutor executor, ListCatalogs useCase, ListCatalogsPresenter presenter) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.listCatalogs = useCase;
|
||||
this.listCatalogsPresenter = presenter;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<PaginatedDto<CatalogDto>> getPaginatedCatalogList(
|
||||
@BeanParam @Valid PaginatedCatalogListRequest request) {
|
||||
return useCaseExecutor
|
||||
.forUseCase(listCatalogs)
|
||||
.withParameter(getParameterFromRequest(request))
|
||||
.withPresenter(listCatalogsPresenter)
|
||||
.run();
|
||||
}
|
||||
|
||||
private ListCatalogs.Input getParameterFromRequest(PaginatedCatalogListRequest request) {
|
||||
var pagination =
|
||||
Pagination.fromPageNumberAndPageSize(request.getPage(), request.getPerPage());
|
||||
|
||||
var brand = request.getBrand();
|
||||
|
||||
if (brand != null) {
|
||||
return new ListCatalogs.Input.WithPaginationForBrand(brand, pagination);
|
||||
}
|
||||
|
||||
return new ListCatalogs.Input.WithPagination(pagination);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package tech.pegase.z3.application.api.v1.catalog;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.DELETE;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.dto.MessageDto;
|
||||
import tech.pegase.z3.application.presenter.catalog.RemoveCatalogPresenter;
|
||||
import tech.pegase.z3.domain.usecase.catalogs.RemoveCatalog;
|
||||
import tech.pegase.z3.domain.usecase.catalogs.RemoveCatalog.Input.ForSlug;
|
||||
import tech.pegase.z3.domain.valueobject.Slug;
|
||||
|
||||
@Path("/api/v1/catalogs")
|
||||
@Authenticated
|
||||
public class RemoveCatalogResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final RemoveCatalog removeCatalogUseCase;
|
||||
private final RemoveCatalogPresenter removeCatalogPresenter;
|
||||
|
||||
@Inject
|
||||
RemoveCatalogResource(
|
||||
UseCaseExecutor executor,
|
||||
RemoveCatalog useCase,
|
||||
RemoveCatalogPresenter presenter) {
|
||||
useCaseExecutor = executor;
|
||||
removeCatalogUseCase = useCase;
|
||||
removeCatalogPresenter = presenter;
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/{catalog}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<MessageDto> removeCatalog(@PathParam("catalog") Slug catalog) {
|
||||
return useCaseExecutor
|
||||
.forUseCase(removeCatalogUseCase)
|
||||
.withParameter(new ForSlug(catalog))
|
||||
.withPresenter(removeCatalogPresenter)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package tech.pegase.z3.application.api.v1.catalog;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.PUT;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.presenter.catalog.UpdateCatalogPresenter;
|
||||
import tech.pegase.z3.application.presenter.catalog.UpdateCatalogPresenter.CatalogDto;
|
||||
import tech.pegase.z3.application.request.catalog.UpdateCatalogRequest;
|
||||
import tech.pegase.z3.domain.usecase.catalogs.UpdateCatalog;
|
||||
import tech.pegase.z3.domain.usecase.catalogs.UpdateCatalog.Input.ForSlug;
|
||||
import tech.pegase.z3.domain.valueobject.Slug;
|
||||
|
||||
@Path("/api/v1/catalogs")
|
||||
@Authenticated
|
||||
public class UpdateCatalogResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final UpdateCatalog updateCatalogUseCase;
|
||||
private final UpdateCatalogPresenter updateCatalogPresenter;
|
||||
|
||||
@Inject
|
||||
UpdateCatalogResource(
|
||||
UseCaseExecutor executor,
|
||||
UpdateCatalog useCase,
|
||||
UpdateCatalogPresenter presenter) {
|
||||
useCaseExecutor = executor;
|
||||
updateCatalogUseCase = useCase;
|
||||
updateCatalogPresenter = presenter;
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/{catalog}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<CatalogDto> updateCatalog(
|
||||
@PathParam("catalog") Slug catalog, @Valid UpdateCatalogRequest request) {
|
||||
return useCaseExecutor
|
||||
.forUseCase(updateCatalogUseCase)
|
||||
.withParameter(new ForSlug(catalog, request.getName()))
|
||||
.withPresenter(updateCatalogPresenter)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
@NullMarked
|
||||
package tech.pegase.z3.application.api.v1.catalog;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package tech.pegase.z3.application.api.v1.link;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.presenter.link.CreateLinkPresenter;
|
||||
import tech.pegase.z3.application.presenter.link.CreateLinkPresenter.LinkDto;
|
||||
import tech.pegase.z3.application.request.link.CreateLinkRequest;
|
||||
import tech.pegase.z3.domain.usecase.links.CreateLink;
|
||||
import tech.pegase.z3.domain.usecase.links.CreateLink.Input.CommonLinkInput;
|
||||
import tech.pegase.z3.domain.usecase.links.CreateLink.Input.WithSourceAndUrl;
|
||||
import tech.pegase.z3.domain.usecase.links.CreateLink.Input.WithUrl;
|
||||
|
||||
@Path("/api/v1/links")
|
||||
@Authenticated
|
||||
public class CreateLinkResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final CreateLink createLink;
|
||||
private final CreateLinkPresenter createLinkPresenter;
|
||||
|
||||
@Inject
|
||||
public CreateLinkResource(
|
||||
UseCaseExecutor executor, CreateLink useCase, CreateLinkPresenter presenter) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.createLink = useCase;
|
||||
this.createLinkPresenter = presenter;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<LinkDto> create(CreateLinkRequest request) {
|
||||
var commonLinkInput = from(request);
|
||||
|
||||
CreateLink.Input parameter =
|
||||
request.getSource() == null
|
||||
? new WithUrl(commonLinkInput)
|
||||
: new WithSourceAndUrl(request.getSource(), commonLinkInput);
|
||||
return useCaseExecutor
|
||||
.forUseCase(createLink)
|
||||
.withParameter(parameter)
|
||||
.withPresenter(createLinkPresenter)
|
||||
.run();
|
||||
}
|
||||
|
||||
CommonLinkInput from(CreateLinkRequest request) {
|
||||
var target = request.getTarget();
|
||||
var isExternal = request.isExternal();
|
||||
var brandUuid = request.getBrand();
|
||||
var tagUuid = request.getTag();
|
||||
var catalogUuid = request.getCatalog();
|
||||
|
||||
return new CommonLinkInput(target, isExternal, brandUuid, tagUuid, catalogUuid);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
package tech.pegase.z3.application.api.v1.link;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import jakarta.ws.rs.core.StreamingOutput;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import org.eclipse.microprofile.config.ConfigProvider;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.presenter.brand.GetBrandPresenter;
|
||||
import tech.pegase.z3.application.presenter.catalog.GetCatalogPresenter;
|
||||
import tech.pegase.z3.application.presenter.link.CsvPartialExportLinkPresenter;
|
||||
import tech.pegase.z3.application.presenter.link.CsvPartialExportLinkPresenter.PartialExport;
|
||||
import tech.pegase.z3.domain.usecase.brands.GetBrand;
|
||||
import tech.pegase.z3.domain.usecase.catalogs.GetCatalog;
|
||||
import tech.pegase.z3.domain.usecase.links.ExportLinks;
|
||||
import tech.pegase.z3.domain.usecase.links.ExportLinks.Input;
|
||||
import tech.pegase.z3.domain.valueobject.Slug;
|
||||
|
||||
@Path("/api/v1/links-export")
|
||||
@Authenticated
|
||||
public class ExportLinksResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final ExportLinks exportLinks;
|
||||
private final GetBrand getBrand;
|
||||
private final GetCatalog getCatalog;
|
||||
private final CsvPartialExportLinkPresenter csvPartialExportLinkPresenter;
|
||||
|
||||
@Inject
|
||||
public ExportLinksResource(
|
||||
UseCaseExecutor executor,
|
||||
ExportLinks useCase,
|
||||
GetBrand getBrandUseCase,
|
||||
GetCatalog getCatalogUseCase,
|
||||
CsvPartialExportLinkPresenter presenter) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.exportLinks = useCase;
|
||||
this.getBrand = getBrandUseCase;
|
||||
this.getCatalog = getCatalogUseCase;
|
||||
this.csvPartialExportLinkPresenter = presenter;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/")
|
||||
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||
public RestResponse<StreamingOutput> exportLink(
|
||||
@QueryParam("per-page") @Valid @jakarta.annotation.Nullable @Nullable @Min(1) @Max(50)
|
||||
Integer perPage) {
|
||||
try {
|
||||
perPage = Optional.ofNullable(perPage).orElse(50);
|
||||
csvPartialExportLinkPresenter.setWithHeaders(true);
|
||||
|
||||
var output = genOutput(perPage);
|
||||
|
||||
return buildResponse(output, "external_links");
|
||||
} catch (IllegalStateException e) {
|
||||
return RestResponse.status(Response.Status.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/brands/{brand: [a-zA-Z0-9-]+}")
|
||||
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||
public RestResponse<StreamingOutput> exportBrandLinks(
|
||||
@PathParam("brand") Slug brand,
|
||||
@QueryParam("per-page") @Valid @jakarta.annotation.Nullable @Nullable @Min(1) @Max(50)
|
||||
Integer perPage) {
|
||||
try {
|
||||
perPage = Optional.ofNullable(perPage).orElse(50);
|
||||
var resolvedBrand = resolveBrand(brand);
|
||||
|
||||
if (resolvedBrand == null) {
|
||||
return RestResponse.status(Status.NOT_FOUND);
|
||||
}
|
||||
|
||||
csvPartialExportLinkPresenter.setWithHeaders(true);
|
||||
|
||||
var output = genBrandOutput(brand, perPage);
|
||||
|
||||
return buildResponse(output, brand.toString());
|
||||
} catch (IllegalStateException e) {
|
||||
return RestResponse.status(Response.Status.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/catalogs/{catalog: [a-zA-Z0-9-]+}")
|
||||
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||
public RestResponse<StreamingOutput> exportCatalogLinks(
|
||||
@PathParam("catalog") Slug catalog,
|
||||
@QueryParam("per-page") @Valid @jakarta.annotation.Nullable @Nullable @Min(1) @Max(50)
|
||||
Integer perPage) {
|
||||
try {
|
||||
perPage = Optional.ofNullable(perPage).orElse(50);
|
||||
var resolvedCatalog = resolveCatalog(catalog);
|
||||
|
||||
if (resolvedCatalog == null) {
|
||||
return RestResponse.status(Status.NOT_FOUND);
|
||||
}
|
||||
|
||||
csvPartialExportLinkPresenter.setWithHeaders(true);
|
||||
|
||||
var output = genCatalogOutput(catalog, perPage);
|
||||
|
||||
return buildResponse(output, catalog.toString());
|
||||
} catch (IllegalStateException e) {
|
||||
return RestResponse.status(Response.Status.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
private GetBrandPresenter.@Nullable BrandDto resolveBrand(Slug brandSlug) {
|
||||
try (var response =
|
||||
useCaseExecutor
|
||||
.forUseCase(getBrand)
|
||||
.withParameter(new GetBrand.Input.ForSlug(brandSlug))
|
||||
.withPresenter(
|
||||
new GetBrandPresenter() {
|
||||
@Override
|
||||
public RestResponse<@Nullable BrandDto> present(GetBrand.Output output) {
|
||||
if (output instanceof GetBrand.Output.Found) {
|
||||
return RestResponse.ok(BrandDto.of(((GetBrand.Output.Found) output).brand()));
|
||||
}
|
||||
return RestResponse.notFound();
|
||||
}
|
||||
})
|
||||
.run()) {
|
||||
|
||||
return response.getStatusInfo().equals(Status.NOT_FOUND) ? null : response.getEntity();
|
||||
}
|
||||
}
|
||||
|
||||
private GetCatalogPresenter.@Nullable CatalogDto resolveCatalog(Slug catalogSlug) {
|
||||
try (var response =
|
||||
useCaseExecutor
|
||||
.forUseCase(getCatalog)
|
||||
.withParameter(new GetCatalog.Input.ForSlug(catalogSlug))
|
||||
.withPresenter(
|
||||
new GetCatalogPresenter() {
|
||||
@Override
|
||||
public RestResponse<@Nullable CatalogDto> present(GetCatalog.Output output) {
|
||||
if (output instanceof GetCatalog.Output.Found) {
|
||||
return RestResponse.ok(
|
||||
CatalogDto.of(((GetCatalog.Output.Found) output).catalog()));
|
||||
}
|
||||
return RestResponse.notFound();
|
||||
}
|
||||
})
|
||||
.run()) {
|
||||
|
||||
return response.getStatusInfo().equals(Status.NOT_FOUND) ? null : response.getEntity();
|
||||
}
|
||||
}
|
||||
|
||||
private StreamingOutput genBrandOutput(Slug brandSlug, int perPage) {
|
||||
return genOutputWith(
|
||||
page -> new Input.PageForBrand(brandSlug, new Input.Pagination(page, perPage)));
|
||||
}
|
||||
|
||||
private StreamingOutput genCatalogOutput(Slug catalogSlug, int perPage) {
|
||||
return genOutputWith(
|
||||
page -> new Input.PageForCatalog(catalogSlug, new Input.Pagination(page, perPage)));
|
||||
}
|
||||
|
||||
private StreamingOutput genOutput(int perPage) {
|
||||
return genOutputWith(page -> new Input.PageForNonBranded(new Input.Pagination(page, perPage)));
|
||||
}
|
||||
|
||||
private StreamingOutput genOutputWith(Function<Integer, Input> inputFunction) {
|
||||
return out -> {
|
||||
var page = 0;
|
||||
PartialExport exportPart;
|
||||
do {
|
||||
exportPart =
|
||||
useCaseExecutor
|
||||
.forUseCase(exportLinks)
|
||||
.withParameter(inputFunction.apply(page++))
|
||||
.withPresenter(csvPartialExportLinkPresenter)
|
||||
.run();
|
||||
if (exportPart instanceof PartialExport.Part(var partContent)) {
|
||||
out.write(partContent.getBytes(StandardCharsets.UTF_8));
|
||||
out.flush();
|
||||
}
|
||||
} while (exportPart instanceof PartialExport.Part);
|
||||
};
|
||||
}
|
||||
|
||||
private RestResponse<StreamingOutput> buildResponse(StreamingOutput output, String exportName) {
|
||||
var appName = ConfigProvider.getConfig().getValue("quarkus.application.name", String.class);
|
||||
|
||||
return RestResponse.ResponseBuilder.create(Status.OK, output)
|
||||
.header(
|
||||
"Content-Disposition",
|
||||
"attachment; filename=\"%s-export-%s-%s.csv\";"
|
||||
.formatted(
|
||||
appName, exportName, new SimpleDateFormat("dd-MM-yyyy").format(new Date())))
|
||||
.header("Content-Type", "application/csv; charset=UTF-8")
|
||||
.header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate")
|
||||
.header("Pragma", "no-cache")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package tech.pegase.z3.application.api.v1.link;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.presenter.link.GetLinkPresenter;
|
||||
import tech.pegase.z3.application.presenter.link.GetLinkPresenter.LinkDto;
|
||||
import tech.pegase.z3.domain.usecase.links.GetLink;
|
||||
import tech.pegase.z3.domain.usecase.links.GetLink.Input.ForSource;
|
||||
import tech.pegase.z3.shared.valueobject.Source;
|
||||
|
||||
@Path("/api/v1/links")
|
||||
@Authenticated
|
||||
public class GetLinkResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final GetLink getLink;
|
||||
private final GetLinkPresenter getLinkResponsePresenter;
|
||||
|
||||
@Inject
|
||||
public GetLinkResource(UseCaseExecutor executor, GetLink useCase, GetLinkPresenter presenter) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.getLink = useCase;
|
||||
this.getLinkResponsePresenter = presenter;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{source: [a-zA-Z0-9/._~!$'()*+,;=:@-]+}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
/* Ici source correspond à la partie path + query + anchor d'une URL sur un QR code. */
|
||||
public RestResponse<LinkDto> getLink(@PathParam("source") Source source) {
|
||||
return useCaseExecutor
|
||||
.forUseCase(getLink)
|
||||
.withParameter(new ForSource(source))
|
||||
.withPresenter(getLinkResponsePresenter)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,231 @@
|
|||
package tech.pegase.z3.application.api.v1.link;
|
||||
|
||||
import com.opencsv.CSVParser;
|
||||
import com.opencsv.CSVParserBuilder;
|
||||
import com.opencsv.CSVReader;
|
||||
import com.opencsv.CSVReaderBuilder;
|
||||
import com.opencsv.exceptions.CsvException;
|
||||
import com.opencsv.exceptions.CsvValidationException;
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.apache.commons.io.input.BOMInputStream;
|
||||
import org.apache.tika.Tika;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.reactive.PartType;
|
||||
import org.jboss.resteasy.reactive.RestForm;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import org.jboss.resteasy.reactive.multipart.FileUpload;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.exception.ServerErrorException;
|
||||
import tech.pegase.z3.application.exception.ValidationException;
|
||||
import tech.pegase.z3.application.exception.ValidationException.ValidationError;
|
||||
import tech.pegase.z3.application.presenter.link.ImportLinksPresenter;
|
||||
import tech.pegase.z3.application.presenter.link.ImportLinksPresenter.ImportFailuresDto;
|
||||
import tech.pegase.z3.domain.usecase.links.ImportLinks;
|
||||
import tech.pegase.z3.domain.usecase.links.ImportLinks.Input.ImportLine;
|
||||
|
||||
@Path("/api/v1/links-import/")
|
||||
@Authenticated
|
||||
public class ImportLinksResource {
|
||||
private static final Logger logger = Logger.getLogger(ImportLinksResource.class.getName());
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final ImportLinks importLinks;
|
||||
private final ImportLinksPresenter importLinksPresenter;
|
||||
|
||||
@Inject
|
||||
public ImportLinksResource(
|
||||
UseCaseExecutor executor, ImportLinks useCase, ImportLinksPresenter presenter) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.importLinks = useCase;
|
||||
this.importLinksPresenter = presenter;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/brands/{brand: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}")
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<ImportFailuresDto> importForBrand(
|
||||
@PathParam("brand") UUID brandUuid,
|
||||
@Nullable @RestForm("tag") UUID tagUuid,
|
||||
@RestForm("file") @PartType("application/octet-stream") FileUpload file) {
|
||||
try {
|
||||
var importLines = uploadedFileToImportLine(file);
|
||||
|
||||
return useCaseExecutor
|
||||
.forUseCase(importLinks)
|
||||
.withParameter(new ImportLinks.Input.ImportForBrand(brandUuid, tagUuid, importLines))
|
||||
.withPresenter(importLinksPresenter)
|
||||
.run();
|
||||
} catch (IllegalStateException | CsvException e) {
|
||||
logger.debug(e.getMessage(), e);
|
||||
return RestResponse.status(Response.Status.BAD_REQUEST);
|
||||
} catch (IOException e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/catalogs/{catalog: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}")
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<ImportFailuresDto> importForCatalog(
|
||||
@PathParam("catalog") UUID catalogUuid,
|
||||
@Nullable @RestForm("tag") UUID tagUuid,
|
||||
@RestForm("file") @PartType("application/octet-stream") FileUpload file) {
|
||||
try {
|
||||
var importLines = uploadedFileToImportLine(file);
|
||||
|
||||
return useCaseExecutor
|
||||
.forUseCase(importLinks)
|
||||
.withParameter(new ImportLinks.Input.ImportForCatalog(catalogUuid, tagUuid, importLines))
|
||||
.withPresenter(importLinksPresenter)
|
||||
.run();
|
||||
} catch (IllegalStateException | CsvException e) {
|
||||
logger.debug(e.getMessage(), e);
|
||||
return RestResponse.status(Response.Status.BAD_REQUEST);
|
||||
} catch (IOException e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<ImportLinks.Input.ImportForBrand.ImportLine> uploadedFileToImportLine(
|
||||
FileUpload file) throws IOException, CsvException {
|
||||
var requiredColumns = List.of("source", "target", "isExternal");
|
||||
var delimiterToUse = detectDelimiterWithColumns(file, requiredColumns, ';');
|
||||
|
||||
assertFileHasHeader(file, requiredColumns, delimiterToUse);
|
||||
assertUploadedFileIsPlainText(file);
|
||||
|
||||
List<ImportLinks.Input.ImportForBrand.ImportLine> output = new ArrayList<>();
|
||||
|
||||
try (var inputStream = Files.newInputStream(file.uploadedFile())) {
|
||||
var csvReader = fromInputStream(inputStream, delimiterToUse);
|
||||
var lines = csvReader.readAll();
|
||||
// Skip header line.
|
||||
lines.removeFirst();
|
||||
for (var line : lines) {
|
||||
var importLine = listToImportLine(List.of(line));
|
||||
output.add(importLine);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
private Character detectDelimiterWithColumns(
|
||||
FileUpload file, List<String> columns, Character defaultDelimiter) {
|
||||
var availableDelimiters = Arrays.asList(';', ',');
|
||||
|
||||
return availableDelimiters.stream()
|
||||
.filter(
|
||||
delimiter -> {
|
||||
try (var inputStream = Files.newInputStream(file.uploadedFile())) {
|
||||
var csvReader = fromInputStream(inputStream, delimiter);
|
||||
var firstLine = List.of(csvReader.readNext());
|
||||
|
||||
return columns.equals(firstLine);
|
||||
} catch (CsvValidationException e) {
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
})
|
||||
.findFirst()
|
||||
.orElse(defaultDelimiter);
|
||||
}
|
||||
|
||||
private ImportLine listToImportLine(List<String> values) {
|
||||
if (values.size() < 3) {
|
||||
throw new IllegalStateException("Import lines requires at least three values");
|
||||
}
|
||||
var source = values.getFirst();
|
||||
var url = values.get(1);
|
||||
var isExternal = Boolean.parseBoolean(values.get(2));
|
||||
return new ImportLine(source, url, isExternal);
|
||||
}
|
||||
|
||||
private void assertFileHasHeader(FileUpload file, List<String> columns, Character delimiter)
|
||||
throws IOException {
|
||||
try (var inputStream = Files.newInputStream(file.uploadedFile())) {
|
||||
var csvReader = fromInputStream(inputStream, delimiter);
|
||||
var firstLine = List.of(csvReader.readNext());
|
||||
|
||||
if (firstLine.size() != 3) {
|
||||
throw ValidationException.of(
|
||||
ValidationError.of("file", "La première ligne est invalide, elle à besoin 3 columns"));
|
||||
}
|
||||
|
||||
if (!columns.equals(firstLine)) {
|
||||
throw ValidationException.of(
|
||||
ValidationError.of(
|
||||
"file",
|
||||
"La première ligne est invalide, il faut 'source', 'target', 'isExternal'"));
|
||||
}
|
||||
} catch (CsvValidationException e) {
|
||||
logger.debug(e.getMessage());
|
||||
throw new ServerErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertUploadedFileIsPlainText(FileUpload file) throws IOException {
|
||||
var guessedMimeType = guessMimeType(file);
|
||||
|
||||
if (!guessedMimeType.equals(MediaType.TEXT_PLAIN)) {
|
||||
logger.debug("File is not plain text");
|
||||
throw ValidationException.of(
|
||||
ValidationError.of("file", "File le fichier doit contenir du texte/csv uniquement"));
|
||||
}
|
||||
}
|
||||
|
||||
private CSVReader fromInputStream(InputStream inputStream, Character delimiter)
|
||||
throws IOException {
|
||||
var bomInputStream =
|
||||
BOMInputStream.builder().setInputStream(inputStream).setInclude(false).get();
|
||||
var reader = new InputStreamReader(new BufferedInputStream(bomInputStream));
|
||||
return getCsvReader(reader, delimiter);
|
||||
}
|
||||
|
||||
private CSVReader getCsvReader(Reader reader, Character delimiter) {
|
||||
var builder = new CSVReaderBuilder(reader);
|
||||
var parser = getCsvParser(delimiter);
|
||||
|
||||
builder.withCSVParser(parser);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private CSVParser getCsvParser(Character delimiter) {
|
||||
var csvParserBuilder = new CSVParserBuilder();
|
||||
|
||||
csvParserBuilder.withSeparator(delimiter);
|
||||
|
||||
return csvParserBuilder.build();
|
||||
}
|
||||
|
||||
private String guessMimeType(FileUpload file) throws IOException {
|
||||
var tika = new Tika();
|
||||
return tika.detect(new File(file.uploadedFile().toUri()));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
package tech.pegase.z3.application.api.v1.link;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.BeanParam;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import java.util.Objects;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.dto.PaginatedDto;
|
||||
import tech.pegase.z3.application.exception.ValidationException;
|
||||
import tech.pegase.z3.application.exception.ValidationException.ValidationError;
|
||||
import tech.pegase.z3.application.presenter.link.ListLinksPresenter;
|
||||
import tech.pegase.z3.application.presenter.link.ListLinksPresenter.LinkDto;
|
||||
import tech.pegase.z3.application.request.link.PaginatedLinkListRequest;
|
||||
import tech.pegase.z3.domain.usecase.links.ListLinks;
|
||||
import tech.pegase.z3.domain.valueobject.concepts.Ordering;
|
||||
import tech.pegase.z3.domain.valueobject.concepts.Ordering.Direction;
|
||||
import tech.pegase.z3.domain.valueobject.concepts.Searching;
|
||||
import tech.pegase.z3.domain.valueobject.orderings.LinkOrdering;
|
||||
import tech.pegase.z3.domain.valueobject.orderings.LinkOrdering.Field;
|
||||
import tech.pegase.z3.domain.valueobject.searchings.LinkSearching;
|
||||
import tech.pegase.z3.shared.pagination.Pagination;
|
||||
|
||||
@Path("/api/v1/links")
|
||||
@Authenticated
|
||||
public class ListLinksResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final ListLinks listLinks;
|
||||
private final ListLinksPresenter listLinksPresenter;
|
||||
|
||||
@Inject
|
||||
public ListLinksResource(
|
||||
UseCaseExecutor executor, ListLinks useCase, ListLinksPresenter presenter) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.listLinks = useCase;
|
||||
this.listLinksPresenter = presenter;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<PaginatedDto<LinkDto>> getPaginatedLinkList(
|
||||
@BeanParam @Valid PaginatedLinkListRequest request) {
|
||||
return useCaseExecutor
|
||||
.forUseCase(listLinks)
|
||||
.withParameter(getParameterFromRequest(request))
|
||||
.withPresenter(listLinksPresenter)
|
||||
.run();
|
||||
}
|
||||
|
||||
private ListLinks.Input getParameterFromRequest(PaginatedLinkListRequest request) {
|
||||
var pagination = Pagination.fromPageNumberAndPageSize(request.getPage(), request.getPerPage());
|
||||
var orderBy = request.getOrderBy();
|
||||
var direction = request.getDirection();
|
||||
var searchOn = request.getSearchOn();
|
||||
var keyword = request.getKeywords();
|
||||
var filters = request.getFilters();
|
||||
|
||||
var defaultOrdering = LinkOrdering.of(Field.SOURCE, Direction.NATURAL);
|
||||
|
||||
assertCanOrder(orderBy, direction);
|
||||
assertCanSearch(searchOn, keyword);
|
||||
|
||||
var ordering =
|
||||
(orderBy != null && direction != null) ? LinkOrdering.of(orderBy, direction) : null;
|
||||
var searching =
|
||||
(searchOn != null && keyword != null) ? LinkSearching.of(searchOn, keyword) : null;
|
||||
|
||||
if (searching != null) {
|
||||
return new ListLinks.Input.WithPaginationAndSearchingAllSorted(
|
||||
pagination, filters, Objects.requireNonNullElse(ordering, defaultOrdering), searching);
|
||||
}
|
||||
|
||||
return new ListLinks.Input.WithPaginationSorted(
|
||||
pagination, filters, Objects.requireNonNullElse(ordering, defaultOrdering));
|
||||
}
|
||||
|
||||
private void assertCanOrder(
|
||||
LinkOrdering.@Nullable Field orderBy, Ordering.@Nullable Direction direction) {
|
||||
if (orderBy != null ^ direction != null) {
|
||||
throw ValidationException.of(
|
||||
ValidationError.of("orderBy", "orderBy est requis avec direction"),
|
||||
ValidationError.of("direction", "direction est requis avec orderBy"));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertCanSearch(
|
||||
LinkSearching.@Nullable Field searchOn, Searching.@Nullable SearchValue keywords) {
|
||||
if (searchOn != null ^ keywords != null) {
|
||||
throw ValidationException.of(
|
||||
ValidationError.of("searchOn", "searchOn est requis avec keywords"),
|
||||
ValidationError.of("keywords", "keywords est requis avec searchOn"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package tech.pegase.z3.application.api.v1.link;
|
||||
|
||||
import io.vertx.core.eventbus.EventBus;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.time.ZonedDateTime;
|
||||
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.events.LinkRedirectedEvent;
|
||||
import tech.pegase.z3.application.presenter.link.ResolveLinkResponsePresenter;
|
||||
import tech.pegase.z3.application.request.link.RedirectLinkRequest;
|
||||
import tech.pegase.z3.domain.usecase.links.RedirectLink;
|
||||
import tech.pegase.z3.domain.usecase.links.RedirectLink.Input;
|
||||
import tech.pegase.z3.domain.usecase.links.RedirectLink.Output;
|
||||
import tech.pegase.z3.domain.valueobject.Fqdn;
|
||||
import tech.pegase.z3.shared.valueobject.Source;
|
||||
|
||||
@Path("/")
|
||||
public class RedirectLinkResource {
|
||||
private final Fqdn resolverFqdn;
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final RedirectLink redirectLink;
|
||||
private final ResolveLinkResponsePresenter redirectLinkResponsePresenter;
|
||||
private final EventBus eventBus;
|
||||
|
||||
public RedirectLinkResource(
|
||||
@ConfigProperty(name = "z3.export.resolver-fqdn") String resolverFqdn,
|
||||
UseCaseExecutor executor,
|
||||
RedirectLink useCase,
|
||||
ResolveLinkResponsePresenter presenter,
|
||||
EventBus eventBus) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.redirectLink = useCase;
|
||||
this.redirectLinkResponsePresenter = presenter;
|
||||
this.resolverFqdn = new Fqdn(resolverFqdn);
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{source: [a-zA-Z0-9/._~!$'()*+,;=:@-]+}")
|
||||
@PermitAll
|
||||
public Response redirect(
|
||||
@PathParam("source") Source source,
|
||||
@QueryParam("host") @Valid @Nullable Fqdn host,
|
||||
@Valid RedirectLinkRequest request) {
|
||||
|
||||
// * Use default Fqdn if none provided
|
||||
var actualHost = host != null ? host : resolverFqdn;
|
||||
|
||||
return useCaseExecutor
|
||||
.forUseCase(redirectLink)
|
||||
.withParameter(new Input.ResolveWith(resolverFqdn, actualHost, source))
|
||||
.withPresenter(
|
||||
new ResolveLinkResponsePresenter() {
|
||||
@Override
|
||||
public Response present(Output output) {
|
||||
var linkIsResolved = output instanceof Output.Found;
|
||||
|
||||
dispatchVisitedLink(source, linkIsResolved, request);
|
||||
|
||||
return redirectLinkResponsePresenter.present(output);
|
||||
}
|
||||
})
|
||||
.run();
|
||||
}
|
||||
|
||||
private void dispatchVisitedLink(
|
||||
Source source, Boolean linkIsResolved, RedirectLinkRequest request) {
|
||||
var ipAddress = request.getIpAddress();
|
||||
var doNotTrack = request.getDoNotTrack();
|
||||
var requestedAt = ZonedDateTime.now();
|
||||
var locale = request.getLocale();
|
||||
var referrerUri = request.getReferrerUri();
|
||||
var userAgent = request.getUserAgent();
|
||||
var screenProperties = request.getScreenProperties();
|
||||
var fingerprint = request.getFingerprint();
|
||||
|
||||
var eventPojo =
|
||||
new LinkRedirectedEvent(
|
||||
source,
|
||||
linkIsResolved,
|
||||
requestedAt,
|
||||
doNotTrack,
|
||||
ipAddress,
|
||||
locale,
|
||||
referrerUri,
|
||||
userAgent,
|
||||
fingerprint,
|
||||
screenProperties);
|
||||
|
||||
eventBus.publish("LinkRedirectedEvent", eventPojo);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package tech.pegase.z3.application.api.v1.link;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.PUT;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.presenter.link.UpdateLinkPresenter;
|
||||
import tech.pegase.z3.application.presenter.link.UpdateLinkPresenter.LinkDto;
|
||||
import tech.pegase.z3.application.request.link.UpdateLinkRequest;
|
||||
import tech.pegase.z3.domain.usecase.links.UpdateLink;
|
||||
import tech.pegase.z3.domain.usecase.links.UpdateLink.Input.ForSource;
|
||||
import tech.pegase.z3.shared.valueobject.Source;
|
||||
|
||||
@Path("/api/v1/links")
|
||||
@Authenticated
|
||||
public class UpdateLinkResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final UpdateLink updateLinkUseCase;
|
||||
private final UpdateLinkPresenter updateLinkPresenter;
|
||||
|
||||
@Inject
|
||||
UpdateLinkResource(UseCaseExecutor executor, UpdateLink useCase, UpdateLinkPresenter presenter) {
|
||||
useCaseExecutor = executor;
|
||||
updateLinkUseCase = useCase;
|
||||
updateLinkPresenter = presenter;
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/{source: [a-zA-Z0-9/._~!$'()*+,;=:@-]+}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public RestResponse<LinkDto> updateLink(
|
||||
@PathParam("source") Source source, @Valid UpdateLinkRequest request) {
|
||||
return useCaseExecutor
|
||||
.forUseCase(updateLinkUseCase)
|
||||
.withParameter(
|
||||
new ForSource(
|
||||
source,
|
||||
request.getTarget(),
|
||||
request.isExternal(),
|
||||
request.getTag(),
|
||||
request.getCatalog()))
|
||||
.withPresenter(updateLinkPresenter)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package tech.pegase.z3.application.api.v1.link;
|
||||
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.PUT;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.jboss.resteasy.reactive.RestResponse;
|
||||
import tech.pegase.happy.core.usecase.UseCaseExecutor;
|
||||
import tech.pegase.z3.application.presenter.link.VerifyLinkPresenter;
|
||||
import tech.pegase.z3.application.presenter.link.VerifyLinkPresenter.LinkValidityDto;
|
||||
import tech.pegase.z3.domain.usecase.links.VerifyLink;
|
||||
import tech.pegase.z3.domain.usecase.links.VerifyLink.Input;
|
||||
import tech.pegase.z3.shared.valueobject.Source;
|
||||
|
||||
@Path("/api/v1/links")
|
||||
@Authenticated
|
||||
public class VerifyLinkResource {
|
||||
private final UseCaseExecutor useCaseExecutor;
|
||||
private final VerifyLink verifyLink;
|
||||
private final VerifyLinkPresenter verifyLinkPresenter;
|
||||
|
||||
@Inject
|
||||
public VerifyLinkResource(
|
||||
UseCaseExecutor executor, VerifyLink useCase, VerifyLinkPresenter presenter) {
|
||||
this.useCaseExecutor = executor;
|
||||
this.verifyLink = useCase;
|
||||
this.verifyLinkPresenter = presenter;
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/{source: [a-zA-Z0-9/._~!$'()*+,;=:@-]+}/verify")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
/* Ici source correspond à la partie path + query + anchor d'une URL sur un QR code. */
|
||||
public RestResponse<LinkValidityDto> verifyLinkValidity(@PathParam("source") Source source) {
|
||||
return useCaseExecutor
|
||||
.forUseCase(verifyLink)
|
||||
.withParameter(new Input.Verify(source))
|
||||
.withPresenter(verifyLinkPresenter)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
@NullMarked
|
||||
package tech.pegase.z3.application.api.v1.link;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue